Move help text from django form field specifications into chromedash-form-field (#1990)

* Add name attribute to each chromedash-form-field. Use to look up help text.

* Move help_text for all new and metadata fields.

* Clean up and add comments.
This commit is contained in:
Daniel LaLiberte 2022-07-01 22:49:07 -04:00 коммит произвёл GitHub
Родитель 8a9f86ef5e
Коммит e6f8094754
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 173 добавлений и 79 удалений

Просмотреть файл

@ -21,6 +21,9 @@ from django.forms.widgets import Textarea, Input
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
# from google.appengine.api import users
from framework import users
@ -96,15 +99,6 @@ SHIPPED_WEBVIEW_HELP_TXT = ('First milestone to ship with this status. '
'Applies to Enabled by default, Browser '
'Intervention, Deprecated, and Removed.')
SUMMARY_HELP_TXT = (
'NOTE: Text in the beta release post, the enterprise release notes, '
'and other external sources will be based on this text.\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'
'Write it from a web developer\'s point of view.\n\n'
'Follow the example link below for more guidance.')
# Patterns from https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s01.html
# Removing single quote ('), backtick (`), and pipe (|) since they are risky unless properly escaped everywhere.
# Also removing ! and % because they have special meaning for some older email routing systems.
@ -149,65 +143,34 @@ MULTI_URL_FIELD_ATTRS = {
ALL_FIELDS = {
'name': forms.CharField(
required=True, label='Feature name',
widget=ChromedashTextInput(),
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>.'
)),
widget=ChromedashTextInput()),
'summary': forms.CharField(
required=True,
widget=ChromedashTextarea(),
help_text=
(SUMMARY_HELP_TXT +
'<br><a target="_blank" href="'
'https://github.com/GoogleChrome/chromium-dashboard/wiki/'
'EditingHelp#summary-example">Guidelines and example</a>.'
)),
widget=ChromedashTextarea()),
'owner': MultiEmailField(
required=True, label='Feature owners',
widget=forms.EmailInput(attrs=MULTI_EMAIL_FIELD_ATTRS),
help_text=('Comma separated list of full email addresses. '
'Prefer @chromium.org.')),
widget=forms.EmailInput(attrs=MULTI_EMAIL_FIELD_ATTRS)),
'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=ChromedashTextarea(),
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>.'
)),
widget=ChromedashTextarea()),
'deprecation_motivation': forms.CharField( # Sets motivation DB field.
label='Motivation', required=False,
@ -255,10 +218,7 @@ ALL_FIELDS = {
'unlisted': forms.BooleanField(
label="Unlisted",
widget=forms.CheckboxInput(attrs={'label': "Unlisted"}),
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.')),
required=False, initial=False),
'spec_link': forms.URLField(
required=False, label='Spec link',
@ -683,24 +643,13 @@ ALL_FIELDS = {
'bug_url': forms.URLField(
required=False, label='Tracking bug URL',
widget=forms.URLInput(attrs=URL_FIELD_ATTRS),
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.')),
widget=forms.URLInput(attrs=URL_FIELD_ATTRS)),
# 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=URL_FIELD_ATTRS),
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>.')),
widget=forms.URLInput(attrs=URL_FIELD_ATTRS)),
'initial_public_proposal_url': forms.URLField(
required=False, label='Initial public proposal URL',
@ -711,9 +660,6 @@ ALL_FIELDS = {
'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]),
@ -724,8 +670,7 @@ ALL_FIELDS = {
'impl_status_chrome': forms.ChoiceField(
required=False, label='Implementation status',
choices=list(models.IMPLEMENTATION_STATUS.items()),
help_text='Implementation status in Chromium'),
choices=list(models.IMPLEMENTATION_STATUS.items())),
'shipped_milestone': forms.IntegerField(
required=False, label='Chrome for desktop',
@ -806,8 +751,7 @@ ALL_FIELDS = {
required=False, initial=False),
'search_tags': forms.CharField(
label='Search tags', required=False,
help_text='Comma separated keywords used only in search'),
label='Search tags', required=False),
'comments': forms.CharField(
label='Comments', required=False,
@ -829,20 +773,59 @@ METADATA_FIELDS = [
]
class ChromedashForm(forms.Form):
def simple_html_output(self, normal_row, help_text_html):
"""
Output HTML. Used by override of as_table() to support chromedash uses only.
Simplified to drop support for hidden form fields and errors at the top,
which we are not using.
"""
output = []
for name, field in self.fields.items():
html_class_attr = ''
bf = self[name]
bf_errors = self.error_class(bf.errors)
# Create a 'class="..."' attribute if the row should have any
# CSS classes applied.
css_classes = bf.css_classes()
if css_classes:
html_class_attr = ' class="%s"' % css_classes
if bf.label:
label = conditional_escape(bf.label)
label = bf.label_tag(label) or ''
else:
label = ''
if field.help_text:
help_text = help_text_html % field.help_text
else:
help_text = ''
output.append(normal_row % {
'name': name,
'errors': bf_errors,
'label': label,
'field': bf,
'help_text': help_text,
'html_class_attr': html_class_attr,
'css_classes': css_classes,
'field_name': bf.html_name,
})
return mark_safe('\n'.join(output))
def as_table(self):
"Return this form rendered as HTML <tr>s -- excluding the <table></table>."
label = '<span slot="label">%(label)s</span>'
field = '<span slot="field">%(field)s</span>'
error = '<span slot="error">%(errors)s</span>'
help = '<span slot="help">%(help_text)s</span>'
html = '<chromedash-form-field %(html_class_attr)s>' + label + field + error + help + '%(label)s' + '</chromedash-form-field>'
return self._html_output(
help = '<span slot="help">%(help_text)s</span>'
html = '<chromedash-form-field name="%(name)s" %(html_class_attr)s>' + label + field + error + help + '%(label)s' + '</chromedash-form-field>'
return self.simple_html_output(
normal_row=html,
error_row='<chromedash-form-field><span slot="error">%s</span></chromedash-form-field>',
row_ender='</chromedash-form-field>',
help_text_html='<span class="helptext">%s</span>',
errors_on_separate_row=False,
help_text_html='<span class="helptext">%s</span>'
)
def define_form_class_using_shared_fields(class_name, field_spec_list):
@ -853,7 +836,8 @@ def define_form_class_using_shared_fields(class_name, field_spec_list):
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]
properties = ALL_FIELDS[shared_field_name]
class_dict[form_field_name] = properties
class_dict['field_order'].append(form_field_name)
return type(class_name, (ChromedashForm,), class_dict)

Просмотреть файл

@ -1,6 +1,12 @@
import {LitElement, css, html} from 'lit';
export class ChromedashFormField extends LitElement {
static get properties() {
return {
name: {type: String},
};
}
static get styles() {
return [
css`
@ -45,20 +51,23 @@ export class ChromedashFormField extends LitElement {
}
render() {
const fieldProps = ALL_FIELDS[this.name] || {};
const helpText = fieldProps.help_text || '';
return html`
<tr>
<th colspan="2">
<b>
<slot name="label">the label goes here</slot>
<slot name="label"></slot>
</b>
</th>
</tr>
<tr>
<td>
<slot name="error" class="errorlist"></slot>
<slot name="field"></slot>
<slot name="error" class="errorlist"></slot>
</td>
<td>
${helpText}
<slot name="help" class="helptext"></slot>
</td>
</tr>`;
@ -67,3 +76,104 @@ export class ChromedashFormField extends LitElement {
customElements.define('chromedash-form-field', ChromedashFormField);
// Map of specifications for all form fields.
// Actually, this includes only fields for which we have migrated the help_text from the guideforms.py specifications.
// TODO:
// * Finish migrating remaining fields.
// * Migrate other properties.
// * Move to its own file.
const ALL_FIELDS = {
'name': {
help_text: html`
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': {
help_text: html`
NOTE: Text in the beta release post, the enterprise release notes,
and other external sources will be based on this text.
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.
Write it from a web developer's point of view.
Follow the example link below for more guidance.<br>
<a target="_blank"
href="https://github.com/GoogleChrome/chromium-dashboard/wiki/EditingHelp#summary-example">
Guidelines and example</a>.`,
},
'owner': {
help_text: html`
Comma separated list of full email addresses. Prefer @chromium.org.`,
},
'unlisted': {
help_text: html`
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.`,
},
'blink_components': {
help_text: html`
Select the most specific component. If unsure, leave as "Blink".`,
},
'category': {
help_text: html`
Select the most specific category. If unsure, leave as "Miscellaneous".`,
},
'feature_type': {
help_text: html`
Select the feature type.`,
},
'intent_stage': {
help_text: html`
Select the appropriate process stage.`,
},
'search_tags': {
help_text: html`
Comma separated keywords used only in search.`,
},
'impl_status_chrome': {
help_text: html`
Implementation status in Chromium.`,
},
'bug_url': {
help_text: html`
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.`,
},
'launch_bug_url': {
help_text: html`
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>.`,
},
'motivation': {
help_text: html`
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>.`,
},
};

Просмотреть файл

@ -56,7 +56,7 @@ table td label input[type=radio]:focus {
{{ overview_form }}
<chromedash-form-field>
<chromedash-form-field name="feature_type">
<span slot="label">Feature type:</span>
<span slot="field" class="choices">