=== modified file 'lava_scheduler_app/models.py'
--- lava_scheduler_app/models.py	2011-10-19 20:45:42 +0000
+++ lava_scheduler_app/models.py	2011-10-28 00:24:13 +0000
@@ -57,6 +57,25 @@
         verbose_name = _(u"Device status"),
     )
 
+    def __unicode__(self):
+        return self.hostname
+
+    @models.permalink
+    def get_absolute_url(self):
+        return ("lava.scheduler.device.detail", [self.pk])
+
+    def recent_jobs(self):
+        return TestJob.objects.select_related(
+            "actual_device",
+            "requested_device",
+            "requested_device_type",
+            "submitter",
+        ).filter(
+            actual_device=self
+        ).order_by(
+            '-start_time'
+        )
+
     def can_admin(self, user):
         return user.has_perm('lava_scheduler_app.change_device')
 
@@ -71,9 +90,6 @@
         self.status = self.IDLE
         self.save()
 
-    def __unicode__(self):
-        return self.hostname
-
     #@classmethod
     #def find_devices_by_type(cls, device_type):
     #    return device_type.device_set.all()
@@ -169,6 +185,10 @@
             r += " for %s" % (self.requested_device.hostname,)
         return r
 
+    @models.permalink
+    def get_absolute_url(self):
+        return ("lava.scheduler.job.detail", [self.pk])
+
     @classmethod
     def from_json_and_user(cls, json_data, user):
         job_data = simplejson.loads(json_data)

=== modified file 'lava_scheduler_app/templates/lava_scheduler_app/_content.html'
--- lava_scheduler_app/templates/lava_scheduler_app/_content.html	2011-08-01 16:15:44 +0000
+++ lava_scheduler_app/templates/lava_scheduler_app/_content.html	2011-10-28 00:24:13 +0000
@@ -23,9 +23,3 @@
 };
 </script>
 {% endblock %}
-
-
-{% block breadcrumbs %}
-{{ block.super }}
-<li><a href="{% url lava_scheduler_app.views.index %}">Scheduler</a></li>
-{% endblock %}

=== modified file 'lava_scheduler_app/templates/lava_scheduler_app/alljobs.html'
--- lava_scheduler_app/templates/lava_scheduler_app/alljobs.html	2011-10-11 04:17:40 +0000
+++ lava_scheduler_app/templates/lava_scheduler_app/alljobs.html	2011-10-28 00:24:13 +0000
@@ -1,10 +1,5 @@
 {% extends "lava_scheduler_app/_content.html" %}
 
-{% block breadcrumbs %}
-{{ block.super }}
-<li><a href="{% url lava_scheduler_app.views.alljobs %}">All Jobs</a></li>
-{% endblock %}
-
 
 {% block content %}
 <h2>All Jobs</h2>
@@ -23,14 +18,14 @@
   <tbody>
     {% for job in jobs %}
     <tr>
-      <td><a href="{% url lava_scheduler_app.views.job pk=job.pk %}">{{ job.id }}</a></td>
+      <td><a href="{{ job.get_absolute_url }}">{{ job.id }}</a></td>
       <td>{{ job.get_status_display }}</td>
-      {% if job.actual_device.pk %}
-      <td><a href="{% url lava_scheduler_app.views.device pk=job.actual_device.pk %}">
-          {{ job.actual_device }}</a></td>
-      {% else %}{% if job.requested_device.pk %}
-      <td><a href="{% url lava_scheduler_app.views.device pk=job.requested_device.pk %}">
-          <i>{{ job.requested_device }}</i></a></td>
+      {% if job.actual_device %}
+      <td><a href="{{ job.actual_device.get_absolute_url }}"
+          >{{ job.actual_device }}</a></td>
+      {% else %}{% if job.requested_device %}
+      <td><a href="{{ job.requested_device.get_absolute_url }}"
+          ><i>{{ job.requested_device }}</i></a></td>
       {% else %}
       <td><i>{{ job.requested_device_type|default:'' }}</i></td>
       {% endif %}{% endif %}

