Revert "Revert "Update dashboard for apps (bug 693855)""
This reverts commit 8f2b7c17de
.
Conflicts:
apps/amo/context_processors.py
apps/amo/tests/test_views.py
media/css/impala/site.less
This commit is contained in:
Родитель
c3475184a4
Коммит
57923a6b35
|
@ -74,6 +74,9 @@ def global_settings(request):
|
|||
'href': reverse('devhub.submit.1')})
|
||||
|
||||
if waffle.flag_is_active(request, 'accept-webapps'):
|
||||
if request.amo_user.is_developer:
|
||||
tools_links.append({'text': _('Manage My Apps'),
|
||||
'href': reverse('devhub.apps')})
|
||||
tools_links.append({'text': _('Submit a New App'),
|
||||
'href': reverse('devhub.submit_apps.1')})
|
||||
|
||||
|
|
|
@ -116,8 +116,7 @@ class TestCommon(amo.tests.TestCase):
|
|||
('Tools', '#'),
|
||||
('Manage My Add-ons', reverse('devhub.addons')),
|
||||
('Submit a New Add-on', reverse('devhub.submit.1')),
|
||||
# TODO(robhudson): Uncomment this when the apps dashboard is live.
|
||||
#('Manage My Apps', reverse('devhub.apps')),
|
||||
('Manage My Apps', reverse('devhub.apps')),
|
||||
('Submit a New App', reverse('devhub.submit_apps.1')),
|
||||
('Developer Hub', reverse('devhub.index')),
|
||||
]
|
||||
|
@ -154,8 +153,7 @@ class TestCommon(amo.tests.TestCase):
|
|||
('Tools', '#'),
|
||||
('Manage My Add-ons', reverse('devhub.addons')),
|
||||
('Submit a New Add-on', reverse('devhub.submit.1')),
|
||||
# TODO(robhudson): Uncomment this when the apps dashboard is live.
|
||||
#('Manage My Apps', reverse('devhub.apps')),
|
||||
('Manage My Apps', reverse('devhub.apps')),
|
||||
('Submit a New App', reverse('devhub.submit_apps.1')),
|
||||
('Developer Hub', reverse('devhub.index')),
|
||||
('Editor Tools', reverse('editors.home')),
|
||||
|
@ -199,8 +197,7 @@ class TestCommon(amo.tests.TestCase):
|
|||
('Tools', '#'),
|
||||
('Manage My Add-ons', reverse('devhub.addons')),
|
||||
('Submit a New Add-on', reverse('devhub.submit.1')),
|
||||
# TODO(robhudson): Uncomment this when the apps dashboard is live.
|
||||
#('Manage My Apps', reverse('devhub.apps')),
|
||||
('Manage My Apps', reverse('devhub.apps')),
|
||||
('Submit a New App', reverse('devhub.submit_apps.1')),
|
||||
('Developer Hub', reverse('devhub.index')),
|
||||
('Editor Tools', reverse('editors.home')),
|
||||
|
|
|
@ -9,7 +9,7 @@ from tower import ugettext as _, ungettext as ngettext
|
|||
|
||||
import amo
|
||||
from amo.urlresolvers import reverse
|
||||
from amo.helpers import breadcrumbs, page_title
|
||||
from amo.helpers import breadcrumbs, impala_breadcrumbs, page_title
|
||||
from access import acl
|
||||
from addons.helpers import new_context
|
||||
|
||||
|
@ -46,7 +46,8 @@ def docs_page_title(context, title=None):
|
|||
|
||||
@register.function
|
||||
@jinja2.contextfunction
|
||||
def dev_breadcrumbs(context, addon=None, items=None, add_default=False):
|
||||
def dev_breadcrumbs(context, addon=None, items=None, add_default=False,
|
||||
impala=False):
|
||||
"""
|
||||
Wrapper function for ``breadcrumbs``. Prepends 'Developer Hub'
|
||||
breadcrumbs.
|
||||
|
@ -58,10 +59,12 @@ def dev_breadcrumbs(context, addon=None, items=None, add_default=False):
|
|||
specified then the Add-on will be linked.
|
||||
**add_default**
|
||||
Prepends trail back to home when True. Default is False.
|
||||
**impala**
|
||||
Whether to use the impala_breadcrumbs helper. Default is False.
|
||||
"""
|
||||
crumbs = [(reverse('devhub.index'), _('Developer Hub'))]
|
||||
|
||||
if context.get('WEBAPPS'):
|
||||
if context.get('webapp'):
|
||||
title = _('My Apps')
|
||||
else:
|
||||
title = _('My Add-ons')
|
||||
|
@ -80,7 +83,10 @@ def dev_breadcrumbs(context, addon=None, items=None, add_default=False):
|
|||
crumbs.append((url, addon.name))
|
||||
if items:
|
||||
crumbs.extend(items)
|
||||
return breadcrumbs(context, crumbs, add_default)
|
||||
if impala:
|
||||
return impala_breadcrumbs(context, crumbs, add_default)
|
||||
else:
|
||||
return breadcrumbs(context, crumbs, add_default)
|
||||
|
||||
|
||||
@register.function
|
||||
|
|
|
@ -1,62 +1,71 @@
|
|||
{% extends "devhub/base.html" %}
|
||||
{% extends "devhub/base_impala.html" %}
|
||||
|
||||
{% block bodyclass %}{{ super() }} inverse{% endblock %}
|
||||
{% if webapp %}
|
||||
{% set title = _('Manage My Apps') %}
|
||||
{% else %}
|
||||
{% set title = _('Manage My Add-ons') %}
|
||||
{% endif %}
|
||||
|
||||
{% block title %}{{ dev_page_title(_('Manage My Add-ons')) }}{% endblock %}
|
||||
{% block title %}{{ dev_page_title(title) }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header>
|
||||
{{ dev_breadcrumbs() }}
|
||||
<hgroup>
|
||||
<h2>{{ _('Manage My Add-ons') }}</h2>
|
||||
<section class="primary">
|
||||
<header class="hero">
|
||||
{{ dev_breadcrumbs(impala=True) }}
|
||||
<h1>{{ title }}</h1>
|
||||
{% if addons %}
|
||||
{% set cnt = addons.paginator.count %}
|
||||
{% if webapp %}
|
||||
{# L10n: {0} is an integer. #}
|
||||
<h2>{{ ngettext('<b>{0}</b> app', '<b>{0}</b> apps', cnt)|f(cnt|numberfmt)|safe }}</h2>
|
||||
{% else %}
|
||||
{# L10n: {0} is an integer. #}
|
||||
<h2>{{ ngettext('<b>{0}</b> add-on', '<b>{0}</b> add-ons', cnt)|f(cnt|numberfmt)|safe }}</h2>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</header>
|
||||
</section>
|
||||
|
||||
{% if addons %}
|
||||
{% set cnt = addons.paginator.count %}
|
||||
{# L10n: {0} is an integer. #}
|
||||
<h3>{{ ngettext('<b>{0}</b> add-on', '<b>{0}</b> add-ons',cnt)|f(cnt|numberfmt)|safe }}</h3>
|
||||
{% endif %}
|
||||
</hgroup>
|
||||
</header>
|
||||
|
||||
{% if not addons %}
|
||||
<div class="action-needed">
|
||||
<h3>{{ _('Welcome to the Developer Dashboard') }}</h3>
|
||||
<p>
|
||||
{% trans %}
|
||||
You don't currently have any add-ons hosted on Mozilla Add-ons. To learn
|
||||
how the process works and submit your first add-on, click Get Started
|
||||
below.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
<p class="button-wrapper">
|
||||
<a href="{{ url('devhub.submit.1') }}"
|
||||
class="action-button rounded">{{ _('Get Started') }}</a>
|
||||
</p>
|
||||
{% if webapp %}
|
||||
<p>
|
||||
{% trans %}
|
||||
You don't currently have any apps hosted on Mozilla Marketplace. To
|
||||
learn how the process works and submit your first app, click Get
|
||||
Started below.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
<p class="button-wrapper">
|
||||
<a href="{{ url('devhub.submit_apps.1') }}"
|
||||
class="action-button rounded">{{ _('Get Started') }}</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
{% trans %}
|
||||
You don't currently have any add-ons hosted on Mozilla Add-ons. To learn
|
||||
how the process works and submit your first add-on, click Get Started
|
||||
below.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
<p class="button-wrapper">
|
||||
<a href="{{ url('devhub.submit.1') }}"
|
||||
class="action-button rounded">{{ _('Get Started') }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<section id="dashboard" class="primary" role="main">
|
||||
<div class="featured listing">
|
||||
<div class="featured-inner">
|
||||
{% set url_base = url('devhub.addons') %}
|
||||
{% if addons.paginator.num_pages > 1 %}
|
||||
{{ addon_listing_header(url_base, sort_opts, sorting) }}
|
||||
{% endif %}
|
||||
|
||||
{{ dev_addon_listing_items(addons.object_list) }}
|
||||
|
||||
{% if addons.paginator.num_pages > 1 %}
|
||||
<div class="listing-footer">
|
||||
{{ addons|paginator }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>{# /featured-inner #}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="dashboard-sidebar" class="secondary" role="complementary">
|
||||
<aside id="devhub-sidebar" class="secondary" role="complementary">
|
||||
<p id="submit-addon" class="cta">
|
||||
<a href="{{ url('devhub.submit.1') }}"
|
||||
class="button prominent">{{ _('Submit a New Add-on') }}</a>
|
||||
{% if webapp %}
|
||||
<a href="{{ url('devhub.submit_apps.1') }}"
|
||||
class="button prominent">{{ _('Submit a New App') }}</a>
|
||||
{% else %}
|
||||
<a href="{{ url('devhub.submit.1') }}"
|
||||
class="button prominent">{{ _('Submit a New Add-on') }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
<div class="recent-activity">
|
||||
<h3>
|
||||
|
@ -78,11 +87,34 @@
|
|||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<p class="older-activity"><a href="{{ url('devhub.feed_all') }}">
|
||||
{{ _('Older activity for My Add-ons') }} ►</a></p>
|
||||
{% if webapp %}
|
||||
<p class="older-activity"><a href="{{ url('devhub.feed_all') }}">
|
||||
{{ _('Older activity for My Apps') }} ►</a></p>
|
||||
{% else %}
|
||||
<p class="older-activity"><a href="{{ url('devhub.feed_all') }}">
|
||||
{{ _('Older activity for My Add-ons') }} ►</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% include "devhub/includes/blog_posts.html" %}
|
||||
{% if not webapp %}
|
||||
{% include "devhub/includes/blog_posts.html" %}
|
||||
{% endif %}
|
||||
|
||||
</aside>
|
||||
<section id="dashboard" class="primary" role="main">
|
||||
<div class="listing island hero c">
|
||||
{% set url_base = url('devhub.apps') if webapp else url('devhub.addons') %}
|
||||
{% if addons.paginator.num_pages > 1 %}
|
||||
{{ impala_addon_listing_header(url_base, sort_opts, sorting) }}
|
||||
{% endif %}
|
||||
<div class="items">
|
||||
{{ dev_addon_listing_items(addons.object_list) }}
|
||||
</div>{# /items #}
|
||||
{% if addons.paginator.num_pages > 1 %}
|
||||
{{ addons|impala_paginator }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<h5>{{ _('Actions') }}</h5>
|
||||
<ul>
|
||||
{% if addon.is_incomplete() %}
|
||||
{% if check_addon_ownership(request, addon, dev=True) %}
|
||||
<li>
|
||||
<a href="{{ url('devhub.submit.resume', addon.slug) }}" class="tooltip"
|
||||
title="{{ _("Resume the submission process for this app.")}}">
|
||||
{{ _('Resume') }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if check_addon_ownership(request, addon) %}
|
||||
<li>
|
||||
<a href="#" class="delete-addon tooltip"
|
||||
title="{{ _('Delete this app.') }}">{{ _('Delete') }}</a>
|
||||
<div class="modal-delete modal hidden">
|
||||
{% include "devhub/addons/listing/delete_form.html" %}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if check_addon_ownership(request, addon, dev=True) %}
|
||||
<li>
|
||||
<a href="{{ url('devhub.addons.edit', addon.slug) }}" class="tooltip"
|
||||
title="{{ _("Edit details about this app's listing.") }}">
|
||||
{{ _('Edit Listing') }}</a>
|
||||
</li>
|
||||
{% if addon.accepts_compatible_apps() and addon.current_version %}
|
||||
<li class="compat"
|
||||
data-src="{{ url('devhub.ajax.compat.status', addon.slug) }}">
|
||||
{% include "devhub/addons/ajax_compat_status.html" %}
|
||||
<div class="compat-error-popup popup error hidden"></div>
|
||||
<div class="compat-update-modal modal hidden"></div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not addon.disabled_by_user %}
|
||||
<li>
|
||||
<a href="{{ locale_url('/statistics/addon/{0}')|f(addon.id) }}" class="tooltip"
|
||||
{# <a href="{{ url('stats.overview', addon.slug) }}" class="tooltip" #}
|
||||
title="{{ _('Daily statistics on downloads and users.') }}">
|
||||
{{ _('Statistics') }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="#" class="more-actions">{{ _('More') }}</a>
|
||||
<div class="more-actions-popup popup hidden">
|
||||
{% set manage_urls = (
|
||||
(url('devhub.addons.owner', addon.slug), _('Manage Authors & License')),
|
||||
(url('devhub.addons.profile', addon.slug), _('Manage Developer Profile')),
|
||||
(url('devhub.addons.payments', addon.slug), _('Manage Payments')),
|
||||
(url('devhub.versions', addon.slug), _('Manage Status'))) %}
|
||||
<ul>
|
||||
{% for url, title in manage_urls %}
|
||||
<li><a href="{{ url }}">{{ title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% set view_urls = ((addon.get_url_path(), _('View App Listing')),
|
||||
(url('devhub.feed', addon.slug), _('View Recent Changes'))) %}
|
||||
<ul>
|
||||
{% for url, title in view_urls %}
|
||||
<li><a href="{{ url }}">{{ title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
|
@ -2,44 +2,52 @@
|
|||
{% set collection = collection or None %}
|
||||
{% set username = request.amo_user.username if request.user.is_authenticated() else '' %}
|
||||
{% for addon in addons %}
|
||||
<div class="item" data-addonid="{{ addon.id }}">
|
||||
{{ dev_heading(addon, amo) }}
|
||||
{% if addon.is_incomplete() %}
|
||||
<p>
|
||||
{% trans %}
|
||||
This add-on will be deleted automatically after a few days if the
|
||||
submission process is not completed.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
{% else %}
|
||||
<div class="item-info">
|
||||
{{ dev_item_info(addon, amo) }}
|
||||
</div>
|
||||
<ul class="item-details">
|
||||
{% if addon.current_version %}
|
||||
{% set link = url('devhub.versions.edit', addon.slug, addon.current_version.id) %}
|
||||
{# L10n: {0} is a version number. #}
|
||||
<li>{{ _('<strong>Latest version:</strong> <a href="{0}">{1}</a>'|
|
||||
f(link, addon.current_version))|xssafe }}</li>
|
||||
{% endif %}
|
||||
{# L10n: {0} is a date. #}
|
||||
<li>{{ _('<strong>Last updated:</strong> {0}'|
|
||||
f(addon.last_updated|datetime))|safe }}</li>
|
||||
<li id="version-status-item">
|
||||
<strong>{{ _('Status:') }}</strong>
|
||||
<a href="{{ url('devhub.versions', addon.slug) }}">
|
||||
{% if addon.disabled_by_user %}
|
||||
<span class="{{ status_class(addon) }}"><b>{{ _('Disabled') }}</b></span>
|
||||
{% else %}
|
||||
<span class="{{ status_class(addon) }}">
|
||||
<b>{{ amo.STATUS_CHOICES[addon.status] }}</b></span>
|
||||
<div class="item addon ignore-compatibility" data-addonid="{{ addon.id }}">
|
||||
<div class="info">
|
||||
{{ dev_heading(addon, amo) }}
|
||||
{% if addon.is_incomplete() %}
|
||||
<p>
|
||||
{% trans %}
|
||||
This submission will be deleted automatically after a few days if
|
||||
the submission process is not completed.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
{% else %}
|
||||
<div class="item-info">
|
||||
{{ dev_item_info(addon, amo) }}
|
||||
</div>
|
||||
<ul class="item-details">
|
||||
{% if not webapp %}
|
||||
{% if addon.current_version %}
|
||||
{% set link = url('devhub.versions.edit', addon.slug, addon.current_version.id) %}
|
||||
{# L10n: {0} is a version number. #}
|
||||
<li>{{ _('<strong>Latest version:</strong> <a href="{0}">{1}</a>'|
|
||||
f(link, addon.current_version))|xssafe }}</li>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div class="item-actions">
|
||||
{% include "devhub/addons/listing/item_actions.html" %}
|
||||
{# L10n: {0} is a date. #}
|
||||
<li>{{ _('<strong>Last updated:</strong> {0}'|
|
||||
f(addon.last_updated|datetime))|safe }}</li>
|
||||
{% endif %}
|
||||
<li id="version-status-item">
|
||||
<strong>{{ _('Status:') }}</strong>
|
||||
<a href="{{ url('devhub.versions', addon.slug) }}">
|
||||
{% if addon.disabled_by_user %}
|
||||
<span class="{{ status_class(addon) }}"><b>{{ _('Disabled') }}</b></span>
|
||||
{% else %}
|
||||
<span class="{{ status_class(addon) }}">
|
||||
<b>{{ amo.STATUS_CHOICES[addon.status] }}</b></span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div class="item-actions">
|
||||
{% if webapp %}
|
||||
{% include "devhub/addons/listing/item_actions_app.html" %}
|
||||
{% else %}
|
||||
{% include "devhub/addons/listing/item_actions.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{% macro dev_heading(addon, amo) %}
|
||||
<h4>
|
||||
<h3>
|
||||
{% set is_complete = not addon.is_incomplete() %}
|
||||
{% if is_complete %}<a href="{{ addon.get_url_path() }}">{% endif %}
|
||||
<img class="icon" src="{{ addon.get_icon_url(64) }}">
|
||||
{{ addon.name }}{% if is_complete %}</a>{% endif %}
|
||||
</h4>
|
||||
</h3>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro dev_item_info(addon, amo) %}
|
||||
|
|
|
@ -37,24 +37,45 @@
|
|||
<nav id="site-nav" class="menu-nav no-img c">
|
||||
<ul>
|
||||
{% if request.user.is_authenticated() and request.amo_user.is_developer %}
|
||||
<li class="top">
|
||||
<a href="{{ url('devhub.addons') }}" class="controller">
|
||||
{{ _('My Add-ons') }}</a>
|
||||
<ul>
|
||||
{% set my_addons = request.amo_user.addons.all()[:8] %}
|
||||
{% for addon in my_addons %}
|
||||
{% if loop.index == 8 %}
|
||||
<li><a href="{{ url('devhub.addons') }}">
|
||||
{{ _('more add-ons...') }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url('devhub.addons.edit', addon.slug) }}">
|
||||
{{ addon.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><em><a href="{{ url('devhub.submit.1') }}">
|
||||
{{ _('Submit a New Add-on') }}</a></em></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if webapp %}
|
||||
<li class="top">
|
||||
<a href="{{ url('devhub.apps') }}" class="controller">
|
||||
{{ _('My Apps') }}</a>
|
||||
<ul>
|
||||
{% set my_apps = request.amo_user.my_apps() %}
|
||||
{% for addon in my_apps %}
|
||||
{% if loop.index == 8 %}
|
||||
<li><a href="{{ url('devhub.apps') }}">
|
||||
{{ _('more apps...') }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url('devhub.addons.edit', addon.slug) }}">
|
||||
{{ addon.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><em><a href="{{ url('devhub.submit_apps.1') }}">
|
||||
{{ _('Submit a New App') }}</a></em></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="top">
|
||||
<a href="{{ url('devhub.addons') }}" class="controller">
|
||||
{{ _('My Add-ons') }}</a>
|
||||
<ul>
|
||||
{% set my_addons = request.amo_user.my_addons() %}
|
||||
{% for addon in my_addons %}
|
||||
{% if loop.index == 8 %}
|
||||
<li><a href="{{ url('devhub.addons') }}">
|
||||
{{ _('more add-ons...') }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url('devhub.addons.edit', addon.slug) }}">
|
||||
{{ addon.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><em><a href="{{ url('devhub.submit.1') }}">
|
||||
{{ _('Submit a New Add-on') }}</a></em></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="#" class="controller">{{ _('Documentation') }}</a>
|
||||
|
|
|
@ -16,40 +16,70 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block aux_nav %}
|
||||
<li class="nomenu"><a class="return" href="{{ url('home') }}">
|
||||
{{ _('Back to Add-ons') }}</a></li>
|
||||
<li class="nomenu">
|
||||
{% if webapp %}
|
||||
<a class="return" href="{{ url('apps.home') }}">{{ _('Back to Apps') }}</a>
|
||||
{% else %}
|
||||
<a class="return" href="{{ url('home') }}">{{ _('Back to Add-ons') }}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block site_header_title %}
|
||||
<h1 class="site-title prominent">
|
||||
<a href="{{ url('devhub.index') }}" title="{{ _('Return to the DevHub homepage')|f(request.APP.pretty) }}">
|
||||
{# L10n: Text in small tag is smaller and on it's own line #}
|
||||
{% trans %}
|
||||
<small>Add-on</small> Developer Hub
|
||||
{% endtrans %}
|
||||
{% if webapp %}
|
||||
{% trans %}App Developer Preview{% endtrans %}
|
||||
{% else %}
|
||||
{# L10n: Text in small tag is smaller and on its own line #}
|
||||
{% trans %}
|
||||
<small>Add-on</small> Developer Hub
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
</a>
|
||||
</h1>
|
||||
<nav id="site-nav" class="menu-nav no-img c">
|
||||
<ul>
|
||||
{% if request.user.is_authenticated() and request.amo_user.is_developer %}
|
||||
<li class="top">
|
||||
<a href="{{ url('devhub.addons') }}" class="controller">
|
||||
{{ _('My Add-ons') }}</a>
|
||||
<ul>
|
||||
{% set my_addons = request.amo_user.addons.all()[:8] %}
|
||||
{% for addon in my_addons %}
|
||||
{% if loop.index == 8 %}
|
||||
<li><a href="{{ url('devhub.addons') }}">
|
||||
{{ _('more add-ons...') }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url('devhub.addons.edit', addon.slug) }}">
|
||||
{{ addon.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><em><a href="{{ url('devhub.submit.1') }}">
|
||||
{{ _('Submit a New Add-on') }}</a></em></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if webapp %}
|
||||
<li class="top">
|
||||
<a href="{{ url('devhub.apps') }}" class="controller">
|
||||
{{ _('My Apps') }}</a>
|
||||
<ul>
|
||||
{% set my_addons = request.amo_user.my_apps() %}
|
||||
{% for addon in my_addons %}
|
||||
{% if loop.index == 8 %}
|
||||
<li><a href="{{ url('devhub.apps') }}">
|
||||
{{ _('more apps...') }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url('devhub.addons.edit', addon.slug) }}">
|
||||
{{ addon.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><em><a href="{{ url('devhub.submit_apps.1') }}">
|
||||
{{ _('Submit a New App') }}</a></em></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="top">
|
||||
<a href="{{ url('devhub.addons') }}" class="controller">
|
||||
{{ _('My Add-ons') }}</a>
|
||||
<ul>
|
||||
{% set my_addons = request.amo_user.my_addons() %}
|
||||
{% for addon in my_addons %}
|
||||
{% if loop.index == 8 %}
|
||||
<li><a href="{{ url('devhub.addons') }}">
|
||||
{{ _('more add-ons...') }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url('devhub.addons.edit', addon.slug) }}">
|
||||
{{ addon.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><em><a href="{{ url('devhub.submit.1') }}">
|
||||
{{ _('Submit a New Add-on') }}</a></em></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="#" class="controller">{{ _('Documentation') }}</a>
|
||||
|
|
|
@ -55,7 +55,8 @@ class MetaTests(amo.tests.TestCase):
|
|||
|
||||
|
||||
class HubTest(amo.tests.TestCase):
|
||||
fixtures = ['browse/nameless-addon', 'base/users']
|
||||
fixtures = ['browse/nameless-addon', 'base/users',
|
||||
'webapps/337141-steamcube']
|
||||
|
||||
def setUp(self):
|
||||
self.url = reverse('devhub.index')
|
||||
|
@ -68,13 +69,11 @@ class HubTest(amo.tests.TestCase):
|
|||
ids = []
|
||||
for i in range(num):
|
||||
addon = Addon.objects.get(id=addon_id)
|
||||
addon.id = addon.guid = None
|
||||
addon.save()
|
||||
AddonUser.objects.create(user=self.user_profile, addon=addon)
|
||||
new_addon = Addon.objects.get(id=addon.id)
|
||||
new_addon.name = str(addon.id)
|
||||
new_addon.save()
|
||||
ids.append(addon.id)
|
||||
data = dict(type=addon.type, status=addon.status,
|
||||
name='cloned-addon-%s-%s' % (addon_id, i))
|
||||
new_addon = Addon.objects.create(**data)
|
||||
AddonUser.objects.create(user=self.user_profile, addon=new_addon)
|
||||
ids.append(new_addon.id)
|
||||
return ids
|
||||
|
||||
|
||||
|
@ -97,6 +96,8 @@ class TestNav(HubTest):
|
|||
"""Check that the correct items are listed for the My Add-ons menu."""
|
||||
# Assign this add-on to the current user profile.
|
||||
addon = Addon.objects.get(id=57132)
|
||||
addon.name = 'Test'
|
||||
addon.save()
|
||||
AddonUser.objects.create(user=self.user_profile, addon=addon)
|
||||
|
||||
r = self.client.get(self.url)
|
||||
|
@ -175,16 +176,14 @@ class TestDashboard(HubTest):
|
|||
r = self.client.get(self.url)
|
||||
doc = pq(r.content)
|
||||
eq_(len(doc('.item .item-info')), 10)
|
||||
eq_(doc('#addon-list-options').length, 0)
|
||||
eq_(doc('.listing-footer .pagination').length, 0)
|
||||
eq_(doc('nav.paginator').length, 0)
|
||||
|
||||
# Create 5 add-ons.
|
||||
self.clone_addon(5)
|
||||
r = self.client.get(self.url + '?page=2')
|
||||
doc = pq(r.content)
|
||||
eq_(len(doc('.item .item-info')), 5)
|
||||
eq_(doc('#addon-list-options').length, 1)
|
||||
eq_(doc('.listing-footer .pagination').length, 1)
|
||||
eq_(doc('nav.paginator').length, 1)
|
||||
|
||||
def test_show_hide_statistics(self):
|
||||
a_pk = self.clone_addon(1)[0]
|
||||
|
@ -208,8 +207,8 @@ class TestDashboard(HubTest):
|
|||
doc = pq(r.content)
|
||||
eq_(a.status, amo.STATUS_PUBLIC)
|
||||
assert doc('.item[data-addonid=%s] ul.item-details' % a_pk)
|
||||
assert doc('.item[data-addonid=%s] h4 a' % a_pk)
|
||||
assert not doc('.item[data-addonid=%s] > p' % a_pk)
|
||||
assert doc('.item[data-addonid=%s] h3 a' % a_pk)
|
||||
assert not doc('.item[data-addonid=%s] > div.info > p' % a_pk)
|
||||
|
||||
def test_incomplete_addon_item(self):
|
||||
a_pk = self.clone_addon(1)[0]
|
||||
|
@ -217,8 +216,8 @@ class TestDashboard(HubTest):
|
|||
r = self.client.get(self.url)
|
||||
doc = pq(r.content)
|
||||
assert not doc('.item[data-addonid=%s] ul.item-details' % a_pk)
|
||||
assert not doc('.item[data-addonid=%s] h4 a' % a_pk)
|
||||
assert doc('.item[data-addonid=%s] > p' % a_pk)
|
||||
assert not doc('.item[data-addonid=%s] h3 a' % a_pk)
|
||||
assert doc('.item[data-addonid=%s] > div.info > p' % a_pk)
|
||||
|
||||
def test_dev_news(self):
|
||||
self.clone_addon(1) # We need one to see this module
|
||||
|
@ -235,6 +234,43 @@ class TestDashboard(HubTest):
|
|||
eq_(doc('.blog-posts li a').eq(4).text(), "hi 4")
|
||||
|
||||
|
||||
class TestAppDashboard(HubTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAppDashboard, self).setUp()
|
||||
self.url = reverse('devhub.apps')
|
||||
waffle.models.Flag.objects.create(name='accept-webapps', everyone=True)
|
||||
|
||||
def test_app_dashboard(self):
|
||||
eq_(self.client.get(self.url).status_code, 200)
|
||||
|
||||
def test_no_apps(self):
|
||||
"""Check that no apps are displayed for this user."""
|
||||
r = self.client.get(self.url)
|
||||
doc = pq(r.content)
|
||||
eq_(doc('.items .item').length, 0)
|
||||
|
||||
def test_app_pagination(self):
|
||||
"""Check that the correct info. is displayed for each app:
|
||||
namely, that apps are paginated at 10 items per page, and that
|
||||
when there is more than one page, the 'Sort by' header and pagination
|
||||
footer appear.
|
||||
"""
|
||||
# Create 10 add-ons.
|
||||
self.clone_addon(10, addon_id=337141)
|
||||
r = self.client.get(self.url)
|
||||
doc = pq(r.content)
|
||||
eq_(len(doc('.item .item-info')), 10)
|
||||
eq_(doc('nav.paginator').length, 0)
|
||||
|
||||
# Create 5 add-ons.
|
||||
self.clone_addon(5, addon_id=337141)
|
||||
r = self.client.get(self.url + '?page=2')
|
||||
doc = pq(r.content)
|
||||
eq_(len(doc('.item .item-info')), 5)
|
||||
eq_(doc('nav.paginator').length, 1)
|
||||
|
||||
|
||||
class TestUpdateCompatibility(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_4594_a9',
|
||||
'base/addon_3615']
|
||||
|
|
|
@ -178,6 +178,7 @@ urlpatterns = decorate(write, patterns('',
|
|||
# Redirect to /addons/ at the base.
|
||||
url('^addon$', lambda r: redirect('devhub.addons', permanent=True)),
|
||||
url('^addons$', views.dashboard, name='devhub.addons'),
|
||||
url('^apps$', use_apps(views.dashboard), name='devhub.apps'),
|
||||
url('^feed$', views.feed, name='devhub.feed_all'),
|
||||
# TODO: not necessary when devhub homepage is moved out of remora
|
||||
url('^feed/all$', lambda r: redirect('devhub.feed_all', permanent=True)),
|
||||
|
|
|
@ -51,11 +51,12 @@ from files.models import File, FileUpload, Platform
|
|||
from files.utils import parse_addon
|
||||
from market.models import AddonPremium
|
||||
import paypal
|
||||
from product_details import product_details
|
||||
from search.views import BaseAjaxSearch
|
||||
from translations.models import delete_translation
|
||||
from users.models import UserProfile
|
||||
from versions.models import Version
|
||||
from product_details import product_details
|
||||
from webapps.views import AppFilter
|
||||
from zadmin.models import ValidationResult
|
||||
|
||||
from . import forms, tasks, feeds, signals
|
||||
|
@ -76,10 +77,14 @@ class AddonFilter(BaseFilter):
|
|||
('rating', _lazy(u'Rating')))
|
||||
|
||||
|
||||
def addon_listing(request, addon_type, default='name'):
|
||||
def addon_listing(request, default='name', webapp=False):
|
||||
"""Set up the queryset and filtering for addon listing for Dashboard."""
|
||||
qs = request.amo_user.addons.all()
|
||||
filter = AddonFilter(request, qs, 'sort', default)
|
||||
Filter = AppFilter if webapp else AddonFilter
|
||||
if webapp:
|
||||
qs = request.amo_user.addons.filter(type=amo.ADDON_WEBAPP)
|
||||
else:
|
||||
qs = request.amo_user.addons.exclude(type=amo.ADDON_WEBAPP)
|
||||
filter = Filter(request, qs, 'sort', default)
|
||||
return filter.qs, filter
|
||||
|
||||
|
||||
|
@ -89,14 +94,16 @@ def index(request):
|
|||
|
||||
|
||||
@login_required
|
||||
def dashboard(request):
|
||||
addons, filter = addon_listing(request, addon_type=amo.ADDON_ANY)
|
||||
def dashboard(request, webapp=False):
|
||||
addon_type = amo.ADDON_WEBAPP if webapp else amo.ADDON_ANY
|
||||
addons, filter = addon_listing(request, webapp=webapp)
|
||||
addons = amo.utils.paginate(request, addons, per_page=10)
|
||||
blog_posts = _get_posts()
|
||||
data = dict(addons=addons, sorting=filter.field,
|
||||
items=_get_items(None, request.amo_user.addons.all())[:4],
|
||||
sort_opts=filter.opts, rss=_get_rss_feed(request),
|
||||
blog_posts=blog_posts, timestamp=int(time.time()))
|
||||
blog_posts=blog_posts, timestamp=int(time.time()),
|
||||
webapp=webapp)
|
||||
return jingo.render(request, 'devhub/addons/dashboard.html', data)
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import amo
|
|||
import amo.models
|
||||
from amo.urlresolvers import reverse
|
||||
from translations.fields import PurifiedField
|
||||
from translations.query import order_by_translation
|
||||
|
||||
log = commonware.log.getLogger('z.users')
|
||||
|
||||
|
@ -148,6 +149,18 @@ class UserProfile(amo.models.OnChangeMixin, amo.models.ModelBase):
|
|||
return self.addons.reviewed().filter(addonuser__user=self,
|
||||
addonuser__listed=True)
|
||||
|
||||
def my_addons(self, n=8):
|
||||
"""Returns n addons (anything not a webapp)"""
|
||||
qs = self.addons.exclude(type=amo.ADDON_WEBAPP)
|
||||
qs = order_by_translation(qs, 'name')
|
||||
return qs[:n]
|
||||
|
||||
def my_apps(self, n=8):
|
||||
"""Returns n apps"""
|
||||
qs = self.addons.filter(type=amo.ADDON_WEBAPP)
|
||||
qs = order_by_translation(qs, 'name')
|
||||
return qs[:n]
|
||||
|
||||
@property
|
||||
def picture_dir(self):
|
||||
split_id = re.match(r'((\d*?)(\d{0,3}?))\d{1,3}$', str(self.id))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from datetime import date
|
||||
import datetime
|
||||
import hashlib
|
||||
from urlparse import urlparse
|
||||
|
||||
|
@ -82,11 +82,11 @@ class TestUserProfile(amo.tests.TestCase):
|
|||
Test for a preview URL if image is set, or default image otherwise.
|
||||
"""
|
||||
u = UserProfile(id=1234, picture_type='image/png',
|
||||
modified=date.today())
|
||||
modified=datetime.date.today())
|
||||
u.picture_url.index('/userpics/0/1/1234.png?modified=')
|
||||
|
||||
u = UserProfile(id=1234567890, picture_type='image/png',
|
||||
modified=date.today())
|
||||
modified=datetime.date.today())
|
||||
u.picture_url.index('/userpics/1234/1234567/1234567890.png?modified=')
|
||||
|
||||
u = UserProfile(id=1234, picture_type=None)
|
||||
|
@ -130,6 +130,28 @@ class TestUserProfile(amo.tests.TestCase):
|
|||
addons = u.addons_listed.values_list('id', flat=True)
|
||||
assert 3615 not in addons
|
||||
|
||||
def test_my_addons(self):
|
||||
"""Test helper method to get N addons."""
|
||||
addon1 = Addon.objects.create(name='test-1', type=amo.ADDON_EXTENSION)
|
||||
AddonUser.objects.create(addon_id=addon1.id, user_id=2519, listed=True)
|
||||
addon2 = Addon.objects.create(name='test-2', type=amo.ADDON_EXTENSION)
|
||||
AddonUser.objects.create(addon_id=addon2.id, user_id=2519, listed=True)
|
||||
u = UserProfile.objects.get(id=2519)
|
||||
addons = u.my_addons()
|
||||
self.assertTrue(sorted([a.name for a in addons]) == [addon1.name,
|
||||
addon2.name])
|
||||
|
||||
def test_my_apps(self):
|
||||
"""Test helper method to get N apps."""
|
||||
addon1 = Addon.objects.create(name='test-1', type=amo.ADDON_WEBAPP)
|
||||
AddonUser.objects.create(addon_id=addon1.id, user_id=2519, listed=True)
|
||||
addon2 = Addon.objects.create(name='test-2', type=amo.ADDON_WEBAPP)
|
||||
AddonUser.objects.create(addon_id=addon2.id, user_id=2519, listed=True)
|
||||
u = UserProfile.objects.get(id=2519)
|
||||
addons = u.my_apps()
|
||||
self.assertTrue(sorted([a.name for a in addons]) == [addon1.name,
|
||||
addon2.name])
|
||||
|
||||
def test_mobile_collection(self):
|
||||
u = UserProfile.objects.get(id='4043307')
|
||||
assert not Collection.objects.filter(author=u)
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
[
|
||||
{
|
||||
"pk": 337141,
|
||||
"model": "addons.addon",
|
||||
"fields": {
|
||||
"dev_agreement": false,
|
||||
"eula": null,
|
||||
"last_updated": "2011-10-18 16:28:24",
|
||||
"view_source": true,
|
||||
"enable_thankyou": false,
|
||||
"total_downloads": 0,
|
||||
"premium_type": 0,
|
||||
"app_slug": "something-something",
|
||||
"developer_comments": null,
|
||||
"_current_version": 1268829,
|
||||
"average_daily_downloads": 0,
|
||||
"_backup_version": null,
|
||||
"manifest_url": "http://micropipes.com/temp/steamcube.webapp",
|
||||
"admin_review_type": 1,
|
||||
"the_future": null,
|
||||
"trusted": false,
|
||||
"total_contributions": null,
|
||||
"locale_disambiguation": null,
|
||||
"binary": false,
|
||||
"guid": null,
|
||||
"weekly_downloads": 0,
|
||||
"support_url": null,
|
||||
"disabled_by_user": false,
|
||||
"paypal_id": "",
|
||||
"average_rating": 0.0,
|
||||
"wants_contributions": false,
|
||||
"average_daily_users": 0,
|
||||
"bayesian_rating": 0.0,
|
||||
"share_count": 0,
|
||||
"ts_slowness": null,
|
||||
"homepage": null,
|
||||
"support_email": null,
|
||||
"public_stats": false,
|
||||
"status": 4,
|
||||
"privacy_policy": null,
|
||||
"description": null,
|
||||
"default_locale": "en-US",
|
||||
"target_locale": null,
|
||||
"suggested_amount": null,
|
||||
"get_satisfaction_product": null,
|
||||
"prerelease": false,
|
||||
"thankyou_note": null,
|
||||
"admin_review": false,
|
||||
"auto_repackage": true,
|
||||
"slug": "app-337141",
|
||||
"external_software": false,
|
||||
"highest_status": 4,
|
||||
"get_satisfaction_company": null,
|
||||
"name": null,
|
||||
"created": "2011-10-18 16:28:24",
|
||||
"type": 11,
|
||||
"icon_type": "icon/games",
|
||||
"annoying": 0,
|
||||
"modified": "2011-10-18 16:29:46",
|
||||
"summary": null,
|
||||
"nomination_message": null,
|
||||
"site_specific": false,
|
||||
"charity": null,
|
||||
"total_reviews": 0,
|
||||
"the_reason": null,
|
||||
"hotness": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 1268829,
|
||||
"model": "versions.version",
|
||||
"fields": {
|
||||
"has_info_request": false,
|
||||
"license": null,
|
||||
"created": "2011-10-18 16:28:24",
|
||||
"has_editor_comment": false,
|
||||
"releasenotes": null,
|
||||
"approvalnotes": "",
|
||||
"modified": "2011-10-18 16:28:24",
|
||||
"version": "1.0",
|
||||
"version_int": 1000000200100,
|
||||
"reviewed": null,
|
||||
"nomination": null,
|
||||
"addon": 337141
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2527085,
|
||||
"model": "translations.translation",
|
||||
"fields": {
|
||||
"localized_string_clean": null,
|
||||
"created": "2011-10-18 16:28:24",
|
||||
"locale": "en-us",
|
||||
"modified": "2011-10-18 16:28:57",
|
||||
"id": 2425897,
|
||||
"localized_string": "Something Something!"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2527086,
|
||||
"model": "translations.translation",
|
||||
"fields": {
|
||||
"localized_string_clean": "A simple 2.5D brain teaser block puzzle game. Find out how far can you get before time runs out?",
|
||||
"created": "2011-10-18 16:28:24",
|
||||
"locale": "en-US",
|
||||
"modified": "2011-10-18 16:28:57",
|
||||
"id": 2425898,
|
||||
"localized_string": "A simple 2.5D brain teaser block puzzle game. Find out how far can you get before time runs out?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2527087,
|
||||
"model": "translations.translation",
|
||||
"fields": {
|
||||
"localized_string_clean": "",
|
||||
"created": "2011-10-18 16:28:57",
|
||||
"locale": "en-us",
|
||||
"modified": "2011-10-18 16:28:57",
|
||||
"id": 2425899,
|
||||
"localized_string": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2425898,
|
||||
"model": "translations.translation",
|
||||
"fields": {
|
||||
"localized_string_clean": "",
|
||||
"created": "2011-07-26 14:16:26",
|
||||
"locale": "en-us",
|
||||
"modified": "2011-07-26 14:16:26",
|
||||
"id": 2326782,
|
||||
"localized_string": null
|
||||
}
|
||||
}
|
||||
]
|
|
@ -325,3 +325,6 @@
|
|||
margin: .5em 0 .25em;
|
||||
}
|
||||
}
|
||||
#dashboard .island {
|
||||
float: left;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
@import 'lib';
|
||||
|
||||
.listing .item {
|
||||
.item-info {
|
||||
border-left: 1px dotted @border-blue;
|
||||
float: right;
|
||||
margin-left: 2%;
|
||||
padding-left: 2%;
|
||||
width: 15em;
|
||||
}
|
||||
.item-info > .downloads,
|
||||
.item-info > .users {
|
||||
color: @green;
|
||||
margin-top: 0;
|
||||
}
|
||||
.item-actions {
|
||||
float: none;
|
||||
a {
|
||||
color: @note-gray;
|
||||
&.more-actions {
|
||||
display: block;
|
||||
position: relative;
|
||||
&:after {
|
||||
border-color: @note-gray transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 3px 3px 0;
|
||||
content: "";
|
||||
margin: 5px 0 0 4px;
|
||||
position: absolute;
|
||||
height: 0;
|
||||
top: 0;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
h5 {
|
||||
font-size: 1em;
|
||||
margin-right: 4px;
|
||||
}
|
||||
h5, > ul, > ul > li {
|
||||
color: @note-gray;
|
||||
display: inline-block;
|
||||
}
|
||||
h5:after {
|
||||
content: ":";
|
||||
}
|
||||
> ul > li {
|
||||
display: inline-block;
|
||||
&:not(:last-child):after {
|
||||
background-color: @note-gray;
|
||||
border-radius: 5em 5em 5em 5em;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 2px;
|
||||
margin: 0 0 4px 1px;
|
||||
width: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
a {
|
||||
color: @link;
|
||||
}
|
||||
h5 {
|
||||
color: @dark-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
.secondary .recent-activity li a {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
}
|
|
@ -199,6 +199,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
&:first-child .info {
|
||||
border: 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
|
@ -314,6 +317,7 @@
|
|||
.items + .paginator,
|
||||
#sorter + .paginator,
|
||||
#sorter + .listing-grid,
|
||||
#sorter + .items,
|
||||
#themes-listing .items {
|
||||
border-top: 1px dotted @border-blue;
|
||||
padding-top: 1em;
|
||||
|
|
|
@ -19,6 +19,7 @@ body {
|
|||
margin: 0 auto;
|
||||
position: relative;
|
||||
min-height: @page-min-height;
|
||||
> header h2,
|
||||
> header h3 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
|
|
@ -507,6 +507,7 @@ MINIFY_BUNDLES = {
|
|||
),
|
||||
'zamboni/devhub_impala': (
|
||||
'css/impala/developers.less',
|
||||
'css/impala/devhub-listing.less',
|
||||
),
|
||||
'zamboni/editors': (
|
||||
'css/zamboni/editors.css',
|
||||
|
|
Загрузка…
Ссылка в новой задаче