create new stages on the feature detail page (#2611)
* create new stages on the feature detail page * comments and spacing * remove unused import * changes suggested by @jrobbins * Update chromedash-feature-detail.js * change capitalization
This commit is contained in:
Родитель
cedeeb91b3
Коммит
6b3c5602fa
|
@ -115,7 +115,7 @@ class StagesAPI(basehandlers.APIHandler):
|
|||
if use_stage_type:
|
||||
if 'stage_type' not in body:
|
||||
self.abort(404, msg='Stage type not specified.')
|
||||
stage.stage_type = body['stage_type']
|
||||
stage.stage_type = int(body['stage_type'])
|
||||
s_type = stage.stage_type
|
||||
|
||||
for field in self.GENERAL_FIELDS:
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
import {LitElement, css, html} from 'lit';
|
||||
import {SHARED_STYLES} from '../sass/shared-css.js';
|
||||
import {CREATEABLE_STAGES, FORMS_BY_STAGE_TYPE} from './form-definition.js';
|
||||
|
||||
|
||||
let addStageDialogEl;
|
||||
let currentFeatureId;
|
||||
|
||||
|
||||
export async function openAddStageDialog(featureId, featureType) {
|
||||
if (!addStageDialogEl || currentFeatureId !== featureId) {
|
||||
addStageDialogEl = document.createElement('chromedash-add-stage-dialog');
|
||||
addStageDialogEl.featureId = featureId;
|
||||
addStageDialogEl.featureType = featureType;
|
||||
document.body.appendChild(addStageDialogEl);
|
||||
await addStageDialogEl.updateComplete;
|
||||
}
|
||||
currentFeatureId = featureId;
|
||||
addStageDialogEl.show();
|
||||
}
|
||||
|
||||
|
||||
class ChromedashAddStageDialog extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
featureId: {type: Number},
|
||||
featureType: {type: Number},
|
||||
canSubmit: {type: Boolean},
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.featureId = 0;
|
||||
this.featureType = 0;
|
||||
this.canSubmit = false;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
...SHARED_STYLES,
|
||||
css`
|
||||
#controls {
|
||||
padding: var(--content-padding);
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
#controls * + * {
|
||||
padding-left: var(--content-padding);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
show() {
|
||||
this.shadowRoot.querySelector('sl-dialog').show();
|
||||
}
|
||||
|
||||
renderSelectMenuItems() {
|
||||
const menuItems = [];
|
||||
for (const stageType of CREATEABLE_STAGES[this.featureType]) {
|
||||
// Get the name of the stage from the form definition based on the stage type.
|
||||
const stageInfo = FORMS_BY_STAGE_TYPE[stageType];
|
||||
menuItems.push(html`
|
||||
<sl-menu-item value="${stageType}">
|
||||
${stageInfo.name}
|
||||
</sl-menu-item>
|
||||
`);
|
||||
}
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
getStageSelectValue() {
|
||||
const selectEl = this.shadowRoot.querySelector('#stage_create_select');
|
||||
return selectEl.value;
|
||||
}
|
||||
|
||||
handleStageCreate() {
|
||||
window.csClient.createStage(this.featureId, this.getStageSelectValue())
|
||||
.then(() => {
|
||||
this.shadowRoot.querySelector('sl-dialog').hide();
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
checkCanSubmit() {
|
||||
this.canSubmit = this.getStageSelectValue() !== 0;
|
||||
}
|
||||
|
||||
renderStageSelect() {
|
||||
return html`
|
||||
<div id="controls">
|
||||
<sl-select
|
||||
placement="top"
|
||||
value=0
|
||||
id="stage_create_select"
|
||||
size="small"
|
||||
@sl-change=${this.checkCanSubmit}
|
||||
style="width:16rem"
|
||||
>
|
||||
<sl-menu-item value="0" disabled>Select a stage to create</sl-menu-item>
|
||||
${this.renderSelectMenuItems()}
|
||||
</sl-select>
|
||||
<sl-button variant="primary"
|
||||
@click=${this.handleStageCreate}
|
||||
?disabled=${!this.canSubmit}
|
||||
size="small"
|
||||
>Create stage</sl-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<sl-dialog label="Create a new stage">
|
||||
${this.renderStageSelect()}
|
||||
</sl-dialog>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
customElements.define('chromedash-add-stage-dialog', ChromedashAddStageDialog);
|
|
@ -1,4 +1,5 @@
|
|||
import {LitElement, css, html, nothing} from 'lit';
|
||||
import {openAddStageDialog} from './chromedash-add-stage-dialog';
|
||||
import {DISPLAY_FIELDS_IN_STAGES} from './form-field-specs';
|
||||
import {PLATFORMS_DISPLAYNAME} from './form-field-enums';
|
||||
import '@polymer/iron-icon';
|
||||
|
@ -388,6 +389,18 @@ class ChromedashFeatureDetail extends LitElement {
|
|||
return this.renderSection(summary, content);
|
||||
}
|
||||
|
||||
renderAddStageButton() {
|
||||
if (!this.canEdit) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<sl-button size="small" @click="${
|
||||
() => openAddStageDialog(this.feature.id, this.feature.feature_type_int)}">
|
||||
Add stage
|
||||
</sl-button>`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<h2>
|
||||
|
@ -397,6 +410,7 @@ class ChromedashFeatureDetail extends LitElement {
|
|||
${this.renderMetadataSection()}
|
||||
${this.feature.stages.map(feStage => this.renderProcessStage(feStage))}
|
||||
${this.renderActivitySection()}
|
||||
${this.renderAddStageButton()}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
FEATURE_TYPES,
|
||||
IMPLEMENTATION_STATUS,
|
||||
} from './form-field-enums';
|
||||
|
||||
|
@ -600,3 +601,29 @@ export const FORMS_BY_STAGE_TYPE = {
|
|||
[STAGE_ENT_ROLLOUT]: FLAT_ENTERPRISE_PREPARE_TO_SHIP_FIELDS,
|
||||
[STAGE_ENT_SHIPPED]: FLAT_PREPARE_TO_SHIP_FIELDS,
|
||||
};
|
||||
|
||||
export const CREATEABLE_STAGES = {
|
||||
[FEATURE_TYPES.FEATURE_TYPE_INCUBATE_ID[0]]: [
|
||||
STAGE_BLINK_ORIGIN_TRIAL,
|
||||
STAGE_BLINK_SHIPPING,
|
||||
STAGE_ENT_ROLLOUT,
|
||||
],
|
||||
[FEATURE_TYPES.FEATURE_TYPE_EXISTING_ID[0]]: [
|
||||
STAGE_FAST_ORIGIN_TRIAL,
|
||||
STAGE_FAST_SHIPPING,
|
||||
STAGE_ENT_ROLLOUT,
|
||||
],
|
||||
[FEATURE_TYPES.FEATURE_TYPE_CODE_CHANGE_ID[0]]: [
|
||||
STAGE_PSA_SHIPPING,
|
||||
STAGE_ENT_ROLLOUT,
|
||||
],
|
||||
[FEATURE_TYPES.FEATURE_TYPE_DEPRECATION_ID[0]]: [
|
||||
STAGE_DEP_DEPRECATION_TRIAL,
|
||||
STAGE_DEP_SHIPPING,
|
||||
STAGE_ENT_ROLLOUT,
|
||||
],
|
||||
[FEATURE_TYPES.FEATURE_TYPE_ENTERPRISE_ID[0]]: [
|
||||
STAGE_ENT_ROLLOUT,
|
||||
STAGE_ENT_SHIPPED,
|
||||
],
|
||||
};
|
||||
|
|
|
@ -317,6 +317,10 @@ class ChromeStatusClient {
|
|||
return this.doGet(`/features/${featureId}/stages/${stageId}`);
|
||||
}
|
||||
|
||||
createStage(featureId, stageType) {
|
||||
return this.doPost(`/features/${featureId}/stages`, {stage_type: stageType});
|
||||
}
|
||||
|
||||
// Processes API
|
||||
getFeatureProcess(featureId) {
|
||||
return this.doGet(`/features/${featureId}/process`);
|
||||
|
|
2
main.py
2
main.py
|
@ -117,6 +117,8 @@ api_routes: list[Route] = [
|
|||
processes_api.ProcessesAPI),
|
||||
Route(f'{API_BASE}/features/<int:feature_id>/progress',
|
||||
processes_api.ProgressAPI),
|
||||
Route(f'{API_BASE}/features/<int:feature_id>/stages',
|
||||
stages_api.StagesAPI),
|
||||
Route(f'{API_BASE}/features/<int:feature_id>/stages/<int:stage_id>',
|
||||
stages_api.StagesAPI),
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче