chromium-dashboard/pages/guideforms.py

1063 строки
43 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2020 Google Inc.
#
# 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.
import logging
from django import forms
from django.core.validators import validate_email
# from google.appengine.api import users
from framework import users
from internals import models
from internals import processes
class MultiEmailField(forms.Field):
def to_python(self, value):
"""Normalize data to a list of strings."""
# Return an empty list if no input was given.
if not value:
return []
return value.split(',')
def validate(self, value):
"""Check if value consists only of valid emails."""
# Use the parent's handling of required fields, etc.
super(MultiEmailField, self).validate(value)
for email in value:
validate_email(email.strip())
SHIPPED_HELP_TXT = (
'First milestone to ship with this status. Applies to: Enabled by '
'default, Browser Intervention, Deprecated and Removed.')
SHIPPED_WEBVIEW_HELP_TXT = ('First milestone to ship with this status. '
'Applies to Enabled by default, Browser '
'Intervention, Deprecated, and Removed.')
SUMMARY_PLACEHOLDER_TXT = (
'NOTE: This text describes this feature in the eventual beta release post '
'as well as possibly in other external documents.\n\n'
'Begin with one line explaining what the feature does. Add one or two '
'lines explaining how this feature helps developers. Avoid language such '
'as "a new feature". They all are or have been new features.\n\n'
'Follow the example link below for more guidance.')
# We define all form fields here so that they can be include in one or more
# stage-specific fields without repeating the details and help text.
ALL_FIELDS = {
'name': forms.CharField(
required=True, label='Feature name',
# Use a specific autocomplete value to avoid "name" autofill.
# https://bugs.chromium.org/p/chromium/issues/detail?id=468153#c164
widget=forms.TextInput(attrs={'autocomplete': 'feature-name'}),
help_text=
('Capitalize only the first letter and the beginnings of '
'proper nouns. '
'<a target="_blank" href="'
'https://github.com/GoogleChrome/chromium-dashboard/wiki/'
'EditingHelp#feature-name">Learn more</a>. '
'<a target="_blank" href="'
'https://github.com/GoogleChrome/chromium-dashboard/wiki/'
'EditingHelp#feature-name-example">Example</a>.'
)),
'summary': forms.CharField(
required=True,
widget=forms.Textarea(
attrs={'cols': 50, 'maxlength': 500,
'placeholder': SUMMARY_PLACEHOLDER_TXT}),
help_text=
('<a target="_blank" href="'
'https://github.com/GoogleChrome/chromium-dashboard/wiki/'
'EditingHelp#summary-example">Guidelines and example</a>.'
)),
'owner': MultiEmailField(
required=True, label='Contact emails',
widget=forms.EmailInput(
attrs={'multiple': True, 'placeholder': 'email,email'}),
help_text=('Comma separated list of full email addresses. '
'Prefer @chromium.org.')),
'category': forms.ChoiceField(
required=False,
help_text=('Select the most specific category. If unsure, '
'leave as "%s".' % models.FEATURE_CATEGORIES[models.MISC]),
initial=models.MISC,
choices=sorted(models.FEATURE_CATEGORIES.items(), key=lambda x: x[1])),
'feature_type': forms.ChoiceField(
required=False,
help_text=('Select the feature type.'),
initial=models.FEATURE_TYPE_INCUBATE_ID,
choices=sorted(models.FEATURE_TYPES.items())),
'intent_stage': forms.ChoiceField(
required=False, label='Process stage',
help_text='Select the appropriate process stage.',
initial=models.INTENT_IMPLEMENT,
choices=list(models.INTENT_STAGES.items())),
'motivation': forms.CharField(
label='Motivation', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Explain why the web needs this change. It may be useful '
'to describe what web developers are forced to do without '
'it. When possible, add links to your explainer '
'backing up your claims. '
'<a target="_blank" href="'
'https://github.com/GoogleChrome/chromium-dashboard/wiki/'
'EditingHelp#motivation-example">Example</a>.'
)),
'deprecation_motivation': forms.CharField( # Sets motivation DB field.
label='Motivation', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Deprecations and removals must have strong reasons, backed up '
'by measurements. There must be clear and actionable paths forward '
'for developers. Please see '
'<a target="_blank" href="'
'https://docs.google.com/a/chromium.org/document/d/'
'1LdqUfUILyzM5WEcOgeAWGupQILKrZHidEXrUxevyi_Y/edit?usp=sharing'
'">Removal guidelines</a>.'
)),
'doc_links': forms.CharField(
label='Doc link(s)', required=False,
widget=forms.Textarea(
attrs={'rows': 4, 'cols': 50, 'maxlength': 500,
'placeholder': 'https://\nhttps://'}),
help_text=('Links to design doc(s) (one URL per line), if and when '
'available. [This is not required to send out an Intent '
'to Prototype. Please update the intent thread with the '
'design doc when ready]. An explainer and/or design doc '
'is sufficient to start this process. [Note: Please '
'include links and data, where possible, to support any '
'claims.]')),
'measurement': forms.CharField(
label='Measurement', required=False,
widget=forms.Textarea(
attrs={'rows': 4, 'cols': 50, 'maxlength': 500}),
help_text=
('It\'s important to measure the adoption and success of web-exposed '
'features. Note here what measurements you have added to track the '
'success of this feature, such as a link to the UseCounter(s) you '
'have set up.')),
# 'standardization' is deprecated
'standard_maturity': forms.ChoiceField(
required=False, label='Standard maturity',
choices=list(models.STANDARD_MATURITY_CHOICES.items()),
initial=models.PROPOSAL_STD,
help_text=('How far along is the standard that this '
'feature implements?')),
'unlisted': forms.BooleanField(
required=False, initial=False,
help_text=('Check this box for draft features that should not appear '
'in the feature list. Anyone with the link will be able to '
'view the feature on the detail page.')),
'spec_link': forms.URLField(
required=False, label='Spec link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('Link to spec, if and when available. Please update the '
'chromestatus.com entry and the intent thread(s) with the '
'spec link when available.')),
'api_spec': forms.BooleanField(
required=False, initial=False, label='API spec',
help_text=('The spec document has details in a specification language '
'such as Web IDL, or there is an exsting MDN page.')),
'spec_mentors': forms.EmailField(
required=False, label='Spec mentor',
widget=forms.EmailInput(
attrs={'multiple': True, 'placeholder': 'email'}),
help_text=
('Experienced <a target="_blank" '
'href="https://www.chromium.org/blink/spec-mentors">'
'spec mentors</a> are available to help you improve your '
'feature spec.')),
'explainer_links': forms.CharField(
label='Explainer link(s)', required=False,
widget=forms.Textarea(
attrs={'rows': 4, 'cols': 50, 'maxlength': 500,
'placeholder': 'https://\nhttps://'}),
help_text=('Link to explainer(s) (one URL per line). You should have '
'at least an explainer in hand and have shared it on a '
'public forum before sending an Intent to Prototype in '
'order to enable discussion with other browser vendors, '
'standards bodies, or other interested parties.')),
'security_review_status': forms.ChoiceField(
required=False,
choices=list(models.REVIEW_STATUS_CHOICES.items()),
initial=models.REVIEW_PENDING,
help_text=('Status of the security review.')),
'privacy_review_status': forms.ChoiceField(
required=False,
choices=list(models.REVIEW_STATUS_CHOICES.items()),
initial=models.REVIEW_PENDING,
help_text=('Status of the privacy review.')),
'tag_review': forms.CharField(
label='TAG Review', required=False,
widget=forms.Textarea(attrs={'rows': 2, 'cols': 50, 'maxlength': 1480}),
help_text=('Link(s) to TAG review(s), or explanation why this is '
'not needed.')),
'tag_review_status': forms.ChoiceField(
required=False,
choices=list(models.REVIEW_STATUS_CHOICES.items()),
initial=models.REVIEW_PENDING,
help_text=('Status of the tag review.')),
'intent_to_implement_url': forms.URLField(
required=False, label='Intent to Prototype link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('After you have started the "Intent to Prototype" '
' discussion thread, link to it here.')),
'intent_to_ship_url': forms.URLField(
required=False, label='Intent to Ship link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('After you have started the "Intent to Ship" discussion '
'thread, link to it here.')),
'ready_for_trial_url': forms.URLField(
required=False, label='Ready for Trial link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('After you have started the "Ready for Trial" discussion '
'thread, link to it here.')),
'intent_to_experiment_url': forms.URLField(
required=False, label='Intent to Experiment link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('After you have started the "Intent to Experiment" '
' discussion thread, link to it here.')),
'intent_to_extend_experiment_url': forms.URLField(
required=False, label='Intent to Extend Experiment link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('If this feature has an "Intent to Extend Experiment" '
' discussion thread, link to it here.')),
'r4dt_url': forms.URLField( # Sets intent_to_experiment_url in DB
required=False, label='Request for Deprecation Trial link',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=('After you have started the "Request for Deprecation Trial" '
'discussion thread, link to it here.')),
'interop_compat_risks': forms.CharField(
required=False, label='Interoperability and Compatibility Risks',
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Describe the degree of <a target="_blank" '
'href="https://www.chromium.org/blink/guidelines/'
'web-platform-changes-guidelines#TOC-Finding-balance'
'">interoperability risk</a>. For a new feature, the main risk is '
'that it fails to become an interoperable part of the web platform '
'if other browsers do not implement it. For a removal, please review '
'our <a target="_blank" href="'
'https://docs.google.com/document/d/'
'1RC-pBBvsazYfCNNUSkPqAVpSpNJ96U8trhNkfV0v9fk/edit">'
'principles of web compatibility</a>.<br>'
'<br>'
'Please include citation links below where possible. Examples include '
'resolutions from relevant standards bodies (e.g. W3C working group), '
'tracking bugs, or links to online conversations. '
'<a target="_blank" href="'
'https://github.com/GoogleChrome/chromium-dashboard/wiki/'
'EditingHelp#interoperability-and-compatibility-risks-example">'
'Example</a>.'
)),
'safari_views': forms.ChoiceField(
required=False, label='Safari views',
choices=list(models.VENDOR_VIEWS_WEBKIT.items()),
initial=models.NO_PUBLIC_SIGNALS,
help_text=(
'See <a target="_blank" href="https://bit.ly/blink-signals">'
'https://bit.ly/blink-signals</a>')),
'safari_views_link': forms.URLField(
required=False, label='',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text='Citation link.'),
'safari_views_notes': forms.CharField(
required=False, label='',
widget=forms.Textarea(
attrs={'rows': 2, 'cols': 50, 'placeholder': 'Notes',
'maxlength': 1480})),
'ff_views': forms.ChoiceField(
required=False, label='Firefox views',
choices=list(models.VENDOR_VIEWS_GECKO.items()),
initial=models.NO_PUBLIC_SIGNALS,
help_text=(
'See <a target="_blank" href="https://bit.ly/blink-signals">'
'https://bit.ly/blink-signals</a>')),
'ff_views_link': forms.URLField(
required=False, label='',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text='Citation link.'),
'ff_views_notes': forms.CharField(
required=False, label='',
widget=forms.Textarea(
attrs={'rows': 2, 'cols': 50, 'placeholder': 'Notes',
'maxlength': 1480})),
'web_dev_views': forms.ChoiceField(
required=False, label='Web / Framework developer views',
choices=list(models.WEB_DEV_VIEWS.items()),
initial=models.DEV_NO_SIGNALS,
help_text=(
'If unsure, default to "No signals". '
'See <a target="_blank" href="https://goo.gle/developer-signals">'
'https://goo.gle/developer-signals</a>')),
'web_dev_views_link': forms.URLField(
required=False, label='',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text='Citation link.'),
'web_dev_views_notes': forms.CharField(
required=False, label='',
widget=forms.Textarea(
attrs={'rows': 2, 'cols': 50, 'placeholder': 'Notes',
'maxlength': 1480}),
help_text=('Reference known representative examples of opinion, '
'both positive and negative.')),
'other_views_notes': forms.CharField(
required=False, label='Other views',
widget=forms.Textarea(
attrs={'rows': 4, 'cols': 50, 'placeholder': 'Notes',
'maxlength': 1480}),
help_text=('For example, other browsers.')),
'ergonomics_risks': forms.CharField(
label='Ergonomics Risks', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Are there any other platform APIs this feature will frequently be '
'used in tandem with? Could the default usage of this API make it '
'hard for Chrome to maintain good performance (i.e. synchronous '
'return, must run on a certain thread, guaranteed return timing)?')),
'activation_risks': forms.CharField(
label='Activation Risks', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Will it be challenging for developers to take advantage of this '
'feature immediately, as-is? Would this feature benefit from '
'having polyfills, significant documentation and outreach, and/or '
'libraries built on top of it to make it easier to use?')),
'security_risks': forms.CharField(
label='Security Risks', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('List any security considerations that were taken into account '
'when deigning this feature.')),
'experiment_goals': forms.CharField(
label='Experiment Goals', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Which pieces of the API surface are you looking to gain insight on? '
'What metrics/measurement/feedback will you be using to validate '
'designs? Double check that your experiment makes sense given that '
'a large developer (e.g. a Google product or Facebook) likely '
'can\'t use it in production due to the limits enforced by origin '
'trials.\n\nIf Intent to Extend Origin Trial, highlight new/different '
'areas for experimentation. Should not be an exact copy of goals '
'from the first Intent to Experiment.')),
# TODO(jrobbins): consider splitting this into start and end fields.
'experiment_timeline': forms.CharField(
label='Experiment Timeline', required=False,
widget=forms.Textarea(attrs={
'rows': 2, 'cols': 50, 'maxlength': 1480,
'placeholder': 'This field is deprecated',
'disabled': 'disabled'}),
help_text=('When does the experiment start and expire? '
'Deprecated: '
'Please use the numeric fields above instead.')),
# TODO(jrobbins and jmedley): Refine help text.
'ot_milestone_desktop_start': forms.IntegerField(
required=False, label='OT desktop start',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('First desktop milestone that will support an origin '
'trial of this feature.')),
'ot_milestone_desktop_end': forms.IntegerField(
required=False, label='OT desktop end',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('Last desktop milestone that will support an origin '
'trial of this feature.')),
'ot_milestone_android_start': forms.IntegerField(
required=False, label='OT android start',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('First android milestone that will support an origin '
'trial of this feature.')),
'ot_milestone_android_end': forms.IntegerField(
required=False, label='OT android end',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('Last android milestone that will support an origin '
'trial of this feature.')),
'experiment_risks': forms.CharField(
label='Experiment Risks', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('When this experiment comes to an end are there any risks to the '
'sites that were using it, for example losing access to important '
'storage due to an experimental storage API?')),
'experiment_extension_reason': forms.CharField(
label='Experiment Extension Reason', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('If this is a repeat experiment, explain why you want to extend this '
'experiment. Also, fill in discussion link fields below.')),
'ongoing_constraints': forms.CharField(
label='Ongoing Constraints', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Do you anticipate adding any ongoing technical constraints to '
'the codebase while implementing this feature? We prefer to avoid '
'features which require or assume a specific architecture. '
'For most features, the answer here is "None."')),
'origin_trial_feedback_url': forms.URLField(
required=False, label='Origin trial feedback summary',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=
('If your feature was available as an origin trial, link to a summary '
'of usage and developer feedback. If not, leave this empty.')),
'finch_url': forms.URLField(
required=False, label='Finch experiment',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=
('If your feature will roll out gradually via a '
'<a href="go/finch" targe="_blank">Finch experiment</a>, '
'link to it here.')),
'i2e_lgtms': forms.EmailField(
required=False, label='Intent to Experiment LGTM by',
widget=forms.EmailInput(
attrs={'multiple': True, 'placeholder': 'email'}),
help_text=('Full email address of API owner who LGTM\'d the '
'Intent to Experiment email thread.')),
'i2s_lgtms': forms.EmailField(
required=False, label='Intent to Ship LGTMs by',
widget=forms.EmailInput(
attrs={'multiple': True, 'placeholder': 'email, email, email'}),
help_text=('Comma separated list of '
'full email addresses of API owners who LGTM\'d '
'the Intent to Ship email thread.')),
'r4dt_lgtms': forms.EmailField( # Sets i2e_lgtms field.
required=False, label='Request for Deprecation Trial LGTM by',
widget=forms.EmailInput(
attrs={'multiple': True, 'placeholder': 'email'}),
help_text=('Full email addresses of API owners who LGTM\'d '
'the Request for Deprecation Trial email thread.')),
'debuggability': forms.CharField(
label='Debuggability', required=True,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Description of the DevTools debugging support for your feature. '
'Please follow <a target="_blank" '
'href="https://goo.gle/devtools-checklist">the '
'DevTools support checklist</a> for guidance.')),
'all_platforms': forms.BooleanField(
required=False, initial=False, label='Supported on all platforms?',
help_text=
('Will this feature be supported on all six Blink platforms '
'(Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?')),
'all_platforms_descr': forms.CharField(
label='Platform Support Explanation', required=False,
widget=forms.Textarea(attrs={'rows': 2, 'cols': 50, 'maxlength': 2000}),
help_text=
('Explain why this feature is, or is not, '
'supported on all platforms.')),
'wpt': forms.BooleanField(
required=False, initial=False, label='Web Platform Tests',
help_text='Is this feature fully tested in Web Platform Tests?'),
'wpt_descr': forms.CharField(
label='Web Platform Tests Description', required=False,
widget=forms.Textarea(attrs={'cols': 50, 'maxlength': 1480}),
help_text=
('Please link to the <a href="https://wpt.fyi/results">results on '
'wpt.fyi</a>. If any part of the feature is not tested by '
'web-platform-tests. Please include links to issues, e.g. a '
'web-platform-tests issue with the "infra" label explaining why a '
'certain thing cannot be tested (<a '
'href="https://github.com/w3c/web-platform-tests/issues/3867">'
'example</a>), a spec issue for some change that would make it '
'possible to test. (<a href="'
'https://github.com/whatwg/fullscreen/issues/70">example</a>), or '
'a Chromium issue to upstream some existing tests (<a href="'
'https://bugs.chromium.org/p/chromium/issues/detail?id=695486">'
'example</a>).')),
'sample_links': forms.CharField(
label='Samples links', required=False,
widget=forms.Textarea(
attrs={'cols': 50, 'maxlength': 500,
'placeholder': 'https://\nhttps://'}),
help_text='Links to samples (one URL per line).'),
'bug_url': forms.URLField(
required=False, label='Tracking bug URL',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=
('Tracking bug url (https://bugs.chromium.org/...). This bug '
'should have "Type=Feature" set and be world readable. '
'Note: This field only accepts one URL.')),
# TODO(jrobbins): Consider a button to file the launch bug automatically,
# or a deep link that has some feature details filled in.
'launch_bug_url': forms.URLField(
required=False, label='Launch bug URL',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=(
'Launch bug url (https://bugs.chromium.org/...) to track launch '
'approvals. '
'<a target="_blank" href="'
'https://bugs.chromium.org/p/chromium/issues/'
'entry?template=Chrome+Launch+Feature" '
'>Create launch bug<a>.')),
'initial_public_proposal_url': forms.URLField(
required=False, label='Initial public proposal URL',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=(
'Link to the first public proposal to create this feature, e.g., '
'a WICG discourse post.')),
'blink_components': forms.ChoiceField(
required=False, label='Blink component',
help_text=
('Select the most specific component. If unsure, leave as "%s".' %
models.BlinkComponent.DEFAULT_COMPONENT),
choices=[(x, x) for x in models.BlinkComponent.fetch_all_components()],
initial=[models.BlinkComponent.DEFAULT_COMPONENT]),
'devrel': forms.EmailField(
required=False, label='Developer relations emails',
widget=forms.EmailInput(
attrs={'multiple': True, 'placeholder': 'email, email'}),
help_text='Comma separated list of full email addresses.'),
'impl_status_chrome': forms.ChoiceField(
required=False, label='Implementation status',
choices=list(models.IMPLEMENTATION_STATUS.items()),
help_text='Implementation status in Chromium'),
'shipped_milestone': forms.IntegerField(
required=False, label='Chrome for desktop',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=SHIPPED_HELP_TXT),
'shipped_android_milestone': forms.IntegerField(
required=False, label='Chrome for Android',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=SHIPPED_HELP_TXT),
'shipped_ios_milestone': forms.IntegerField(
required=False, label='Chrome for iOS (RARE)',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=SHIPPED_HELP_TXT),
'shipped_webview_milestone': forms.IntegerField(
required=False, label='Android Webview',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=SHIPPED_WEBVIEW_HELP_TXT),
'requires_embedder_support': forms.BooleanField(
required=False, initial=False,
help_text=(
'Will this feature require support in //chrome? '
'That includes any code in //chrome, even if that is for '
'functionality on top of the spec. Other //content embedders '
'will need to be aware of that functionality. '
'Please add a row to this '
'<a href="https://docs.google.com/spreadsheets/d/'
'1QV4SW4JBG3IyLzaonohUhim7nzncwK4ioop2cgUYevw/edit#gid=0'
'" target="_blank">tracking spreadsheet</a>.')),
'devtrial_instructions': forms.URLField(
required=False, label='DevTrial instructions',
widget=forms.URLInput(attrs={'placeholder': 'https://'}),
help_text=(
'Link to a HOWTO or FAQ describing how developers can get started '
'using this feature in a DevTrial. <a target="_blank" href="'
'https://github.com/samuelgoto/WebID/blob/master/HOWTO.md'
'">Example 1</a>. <a target="_blank" href="'
'https://github.com/WICG/idle-detection/blob/main/HOWTO.md'
'">Example 2</a>.')),
'dt_milestone_desktop_start': forms.IntegerField(
required=False, label='DevTrail on desktop',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('First milestone that allows developers to try '
'this feature on desktop platforms by setting a flag.')),
'dt_milestone_android_start': forms.IntegerField(
required=False, label='DevTrail on Android',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('First milestone that allows developers to try '
'this feature on Android by setting a flag.')),
'dt_milestone_ios_start': forms.IntegerField(
required=False, label='DevTrial on iOS (RARE)',
widget=forms.NumberInput(attrs={'placeholder': 'Milestone #'}),
help_text=('First milestone that allows developers to try '
'this feature on iOS by setting a flag.')),
'flag_name': forms.CharField(
label='Flag name', required=False,
help_text='Name of the flag that enables this feature.'),
'prefixed': forms.BooleanField(
required=False, initial=False, label='Prefixed?'),
'search_tags': forms.CharField(
label='Search tags', required=False,
help_text='Comma separated keywords used only in search'),
'comments': forms.CharField(
label='Comments', required=False,
widget=forms.Textarea(attrs={
'cols': 50, 'rows': 4, 'maxlength': 1480}),
help_text='Additional comments, caveats, info...'),
}
# These are shown in a top card for all processes.
METADATA_FIELDS = [
'name', 'summary', 'unlisted', 'owner',
'category',
'feature_type', 'intent_stage',
'search_tags',
# Implemention
'impl_status_chrome',
'blink_components',
'bug_url', 'launch_bug_url',
]
def define_form_class_using_shared_fields(class_name, field_spec_list):
"""Define a new subsblass of forms.Form with the given fields, in order."""
# field_spec_list is normally just a list of simple field names,
# but entries can also have syntax "form_field=shared_field".
class_dict = {'field_order': []}
for field_spec in field_spec_list:
form_field_name = field_spec.split('=')[0] # first or only
shared_field_name = field_spec.split('=')[-1] # last or only
class_dict[form_field_name] = ALL_FIELDS[shared_field_name]
class_dict['field_order'].append(form_field_name)
return type(class_name, (forms.Form,), class_dict)
NewFeatureForm = define_form_class_using_shared_fields(
'NewFeatureForm',
('name', 'summary',
'unlisted', 'owner',
'blink_components', 'category'))
# Note: feature_type is done with custom HTML
MetadataForm = define_form_class_using_shared_fields(
'MetadataForm', METADATA_FIELDS)
NewFeature_Incubate = define_form_class_using_shared_fields(
'NewFeature_Incubate',
('motivation', 'initial_public_proposal_url', 'explainer_links',
'bug_url', 'launch_bug_url', 'comments'))
ImplStatus_Incubate = define_form_class_using_shared_fields(
'ImplStatus_Incubate',
('requires_embedder_support',
))
NewFeature_Prototype = define_form_class_using_shared_fields(
'NewFeature_Prototype',
('spec_link', 'standard_maturity', 'api_spec', 'spec_mentors',
'intent_to_implement_url', 'comments'))
# TODO(jrobbins): advise user to request a tag review
Any_DevTrial = define_form_class_using_shared_fields(
'Any_DevTrial',
('bug_url', 'devtrial_instructions', 'doc_links',
'interop_compat_risks',
'safari_views', 'safari_views_link', 'safari_views_notes',
'ff_views', 'ff_views_link', 'ff_views_notes',
'web_dev_views', 'web_dev_views_link', 'web_dev_views_notes',
'other_views_notes',
'security_review_status', 'privacy_review_status',
'ergonomics_risks', 'activation_risks', 'security_risks', 'debuggability',
'all_platforms', 'all_platforms_descr', 'wpt', 'wpt_descr',
'sample_links', 'devrel', 'ready_for_trial_url', 'comments'))
# TODO(jrobbins): api overview link
ImplStatus_DevTrial = define_form_class_using_shared_fields(
'ImplStatus_InDevTrial',
('dt_milestone_desktop_start', 'dt_milestone_android_start',
'dt_milestone_ios_start',
'flag_name'))
NewFeature_EvalReadinessToShip = define_form_class_using_shared_fields(
'NewFeature_EvalReadinessToShip',
('doc_links', 'tag_review', 'spec_link',
'standard_maturity', 'interop_compat_risks',
'safari_views', 'safari_views_link', 'safari_views_notes',
'ff_views', 'ff_views_link', 'ff_views_notes',
'web_dev_views', 'web_dev_views_link', 'web_dev_views_notes',
'other_views_notes',
'prefixed', 'comments'))
ImplStatus_AllMilestones = define_form_class_using_shared_fields(
'ImplStatus_AllMilestones',
('shipped_milestone', 'shipped_android_milestone',
'shipped_ios_milestone', 'shipped_webview_milestone'))
ImplStatus_EvalReadinessToShip = define_form_class_using_shared_fields(
'ImplStatus_AllMilestones',
('shipped_milestone', 'shipped_android_milestone',
'shipped_ios_milestone', 'shipped_webview_milestone',
'measurement'))
NewFeature_OriginTrial = define_form_class_using_shared_fields(
'NewFeature_OriginTrial',
('experiment_goals', 'experiment_risks',
'experiment_extension_reason', 'ongoing_constraints',
'origin_trial_feedback_url', 'intent_to_experiment_url',
'intent_to_extend_experiment_url',
'i2e_lgtms', 'comments'))
ImplStatus_OriginTrial = define_form_class_using_shared_fields(
'ImplStatus_OriginTrial',
('ot_milestone_desktop_start', 'ot_milestone_desktop_end',
'ot_milestone_android_start', 'ot_milestone_android_end',
'experiment_timeline', # deprecated
))
Most_PrepareToShip = define_form_class_using_shared_fields(
'Most_PrepareToShip',
('tag_review', 'tag_review_status',
'origin_trial_feedback_url',
'launch_bug_url', 'intent_to_ship_url', 'i2s_lgtms', 'comments'))
Any_Ship = define_form_class_using_shared_fields(
'Any_Ship',
('launch_bug_url', 'finch_url', 'comments'))
Existing_Prototype = define_form_class_using_shared_fields(
'Existing_Prototype',
('owner', 'blink_components', 'motivation', 'explainer_links',
'spec_link', 'standard_maturity', 'api_spec', 'bug_url', 'launch_bug_url',
'intent_to_implement_url', 'comments'))
Existing_OriginTrial = define_form_class_using_shared_fields(
'Existing_OriginTrial',
('experiment_goals', 'experiment_risks',
'experiment_extension_reason', 'ongoing_constraints',
'intent_to_experiment_url', 'intent_to_extend_experiment_url',
'i2e_lgtms', 'origin_trial_feedback_url', 'comments'))
PSA_Implement = define_form_class_using_shared_fields(
'Any_Implement',
('spec_link', 'standard_maturity', 'comments'))
# TODO(jrobbins): advise user to request a tag review
PSA_PrepareToShip = define_form_class_using_shared_fields(
'PSA_PrepareToShip',
('tag_review',
'intent_to_implement_url', 'origin_trial_feedback_url',
'launch_bug_url', 'intent_to_ship_url', 'comments'))
Deprecation_Implement = define_form_class_using_shared_fields(
'Deprecation_Implement',
('motivation=deprecation_motivation',
'spec_link', 'comments'))
# Note: Even though this is similar to another form, it is likely to change.
Deprecation_PrepareToShip = define_form_class_using_shared_fields(
'Deprecation_PrepareToShip',
('impl_status_chrome', 'tag_review',
'intent_to_implement_url', 'origin_trial_feedback_url',
'launch_bug_url', 'comments'))
# Note: Even though this is similar to another form, it is likely to change.
Deprecation_DeprecationTrial = define_form_class_using_shared_fields(
'Deprecation_DeprecationTrial',
('experiment_goals', 'experiment_risks',
'ot_milestone_desktop_start', 'ot_milestone_desktop_end',
'ot_milestone_android_start', 'ot_milestone_android_end',
'experiment_timeline', # deprecated
'experiment_extension_reason', 'ongoing_constraints',
'intent_to_experiment_url=r4dt_url',
'intent_to_extend_experiment_url',
'i2e_lgtms=r4dt_lgtms', # form field name matches underlying DB field.
'origin_trial_feedback_url', 'comments'))
# Note: Even though this is similar to another form, it is likely to change.
Deprecation_PrepareToShip = define_form_class_using_shared_fields(
'Deprecation_PrepareToShip',
('impl_status_chrome',
'intent_to_ship_url', 'i2s_lgtms',
'launch_bug_url', 'comments'))
Deprecation_Removed = define_form_class_using_shared_fields(
'Deprecation_Removed',
('comments',))
Flat_Metadata = define_form_class_using_shared_fields(
'Flat_Metadata',
(# Standardizaton
'name', 'summary', 'unlisted', 'owner',
'category',
'feature_type', 'intent_stage',
'search_tags',
# Implementtion
'impl_status_chrome',
'blink_components',
'bug_url', 'launch_bug_url',
'comments'))
Flat_Identify = define_form_class_using_shared_fields(
'Flat_Identify',
(# Standardization
# TODO(jrobbins): display deprecation_motivation instead when deprecating.
'motivation', 'initial_public_proposal_url', 'explainer_links',
# Implementtion
'requires_embedder_support'))
Flat_Implement = define_form_class_using_shared_fields(
'Flat_Implement',
(# Standardization
'spec_link', 'standard_maturity', 'api_spec', 'spec_mentors',
'intent_to_implement_url'))
Flat_DevTrial = define_form_class_using_shared_fields(
'Flat_DevTrial',
(# Standardizaton
'devtrial_instructions', 'doc_links',
'interop_compat_risks',
'safari_views', 'safari_views_link', 'safari_views_notes',
'ff_views', 'ff_views_link', 'ff_views_notes',
'web_dev_views', 'web_dev_views_link', 'web_dev_views_notes',
'other_views_notes',
'security_review_status', 'privacy_review_status',
'ergonomics_risks', 'activation_risks', 'security_risks', 'debuggability',
'all_platforms', 'all_platforms_descr', 'wpt', 'wpt_descr',
'sample_links', 'devrel', 'ready_for_trial_url',
# TODO(jrobbins): UA support signals section
# Implementation
'dt_milestone_desktop_start', 'dt_milestone_android_start',
'dt_milestone_ios_start',
'flag_name'))
# TODO(jrobbins): api overview link
Flat_OriginTrial = define_form_class_using_shared_fields(
'Flat_OriginTrial',
(# Standardization
'experiment_goals',
'experiment_risks',
'experiment_extension_reason', 'ongoing_constraints',
# TODO(jrobbins): display r4dt_url instead when deprecating.
'intent_to_experiment_url', 'intent_to_extend_experiment_url',
'i2e_lgtms',
'origin_trial_feedback_url',
# Implementation
'ot_milestone_desktop_start', 'ot_milestone_desktop_end',
'ot_milestone_android_start', 'ot_milestone_android_end',
'experiment_timeline', # deprecated
))
Flat_PrepareToShip = define_form_class_using_shared_fields(
'Flat_PrepareToShip',
(# Standardization
'tag_review', 'tag_review_status',
'intent_to_ship_url', 'i2s_lgtms',
# Implementation
'measurement'))
Flat_Ship = define_form_class_using_shared_fields(
'Flat_Ship',
(# Implementation
'finch_url',
'shipped_milestone', 'shipped_android_milestone',
'shipped_ios_milestone', 'shipped_webview_milestone'))
FIELD_NAME_TO_DISPLAY_TYPE = {
'doc_links': 'urllist',
'explainer_links': 'urllist',
'sample_links': 'urllist',
# Otherwise, FIELD_TYPE_TO_DISPLAY_TYPE is used.
}
FIELD_TYPE_TO_DISPLAY_TYPE = {
forms.BooleanField: 'bool',
forms.URLField: 'url',
# choice, char, int can all render as plain text.
}
def make_human_readable(field_name):
return field_name.replace('_', ' ').capitalize()
def make_display_spec(field_name):
"""Return a tuple of field info that can easily be sent in JSON."""
form_field = ALL_FIELDS[field_name]
display_name = form_field.label or make_human_readable(field_name)
field_type = (FIELD_NAME_TO_DISPLAY_TYPE.get(field_name) or
FIELD_TYPE_TO_DISPLAY_TYPE.get(type(form_field)) or
'text')
return (field_name, display_name, field_type)
def make_display_specs(*shared_field_names):
"""Return a list of field specs for each of the fields named in the args."""
return [make_display_spec(field_name)
for field_name in shared_field_names]
DEPRECATED_FIELDS = ['standardization']
DISPLAY_IN_FEATURE_HIGHLIGHTS = [
'name', 'summary',
'motivation', 'deprecation_motivation',
'unlisted', 'owner',
'search_tags',
# Implementtion
'impl_status_chrome',
'blink_components',
'bug_url',
'comments',
]
DISPLAY_FIELDS_IN_STAGES = {
'Metadata': make_display_specs(
'category', 'feature_type', 'intent_stage',
),
models.INTENT_INCUBATE: make_display_specs(
'initial_public_proposal_url', 'explainer_links',
'requires_embedder_support'),
models.INTENT_IMPLEMENT: make_display_specs(
'spec_link', 'standard_maturity', 'api_spec', 'spec_mentors',
'intent_to_implement_url'),
models.INTENT_EXPERIMENT: make_display_specs(
'devtrial_instructions', 'doc_links',
'interop_compat_risks',
'safari_views', 'safari_views_link', 'safari_views_notes',
'ff_views', 'ff_views_link', 'ff_views_notes',
'web_dev_views', 'web_dev_views_link', 'web_dev_views_notes',
'other_views_notes',
'security_review_status', 'privacy_review_status',
'ergonomics_risks', 'activation_risks', 'security_risks',
'debuggability',
'all_platforms', 'all_platforms_descr', 'wpt', 'wpt_descr',
'sample_links', 'devrel', 'ready_for_trial_url',
'dt_milestone_desktop_start', 'dt_milestone_android_start',
'dt_milestone_ios_start',
'flag_name'),
models.INTENT_IMPLEMENT_SHIP: make_display_specs(
'launch_bug_url',
'tag_review', 'tag_review_status',
'measurement', 'prefixed'),
models.INTENT_EXTEND_TRIAL: make_display_specs(
'experiment_goals', 'experiment_risks',
'experiment_extension_reason', 'ongoing_constraints',
'origin_trial_feedback_url', 'intent_to_experiment_url',
'r4dt_url',
'intent_to_extend_experiment_url',
'i2e_lgtms', 'r4dt_lgtms',
'ot_milestone_desktop_start', 'ot_milestone_desktop_end',
'ot_milestone_android_start', 'ot_milestone_android_end',
'experiment_timeline', # Deprecated
),
models.INTENT_SHIP: make_display_specs(
'finch_url',
'shipped_milestone', 'shipped_android_milestone',
'shipped_ios_milestone', 'shipped_webview_milestone',
'intent_to_ship_url', 'i2s_lgtms'),
models.INTENT_SHIPPED: make_display_specs(
),
'Misc': make_display_specs(
),
}