launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #29662
[Merge] ~cjwatson/launchpad:mypy-next-cancel-url into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:mypy-next-cancel-url into launchpad:master.
Commit message:
Avoid substitution issue with next_url and cancel_url
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/437116
Launchpad's form views are allowed to define `next_url` and `cancel_url` to indicate where the form should redirect to after a successful submission or if the user chooses to cancel. Some do this by assigning to those attributes (especially if the URL is computed based on the submitted form), while some do this by defining those attributes as properties (especially if there are multiple form actions that use the same URLs). There's no obvious way to settle on one approach or the other here, but until now it hasn't mattered.
Unfortunately, `mypy` detects a technical difficulty here. If a base class declares something as a plain attribute, then a subclass that redefines that as a property without also providing a setter (which wouldn't really make sense here) violates the Liskov substitution principle, because assigning to that attribute is allowed for instances of the base class but forbidden for instances of the subclass.
However, if we change the base class to make those attributes be read-only properties (which is all that the general form view infrastructure needs), and then redefine them as plain class attributes (e.g. with `next_url = None`) in all the subclasses that need to assign to them at some point, then the type checker is happier and everything still works. This slightly increases the friction of writing views that assign to those attributes, but for many cases of new views properties will be just fine, and it's lightweight enough not to be too big a problem anyway.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:mypy-next-cancel-url into launchpad:master.
diff --git a/lib/lp/answers/browser/faq.py b/lib/lp/answers/browser/faq.py
index 732bd2d..e8cf8c7 100644
--- a/lib/lp/answers/browser/faq.py
+++ b/lib/lp/answers/browser/faq.py
@@ -69,6 +69,7 @@ class FAQEditView(LaunchpadEditFormView):
schema = IFAQ
label = _("Edit FAQ")
field_names = ["title", "keywords", "content"]
+ next_url = None
@property
def page_title(self):
diff --git a/lib/lp/answers/browser/faqtarget.py b/lib/lp/answers/browser/faqtarget.py
index 7f37282..093ed63 100644
--- a/lib/lp/answers/browser/faqtarget.py
+++ b/lib/lp/answers/browser/faqtarget.py
@@ -35,6 +35,7 @@ class FAQCreateView(LaunchpadFormView):
schema = IFAQ
label = _("Create a new FAQ")
field_names = ["title", "keywords", "content"]
+ next_url = None
custom_widget_keywords = TokensTextWidget
diff --git a/lib/lp/answers/browser/question.py b/lib/lp/answers/browser/question.py
index 65bbd94..6d3ff60 100644
--- a/lib/lp/answers/browser/question.py
+++ b/lib/lp/answers/browser/question.py
@@ -309,6 +309,7 @@ class QuestionSetView(LaunchpadFormView):
schema = IAnswersFrontPageSearchForm
custom_widget_scope = ProjectScopeWidget
+ next_url = None
page_title = "Launchpad Answers"
label = "Questions and Answers"
@@ -964,6 +965,7 @@ class QuestionWorkflowView(LaunchpadFormView, LinkFAQMixin):
"""
schema = IQuestionAddMessageForm
+ next_url = None
# Do not autofocus the message widget.
initial_focus_widget = None
@@ -1364,6 +1366,7 @@ class QuestionCreateFAQView(LinkFAQMixin, LaunchpadFormView):
"""View to create a new FAQ."""
schema = IFAQ
+ next_url = None
label = _("Create a new FAQ")
@property
diff --git a/lib/lp/answers/browser/questiontarget.py b/lib/lp/answers/browser/questiontarget.py
index 8682cf9..ed993fb 100644
--- a/lib/lp/answers/browser/questiontarget.py
+++ b/lib/lp/answers/browser/questiontarget.py
@@ -746,6 +746,7 @@ class ManageAnswerContactView(UserSupportLanguagesMixin, LaunchpadFormView):
label = page_title
custom_widget_answer_contact_teams = LabeledMultiCheckBoxWidget
+ next_url = None
def setUpFields(self):
"""See `LaunchpadFormView`."""
diff --git a/lib/lp/app/browser/launchpadform.py b/lib/lp/app/browser/launchpadform.py
index 126eb3f..3578008 100644
--- a/lib/lp/app/browser/launchpadform.py
+++ b/lib/lp/app/browser/launchpadform.py
@@ -67,10 +67,15 @@ class LaunchpadFormView(LaunchpadView):
field_names = None # type: Optional[List[str]]
# The next URL to redirect to on successful form submission
- next_url = None # type: Optional[str]
+ @property
+ def next_url(self) -> Optional[str]:
+ return None
+
# The cancel URL is rendered as a Cancel link in the form
# macro if set in a derived class.
- cancel_url = None # type: Optional[str]
+ @property
+ def cancel_url(self) -> Optional[str]:
+ return None
# The name of the widget that will receive initial focus in the form.
# By default, the first widget will receive focus. Set this to None
diff --git a/lib/lp/app/doc/launchpadform.rst b/lib/lp/app/doc/launchpadform.rst
index 996ec23..a138ca8 100644
--- a/lib/lp/app/doc/launchpadform.rst
+++ b/lib/lp/app/doc/launchpadform.rst
@@ -396,6 +396,7 @@ Form Rendering
>>> class RenderFormTest(LaunchpadFormView):
... schema = IFormTest
... field_names = ["displayname"]
+ ... next_url = None
...
... def template(self):
... return "Content that comes from a ZCML registered template."
diff --git a/lib/lp/blueprints/browser/specification.py b/lib/lp/blueprints/browser/specification.py
index 1186390..92f61af 100644
--- a/lib/lp/blueprints/browser/specification.py
+++ b/lib/lp/blueprints/browser/specification.py
@@ -867,6 +867,7 @@ class SpecificationEditView(LaunchpadEditFormView):
schema = SpecificationEditSchema
field_names = ["name", "title", "specurl", "summary", "whiteboard"]
+ next_url = None
label = "Edit specification"
custom_widget_summary = CustomWidgetFactory(TextAreaWidget, height=5)
custom_widget_whiteboard = CustomWidgetFactory(TextAreaWidget, height=10)
@@ -1002,6 +1003,7 @@ class SpecificationGoalProposeView(LaunchpadEditFormView):
label = "Target to a distribution series"
field_names = ["distroseries", "whiteboard"]
custom_widget_whiteboard = CustomWidgetFactory(TextAreaWidget, height=5)
+ next_url = None
@property
def initial_values(self):
@@ -1123,6 +1125,7 @@ class SpecificationRetargetingView(LaunchpadFormView):
class SpecificationSupersedingView(LaunchpadFormView):
schema = ISpecification
field_names = ["superseded_by"]
+ next_url = None
label = _("Mark blueprint superseded")
@property
@@ -1386,6 +1389,7 @@ class SpecificationSprintAddView(LaunchpadFormView):
schema = ISprintSpecification
label = _("Propose specification for meeting agenda")
field_names = ["sprint"]
+ next_url = None
# ISprintSpecification.sprint is a read-only field, so we need to set
# for_input to True here to ensure it's rendered as an input widget.
for_input = True
@@ -1657,6 +1661,7 @@ class SpecificationLinkBranchView(LaunchpadFormView):
class SpecificationSetView(AppFrontPageSearchView, HasSpecificationsView):
"""View for the Blueprints index page."""
+ next_url = None
label = "Blueprints"
@property
diff --git a/lib/lp/blueprints/browser/specificationdependency.py b/lib/lp/blueprints/browser/specificationdependency.py
index cdf6ed7..513ac61 100644
--- a/lib/lp/blueprints/browser/specificationdependency.py
+++ b/lib/lp/blueprints/browser/specificationdependency.py
@@ -75,6 +75,7 @@ class SpecificationDependencyRemoveView(LaunchpadFormView):
schema = ISpecificationDependencyRemoval
label = "Remove a dependency"
field_names = ["dependency"]
+ next_url = None
for_input = True
@action("Continue", name="continue")
diff --git a/lib/lp/blueprints/browser/sprint.py b/lib/lp/blueprints/browser/sprint.py
index 047084a..9d66d8b 100644
--- a/lib/lp/blueprints/browser/sprint.py
+++ b/lib/lp/blueprints/browser/sprint.py
@@ -403,6 +403,7 @@ class SprintDeleteView(LaunchpadFormView):
schema = ISprint
field_names = [] # type: List[str]
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/bugs/browser/bugalsoaffects.py b/lib/lp/bugs/browser/bugalsoaffects.py
index 0ec2af3..642dd90 100644
--- a/lib/lp/bugs/browser/bugalsoaffects.py
+++ b/lib/lp/bugs/browser/bugalsoaffects.py
@@ -207,6 +207,8 @@ class BugTaskCreationStep(AlsoAffectsStep):
registered.
"""
+ next_url = None
+
custom_widget_bug_url = CustomWidgetFactory(
StrippedTextWidget, displayWidth=62
)
@@ -820,6 +822,7 @@ class BugAlsoAffectsProductWithProductCreationView(
StrippedTextWidget, displayWidth=62
)
custom_widget_existing_product = LaunchpadRadioWidget
+ next_url = None
existing_products = None
MAX_PRODUCTS_TO_DISPLAY = 10
licenses = [License.DONT_KNOW]
diff --git a/lib/lp/bugs/browser/bugattachment.py b/lib/lp/bugs/browser/bugattachment.py
index ce004b8..0588b51 100644
--- a/lib/lp/bugs/browser/bugattachment.py
+++ b/lib/lp/bugs/browser/bugattachment.py
@@ -106,6 +106,8 @@ class BugAttachmentEditView(LaunchpadFormView, BugAttachmentContentCheck):
schema = IBugAttachmentEditForm
field_names = ["title", "patch", "contenttype"]
+ next_url = None
+ cancel_url = None
def __init__(self, context, request):
LaunchpadFormView.__init__(self, context, request)
@@ -206,6 +208,8 @@ class BugAttachmentPatchConfirmationView(LaunchpadFormView):
"""
schema = IBugAttachmentIsPatchConfirmationForm
+ next_url = None
+ cancel_url = None
custom_widget_patch = LaunchpadBooleanRadioWidget
diff --git a/lib/lp/bugs/browser/buglinktarget.py b/lib/lp/bugs/browser/buglinktarget.py
index 9dda500..693a9eb 100644
--- a/lib/lp/bugs/browser/buglinktarget.py
+++ b/lib/lp/bugs/browser/buglinktarget.py
@@ -39,6 +39,7 @@ class BugLinkView(LaunchpadFormView):
label = _("Link a bug report")
schema = IBugLinkForm
page_title = label
+ next_url = None
focused_element_id = "bug"
@@ -139,6 +140,7 @@ class BugsUnlinkView(LaunchpadFormView):
schema = IUnlinkBugsForm
custom_widget_bugs = LabeledMultiCheckBoxWidget
page_title = label
+ next_url = None
@property
def cancel_url(self):
diff --git a/lib/lp/bugs/browser/bugmessage.py b/lib/lp/bugs/browser/bugmessage.py
index 30cff9e..45761fc 100644
--- a/lib/lp/bugs/browser/bugmessage.py
+++ b/lib/lp/bugs/browser/bugmessage.py
@@ -25,6 +25,7 @@ class BugMessageAddFormView(LaunchpadFormView, BugAttachmentContentCheck):
"""Browser view class for adding a bug comment/attachment."""
schema = IBugMessageAddForm
+ next_url = None
initial_focus_widget = None
custom_widget_comment = CustomWidgetFactory(
diff --git a/lib/lp/bugs/browser/bugtarget.py b/lib/lp/bugs/browser/bugtarget.py
index 5ae70f2..ed93035 100644
--- a/lib/lp/bugs/browser/bugtarget.py
+++ b/lib/lp/bugs/browser/bugtarget.py
@@ -207,12 +207,12 @@ class FileBugViewBase(LaunchpadFormView):
"""Base class for views related to filing a bug."""
schema = IBug
-
custom_widget_information_type = LaunchpadRadioWidgetWithDescription
custom_widget_comment = CustomWidgetFactory(
TextAreaWidget, cssClass="comment-text"
)
custom_widget_packagename = FileBugSourcePackageNameWidget
+ next_url = None
extra_data_token = None
@@ -1350,6 +1350,7 @@ class OfficialBugTagsManageView(LaunchpadEditFormView):
schema = IOfficialBugTagTargetPublic
custom_widget_official_bug_tags = LargeBugTagsWidget
+ next_url = None
label = "Manage official bug tags"
diff --git a/lib/lp/bugs/browser/bugtracker.py b/lib/lp/bugs/browser/bugtracker.py
index 7460e9b..0c02abc 100644
--- a/lib/lp/bugs/browser/bugtracker.py
+++ b/lib/lp/bugs/browser/bugtracker.py
@@ -112,6 +112,7 @@ class BugTrackerAddView(LaunchpadFormView):
"summary",
"contactdetails",
]
+ next_url = None
def setUpWidgets(self, context=None):
# We only show those bug tracker types for which there can be
@@ -251,7 +252,6 @@ BUG_TRACKER_ACTIVE_VOCABULARY = SimpleVocabulary.fromItems(
class BugTrackerEditView(LaunchpadEditFormView):
schema = IBugTracker
-
custom_widget_summary = CustomWidgetFactory(
TextAreaWidget, width=30, height=5
)
@@ -259,6 +259,7 @@ class BugTrackerEditView(LaunchpadEditFormView):
custom_widget_active = CustomWidgetFactory(
LaunchpadRadioWidget, orientation="vertical"
)
+ next_url = None
@property
def page_title(self):
diff --git a/lib/lp/buildmaster/browser/builder.py b/lib/lp/buildmaster/browser/builder.py
index 1c24da5..2d3343a 100644
--- a/lib/lp/buildmaster/browser/builder.py
+++ b/lib/lp/buildmaster/browser/builder.py
@@ -422,6 +422,7 @@ class BuilderSetAddView(LaunchpadFormView):
"""View class for adding new Builders."""
schema = IBuilder
+ next_url = None
label = "Register a new build machine"
diff --git a/lib/lp/charms/browser/charmrecipe.py b/lib/lp/charms/browser/charmrecipe.py
index f80aebb..fefba73 100644
--- a/lib/lp/charms/browser/charmrecipe.py
+++ b/lib/lp/charms/browser/charmrecipe.py
@@ -299,6 +299,8 @@ def log_oops(error, request):
class CharmRecipeAuthorizeMixin:
+ next_url = None
+
def requestAuthorization(self, recipe):
try:
self.next_url = CharmRecipeAuthorizeView.requestAuthorization(
@@ -629,6 +631,7 @@ class CharmRecipeDeleteView(BaseCharmRecipeEditView):
page_title = "Delete"
field_names = []
+ next_url = None
@action("Delete charm recipe", name="delete")
def delete_action(self, action, data):
@@ -644,6 +647,7 @@ class CharmRecipeRequestBuildsView(LaunchpadFormView):
def label(self):
return "Request builds for %s" % self.context.name
+ next_url = None
page_title = "Request builds"
class schema(Interface):
diff --git a/lib/lp/code/browser/branch.py b/lib/lp/code/browser/branch.py
index 0b4add6..c12a290 100644
--- a/lib/lp/code/browser/branch.py
+++ b/lib/lp/code/browser/branch.py
@@ -645,8 +645,8 @@ class BranchView(
class BranchRescanView(LaunchpadEditFormView):
schema = Interface
-
field_names = []
+ next_url = None
@action("Rescan", name="rescan")
def rescan(self, action, data):
@@ -966,6 +966,7 @@ class BranchDeletionView(LaunchpadFormView):
schema = IBranch
field_names = []
+ next_url = None
@property
def page_title(self):
@@ -1301,6 +1302,7 @@ class RegisterBranchMergeProposalView(LaunchpadFormView):
"""The view to register new branch merge proposals."""
schema = RegisterProposalSchema
+ next_url = None
for_input = True
custom_widget_target_branch = TargetBranchWidget
diff --git a/lib/lp/code/browser/branchmergeproposal.py b/lib/lp/code/browser/branchmergeproposal.py
index a789afb..019b22c 100644
--- a/lib/lp/code/browser/branchmergeproposal.py
+++ b/lib/lp/code/browser/branchmergeproposal.py
@@ -627,6 +627,7 @@ class BranchMergeProposalView(
"""A basic view used for the index page."""
schema = ClaimButton
+ next_url = None
def initialize(self):
super().initialize()
@@ -887,8 +888,8 @@ class BranchMergeProposalView(
class BranchMergeProposalRescanView(LaunchpadEditFormView):
schema = Interface
-
field_names = []
+ next_url = None
@action("Rescan", name="rescan")
def rescan(self, action, data):
@@ -1039,8 +1040,8 @@ class BranchMergeProposalVoteView(LaunchpadView):
class BranchMergeProposalScheduleUpdateDiffView(LaunchpadEditFormView):
schema = Interface
-
field_names = []
+ next_url = None
@action("Update", name="update")
def update(self, action, data):
@@ -1118,6 +1119,9 @@ class MergeProposalEditView(
):
"""A base class for merge proposal edit views."""
+ next_url = None
+ cancel_url = None
+
def initialize(self):
# Record next_url and cancel url now
self.next_url = canonical_url(self.context)
@@ -1143,6 +1147,8 @@ class BranchMergeProposalResubmitView(
"""The view to resubmit a proposal to merge."""
schema = ResubmitSchema
+ next_url = None
+ cancel_url = None
for_input = True
page_title = label = "Resubmit proposal to merge"
@@ -1277,6 +1283,7 @@ class BranchMergeProposalDeleteView(MergeProposalEditView):
schema = IBranchMergeProposal
field_names = []
+ next_url = None
page_title = label = "Delete proposal to merge branch"
def initialize(self):
diff --git a/lib/lp/code/browser/codeimport.py b/lib/lp/code/browser/codeimport.py
index 7856269..e856781 100644
--- a/lib/lp/code/browser/codeimport.py
+++ b/lib/lp/code/browser/codeimport.py
@@ -345,6 +345,7 @@ class CodeImportNewView(CodeImportBaseView, CodeImportNameValidationMixin):
"""The view to request a new code import."""
schema = NewCodeImportForm
+ next_url = None
for_input = True
custom_widget_rcs_type = LaunchpadRadioWidget
@@ -635,6 +636,8 @@ class CodeImportEditView(CodeImportBaseView):
"""
schema = EditCodeImportForm
+ next_url = None
+ cancel_url = None
# Need this to render the context to prepopulate the form fields.
# Added here as the base class isn't LaunchpadEditFormView.
diff --git a/lib/lp/code/browser/gitref.py b/lib/lp/code/browser/gitref.py
index df8c704..33f630a 100644
--- a/lib/lp/code/browser/gitref.py
+++ b/lib/lp/code/browser/gitref.py
@@ -333,6 +333,7 @@ class GitRefRegisterMergeProposalView(LaunchpadFormView):
"""The view to register new Git merge proposals."""
schema = GitRefRegisterMergeProposalSchema
+ next_url = None
for_input = True
custom_widget_target_git_ref = CustomWidgetFactory(
diff --git a/lib/lp/code/browser/gitrepository.py b/lib/lp/code/browser/gitrepository.py
index c3724f0..17056f8 100644
--- a/lib/lp/code/browser/gitrepository.py
+++ b/lib/lp/code/browser/gitrepository.py
@@ -552,8 +552,8 @@ class GitRepositoryView(
class GitRepositoryForkView(LaunchpadEditFormView):
schema = Interface
-
field_names = []
+ next_url = None
def initialize(self):
if not getFeatureFlag(GIT_REPOSITORY_FORK_ENABLED):
@@ -596,8 +596,8 @@ class GitRepositoryForkView(LaunchpadEditFormView):
class GitRepositoryRescanView(LaunchpadEditFormView):
schema = Interface
-
field_names = []
+ next_url = None
@action("Rescan", name="rescan")
def rescan(self, action, data):
@@ -1019,6 +1019,8 @@ class GitRulePatternField(UniqueField):
class GitRepositoryPermissionsView(LaunchpadFormView):
"""A view to manage repository permissions."""
+ next_url = None
+
heads_prefix = "refs/heads/"
tags_prefix = "refs/tags/"
@@ -1552,6 +1554,7 @@ class GitRepositoryDeletionView(LaunchpadFormView):
schema = IGitRepository
field_names = []
+ next_url = None
@property
def page_title(self):
diff --git a/lib/lp/code/browser/sourcepackagerecipe.py b/lib/lp/code/browser/sourcepackagerecipe.py
index 002520d..baed5b7 100644
--- a/lib/lp/code/browser/sourcepackagerecipe.py
+++ b/lib/lp/code/browser/sourcepackagerecipe.py
@@ -445,6 +445,8 @@ class SourcePackageRecipeRequestBuildsHtmlView(
):
"""Supports HTML form recipe build requests."""
+ next_url = None
+
@property
def title(self):
return "Request builds for %s" % self.context.name
@@ -536,6 +538,8 @@ class SourcePackageRecipeRequestDailyBuildView(LaunchpadFormView):
This view works for both ajax and html form requests.
"""
+ next_url = None
+
# Attributes for the html version
page_title = "Build now"
@@ -782,6 +786,7 @@ class SourcePackageRecipeAddView(
title = label = "Create a new source package recipe"
schema = ISourcePackageAddSchema
+ next_url = None
custom_widget_distroseries = LabeledMultiCheckBoxWidget
custom_widget_owner = RecipeOwnerWidget
custom_widget_use_ppa = LaunchpadRadioWidget
@@ -959,6 +964,7 @@ class SourcePackageRecipeEditView(
label = title
schema = ISourcePackageEditSchema
+ next_url = None
custom_widget_distroseries = LabeledMultiCheckBoxWidget
def setUpFields(self):
diff --git a/lib/lp/coop/answersbugs/browser.py b/lib/lp/coop/answersbugs/browser.py
index 879a801..70c5abd 100644
--- a/lib/lp/coop/answersbugs/browser.py
+++ b/lib/lp/coop/answersbugs/browser.py
@@ -16,8 +16,8 @@ class QuestionMakeBugView(LaunchpadFormView):
"""Browser class for adding a bug from a question."""
schema = IBug
-
field_names = ["title", "description"]
+ next_url = None
def initialize(self):
"""Initialize the view when a Bug may be reported for the Question."""
diff --git a/lib/lp/oci/browser/ocirecipe.py b/lib/lp/oci/browser/ocirecipe.py
index 1e5e06e..7fe9c3d 100644
--- a/lib/lp/oci/browser/ocirecipe.py
+++ b/lib/lp/oci/browser/ocirecipe.py
@@ -403,6 +403,8 @@ class InvisibleCredentialsWidget(DisplayWidget):
class OCIRecipeEditPushRulesView(LaunchpadFormView):
"""View for +ocirecipe-edit-push-rules.pt."""
+ next_url = None
+
class schema(Interface):
"""Schema for editing push rules."""
@@ -794,6 +796,8 @@ class OCIRecipeEditPushRulesView(LaunchpadFormView):
class OCIRecipeRequestBuildsView(LaunchpadFormView):
"""A view for requesting builds of an OCI recipe."""
+ next_url = None
+
@property
def label(self):
return "Request builds for %s" % self.context.name
@@ -986,6 +990,7 @@ class OCIRecipeAddView(
"build_daily",
)
custom_widget_git_ref = GitRefWidget
+ next_url = None
def initialize(self):
super().initialize()
@@ -1133,6 +1138,7 @@ class OCIRecipeAddView(
class BaseOCIRecipeEditView(LaunchpadEditFormView):
schema = IOCIRecipeEditSchema
+ next_url = None
@property
def private(self):
@@ -1345,6 +1351,7 @@ class OCIRecipeDeleteView(BaseOCIRecipeEditView):
page_title = "Delete"
field_names = ()
+ next_url = None
@action("Delete OCI recipe", name="delete")
def delete_action(self, action, data):
diff --git a/lib/lp/registry/browser/announcement.py b/lib/lp/registry/browser/announcement.py
index ef7957e..6260fdf 100644
--- a/lib/lp/registry/browser/announcement.py
+++ b/lib/lp/registry/browser/announcement.py
@@ -131,6 +131,7 @@ class AnnouncementAddView(LaunchpadFormView):
"""A view for creating a new Announcement."""
schema = AddAnnouncementForm
+ next_url = None
label = "Make an announcement"
page_title = label
@@ -162,6 +163,7 @@ class AnnouncementEditView(AnnouncementFormMixin, LaunchpadFormView):
"""A view which allows you to edit the announcement."""
schema = AddAnnouncementForm
+ next_url = None
field_names = [
"title",
"summary",
@@ -203,6 +205,7 @@ class AnnouncementRetargetView(AnnouncementFormMixin, LaunchpadFormView):
schema = AnnouncementRetargetForm
field_names = ["target"]
+ next_url = None
page_title = "Move announcement"
def validate(self, data):
@@ -242,6 +245,7 @@ class AnnouncementPublishView(AnnouncementFormMixin, LaunchpadFormView):
schema = AddAnnouncementForm
field_names = ["publication_date"]
+ next_url = None
page_title = "Publish announcement"
custom_widget_publication_date = AnnouncementDateWidget
@@ -257,6 +261,7 @@ class AnnouncementRetractView(AnnouncementFormMixin, LaunchpadFormView):
"""A view to unpublish an announcement."""
schema = IAnnouncement
+ next_url = None
page_title = "Retract announcement"
@action(_("Retract"), name="retract")
@@ -269,6 +274,7 @@ class AnnouncementDeleteView(AnnouncementFormMixin, LaunchpadFormView):
"""A view to delete an annoucement."""
schema = IAnnouncement
+ next_url = None
page_title = "Delete announcement"
@action(_("Delete"), name="delete", validator="validate_cancel")
diff --git a/lib/lp/registry/browser/codeofconduct.py b/lib/lp/registry/browser/codeofconduct.py
index 3c47070..531e8c2 100644
--- a/lib/lp/registry/browser/codeofconduct.py
+++ b/lib/lp/registry/browser/codeofconduct.py
@@ -179,6 +179,7 @@ class AffirmCodeOfConductView(LaunchpadFormView):
)
field_names = ["affirmed"]
+ next_url = None
@property
def page_title(self):
@@ -206,6 +207,7 @@ class SignedCodeOfConductAddView(LaunchpadFormView):
schema = ISignedCodeOfConduct
field_names = ["signedcode"]
+ next_url = None
@property
def page_title(self):
diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
index 7180941..ba5d9e9 100644
--- a/lib/lp/registry/browser/distribution.py
+++ b/lib/lp/registry/browser/distribution.py
@@ -1052,6 +1052,7 @@ class DistributionAddView(
]
custom_widget_require_virtualized = CheckBoxWidget
custom_widget_processors = LabeledMultiCheckBoxWidget
+ next_url = None
@property
def page_title(self):
@@ -1227,11 +1228,11 @@ class DistributionAdminView(LaunchpadEditFormView):
"redirect_default_traversal",
"information_type",
]
-
custom_widget_information_type = CustomWidgetFactory(
LaunchpadRadioWidgetWithDescription,
vocabulary=InformationTypeVocabulary(types=PILLAR_INFORMATION_TYPES),
)
+ next_url = None
@property
def label(self):
@@ -1602,6 +1603,7 @@ class DistributionPublisherConfigView(LaunchpadFormView):
schema = IPublisherConfig
field_names = ["root_dir", "base_url", "copy_base_url"]
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/registry/browser/distributionmirror.py b/lib/lp/registry/browser/distributionmirror.py
index 262784e..0876547 100644
--- a/lib/lp/registry/browser/distributionmirror.py
+++ b/lib/lp/registry/browser/distributionmirror.py
@@ -178,6 +178,7 @@ class DistributionMirrorDeleteView(LaunchpadFormView):
schema = IDistributionMirror
field_names = []
+ next_url = None
@property
def label(self):
@@ -231,6 +232,7 @@ class DistributionMirrorAddView(LaunchpadFormView):
"content",
"official_candidate",
]
+ next_url = None
invariant_context = None
@property
@@ -273,6 +275,7 @@ class DistributionMirrorReviewView(LaunchpadEditFormView):
schema = IDistributionMirror
field_names = ["status", "whiteboard"]
+ next_url = None
@property
def label(self):
@@ -316,6 +319,7 @@ class DistributionMirrorEditView(LaunchpadEditFormView):
"content",
"official_candidate",
]
+ next_url = None
@property
def label(self):
@@ -342,6 +346,7 @@ class DistributionMirrorResubmitView(LaunchpadEditFormView):
schema = IDistributionMirror
field_names = []
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/registry/browser/distroseries.py b/lib/lp/registry/browser/distroseries.py
index f1a25fe..b9e1af2 100644
--- a/lib/lp/registry/browser/distroseries.py
+++ b/lib/lp/registry/browser/distroseries.py
@@ -614,6 +614,7 @@ class DistroSeriesEditView(LaunchpadEditFormView, SeriesStatusMixin):
schema = IDistroSeries
field_names = ["display_name", "title", "summary", "description"]
custom_widget_status = LaunchpadDropdownWidget
+ next_url = None
@property
def label(self):
@@ -672,6 +673,7 @@ class DistroSeriesAdminView(LaunchpadEditFormView, SeriesStatusMixin):
"inherit_overrides_from_parents",
]
custom_widget_status = LaunchpadDropdownWidget
+ next_url = None
@property
def label(self):
@@ -745,6 +747,7 @@ class DistroSeriesAddView(LaunchpadFormView):
"display_name",
"summary",
]
+ next_url = None
help_links = {
"name": "/+help-registry/distribution-add-series.html#codename",
@@ -952,6 +955,7 @@ class DistroSeriesDifferenceBaseView(
header="Select person being sponsored",
show_assign_me_button=False,
)
+ next_url = None
# Differences type to display. Can be overrided by sublasses.
differences_type = DistroSeriesDifferenceType.DIFFERENT_VERSIONS
diff --git a/lib/lp/registry/browser/featuredproject.py b/lib/lp/registry/browser/featuredproject.py
index 4152919..6eb67f9 100644
--- a/lib/lp/registry/browser/featuredproject.py
+++ b/lib/lp/registry/browser/featuredproject.py
@@ -48,6 +48,7 @@ class FeaturedProjectsView(LaunchpadFormView):
schema = FeaturedProjectForm
custom_widget_remove = LabeledMultiCheckBoxWidget
+ next_url = None
@action(_("Update featured project list"), name="update")
def update_action(self, action, data):
diff --git a/lib/lp/registry/browser/karma.py b/lib/lp/registry/browser/karma.py
index 19daccc..b9c2a09 100644
--- a/lib/lp/registry/browser/karma.py
+++ b/lib/lp/registry/browser/karma.py
@@ -42,6 +42,7 @@ class KarmaActionEditView(LaunchpadEditFormView):
schema = IKarmaAction
field_names = ["name", "category", "points", "title", "summary"]
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/registry/browser/milestone.py b/lib/lp/registry/browser/milestone.py
index e6926a3..8462a5c 100644
--- a/lib/lp/registry/browser/milestone.py
+++ b/lib/lp/registry/browser/milestone.py
@@ -478,8 +478,8 @@ class MilestoneAddView(MilestoneTagBase, LaunchpadFormView):
schema = IMilestone
field_names = ["name", "code_name", "dateexpected", "summary"]
label = "Register a new milestone"
-
custom_widget_dateexpected = DateWidget
+ next_url = None
@action(_("Register Milestone"), name="register")
def register_action(self, action, data):
@@ -516,8 +516,8 @@ class MilestoneEditView(MilestoneTagBase, LaunchpadEditFormView):
schema = IMilestone
label = "Modify milestone details"
-
custom_widget_dateexpected = DateWidget
+ next_url = None
@property
def cancel_url(self):
@@ -582,6 +582,7 @@ class MilestoneDeleteView(LaunchpadFormView, RegistryDeleteViewMixin):
schema = IMilestone
field_names = []
+ next_url = None
@property
def cancel_url(self):
@@ -644,6 +645,7 @@ class MilestoneTagView(
"""A View for listing bugtasks and specification for milestone tags."""
schema = ISearchMilestoneTagsForm
+ next_url = None
def __init__(self, context, request):
"""See `LaunchpadView`.
diff --git a/lib/lp/registry/browser/ociproject.py b/lib/lp/registry/browser/ociproject.py
index e5d00c7..fe0817e 100644
--- a/lib/lp/registry/browser/ociproject.py
+++ b/lib/lp/registry/browser/ociproject.py
@@ -111,6 +111,7 @@ class OCIProjectAddView(LaunchpadFormView):
schema = IOCIProjectName
field_names = ["name"]
+ next_url = None
def initialize(self):
if not getFeatureFlag(
diff --git a/lib/lp/registry/browser/peoplemerge.py b/lib/lp/registry/browser/peoplemerge.py
index 63f7bd9..1a2d1f3 100644
--- a/lib/lp/registry/browser/peoplemerge.py
+++ b/lib/lp/registry/browser/peoplemerge.py
@@ -112,6 +112,7 @@ class ValidatingMergeView(LaunchpadFormView):
class AdminMergeBaseView(ValidatingMergeView):
"""Base view for the pages where admins can merge people/teams."""
+ next_url = None
page_title = "Merge Launchpad accounts"
# Both subclasses share the same template so we need to define these
# variables (which are used in the template) here rather than on
@@ -476,6 +477,7 @@ class RequestPeopleMergeView(ValidatingMergeView):
label = "Merge Launchpad accounts"
page_title = label
schema = IRequestPeopleMerge
+ next_url = None
@property
def cancel_url(self):
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 8145cc0..ed88065 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -1087,6 +1087,7 @@ class PersonDeactivateAccountView(LaunchpadFormView):
custom_widget_comment = CustomWidgetFactory(
TextAreaWidget, height=5, width=60
)
+ next_url = None
def validate(self, data):
"""See `LaunchpadFormView`."""
@@ -2888,6 +2889,7 @@ class PersonEditEmailsView(LaunchpadFormView):
"""
schema = IEmailAddress
+ next_url = None
custom_widget_VALIDATED_SELECTED = CustomWidgetFactory(
LaunchpadRadioWidget, orientation="vertical"
@@ -3275,6 +3277,7 @@ class PersonEditMailingListsView(LaunchpadFormView):
"""A view for editing a person's mailing list subscriptions."""
schema = IEmailAddress
+ next_url = None
custom_widget_mailing_list_auto_subscribe_policy = (
LaunchpadRadioWidgetWithDescription
@@ -4004,6 +4007,7 @@ class PersonEditOCIRegistryCredentialsView(LaunchpadFormView):
)
schema = Interface
+ next_url = None
def initialize(self):
if not user_can_edit_credentials_for_owner(self.context, self.user):
@@ -4679,6 +4683,7 @@ class EmailToPersonView(LaunchpadFormView):
schema = IEmailToPerson
field_names = ["subject", "message"]
custom_widget_subject = CustomWidgetFactory(TextWidget, displayWidth=60)
+ next_url = None
def initialize(self):
"""See `ILaunchpadFormView`."""
diff --git a/lib/lp/registry/browser/poll.py b/lib/lp/registry/browser/poll.py
index b182a91..f13348f 100644
--- a/lib/lp/registry/browser/poll.py
+++ b/lib/lp/registry/browser/poll.py
@@ -419,6 +419,7 @@ class PollAddView(LaunchpadFormView):
"dateopens",
"datecloses",
]
+ next_url = None
invariant_context = None
page_title = "New poll"
@@ -459,6 +460,7 @@ class PollEditView(LaunchpadEditFormView):
"dateopens",
"datecloses",
]
+ next_url = None
@property
def cancel_url(self):
@@ -479,6 +481,7 @@ class PollOptionEditView(LaunchpadEditFormView):
page_title = "Edit option"
field_names = ["name", "title"]
custom_widget_title = CustomWidgetFactory(TextWidget, displayWidth=30)
+ next_url = None
@property
def cancel_url(self):
@@ -499,6 +502,7 @@ class PollOptionAddView(LaunchpadFormView):
page_title = "New option"
field_names = ["name", "title"]
custom_widget_title = CustomWidgetFactory(TextWidget, displayWidth=30)
+ next_url = None
@property
def cancel_url(self):
diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py
index f90e27a..5f90da9 100644
--- a/lib/lp/registry/browser/product.py
+++ b/lib/lp/registry/browser/product.py
@@ -2601,6 +2601,7 @@ class ProjectAddStepTwo(StepView, ProductLicenseMixin, ReturnToReferrerMixin):
"owner",
]
schema = IProduct
+ next_url = None
step_name = "projectaddstep2"
template = ViewPageTemplateFile("../templates/product-new.pt")
page_title = ProjectAddStepOne.page_title
diff --git a/lib/lp/registry/browser/productrelease.py b/lib/lp/registry/browser/productrelease.py
index 3bf5b32..99ae3db 100644
--- a/lib/lp/registry/browser/productrelease.py
+++ b/lib/lp/registry/browser/productrelease.py
@@ -99,7 +99,6 @@ class ProductReleaseAddViewBase(LaunchpadFormView):
"""
schema = IProductRelease
-
custom_widget_datereleased = DateTimeWidget
custom_widget_release_notes = CustomWidgetFactory(
TextAreaWidget, height=7, width=62
@@ -107,6 +106,7 @@ class ProductReleaseAddViewBase(LaunchpadFormView):
custom_widget_changelog = CustomWidgetFactory(
TextAreaWidget, height=7, width=62
)
+ next_url = None
def _prependKeepMilestoneActiveField(self):
keep_milestone_active_checkbox = FormFields(
@@ -235,7 +235,6 @@ class ProductReleaseEditView(LaunchpadEditFormView):
"release_notes",
"changelog",
]
-
custom_widget_datereleased = DateTimeWidget
custom_widget_release_notes = CustomWidgetFactory(
TextAreaWidget, height=7, width=62
@@ -243,6 +242,7 @@ class ProductReleaseEditView(LaunchpadEditFormView):
custom_widget_changelog = CustomWidgetFactory(
TextAreaWidget, height=7, width=62
)
+ next_url = None
@property
def label(self):
@@ -279,10 +279,10 @@ class ProductReleaseAddDownloadFileView(LaunchpadFormView):
"""A view for adding a file to an `IProductRelease`."""
schema = IProductReleaseFileAddForm
-
custom_widget_description = CustomWidgetFactory(
TextWidget, displayWidth=60
)
+ next_url = None
@property
def label(self):
@@ -365,6 +365,7 @@ class ProductReleaseDeleteView(LaunchpadFormView, RegistryDeleteViewMixin):
schema = IProductRelease
field_names = []
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/registry/browser/productseries.py b/lib/lp/registry/browser/productseries.py
index 9b05317..807d373 100644
--- a/lib/lp/registry/browser/productseries.py
+++ b/lib/lp/registry/browser/productseries.py
@@ -712,6 +712,7 @@ class ProductSeriesDeleteView(RegistryDeleteViewMixin, LaunchpadEditFormView):
schema = IProductSeries
field_names = []
+ next_url = None
@property
def label(self):
@@ -846,6 +847,7 @@ class ProductSeriesReviewView(LaunchpadEditFormView):
schema = IProductSeries
field_names = ["product", "name"]
custom_widget_name = CustomWidgetFactory(TextWidget, displayWidth=20)
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/registry/browser/sourcepackage.py b/lib/lp/registry/browser/sourcepackage.py
index 461a963..9fb232e 100644
--- a/lib/lp/registry/browser/sourcepackage.py
+++ b/lib/lp/registry/browser/sourcepackage.py
@@ -595,6 +595,7 @@ class SourcePackageAssociationPortletView(LaunchpadFormView):
custom_widget_upstream = CustomWidgetFactory(
LaunchpadRadioWidget, orientation="vertical"
)
+ next_url = None
product_suggestions = None
initial_focus_widget = None
max_suggestions = 9
diff --git a/lib/lp/registry/browser/team.py b/lib/lp/registry/browser/team.py
index 8de222c..386c325 100644
--- a/lib/lp/registry/browser/team.py
+++ b/lib/lp/registry/browser/team.py
@@ -622,6 +622,7 @@ class TeamMailingListConfigurationView(MailingListTeamBaseView):
TextAreaWidget, width=72, height=10
)
page_title = label
+ next_url = None
def __init__(self, context, request):
"""Set feedback messages for users who want to edit the mailing list.
@@ -958,6 +959,7 @@ class TeamMailingListModerationView(MailingListTeamBaseView):
"""A view for moderating the held messages of a mailing list."""
schema = Interface
+ next_url = None
label = "Mailing list moderation"
def __init__(self, context, request):
@@ -1070,7 +1072,6 @@ class TeamAddView(TeamFormMixin, HasRenewalPolicyMixin, LaunchpadFormView):
invariant_context = None
page_title = "Register a new team in Launchpad"
label = page_title
-
custom_widget_teamowner = HiddenUserWidget
custom_widget_renewal_policy = CustomWidgetFactory(
LaunchpadRadioWidget, orientation="vertical"
@@ -1081,6 +1082,7 @@ class TeamAddView(TeamFormMixin, HasRenewalPolicyMixin, LaunchpadFormView):
custom_widget_defaultrenewalperiod = CustomWidgetFactory(
IntWidget, widget_class="field subordinate"
)
+ next_url = None
def setUpFields(self):
"""See `LaunchpadViewForm`.
@@ -1165,6 +1167,7 @@ class SimpleTeamAddView(TeamAddView):
class ProposedTeamMembersEditView(LaunchpadFormView):
schema = Interface
+ next_url = None
label = "Proposed team members"
@action("Save changes", name="save")
@@ -2097,6 +2100,7 @@ class TeamAddMyTeamsView(LaunchpadFormView):
page_title = "Propose/add one of your teams to another one"
custom_widget_teams = LabeledMultiCheckBoxWidget
+ next_url = None
def initialize(self):
context = self.context
diff --git a/lib/lp/services/oauth/browser/__init__.py b/lib/lp/services/oauth/browser/__init__.py
index 2a67f72..3b30e33 100644
--- a/lib/lp/services/oauth/browser/__init__.py
+++ b/lib/lp/services/oauth/browser/__init__.py
@@ -182,6 +182,7 @@ class OAuthAuthorizeTokenView(LaunchpadFormView, JSONTokenMixin):
page_title = label
schema = IOAuthRequestToken
field_names = []
+ next_url = None
token = None
@property
diff --git a/lib/lp/services/webhooks/browser.py b/lib/lp/services/webhooks/browser.py
index fefbf51..73b9f35 100644
--- a/lib/lp/services/webhooks/browser.py
+++ b/lib/lp/services/webhooks/browser.py
@@ -112,6 +112,7 @@ class WebhookAddView(LaunchpadFormView):
schema = WebhookEditSchema
custom_widget_event_types = LabeledMultiCheckBoxWidget
+ next_url = None
@property
def inside_breadcrumb(self):
@@ -184,6 +185,7 @@ class WebhookView(LaunchpadEditFormView):
class WebhookDeleteView(LaunchpadFormView):
schema = Interface
+ next_url = None
page_title = label = "Delete webhook"
diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py
index 80819c0..9917601 100644
--- a/lib/lp/snappy/browser/snap.py
+++ b/lib/lp/snappy/browser/snap.py
@@ -399,6 +399,8 @@ def builds_and_requests_for_snap(snap):
class SnapRequestBuildsView(LaunchpadFormView):
"""A view for requesting builds of a snap package."""
+ next_url = None
+
@property
def label(self):
return "Request builds for %s" % self.context.name
@@ -527,6 +529,8 @@ def log_oops(error, request):
class SnapAuthorizeMixin:
+ next_url = None
+
def requestAuthorization(self, snap):
try:
self.next_url = SnapAuthorizeView.requestAuthorization(
@@ -552,6 +556,7 @@ class SnapAddView(
page_title = label = "Create a new snap package"
schema = ISnapEditSchema
+ next_url = None
custom_widget_vcs = LaunchpadRadioWidget
custom_widget_git_ref = CustomWidgetFactory(
@@ -770,6 +775,7 @@ class BaseSnapEditView(
):
schema = ISnapEditSchema
+ next_url = None
@property
def cancel_url(self):
@@ -1152,6 +1158,7 @@ class SnapDeleteView(BaseSnapEditView):
page_title = "Delete"
field_names = []
+ next_url = None
@action("Delete snap package", name="delete")
def delete_action(self, action, data):
diff --git a/lib/lp/soyuz/browser/archive.py b/lib/lp/soyuz/browser/archive.py
index 6bbca05..943ef77 100644
--- a/lib/lp/soyuz/browser/archive.py
+++ b/lib/lp/soyuz/browser/archive.py
@@ -1179,6 +1179,7 @@ class ArchiveSourceSelectionFormView(ArchiveSourcePackageListViewBase):
"""Base class to implement a source selection widget for PPAs."""
custom_widget_selected_sources = LabeledMultiCheckBoxWidget
+ next_url = None
selectable_sources = True
@@ -1745,7 +1746,6 @@ class ArchiveEditDependenciesView(ArchiveViewBase, LaunchpadFormView):
"""Archive dependencies view class."""
schema = IArchiveEditDependenciesForm
-
custom_widget_selected_dependencies = CustomWidgetFactory(
PlainMultiCheckBoxWidget,
cssClass="line-through-when-checked ppa-dependencies",
@@ -1756,6 +1756,8 @@ class ArchiveEditDependenciesView(ArchiveViewBase, LaunchpadFormView):
custom_widget_primary_components = CustomWidgetFactory(
LaunchpadRadioWidget, cssClass="highlight-selected"
)
+ next_url = None
+ cancel_url = None
label = "Edit PPA dependencies"
page_title = label
@@ -2117,6 +2119,7 @@ class ArchiveActivateView(LaunchpadFormView):
field_names = ("name", "displayname", "description")
custom_widget_description = CustomWidgetFactory(TextAreaWidget, height=3)
custom_widget_name = CustomWidgetFactory(PPANameWidget, label="URL")
+ next_url = None
label = "Activate a Personal Package Archive"
page_title = "Activate PPA"
@@ -2234,6 +2237,7 @@ class BaseArchiveEditView(LaunchpadEditFormView, ArchiveViewBase):
schema = IArchive
field_names = []
+ next_url = None
@action(_("Save"), name="save", validator="validate_save")
def save_action(self, action, data):
diff --git a/lib/lp/soyuz/browser/archivesubscription.py b/lib/lp/soyuz/browser/archivesubscription.py
index de0bb9a..425b07b 100644
--- a/lib/lp/soyuz/browser/archivesubscription.py
+++ b/lib/lp/soyuz/browser/archivesubscription.py
@@ -132,6 +132,7 @@ class ArchiveSubscribersView(LaunchpadFormView):
custom_widget_subscriber = CustomWidgetFactory(
PersonPickerWidget, header="Select the subscriber"
)
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/soyuz/browser/build.py b/lib/lp/soyuz/browser/build.py
index 27d3b5b..81af820 100644
--- a/lib/lp/soyuz/browser/build.py
+++ b/lib/lp/soyuz/browser/build.py
@@ -342,6 +342,8 @@ class BuildRescoringView(LaunchpadFormView):
"""View class for build rescoring."""
schema = IBuildRescoreForm
+ next_url = None
+ cancel_url = None
@property
def label(self):
diff --git a/lib/lp/soyuz/browser/distroarchseries.py b/lib/lp/soyuz/browser/distroarchseries.py
index d3dae16..8415df0 100644
--- a/lib/lp/soyuz/browser/distroarchseries.py
+++ b/lib/lp/soyuz/browser/distroarchseries.py
@@ -100,6 +100,7 @@ class DistroArchSeriesAddView(LaunchpadFormView):
schema = DistroArchSeriesAddSchema
field_names = ["architecturetag", "processor", "official"]
+ next_url = None
@property
def label(self):
diff --git a/lib/lp/soyuz/browser/livefs.py b/lib/lp/soyuz/browser/livefs.py
index 0fea4d9..b5c1cfc 100644
--- a/lib/lp/soyuz/browser/livefs.py
+++ b/lib/lp/soyuz/browser/livefs.py
@@ -227,6 +227,7 @@ class LiveFSAddView(LiveFSMetadataValidatorMixin, LaunchpadFormView):
schema = ILiveFSEditSchema
field_names = ["owner", "name", "distro_series", "metadata"]
custom_widget_distro_series = LaunchpadRadioWidget
+ next_url = None
def initialize(self):
"""See `LaunchpadView`."""
@@ -281,6 +282,7 @@ class LiveFSAddView(LiveFSMetadataValidatorMixin, LaunchpadFormView):
class BaseLiveFSEditView(LaunchpadEditFormView):
schema = ILiveFSEditSchema
+ next_url = None
@property
def cancel_url(self):
@@ -383,6 +385,7 @@ class LiveFSDeleteView(BaseLiveFSEditView):
label = title
field_names = []
+ next_url = None
@property
def has_builds(self):
diff --git a/lib/lp/translations/browser/distroseries.py b/lib/lp/translations/browser/distroseries.py
index 563d9b0..c9e12a3 100644
--- a/lib/lp/translations/browser/distroseries.py
+++ b/lib/lp/translations/browser/distroseries.py
@@ -58,6 +58,7 @@ class DistroSeriesLanguagePackView(LaunchpadEditFormView):
"""Browser view to manage used language packs."""
schema = IDistroSeries
+ next_url = None
label = "Language packs"
page_title = "Language packs"
diff --git a/lib/lp/translations/browser/hastranslationimports.py b/lib/lp/translations/browser/hastranslationimports.py
index c1f7623..7d14f94 100644
--- a/lib/lp/translations/browser/hastranslationimports.py
+++ b/lib/lp/translations/browser/hastranslationimports.py
@@ -46,7 +46,6 @@ class HasTranslationImportsView(LaunchpadFormView):
schema = IHasTranslationImports
field_names = []
-
custom_widget_filter_target = CustomWidgetFactory(
DropdownWidget, cssClass="inlined-widget"
)
@@ -59,6 +58,7 @@ class HasTranslationImportsView(LaunchpadFormView):
custom_widget_status = CustomWidgetFactory(
DropdownWidget, cssClass="inlined-widget"
)
+ next_url = None
translation_import_queue_macros = ViewPageTemplateFile(
"../templates/translation-import-queue-macros.pt"
diff --git a/lib/lp/translations/browser/person.py b/lib/lp/translations/browser/person.py
index 12e0c34..f7a5037 100644
--- a/lib/lp/translations/browser/person.py
+++ b/lib/lp/translations/browser/person.py
@@ -454,6 +454,7 @@ class PersonTranslationRelicensingView(LaunchpadFormView):
LaunchpadRadioWidget, orientation="vertical"
)
custom_widget_back_to = CustomWidgetFactory(TextWidget, visible=False)
+ next_url = None
page_title = "Licensing"
diff --git a/lib/lp/translations/browser/translationgroup.py b/lib/lp/translations/browser/translationgroup.py
index 2aa2d50..4135fdf 100644
--- a/lib/lp/translations/browser/translationgroup.py
+++ b/lib/lp/translations/browser/translationgroup.py
@@ -190,6 +190,7 @@ class TranslationGroupAddView(LaunchpadFormView):
schema = ITranslationGroup
field_names = ["name", "title", "summary", "translation_guide_url"]
+ next_url = None
label = "Create a new translation group"
page_title = label