Index: django/contrib/admin/templatetags/adminapplist.py
===================================================================
--- django/contrib/admin/templatetags/adminapplist.py	(revision 3534)
+++ django/contrib/admin/templatetags/adminapplist.py	(working copy)
@@ -1,58 +1,58 @@
 from django import template
-from django.db.models import get_models
+from django.db import models
+from django.utils.text import capfirst
 
 register = template.Library()
 
+def get_app_label(app):
+    """
+    Get the app_label of a given app. This is pretty hackish.
+    """
+    app_models = models.get_models(app)
+    return app_models[0]._meta.app_label
+
+def get_admin_app_models(app, user):
+    model_list = []
+    app_label = get_app_label(app)
+    for m in models.get_models(app):
+        if m._meta.admin:
+            perms = {
+                'add': user.has_perm("%s.%s" % (app_label, m._meta.get_add_permission())),
+                'change': user.has_perm("%s.%s" % (app_label, m._meta.get_change_permission())),
+                'delete': user.has_perm("%s.%s" % (app_label, m._meta.get_delete_permission())),
+            }
+            # Check whether user has any perm for this model.
+            # If so, add the module to the model_list.
+            if True in perms.values():
+                model_list.append({
+                    'name': capfirst(m._meta.verbose_name_plural),
+                    'admin_url': '%s/%s/' % (app_label, m.__name__.lower()),
+                    'perms': perms,
+                })
+    return model_list
+
+def sorted_model_list(model_list):
+    # Sort using verbose decorate-sort-undecorate pattern
+    # instead of key argument to sort() for python 2.3 compatibility
+    decorated = [(x['name'], x) for x in model_list]
+    decorated.sort()
+    return [x for key, x in decorated]
+
 class AdminApplistNode(template.Node):
     def __init__(self, varname):
         self.varname = varname
 
     def render(self, context):
-        from django.db import models
-        from django.utils.text import capfirst
         app_list = []
         user = context['user']
 
         for app in models.get_apps():
-            # Determine the app_label.
-            app_models = get_models(app)
-            if not app_models:
-                continue
-            app_label = app_models[0]._meta.app_label
-
-            has_module_perms = user.has_module_perms(app_label)
-
-            if has_module_perms:
-                model_list = []
-                for m in app_models:
-                    if m._meta.admin:
-                        perms = {
-                            'add': user.has_perm("%s.%s" % (app_label, m._meta.get_add_permission())),
-                            'change': user.has_perm("%s.%s" % (app_label, m._meta.get_change_permission())),
-                            'delete': user.has_perm("%s.%s" % (app_label, m._meta.get_delete_permission())),
-                        }
-
-                        # Check whether user has any perm for this module.
-                        # If so, add the module to the model_list.
-                        if True in perms.values():
-                            model_list.append({
-                                'name': capfirst(m._meta.verbose_name_plural),
-                                'admin_url': '%s/%s/' % (app_label, m.__name__.lower()),
-                                'perms': perms,
-                            })
-
-                if model_list:
-                    # Sort using verbose decorate-sort-undecorate pattern
-                    # instead of key argument to sort() for python 2.3 compatibility
-                    decorated = [(x['name'], x) for x in model_list]
-                    decorated.sort()
-                    model_list = [x for key, x in decorated]
-
-                    app_list.append({
-                        'name': app_label.title(),
-                        'has_module_perms': has_module_perms,
-                        'models': model_list,
-                    })
+            model_list = get_admin_app_models(app, user)
+            if model_list:
+                app_list.append({
+                    'name': get_app_label(app).title(),
+                    'models': sorted_model_list(model_list),
+                })
         context[self.varname] = app_list
         return ''
 
@@ -77,3 +77,45 @@
     return AdminApplistNode(tokens[2])
 
 register.tag('get_admin_app_list', get_admin_app_list)