=== modified file 'lava_scheduler_app/templates/lava_scheduler_app/device.html'
--- lava_scheduler_app/templates/lava_scheduler_app/device.html	2011-08-22 05:20:36 +0000
+++ lava_scheduler_app/templates/lava_scheduler_app/device.html	2011-10-28 00:24:13 +0000
@@ -13,18 +13,18 @@
 {% endblock %}
 
 {% block content %}
-<h2>Device {{ device.hostname }}</h2>
+<h2>Device {{ device }}</h2>
 
 {% if show_maintenance %}
 <form style="display:inline; float:right" method="POST"
-      action="{% url lava_scheduler_app.views.device_maintenance_mode device.pk %}">
+      action="{% url lava.scheduler.device.maintenance device.pk %}">
   {% csrf_token %}
   <button id="maintenance-button">Put into maintenance mode</button>
 </form>
 {% endif %}
 {% if show_online %}
 <form style="display:inline; float:right" method="POST"
-      action="{% url lava_scheduler_app.views.device_online device.pk %}">
+      action="{% url lava.scheduler.device.online device.pk %}">
   {% csrf_token %}
   <button id="online-button">Put online</button>
 </form>
@@ -41,15 +41,11 @@
   <div class="column">
     <dt>Status:</dt>
     <dd>{{ device.get_status_display }}</dd>
-
-{% if device.current_job %}
+    {% if device.current_job %}
     <dt>Currently running:</dt>
-    <dd>
-      <a href="{% url lava_scheduler_app.views.job pk=device.current_job.pk %}">
-        Job {{ device.current_job.id }}
-      </a>
-    </dd>
-{% endif %}
+    <dd><a href="{{ device.current_job.get_absolute_url }}"
+      >Job {{ device.current_job }}</a></dd>
+    {% endif %}
   </div>
   <div style="clear: both"></div>
 </div>
@@ -66,9 +62,9 @@
     </tr>
   </thead>
   <tbody>
-    {% for job in recent_jobs %}
+    {% for job in recent_job_list %}
     <tr>
-      <td><a href="{% url lava_scheduler_app.views.job pk=job.pk %}">{{ job.id }}</a></td>
+      <td><a href="{{ job.get_absolute_url }}">{{ job.id }}</a></td>
       <td>{{ job.get_status_display }}</td>
       <td>{{ job.actual_device|default:'' }}</td>
       <td>{{ job.submitter }}</td>

=== modified file 'lava_scheduler_app/templates/lava_scheduler_app/index.html'
--- lava_scheduler_app/templates/lava_scheduler_app/index.html	2011-10-11 04:17:40 +0000
+++ lava_scheduler_app/templates/lava_scheduler_app/index.html	2011-10-28 00:24:13 +0000
@@ -15,9 +15,7 @@
     {% for device in devices %}
     <tr>
       <td>
-        <a href="{% url lava_scheduler_app.views.device pk=device.pk %}">
-          {{ device.hostname }}
-        </a>
+        <a href="{{ device.get_absolute_url }}">{{ device.hostname }}</a>
       </td>
       <td>{{ device.device_type }}</td>
       <td>{{ device.get_status_display }}</td>
@@ -42,14 +40,14 @@
   <tbody>
     {% for job in jobs %}
     <tr>
-      <td><a href="{% url lava_scheduler_app.views.job pk=job.pk %}">{{ job.id }}</a></td>
+      <td><a href="{{ job.get_absolute_url }}">{{ job.id }}</a></td>
       <td>{{ job.get_status_display }}</td>
-      {% if job.actual_device.pk %}
-      <td><a href="{% url lava_scheduler_app.views.device pk=job.actual_device.pk %}">
-          {{ job.actual_device }}</a></td>
-      {% else %}{% if job.requested_device.pk %}
-      <td><a href="{% url lava_scheduler_app.views.device pk=job.requested_device.pk %}">
-          <i>{{ job.requested_device }}</i></a></td>
+      {% if job.actual_device %}
+      <td><a href="{{ job.actual_device.get_absolute_url }}"
+          >{{ job.actual_device }}</a></td>
+      {% else %}{% if job.requested_device %}
+      <td><a href="{{ job.requested_device.get_absolute_url }}"
+          ><i>{{ job.requested_device }}</i></a></td>
       {% else %}
       <td><i>{{ job.requested_device_type|default:'' }}</i></td>
       {% endif %}{% endif %}
