diff --git a/tests/unit/manage/test_views.py b/tests/unit/manage/test_views.py index cdb2c632de98..4cc1b4deb7a2 100644 --- a/tests/unit/manage/test_views.py +++ b/tests/unit/manage/test_views.py @@ -13,13 +13,14 @@ import uuid import pretend +import pytest from pyramid.httpexceptions import HTTPSeeOther from webob.multidict import MultiDict from warehouse.manage import views from warehouse.accounts.interfaces import IUserService -from warehouse.packaging.models import JournalEntry, Role +from warehouse.packaging.models import JournalEntry, Project, Role from ...common.db.packaging import ProjectFactory, RoleFactory, UserFactory @@ -50,6 +51,84 @@ def test_manage_project_settings(self): "project": project, } + def test_delete_project_no_confirm(self): + project = pretend.stub(normalized_name='foo') + request = pretend.stub( + POST={}, + session=pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None), + ), + route_path=lambda *a, **kw: "/foo/bar/", + ) + + with pytest.raises(HTTPSeeOther) as exc: + views.delete_project(project, request) + assert exc.value.status_code == 303 + assert exc.value.headers["Location"] == "/foo/bar/" + + assert request.session.flash.calls == [ + pretend.call("Must confirm the request.", queue="error"), + ] + + def test_delete_project_wrong_confirm(self): + project = pretend.stub(normalized_name='foo') + request = pretend.stub( + POST={"confirm": "bar"}, + session=pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None), + ), + route_path=lambda *a, **kw: "/foo/bar/", + ) + + with pytest.raises(HTTPSeeOther) as exc: + views.delete_project(project, request) + assert exc.value.status_code == 303 + assert exc.value.headers["Location"] == "/foo/bar/" + + assert request.session.flash.calls == [ + pretend.call("'bar' is not the same as 'foo'", queue="error"), + ] + + def test_delete_project(self, db_request): + project = ProjectFactory.create(name="foo") + + db_request.route_path = pretend.call_recorder( + lambda *a, **kw: "/the-redirect" + ) + db_request.session = pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None), + ) + db_request.POST["confirm"] = project.normalized_name + db_request.user = UserFactory.create() + db_request.remote_addr = "192.168.1.1" + + result = views.delete_project(project, db_request) + + assert db_request.session.flash.calls == [ + pretend.call( + "Successfully deleted the project 'foo'.", + queue="success" + ), + ] + assert db_request.route_path.calls == [ + pretend.call('manage.projects'), + ] + assert isinstance(result, HTTPSeeOther) + assert result.headers["Location"] == "/the-redirect" + assert not (db_request.db.query(Project) + .filter(Project.name == "foo").count()) + + +class TestManageProjectReleases: + + def test_manage_project_releases(self): + request = pretend.stub() + project = pretend.stub() + + assert views.manage_project_releases(project, request) == { + "project": project, + } + class TestManageProjectRoles: @@ -76,7 +155,6 @@ def test_get_manage_project_roles(self, db_request): pretend.call(db_request.POST, user_service=user_service), ] assert result == { - "project": project, "roles_by_user": {user.username: [role]}, "form": form_obj, @@ -252,7 +330,7 @@ def test_change_role(self, db_request): assert role.role_name == new_role_name assert db_request.route_path.calls == [ - pretend.call('manage.project.roles', name=project.name), + pretend.call('manage.project.roles', project_name=project.name), ] assert db_request.session.flash.calls == [ pretend.call("Successfully changed role", queue="success"), @@ -282,7 +360,7 @@ def test_change_role_invalid_role_name(self, pyramid_request): result = views.change_project_role(project, pyramid_request) assert pyramid_request.route_path.calls == [ - pretend.call('manage.project.roles', name=project.name), + pretend.call('manage.project.roles', project_name=project.name), ] assert isinstance(result, HTTPSeeOther) assert result.headers["Location"] == "/the-redirect" @@ -317,7 +395,7 @@ def test_change_role_when_multiple(self, db_request): assert db_request.db.query(Role).all() == [maintainer_role] assert db_request.route_path.calls == [ - pretend.call('manage.project.roles', name=project.name), + pretend.call('manage.project.roles', project_name=project.name), ] assert db_request.session.flash.calls == [ pretend.call("Successfully changed role", queue="success"), @@ -441,7 +519,7 @@ def test_delete_role(self, db_request): result = views.delete_project_role(project, db_request) assert db_request.route_path.calls == [ - pretend.call('manage.project.roles', name=project.name), + pretend.call('manage.project.roles', project_name=project.name), ] assert db_request.db.query(Role).all() == [] assert db_request.session.flash.calls == [ diff --git a/tests/unit/test_routes.py b/tests/unit/test_routes.py index 74070747ce5b..78eadaebdff0 100644 --- a/tests/unit/test_routes.py +++ b/tests/unit/test_routes.py @@ -144,30 +144,44 @@ def add_policy(name, filename): ), pretend.call( "manage.project.settings", - "/manage/project/{name}/settings/", + "/manage/project/{project_name}/settings/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", + domain=warehouse, + ), + pretend.call( + "manage.project.delete_project", + "/manage/project/{project_name}/delete_project/", + factory="warehouse.packaging.models:ProjectFactory", + traverse="/{project_name}", + domain=warehouse, + ), + pretend.call( + "manage.project.releases", + "/manage/project/{project_name}/releases/", + factory="warehouse.packaging.models:ProjectFactory", + traverse="/{project_name}", domain=warehouse, ), pretend.call( "manage.project.roles", - "/manage/project/{name}/collaboration/", + "/manage/project/{project_name}/collaboration/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", domain=warehouse, ), pretend.call( "manage.project.change_role", - "/manage/project/{name}/collaboration/change/", + "/manage/project/{project_name}/collaboration/change/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", domain=warehouse, ), pretend.call( "manage.project.delete_role", - "/manage/project/{name}/collaboration/delete/", + "/manage/project/{project_name}/collaboration/delete/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", domain=warehouse, ), pretend.call( diff --git a/tests/unit/admin/test_utils.py b/tests/unit/utils/test_project.py similarity index 91% rename from tests/unit/admin/test_utils.py rename to tests/unit/utils/test_project.py index 1909ccbf72d6..dc7fffaf84d6 100644 --- a/tests/unit/admin/test_utils.py +++ b/tests/unit/utils/test_project.py @@ -14,10 +14,10 @@ from pretend import call, call_recorder, stub from pyramid.httpexceptions import HTTPSeeOther -from warehouse.admin.utils import confirm_project, remove_project from warehouse.packaging.models import ( Project, Release, Dependency, File, Role, JournalEntry ) +from warehouse.utils.project import confirm_project, remove_project from ...common.db.accounts import UserFactory from ...common.db.packaging import ( @@ -34,7 +34,7 @@ def test_confirm(): session=stub(flash=call_recorder(lambda *a, **kw: stub())), ) - confirm_project(project, request) + confirm_project(project, request, fail_route='fail_route') assert request.route_path.calls == [] assert request.session.flash.calls == [] @@ -49,11 +49,11 @@ def test_confirm_no_input(): ) with pytest.raises(HTTPSeeOther) as err: - confirm_project(project, request) + confirm_project(project, request, fail_route='fail_route') assert err.value == '/the-redirect' assert request.route_path.calls == [ - call('admin.project.detail', project_name='foobar') + call('fail_route', project_name='foobar') ] assert request.session.flash.calls == [ call('Must confirm the request.', queue='error') @@ -69,11 +69,11 @@ def test_confirm_incorrect_input(): ) with pytest.raises(HTTPSeeOther) as err: - confirm_project(project, request) + confirm_project(project, request, fail_route='fail_route') assert err.value == '/the-redirect' assert request.route_path.calls == [ - call('admin.project.detail', project_name='foobar') + call('fail_route', project_name='foobar') ] assert request.session.flash.calls == [ call("'bizbaz' is not the same as 'foobar'", queue='error') diff --git a/warehouse/admin/views/blacklist.py b/warehouse/admin/views/blacklist.py index 309c5ab7b335..00f38f8699f8 100644 --- a/warehouse/admin/views/blacklist.py +++ b/warehouse/admin/views/blacklist.py @@ -20,12 +20,12 @@ from sqlalchemy.orm.exc import NoResultFound from warehouse.accounts.models import User -from warehouse.admin.utils import remove_project from warehouse.packaging.models import ( Project, Release, File, Role, BlacklistedProject ) from warehouse.utils.http import is_safe_url from warehouse.utils.paginate import paginate_url_factory +from warehouse.utils.project import remove_project @view_config( diff --git a/warehouse/admin/views/projects.py b/warehouse/admin/views/projects.py index 74f6140ea872..642748b33d65 100644 --- a/warehouse/admin/views/projects.py +++ b/warehouse/admin/views/projects.py @@ -22,9 +22,9 @@ from sqlalchemy import or_ from warehouse.accounts.models import User -from warehouse.admin.utils import confirm_project, remove_project from warehouse.packaging.models import Project, Release, Role, JournalEntry from warehouse.utils.paginate import paginate_url_factory +from warehouse.utils.project import confirm_project, remove_project from warehouse.forklift.legacy import MAX_FILESIZE ONE_MB = 1024 * 1024 # bytes @@ -265,7 +265,7 @@ def set_upload_limit(project, request): require_methods=False, ) def delete_project(project, request): - confirm_project(project, request) + confirm_project(project, request, fail_route="admin.project.detail") remove_project(project, request) return HTTPSeeOther(request.route_path('admin.project.list')) diff --git a/warehouse/manage/views.py b/warehouse/manage/views.py index da721a3e748f..edb948ddb9a7 100644 --- a/warehouse/manage/views.py +++ b/warehouse/manage/views.py @@ -22,6 +22,7 @@ from warehouse.accounts.models import User from warehouse.manage.forms import CreateRoleForm, ChangeRoleForm from warehouse.packaging.models import JournalEntry, Role +from warehouse.utils.project import confirm_project, remove_project @view_config( @@ -46,7 +47,7 @@ def manage_projects(request): @view_config( route_name="manage.project.settings", - renderer="manage/project.html", + renderer="manage/settings.html", uses_session=True, permission="manage", effective_principals=Authenticated, @@ -55,6 +56,30 @@ def manage_project_settings(project, request): return {"project": project} +@view_config( + route_name="manage.project.delete_project", + uses_session=True, + require_methods=["POST"], + permission="manage", +) +def delete_project(project, request): + confirm_project(project, request, fail_route="manage.project.settings") + remove_project(project, request) + + return HTTPSeeOther(request.route_path('manage.projects')) + + +@view_config( + route_name="manage.project.releases", + renderer="manage/releases.html", + uses_session=True, + permission="manage", + effective_principals=Authenticated, +) +def manage_project_releases(project, request): + return {"project": project} + + @view_config( route_name="manage.project.roles", renderer="manage/roles.html", @@ -208,7 +233,7 @@ def change_project_role(project, request, _form_class=ChangeRoleForm): request.session.flash("Could not find role", queue="error") return HTTPSeeOther( - request.route_path('manage.project.roles', name=project.name) + request.route_path('manage.project.roles', project_name=project.name) ) @@ -253,5 +278,5 @@ def delete_project_role(project, request): request.session.flash("Successfully removed role", queue="success") return HTTPSeeOther( - request.route_path('manage.project.roles', name=project.name) + request.route_path('manage.project.roles', project_name=project.name) ) diff --git a/warehouse/routes.py b/warehouse/routes.py index 05beb2f14d28..c6891e57f81f 100644 --- a/warehouse/routes.py +++ b/warehouse/routes.py @@ -110,30 +110,44 @@ def includeme(config): config.add_route("manage.projects", "/manage/projects/", domain=warehouse) config.add_route( "manage.project.settings", - "/manage/project/{name}/settings/", + "/manage/project/{project_name}/settings/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", + domain=warehouse, + ) + config.add_route( + "manage.project.delete_project", + "/manage/project/{project_name}/delete_project/", + factory="warehouse.packaging.models:ProjectFactory", + traverse="/{project_name}", + domain=warehouse, + ) + config.add_route( + "manage.project.releases", + "/manage/project/{project_name}/releases/", + factory="warehouse.packaging.models:ProjectFactory", + traverse="/{project_name}", domain=warehouse, ) config.add_route( "manage.project.roles", - "/manage/project/{name}/collaboration/", + "/manage/project/{project_name}/collaboration/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", domain=warehouse, ) config.add_route( "manage.project.change_role", - "/manage/project/{name}/collaboration/change/", + "/manage/project/{project_name}/collaboration/change/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", domain=warehouse, ) config.add_route( "manage.project.delete_role", - "/manage/project/{name}/collaboration/delete/", + "/manage/project/{project_name}/collaboration/delete/", factory="warehouse.packaging.models:ProjectFactory", - traverse="/{name}", + traverse="/{project_name}", domain=warehouse, ) diff --git a/warehouse/static/sass/blocks/_modal.scss b/warehouse/static/sass/blocks/_modal.scss index e58bc3a3318f..546cda8790de 100644 --- a/warehouse/static/sass/blocks/_modal.scss +++ b/warehouse/static/sass/blocks/_modal.scss @@ -33,7 +33,6 @@ */ - .modal { @include overlay; opacity: 0; @@ -41,6 +40,7 @@ display: flex; align-items: center; justify-content: center; + flex-grow: 1; &:target { opacity: 1; @@ -56,12 +56,19 @@ overflow: auto; background: $white; position: relative; + margin: auto; } &__body { padding: $spacing-unit; } + @media screen and (max-width: $tablet) { + &__body { + padding: $spacing-unit / 2; + } + } + &__title { font-size: 1.5rem; } @@ -99,6 +106,7 @@ input { width: 100%; + min-width: 100%; margin: 5px 0 20px 0; } diff --git a/warehouse/static/sass/blocks/_package-snippet.scss b/warehouse/static/sass/blocks/_package-snippet.scss index 3a8fe1fdddd8..fba23c04f768 100644 --- a/warehouse/static/sass/blocks/_package-snippet.scss +++ b/warehouse/static/sass/blocks/_package-snippet.scss @@ -64,15 +64,23 @@ } &__buttons { - width: 165px; + width: 140px; .button { display: inline-block; float: left; } - .button--highlight { + .button--primary { margin-right: 5px; } } + + &--margin-bottom { + margin-bottom: 0; + + @media only screen and (max-width: $tablet) { + margin-bottom: 30px; + } + } } diff --git a/warehouse/static/sass/blocks/_project-description.scss b/warehouse/static/sass/blocks/_project-description.scss index 2f710717399d..9aadde35b2b0 100644 --- a/warehouse/static/sass/blocks/_project-description.scss +++ b/warehouse/static/sass/blocks/_project-description.scss @@ -25,13 +25,6 @@ margin-bottom: $spacing-unit; line-height: 1.5; - // Remove top margin on first heading, even if it nested inside a div - > :first-child, - > div:first-child > :first-child { - display: inline-block; - margin-top: 0 !important; - } - h1, h2, h3, @@ -89,6 +82,10 @@ font-style: italic; padding-left: ($spacing-unit / 2); color: lighten($text-color, 20); + + @media only screen and (max-width: $tablet) { + margin-left: 0; + } } dl { diff --git a/warehouse/static/sass/blocks/_tabs.scss b/warehouse/static/sass/blocks/_tabs.scss deleted file mode 100644 index ce76d52baf6d..000000000000 --- a/warehouse/static/sass/blocks/_tabs.scss +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - Set of links styled as tabs. - - -*/ - -$tabs-color: darken($base-grey, 10); - -.tabs { - border-bottom: 2px solid $tabs-color; - @include clearfix; - margin-top: $spacing-unit; - position: relative; - - &__tab { - display: inline-block; - float: left; - line-height: 41px; - padding: 0 $spacing-unit / 2; - font-size: 17px; - font-weight: 600; - border-radius: 5px 5px 0 0; - border: 2px solid $tabs-color; - margin-right: 5px; - position: relative; - top: 2px; - background-color: #fafafa; - - &:focus, - &:hover, - &:active { - border-color: $brand-color; - border-bottom-color: $tabs-color; - text-decoration: none; - outline: none; - } - - &--is-active { - border-bottom-color: $white; - color: lighten($text-color, 10); - background-color: $white; - - &:focus, - &:hover, - &:active { - border-color: $tabs-color; - text-decoration: none; - color: lighten($text-color, 10); - border-bottom-color: $white; - } - } - } -} diff --git a/warehouse/static/sass/blocks/_vertical-tabs.scss b/warehouse/static/sass/blocks/_vertical-tabs.scss index 13bbe5e447c1..fda4d381b39f 100644 --- a/warehouse/static/sass/blocks/_vertical-tabs.scss +++ b/warehouse/static/sass/blocks/_vertical-tabs.scss @@ -39,10 +39,14 @@ overflow: hidden; margin: $spacing-unit 0; + @media only screen and (max-width: $tablet) { + margin: 0; + } + &__tabs { @include span-columns(3); - @media only screen and (max-width: $tablet){ + @media only screen and (max-width: $tablet) { display: none; } } @@ -59,8 +63,7 @@ &--mobile { display: none; - - @media only screen and (max-width: $tablet){ + @media only screen and (max-width: $tablet) { display: block; border-top: 1px solid $border-color; @@ -70,6 +73,12 @@ } } + &--no-top-border { + @media only screen and (max-width: $tablet) { + border-top: 0; + } + } + &--is-active, &--is-active:hover { background: $brand-color; @@ -94,7 +103,7 @@ &__panel { @include span-columns(9); - @media only screen and (max-width: $tablet){ + @media only screen and (max-width: $tablet) { width: 100%; } } @@ -102,8 +111,8 @@ &__content { padding-left: $spacing-unit; - @media only screen and (max-width: $tablet){ - padding: $spacing-unit ($spacing-unit / 2); + @media only screen and (max-width: $tablet) { + padding: 25px 10px 10px 10px; } } } diff --git a/warehouse/static/sass/layout-helpers/_containers.scss b/warehouse/static/sass/layout-helpers/_containers.scss index eab33705b0da..b93b7178ca2f 100644 --- a/warehouse/static/sass/layout-helpers/_containers.scss +++ b/warehouse/static/sass/layout-helpers/_containers.scss @@ -21,6 +21,18 @@ @include site-container; } +/* + Container for vertical tabs +*/ + +.tabs-container { + @include site-container; + + @media only screen and (max-width: $tablet){ + padding: 5px; + } +} + /* Narrow container for text only pages:
diff --git a/warehouse/static/sass/tools/_typography.scss b/warehouse/static/sass/tools/_typography.scss index ef825b75cf9b..e6e5d72bebf0 100644 --- a/warehouse/static/sass/tools/_typography.scss +++ b/warehouse/static/sass/tools/_typography.scss @@ -31,7 +31,7 @@ // h1 for all other pages @mixin h1-title { - font-size: 1.9rem; + font-size: 1.5rem; font-weight: $bold-font-weight; } diff --git a/warehouse/static/sass/warehouse.scss b/warehouse/static/sass/warehouse.scss index 6b7b4845b3fb..f5b5493c934f 100644 --- a/warehouse/static/sass/warehouse.scss +++ b/warehouse/static/sass/warehouse.scss @@ -102,7 +102,6 @@ @import "blocks/status-badge"; @import "blocks/statistics-bar"; @import "blocks/table"; -@import "blocks/tabs"; @import "blocks/tooltip"; @import "blocks/vertical-tabs"; @import "blocks/viewport-section"; @@ -143,7 +142,6 @@ // Adjust size of h1s on standalone pages .page-title { - @include h2; @include h1-title; } diff --git a/warehouse/templates/includes/edit-project-button.html b/warehouse/templates/includes/edit-project-button.html index 636612ed91d9..5ea96acada81 100644 --- a/warehouse/templates/includes/edit-project-button.html +++ b/warehouse/templates/includes/edit-project-button.html @@ -13,5 +13,5 @@ -#} {% if request.user %} - Edit Project + Edit Project {% endif %} diff --git a/warehouse/templates/manage/manage_base.html b/warehouse/templates/manage/manage_base.html index 38c2e5f6dd3d..9995ec8f5297 100644 --- a/warehouse/templates/manage/manage_base.html +++ b/warehouse/templates/manage/manage_base.html @@ -16,28 +16,38 @@ {% block title %}Manage{% endblock %} {% block content %} -
-
-
-
- +
+
+
+ -
-
- {% block main %}{% endblock %} -
+
+
+ + + +
+ {% block main %}{% endblock %}
-
+ {% endblock %} diff --git a/warehouse/templates/manage/manage_project_base.html b/warehouse/templates/manage/manage_project_base.html new file mode 100644 index 000000000000..94a68df908f2 --- /dev/null +++ b/warehouse/templates/manage/manage_project_base.html @@ -0,0 +1,94 @@ +{# + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-#} +{% extends "base.html" %} + +{% set user = request.user %} +{% set projects = user.projects %} +{% set current_project = project %} +{% set active_tab = active_tab|default('releases') %} + +{% block title %}Manage '{{ project.name }}'{% endblock %} + +{% block content %} +
+
+ +
+ + +
+
+
+
+

{{ project.name }}

+ {% set release = project.releases[0] if project.releases else None %} + {% if release %} +

{{ release.summary }}

+ {% endif %} +
+ +
+
+ + + + {% block main %}{% endblock %} +
+ {% block mobile_tabs_bottom %}{% endblock %} +
+
+
+{% endblock %} diff --git a/warehouse/templates/manage/profile.html b/warehouse/templates/manage/profile.html index 3d3c7077f729..ea2e90aeca3b 100644 --- a/warehouse/templates/manage/profile.html +++ b/warehouse/templates/manage/profile.html @@ -15,7 +15,10 @@ {% set user = request.user %} {% set title = "Manage Your Profile" %} + {% block profile_active %}vertical-tabs__tab--is-active{% endblock %} +{% block profile_mobile_active %}vertical-tabs__tab--is-active{% endblock %} + {% block title %}{{ title }}{% endblock %} {% block main %} diff --git a/warehouse/templates/manage/project.html b/warehouse/templates/manage/project.html deleted file mode 100644 index da30bb5766bc..000000000000 --- a/warehouse/templates/manage/project.html +++ /dev/null @@ -1,229 +0,0 @@ -{# - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. --#} -{% extends "base.html" %} - -{% set user = request.user %} -{% set projects = user.projects %} -{% set current_project = project %} -{% set active_tab = active_tab|default('releases') %} - -{% block title %}Manage '{{ project.name }}'{% endblock %} - -{% block content %} -
-
-
-
- -
-
-
-
-
-
-

{{ project.name }}

- {% set release = project.releases[0] if project.releases else None %} - {% if release %} -

{{ release.summary }}

- {% endif %} -
- -
-
- - {% block main %} -

Releases ({{ project.releases|length }})

- {% if project.releases %} - - - - - - - - - {% for release in project.releases %} - - - - - - - {% endfor %} - -
VersionRelease DateSummary
- {# TODO: https://github.com/pypa/warehouse/issues/2807 {{ release.version }} #} - {{ release.version }} - - {% if release.summary %} - {{ release.summary }} - {% else %} - — - {% endif %} - - -
-
- {% else %} -

No releases

- {% endif %} - {# TODO: https://github.com/pypa/warehouse/issues/2809 -
-

Creating a New Release

-

TODO: Some help text here

-
- #} - {% endblock %} -
-
-
- - - {# TODO: https://github.com/pypa/warehouse/issues/2805 - - #} - - {# TODO: https://github.com/pypa/warehouse/issues/2808 - {% for release in project.releases %} - - {% endfor %} - #} - -
-
-{% endblock %} diff --git a/warehouse/templates/manage/projects.html b/warehouse/templates/manage/projects.html index d73cad806813..7f3d33cc95d1 100644 --- a/warehouse/templates/manage/projects.html +++ b/warehouse/templates/manage/projects.html @@ -14,6 +14,8 @@ {% extends "manage_base.html" %} {% block projects_active %}vertical-tabs__tab--is-active{% endblock %} +{% block projects_mobile_active %}vertical-tabs__tab--is-active{% endblock %} + {% block title %}{{ title }}{% endblock %} {% block main %} @@ -36,7 +38,7 @@

{{ project.name }}

{% endif %}
- Edit + Edit View
diff --git a/warehouse/templates/manage/releases.html b/warehouse/templates/manage/releases.html new file mode 100644 index 000000000000..ba5c9a5fc3b9 --- /dev/null +++ b/warehouse/templates/manage/releases.html @@ -0,0 +1,121 @@ +{# + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-#} +{% extends "manage_project_base.html" %} + +{% set active_tab = 'releases' %} + +{% block title %}Manage '{{ project.name }}' releases{% endblock %} + +{% block main %} +

Releases ({{ project.releases|length }})

+ {% if project.releases %} + + + + + + + + + {% for release in project.releases %} + + + + + + + {% endfor %} + +
VersionRelease DateSummary
+ {# TODO: https://github.com/pypa/warehouse/issues/2807 {{ release.version }} #} + {{ release.version }} + + {% if release.summary %} + {{ release.summary }} + {% else %} + — + {% endif %} + + +
+
+ {% else %} +

No releases

+ {% endif %} + {# TODO: https://github.com/pypa/warehouse/issues/2809 +
+

Creating a New Release

+

TODO: Some help text here

+
+ #} + + {# TODO: https://github.com/pypa/warehouse/issues/2808 + {% for release in project.releases %} + + {% endfor %} + #} +{% endblock %} diff --git a/warehouse/templates/manage/roles.html b/warehouse/templates/manage/roles.html index b6616161be5f..3fd2c686f012 100644 --- a/warehouse/templates/manage/roles.html +++ b/warehouse/templates/manage/roles.html @@ -11,11 +11,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -#} -{% extends "project.html" %} +{% extends "manage_project_base.html" %} -{% block title %}{{ project.name }}{% endblock %} {% set active_tab = 'collaborators' %} +{% block title %}Manage '{{ project.name }}' collaboration{% endblock %} + {% block main %}

Collaborators

Use this page to control which PyPI users can help you to manage '{{ project.name }}'.

@@ -28,7 +29,6 @@

Collaborators

May upload releases for a package.
-
@@ -60,7 +60,7 @@

Collaborators

{% if role.user == request.user %} {{ role.role_name }} {% else %} - + {% for role in roles %} @@ -84,7 +84,7 @@

Collaborators

{% endif %}
User
- + {# The following three lines are added to handle multiple roles for a diff --git a/warehouse/templates/manage/settings.html b/warehouse/templates/manage/settings.html new file mode 100644 index 000000000000..f2e6c2ad2974 --- /dev/null +++ b/warehouse/templates/manage/settings.html @@ -0,0 +1,77 @@ +{# + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-#} +{% extends "manage_project_base.html" %} + +{% set active_tab = 'settings' %} + +{% block title %}Manage '{{ project.name }}' settings{% endblock %} + +{% block main %} +

Project Settings

+ +
+

Delete project

+

+ {% if project.releases %} + Deleting will irreversibly delete this project along with + + {{ project.releases|length() }} + {% trans count=project.releases|length %} + release. + {% pluralize %} + releases. + {% endtrans %} + + {% else %} + Deleting will irreversibly delete this project. + {% endif %} +

+ Delete +
+ + +{% endblock %} diff --git a/warehouse/templates/packaging/detail.html b/warehouse/templates/packaging/detail.html index 5946bc070480..ed537f583e4f 100644 --- a/warehouse/templates/packaging/detail.html +++ b/warehouse/templates/packaging/detail.html @@ -112,20 +112,28 @@

-
-
+
{% if release.urls.values() | contains_valid_uris %} @@ -206,9 +214,26 @@

Classifiers

{% endif %}
+ + {# Tab: Project Description #} - Project Description
+

Project Description

{% if release.description %}
{{ release.description|readme(format="rst") }} @@ -221,9 +246,8 @@

Classifiers

{# Tab: Release History #} - Release History
-

Release History

+

Release History

{% for hrelease in all_releases %} @@ -259,9 +283,8 @@

Release History

{% if files %} {# Tab: Downloads #} - Download Files
-

Download Files

+

Download Files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

diff --git a/warehouse/admin/utils.py b/warehouse/utils/project.py similarity index 90% rename from warehouse/admin/utils.py rename to warehouse/utils/project.py index be8a36d5c625..53ca5b3dad7d 100644 --- a/warehouse/admin/utils.py +++ b/warehouse/utils/project.py @@ -18,7 +18,7 @@ ) -def confirm_project(project, request): +def confirm_project(project, request, fail_route): confirm = request.POST.get("confirm") project_name = project.normalized_name if not confirm: @@ -27,10 +27,7 @@ def confirm_project(project, request): queue="error", ) raise HTTPSeeOther( - request.route_path( - 'admin.project.detail', - project_name=project_name - ) + request.route_path(fail_route, project_name=project_name) ) if canonicalize_name(confirm) != project.normalized_name: request.session.flash( @@ -38,10 +35,7 @@ def confirm_project(project, request): queue="error", ) raise HTTPSeeOther( - request.route_path( - 'admin.project.detail', - project_name=project_name - ) + request.route_path(fail_route, project_name=project_name) )