launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26113
[Merge] ~twom/launchpad:oci-policy-list-some-recipes-for-tasty-ui into launchpad:master
Tom Wardill has proposed merging ~twom/launchpad:oci-policy-list-some-recipes-for-tasty-ui into launchpad:master.
Commit message:
Add recipe view to OCI Project +index
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/396927
If a project has recipes, we should use the spare space on the OCI Project page to view them.
* List official recipes, put the others behind a 'View all recipes' link.
* Move Create OCI Recipe button to right hand side context menu
https://people.canonical.com/~tomwardill/recipe-view-on-project.png
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:oci-policy-list-some-recipes-for-tasty-ui into launchpad:master.
diff --git a/lib/lp/registry/browser/ociproject.py b/lib/lp/registry/browser/ociproject.py
index 380b94a..8a032b6 100644
--- a/lib/lp/registry/browser/ociproject.py
+++ b/lib/lp/registry/browser/ociproject.py
@@ -187,12 +187,22 @@ class OCIProjectNavigationMenu(NavigationMenu):
facet = 'overview'
- links = ('edit',)
+ links = ('edit', 'create_recipe', 'view_recipes')
@enabled_with_permission('launchpad.Edit')
def edit(self):
return Link('+edit', 'Edit OCI project', icon='edit')
+ @enabled_with_permission('launchpad.AnyLegitimatePerson')
+ def create_recipe(self):
+ return Link('+new-recipe', 'Create OCI recipe', icon='add')
+
+ def view_recipes(self):
+ enabled = not getUtility(IOCIRecipeSet).findByOCIProject(
+ self.context).is_empty()
+ return Link(
+ '+recipes', 'View all recipes', icon='info', enabled=enabled)
+
class OCIProjectContextMenu(ContextMenu):
"""Context menu for OCI projects."""
@@ -211,7 +221,7 @@ class OCIProjectContextMenu(ContextMenu):
enabled = not getUtility(IOCIRecipeSet).findByOCIProject(
self.context).is_empty()
return Link(
- '+recipes', 'View OCI recipes', icon='info', enabled=enabled)
+ '+recipes', 'View all recipes', icon='info', enabled=enabled)
class OCIProjectIndexView(LaunchpadView):
@@ -227,6 +237,16 @@ class OCIProjectIndexView(LaunchpadView):
def git_ssh_hostname(self):
return urlsplit(config.codehosting.git_ssh_root).hostname
+ @property
+ def official_recipe_count(self):
+ return self.context.getOfficialRecipes().count()
+
+ @property
+ def other_recipe_count(self):
+ all_count = self.context.getRecipes().count()
+ official_count = self.context.getOfficialRecipes().count()
+ return all_count - official_count
+
class OCIProjectEditView(LaunchpadEditFormView):
"""Edit an OCI project."""
diff --git a/lib/lp/registry/browser/tests/test_ociproject.py b/lib/lp/registry/browser/tests/test_ociproject.py
index a8b4113..980957a 100644
--- a/lib/lp/registry/browser/tests/test_ociproject.py
+++ b/lib/lp/registry/browser/tests/test_ociproject.py
@@ -14,7 +14,7 @@ from datetime import datetime
import pytz
from zope.security.proxy import removeSecurityProxy
-from lp.oci.interfaces.ocirecipe import OCI_RECIPE_ALLOW_CREATE
+from lp.oci.tests.helpers import OCIConfigHelperMixin
from lp.registry.interfaces.ociproject import (
OCI_PROJECT_ALLOW_CREATE,
OCIProjectCreateFeatureDisabled,
@@ -79,10 +79,14 @@ class TestOCIProjectNavigation(TestCaseWithFactory):
self.assertEqual(oci_project, obj)
-class TestOCIProjectView(BrowserTestCase):
+class TestOCIProjectView(OCIConfigHelperMixin, BrowserTestCase):
layer = DatabaseFunctionalLayer
+ def setUp(self):
+ super(TestOCIProjectView, self).setUp()
+ self.setConfig()
+
def test_index_distribution_pillar(self):
distribution = self.factory.makeDistribution(displayname="My Distro")
oci_project = self.factory.makeOCIProject(
@@ -149,6 +153,63 @@ class TestOCIProjectView(BrowserTestCase):
Name: oci-name
""", self.getMainText(oci_project, user=owner))
+ def test_shows_official_recipes(self):
+ distribution = self.factory.makeDistribution(displayname="My Distro")
+ oci_project = self.factory.makeOCIProject(
+ pillar=distribution, ociprojectname="oci-name")
+ self.factory.makeOCIRecipe(oci_project=oci_project, official=True)
+ browser = self.getViewBrowser(
+ oci_project, view_name="+index", user=distribution.owner)
+ self.assertIn("Official recipes", browser.contents)
+ self.assertNotIn("non-official recipe", browser.contents)
+ self.assertNotIn(
+ "There are no recipes registered for this OCI project.",
+ browser.contents)
+
+ def test_shows_official_and_unofficial_recipes(self):
+ distribution = self.factory.makeDistribution(displayname="My Distro")
+ oci_project = self.factory.makeOCIProject(
+ pillar=distribution, ociprojectname="oci-name")
+ self.factory.makeOCIRecipe(oci_project=oci_project, official=True)
+ self.factory.makeOCIRecipe(oci_project=oci_project, official=False)
+ browser = self.getViewBrowser(
+ oci_project, view_name="+index", user=distribution.owner)
+ self.assertIn("Official recipes", browser.contents)
+ self.assertIn(
+ "There is <strong>1</strong> non-official recipe.",
+ browser.contents)
+ self.assertNotIn(
+ "There are no recipes registered for this OCI project.",
+ browser.contents)
+
+ def test_shows_unofficial_recipes(self):
+ distribution = self.factory.makeDistribution(displayname="My Distro")
+ oci_project = self.factory.makeOCIProject(
+ pillar=distribution, ociprojectname="oci-name")
+ self.factory.makeOCIRecipe(oci_project=oci_project, official=False)
+ self.factory.makeOCIRecipe(oci_project=oci_project, official=False)
+ browser = self.getViewBrowser(
+ oci_project, view_name="+index", user=distribution.owner)
+ self.assertNotIn("Official recipes", browser.contents)
+ self.assertIn(
+ "There are <strong>2</strong> non-official recipes.",
+ browser.contents)
+ self.assertNotIn(
+ "There are no recipes registered for this OCI project.",
+ browser.contents)
+
+ def test_shows_no_recipes(self):
+ distribution = self.factory.makeDistribution(displayname="My Distro")
+ oci_project = self.factory.makeOCIProject(
+ pillar=distribution, ociprojectname="oci-name")
+ browser = self.getViewBrowser(
+ oci_project, view_name="+index", user=distribution.owner)
+ self.assertNotIn("Official recipes", browser.contents)
+ self.assertNotIn("non-official recipe", browser.contents)
+ self.assertIn(
+ "There are no recipes registered for this OCI project.",
+ browser.contents)
+
class TestOCIProjectEditView(BrowserTestCase):
diff --git a/lib/lp/registry/templates/ociproject-index.pt b/lib/lp/registry/templates/ociproject-index.pt
index 9fc5197..70b1088 100644
--- a/lib/lp/registry/templates/ociproject-index.pt
+++ b/lib/lp/registry/templates/ociproject-index.pt
@@ -18,7 +18,7 @@
</metal:registering>
<metal:side fill-slot="side">
- <div tal:replace="structure context/@@+global-actions"/>
+ <tal:menu replace="structure context/@@+global-actions" />
</metal:side>
<metal:heading fill-slot="heading">
@@ -65,14 +65,53 @@
</div>
<h2>Recipes</h2>
- <div id="recipe-summary"
- tal:define="link context/menu:context/view_recipes"
- tal:condition="link/enabled"
- tal:content="structure link/render"/>
- <tal:create-recipe
- define="link context/menu:context/create_recipe"
- condition="link/enabled"
- replace="structure link/render"/>
+
+ <h3 tal:condition="view/official_recipe_count">Official recipes</h3>
+ <table class="listing" id="mirrors_list" tal:condition="view/official_recipe_count">
+ <tbody>
+ <tr class="head">
+ <th>Name</th>
+ <th>Owner</th>
+ <th>Source</th>
+ <th>Build file</th>
+ <th>Date created</th>
+ </tr>
+
+ <tr tal:repeat="recipe context/getOfficialRecipes">
+ <td>
+ <a tal:content="recipe/name"
+ tal:attributes="href recipe/fmt:url" />
+ </td>
+ <td tal:content="structure recipe/owner/fmt:link" />
+ <td tal:content="recipe/git_ref/identity" />
+ <td tal:content="recipe/build_file" />
+ <td tal:content="recipe/date_created/fmt:displaydate" />
+ </tr>
+ </tbody>
+ </table>
+ <div tal:condition="python: not view.official_recipe_count and view.other_recipe_count">
+ <p>There are no official recipes for this OCI project.</p>
+ </div>
+
+ <div tal:define="count view/other_recipe_count"
+ tal:condition="count">
+ <span tal:condition="python: count == 1">
+ There is <strong>1</strong> non-official recipe.</span>
+ <span tal:condition="python: count != 1">
+ There are <strong tal:content="count" /> non-official recipes.
+ </span>
+ <p>
+ <tal:summary
+ tal:define="link context/menu:context/view_recipes"
+ tal:condition="link/enabled"
+ tal:content="structure link/render"/>
+ </p>
+ </div>
+
+ <div tal:condition="python: not view.official_recipe_count and not view.other_recipe_count">
+ <p>There are no recipes registered for this OCI project.</p>
+ </div>
+
</div>
</body>
</html>