@@ -61,7 +59,7 @@
   </tbody>
 </table>
 
-<a href="{% url lava_scheduler_app.views.alljobs %}">All jobs</a>
+<a href="{% url lava.scheduler.job.list %}">All jobs</a>
 
 <script>
 $(document).ready(

=== modified file 'lava_scheduler_app/templates/lava_scheduler_app/job.html'
--- lava_scheduler_app/templates/lava_scheduler_app/job.html	2011-10-06 03:06:09 +0000
+++ lava_scheduler_app/templates/lava_scheduler_app/job.html	2011-10-28 00:24:13 +0000
@@ -24,7 +24,7 @@
 
 {% if show_cancel %}
 <form style="display:inline; float:right" method="POST" 
-      action="{% url lava_scheduler_app.views.job_cancel job.pk %}">
+      action="{% url lava.scheduler.job.cancel job.pk %}">
   {% csrf_token %}
   <button id="cancel-button">Cancel</button>
 </form>

=== modified file 'lava_scheduler_app/urls.py'
--- lava_scheduler_app/urls.py	2011-08-23 04:04:17 +0000
+++ lava_scheduler_app/urls.py	2011-10-28 00:24:13 +0000
@@ -2,13 +2,30 @@
 
 urlpatterns = patterns(
     'lava_scheduler_app.views',
-    url(r'^$', 'index'),
-    url(r'^alljobs$', 'alljobs'),
-    url(r'^device/(?P<pk>[-_a-zA-Z0-9]+)$', 'device'),
-    url(r'^device/(?P<pk>[-_a-zA-Z0-9]+)/maintenance$', 'device_maintenance_mode'),
-    url(r'^device/(?P<pk>[-_a-zA-Z0-9]+)/online$', 'device_online'),
-    url(r'^job/(?P<pk>[0-9]+)$', 'job'),
-    url(r'^job/(?P<pk>[0-9]+)/cancel$', 'job_cancel'),
-    url(r'^job/(?P<pk>[0-9]+)/json$', 'job_json'),
-    url(r'^job/(?P<pk>[0-9]+)/output$', 'job_output'),
-    )
+    url(r'^$', 
+        'index',
+        name='lava.scheduler'),
+    url(r'^alljobs$', 
+        'job_list', 
+        name='lava.scheduler.job.list'),
+    url(r'^device/(?P<pk>[-_a-zA-Z0-9]+)$', 
+        'device_detail', 
+        name='lava.scheduler.device.detail'),
+    url(r'^device/(?P<pk>[-_a-zA-Z0-9]+)/maintenance$', 
+        'device_maintenance_mode', 
+        name='lava.scheduler.device.maintenance'),
+    url(r'^device/(?P<pk>[-_a-zA-Z0-9]+)/online$',
+        'device_online',
+        name='lava.scheduler.device.online'),
+    url(r'^job/(?P<pk>[0-9]+)$',
+        'job_detail',
+        name='lava.scheduler.job.detail'),
+    url(r'^job/(?P<pk>[0-9]+)/cancel$',
+        'job_cancel',
+        name='lava.scheduler.job.cancel'),
+    url(r'^job/(?P<pk>[0-9]+)/json$',
+        'job_json', 
+        name='lava.scheduler.job.json'),
+    url(r'^job/(?P<pk>[0-9]+)/output$',
+        'job_output',
+        name='lava.scheduler.job.output'))

=== modified file 'lava_scheduler_app/views.py'
--- lava_scheduler_app/views.py	2011-10-13 22:58:01 +0000
+++ lava_scheduler_app/views.py	2011-10-28 00:24:13 +0000
@@ -11,9 +11,14 @@
     get_object_or_404,
     redirect,
     render_to_response,
-    )
+)
 
 from lava_scheduler_app.models import Device, TestJob
+from lava_server.views import index as lava_index
+from lava_server.bread_crumbs import (
+    BreadCrumb,
+    BreadCrumbTrail,
+)
 
 
 def post_only(func):
@@ -24,6 +29,7 @@
     return decorated
 
 