+
+class AdminAppNode(template.Node):
+    def __init__(self, app_label_varname, varname):
+        self.app_label_varname = app_label_varname
+        self.varname = varname
+
+    def render(self, context):
+        user = context['user']
+
+        app_label = context[self.app_label_varname]
+        app = models.get_app(app_label)
+
+        if user.has_module_perms(app_label):
+            model_list = get_admin_app_models(app, user)
+
+        context[self.varname] = {
+            'name': app_label.title(),
+            'models': sorted_model_list(model_list),
+        }
+        return ''
+
+def get_admin_app(parser, token):
+    """
+    Returns an installed application if the current user has at least one 
+    permission for one of the application's models.
+
+    Syntax::
+    
+        {% get_admin_app [context_var_containing_app_label] as [context_var_containing_app] %}
+
+    Example usage::
+
+        {% get_admin_app app_label as admin_app %}
+    """
+    tokens = token.contents.split()
+    if len(tokens) < 4:
+        raise template.TemplateSyntaxError, "'%s' tag requires three arguments" % tokens[0]
+    if tokens[2] != 'as':
+        raise template.TemplateSyntaxError, "Second argument to '%s' tag must be 'as'" % tokens[0]
+    return AdminAppNode(tokens[1], tokens[3])
+
+register.tag('get_admin_app', get_admin_app)
Index: django/contrib/admin/urls.py
===================================================================
--- django/contrib/admin/urls.py	(revision 3534)
+++ django/contrib/admin/urls.py	(working copy)
@@ -31,6 +31,9 @@
     # "Add user" -- a special-case view
     ('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'),
 
+    # App index
+    ('^([^/]+)/$', 'django.contrib.admin.views.main.app_index'),
+
     # Add/change/delete/history
     ('^([^/]+)/([^/]+)/$', 'django.contrib.admin.views.main.change_list'),
     ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),
Index: django/contrib/admin/views/auth.py
===================================================================
--- django/contrib/admin/views/auth.py	(revision 3534)
+++ django/contrib/admin/views/auth.py	(working copy)
@@ -36,4 +36,5 @@
         'first_form_field_id': 'id_username',
         'opts': User._meta,
         'username_help_text': User._meta.get_field('username').help_text,
+        'app_label': 'auth'
     }, context_instance=template.RequestContext(request))
Index: django/contrib/admin/views/main.py
===================================================================
--- django/contrib/admin/views/main.py	(revision 3534)
+++ django/contrib/admin/views/main.py	(working copy)
@@ -223,6 +223,17 @@
     return render_to_response('admin/index.html', {'title': _('Site administration')}, context_instance=template.RequestContext(request))
 index = staff_member_required(never_cache(index))
 
+def app_index(request, app_label):
+    ctx = template.RequestContext(request)
+    extra_ctx = {
+        'title': capfirst(app_label),
+        'app_label': app_label,
+    }
+    return render_to_response(('admin/%s/app_index.html' % app_label,
+                               'admin/app_index.html',), extra_ctx, ctx)
+                               
+app_index = staff_member_required(never_cache(app_index))
+
 def add_stage(request, app_label, model_name, show_delete=False, form_url='', post_url=None, post_url_continue='../%s/', object_id_override=None):
     model = models.get_model(app_label, model_name)
     if model is None:
@@ -288,6 +299,7 @@
         'form': form,
         'is_popup': request.REQUEST.has_key('_popup'),
         'show_delete': show_delete,
+        'app_label': app_label
     })
 
     if object_id_override is not None:
@@ -391,6 +403,7 @@
         'object_id': object_id,
         'original': manipulator.original_object,
         'is_popup': request.REQUEST.has_key('_popup'),
+        'app_label': app_label,
     })
     return render_change_form(model, manipulator, c, change=True)
 change_stage = staff_member_required(never_cache(change_stage))
@@ -515,6 +528,7 @@
         "deleted_objects": deleted_objects,
         "perms_lacking": perms_needed,
         "opts": model._meta,