+@BreadCrumb("Scheduler", parent=lava_index)
 def index(request):
     return render_to_response(
         "lava_scheduler_app/index.html",
@@ -33,29 +39,34 @@
                 "actual_device", "requested_device", "requested_device_type",
                 "submitter").filter(status__in=[
                 TestJob.SUBMITTED, TestJob.RUNNING]),
+            'bread_crumb_trail': BreadCrumbTrail.leading_to(index),
         },
         RequestContext(request))
 
 
-def alljobs(request):
+@BreadCrumb("All Jobs", parent=index)
+def job_list(request):
     return render_to_response(
         "lava_scheduler_app/alljobs.html",
         {
             'jobs': TestJob.objects.select_related(
                 "actual_device", "requested_device", "requested_device_type",
                 "submitter").all(),
+            'bread_crumb_trail': BreadCrumbTrail.leading_to(job_list),
         },
         RequestContext(request))
 
 
-def job(request, pk):
-    job = TestJob.objects.get(pk=pk)
+@BreadCrumb("Job #{pk}", parent=index, needs=['pk'])
+def job_detail(request, pk):
+    job = get_object_or_404(TestJob, pk=pk)
     return render_to_response(
         "lava_scheduler_app/job.html",
         {
             'log_file_present': bool(job.log_file),
             'job': TestJob.objects.get(pk=pk),
             'show_cancel': job.status <= TestJob.RUNNING and job.can_cancel(request.user),
+            'bread_crumb_trail': BreadCrumbTrail.leading_to(job_detail, pk=pk),
         },
         RequestContext(request))
 
@@ -67,7 +78,7 @@
 def job_output(request, pk):
     start = int(request.GET.get('start', 0))
     count_present = 'count' in request.GET
-    job = TestJob.objects.get(pk=pk)
+    job = get_object_or_404(TestJob, pk=pk)
     log_file = job.log_file
     log_file.seek(0, os.SEEK_END)
     size = int(request.GET.get('count', log_file.tell()))
@@ -96,10 +107,10 @@
 
 @post_only
 def job_cancel(request, pk):
-    job = TestJob.objects.get(pk=pk)
+    job = get_object_or_404(TestJob, pk=pk)
     if job.can_cancel(request.user):
         job.cancel()
-        return redirect('lava_scheduler_app.views.job', pk=job.pk)
+        return redirect(job)
     else:
         return HttpResponseForbidden(
             "you cannot cancel this job", content_type="text/plain")
@@ -118,21 +129,19 @@
     return HttpResponse(json_text, content_type=content_type)
 
 
-def device(request, pk):
-    device = Device.objects.get(pk=pk)
-    recent_jobs = TestJob.objects.select_related(
-                "actual_device", "requested_device", "requested_device_type",
-                "submitter").filter(
-        actual_device=device).order_by('-start_time')
+@BreadCrumb("Device {pk}", parent=index, needs=['pk'])
+def device_detail(request, pk):
+    device = get_object_or_404(Device, pk=pk)
     return render_to_response(
         "lava_scheduler_app/device.html",
         {
             'device': device,
-            'recent_jobs': recent_jobs,
+            'recent_job_list': device.recent_jobs,
             'show_maintenance': device.can_admin(request.user) and \
                 device.status in [Device.IDLE, Device.RUNNING],
             'show_online': device.can_admin(request.user) and \
                 device.status in [Device.OFFLINE, Device.OFFLINING],
+            'bread_crumb_trail': BreadCrumbTrail.leading_to(device_detail, pk=pk),
         },
         RequestContext(request))
 
@@ -142,7 +151,7 @@
     device = Device.objects.get(pk=pk)
     if device.can_admin(request.user):
         device.put_into_maintenance_mode()
-        return redirect('lava_scheduler_app.views.device', pk=device.pk)
+        return redirect(device)
     else:
         return HttpResponseForbidden(
             "you cannot administer this device", content_type="text/plain")
@@ -153,7 +162,7 @@
     device = Device.objects.get(pk=pk)
     if device.can_admin(request.user):
         device.put_into_online_mode()
-        return redirect('lava_scheduler_app.views.device', pk=device.pk)
+        return redirect(device)
     else:
         return HttpResponseForbidden(
             "you cannot administer this device", content_type="text/plain")