+        'app_label': app_label,
     }
     return render_to_response(["admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower() ),
                                "admin/%s/delete_confirmation.html" % app_label ,
@@ -535,6 +549,7 @@
         'action_list': action_list,
         'module_name': capfirst(model._meta.verbose_name_plural),
         'object': obj,
+        'app_label': app_label,
     }
     return render_to_response(["admin/%s/%s/object_history.html" % (app_label, model._meta.object_name.lower()),
                                "admin/%s/object_history.html" % app_label ,
@@ -747,6 +762,7 @@
         'title': cl.title,
         'is_popup': cl.is_popup,
         'cl': cl,
+        'app_label': app_label,
     })
     c.update({'has_add_permission': c['perms'][app_label][cl.opts.get_add_permission()]}),
     return render_to_response(['admin/%s/%s/change_list.html' % (app_label, cl.opts.object_name.lower()),
Index: django/contrib/admin/templates/admin/change_list.html
===================================================================
--- django/contrib/admin/templates/admin/change_list.html	(revision 3534)
+++ django/contrib/admin/templates/admin/change_list.html	(working copy)
@@ -3,7 +3,7 @@
 {% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %}
 {% block bodyclass %}change-list{% endblock %}
 {% block userlinks %}<a href="../../doc/">{% trans 'Documentation' %}</a> / <a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
-{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; {{ cl.opts.verbose_name_plural|capfirst|escape }}</div>{% endblock %}{% endif %}
+{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; <a href="../">{{ app_label|capfirst }}</a> &rsaquo; {{ cl.opts.verbose_name_plural|capfirst|escape }}</div>{% endblock %}{% endif %}
 {% block coltype %}flex{% endblock %}
 {% block content %}
 <div id="content-main">
Index: django/contrib/admin/templates/admin/object_history.html
===================================================================
--- django/contrib/admin/templates/admin/object_history.html	(revision 3534)
+++ django/contrib/admin/templates/admin/object_history.html	(working copy)
@@ -2,7 +2,7 @@
 {% load i18n %}
 {% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
 {% block breadcrumbs %}
-<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name|escape }}</a> &rsaquo; <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
+<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../../">{{ app_label|capfirst }}</a> &rsaquo; <a href="../../">{{ module_name|escape }}</a> &rsaquo; <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
 {% endblock %}
 
 {% block content %}
Index: django/contrib/admin/templates/admin/app_index.html
===================================================================
--- django/contrib/admin/templates/admin/app_index.html	(revision 0)
+++ django/contrib/admin/templates/admin/app_index.html	(revision 0)
@@ -0,0 +1,65 @@
+{% extends "admin/index.html" %}
+{% load i18n %}
+{% load adminapplist %}
+
+{% block userlinks %}<a href="../doc/">{% trans 'Documentation' %}</a> / <a href="../password_change/">{% trans 'Change password' %}</a> / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+     <a href="../">{% trans "Home" %}</a> &rsaquo;
+     {{ app_label|capfirst }}
+</div>
+{% endif %}{% endblock %}
+{% block content %}
+<div id="content-main">
+
+{% get_admin_app app_label as app %}
+
+<div class="module">
+    <table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}">
+    <caption>{{ app.name }}</caption>
+    {% for model in app.models %}
+        <tr>
+        {% if model.perms.change %}
+            <th scope="row"><a href="../{{ model.admin_url }}">{{ model.name }}</a></th>
+        {% else %}
+            <th scope="row">{{ model.name }}</th>
+        {% endif %}
+
+        {% if model.perms.add %}
+            <td><a href="../{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
+        {% else %}
+            <td>&nbsp;</td>
+        {% endif %}
+
+        {% if model.perms.change %}
+            <td><a href="../{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
+        {% else %}
+            <td>&nbsp;</td>
+        {% endif %}
+        </tr>
+    {% endfor %}
+    </table>
+</div>
+
+</div>
+{% endblock %}
+
+{% block sidebar %}
+<div id="content-related">
+    <div class="module" id="recent-actions-module">
+        <h2>{% trans 'Recent Actions' %}</h2>
+        <h3>{% trans 'My Actions' %}</h3>
+            {% load log %}
+            {% get_admin_log 10 as admin_log for_user user %}
+            {% if not admin_log %}
+            <p>{% trans 'None available' %}</p>
+            {% else %}
+            <ul class="actionlist">
+            {% for entry in admin_log %}
+                <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="../{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst|escape }}</span></li>
+            {% endfor %}
+            </ul>
+            {% endif %}
+    </div>
+</div>
+{% endblock %}
Index: django/contrib/admin/templates/admin/change_form.html
===================================================================
--- django/contrib/admin/templates/admin/change_form.html	(revision 3534)
+++ django/contrib/admin/templates/admin/change_form.html	(working copy)
@@ -11,6 +11,7 @@
 {% block breadcrumbs %}{% if not is_popup %}
 <div class="breadcrumbs">
      <a href="../../../">{% trans "Home" %}</a> &rsaquo;
+     <a href="../../">{{ app_label|capfirst }}</a> &rsaquo;
      <a href="../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
      {% if add %}{% trans "Add" %} {{ opts.verbose_name|escape }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %}
 </div>
Index: django/contrib/admin/templates/admin/delete_confirmation.html
===================================================================
--- django/contrib/admin/templates/admin/delete_confirmation.html	(revision 3534)
+++ django/contrib/admin/templates/admin/delete_confirmation.html	(working copy)
@@ -4,6 +4,7 @@
 {% block breadcrumbs %}
 <div class="breadcrumbs">
      <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
+     <a href="../../../">{{ app_label|capfirst }}</a> &rsaquo;
      <a href="../../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
      <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo;
      {% trans 'Delete' %}
