Typescript Migration: enterprise release notes (#4030)

* save temp

* migrated enterprise release notes page

* test file and lint

* adjust Feature import

* fix rawQuery return type and minor test fixes

* lint

* fixed type bug

* fix
This commit is contained in:
Mark Xiong 2024-07-30 22:32:27 -05:00 коммит произвёл GitHub
Родитель 372821fe96
Коммит 016756436a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 95 добавлений и 93 удалений

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

@ -1,5 +1,7 @@
import {html, LitElement, css} from 'lit';
import {css, html, LitElement, TemplateResult} from 'lit';
import {customElement, state} from 'lit/decorators.js';
import {SHARED_STYLES} from '../css/shared-css.js';
import {Feature} from '../js-src/cs-client.js';
import {
ENTERPRISE_FEATURE_CATEGORIES,
PLATFORM_CATEGORIES,
@ -8,33 +10,32 @@ import {
STAGE_TYPES_SHIPPING,
} from './form-field-enums.js';
import {
showToastMessage,
updateURLParams,
parseRawQuery,
renderHTMLIf,
showToastMessage,
updateURLParams,
} from './utils.js';
const milestoneQueryParamKey = 'milestone';
export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
static get properties() {
return {
currentFeatures: {type: Array},
upcomingFeatures: {type: Array},
features: {type: Array},
channels: {type: Object},
selectedMilestone: {type: Number},
};
}
interface Channels {
stable: {
version: number;
};
}
constructor() {
super();
this.currentFeatures = [];
this.upcomingFeatures = [];
this.features = [];
this.channels = {};
this.selectedMilestone = undefined;
}
@customElement('chromedash-enterprise-release-notes-page')
export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
@state()
currentFeatures: Feature[] = [];
@state()
upcomingFeatures: Feature[] = [];
@state()
features: Feature[] = [];
@state()
channels!: Channels;
@state()
selectedMilestone?: number;
static get styles() {
return [
@ -144,8 +145,11 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
stage.ios_last,
stage.webview_last,
];
const milestoneAndPlatformsMap = milestones.reduce(
(acc, milestone) => ({...acc, [milestone]: new Set()}),
const milestoneAndPlatformsMap: Record<
number,
Set<number>
> = milestones.reduce(
(acc, milestone) => ({...acc, [milestone]: new Set<number>()}),
{}
);
@ -252,15 +256,15 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
.sort((a, b) => {
// Highest impact of the stages from feature A.
const impactA = Math.max(
a.stages
...a.stages
.filter(s => s.rollout_milestone === this.selectedMilestone)
.map(s => s.rollout_impact)
.map(s => s.rollout_impact ?? 0)
);
// Highest impact of the stages from feature B.
const impactB = Math.max(
b.stages
...b.stages
.filter(s => s.rollout_milestone === this.selectedMilestone)
.map(s => s.rollout_impact)
.map(s => s.rollout_impact ?? 0)
);
return impactB - impactA;
});
@ -271,20 +275,24 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
.filter(
({stages}) =>
!stages.some(s => s.rollout_milestone === this.selectedMilestone) &&
stages.some(s => s.rollout_milestone > this.selectedMilestone)
stages.some(s => s.rollout_milestone! > this.selectedMilestone!)
)
.sort((a, b) => {
const minA =
Math.min(
a.stages
.filter(s => (s.rollout_milestone || 0) > this.selectedMilestone)
.map(s => s.rollout_milestone)
...a.stages
.filter(
s => (s.rollout_milestone! || 0) > this.selectedMilestone!
)
.map(s => s.rollout_milestone!)
) || 0;
const minB =
Math.min(
b.stages
.filter(s => (s.rollout_milestone || 0) > this.selectedMilestone)
.map(s => s.rollout_milestone)
...b.stages
.filter(
s => (s.rollout_milestone! || 0) > this.selectedMilestone!
)
.map(s => s.rollout_milestone!)
) || 0;
return minA - minB;
});
@ -321,9 +329,10 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
}
updateSelectedMilestone() {
this.selectedMilestone = parseInt(
this.shadowRoot.querySelector('#milestone-selector').value
);
const milestoneSelector = this.shadowRoot!.querySelector(
'#milestone-selector'
) as HTMLSelectElement;
this.selectedMilestone = parseInt(milestoneSelector.value);
window.csClient
.getFeaturesForEnterpriseReleaseNotes(this.selectedMilestone)
.then(({features}) => this.updateFeatures(features))
@ -334,16 +343,16 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
});
}
update() {
update(changedProperties: Map<string | number | symbol, unknown>) {
if (this.selectedMilestone !== undefined) {
updateURLParams(milestoneQueryParamKey, this.selectedMilestone);
}
super.update();
super.update(changedProperties);
}
renderMilestoneSelector() {
const options = [];
for (let i = 0; i < this.selectedMilestone + 20; ++i) {
const options: TemplateResult[] = [];
for (let i = 0; i < this.selectedMilestone! + 20; ++i) {
options.push(
html`<sl-option value="${i}">Chrome ${i} release summary</sl-option>`
);
@ -353,7 +362,7 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
placement="top"
hoist
size="small"
value=${this.selectedMilestone}
value=${this.selectedMilestone!}
@sl-change=${this.updateSelectedMilestone}
>
${options.map(option => option)}
@ -511,8 +520,7 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
'Upcoming Chrome browser updates',
this.upcomingFeatures,
(m, milestones) =>
milestones.find(x => parseInt(x) > parseInt(this.selectedMilestone)) ===
m
milestones.find(x => parseInt(x) > this.selectedMilestone!) === m
)}`;
}
@ -524,8 +532,3 @@ export class ChromedashEnterpriseReleaseNotesPage extends LitElement {
`;
}
}
customElements.define(
'chromedash-enterprise-release-notes-page',
ChromedashEnterpriseReleaseNotesPage
);

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

@ -256,17 +256,17 @@ describe('chromedash-enterprise-release-notes-page', () => {
<chromedash-enterprise-release-notes-page></chromedash-enterprise-release-notes-page>`);
assert.exists(component);
assert.instanceOf(component, ChromedashEnterpriseReleaseNotesPage);
assert.equal(parseRawQuery(window.location.search).milestone, 100);
assert.equal((parseRawQuery(window.location.search)).milestone, '100');
// Select a future milestone
component.selectedMilestone = 110;
await nextFrame();
assert.equal(parseRawQuery(window.location.search).milestone, 110);
assert.equal((parseRawQuery(window.location.search)).milestone, '110');
// Select a previous milestone
component.selectedMilestone = 90;
await nextFrame();
assert.equal(parseRawQuery(window.location.search).milestone, 90);
assert.equal((parseRawQuery(window.location.search)).milestone, '90');
});
it('renders with no data', async () => {
@ -280,8 +280,8 @@ describe('chromedash-enterprise-release-notes-page', () => {
// invalid feature requests would trigger the toast to show message
const toastEl = document.querySelector('chromedash-toast');
const toastMsgSpan = toastEl.shadowRoot.querySelector('span#msg');
assert.include(toastMsgSpan.innerHTML,
const toastMsgSpan = toastEl?.shadowRoot?.querySelector('span#msg');
assert.include(toastMsgSpan?.innerHTML,
'Some errors occurred. Please refresh the page or try again later.');
});
@ -291,8 +291,8 @@ describe('chromedash-enterprise-release-notes-page', () => {
assert.exists(component);
assert.instanceOf(component, ChromedashEnterpriseReleaseNotesPage);
const releaseNotesSummary = component.shadowRoot.querySelector('#release-notes-summary');
const children = [...releaseNotesSummary.querySelectorAll('tr > *')];
const releaseNotesSummary = component.renderRoot.querySelector('#release-notes-summary');
const children = Array.from(releaseNotesSummary!.querySelectorAll('tr > *'));
// Validate first headers
assert.equal(children[0].textContent, 'Chrome browser updates');
@ -343,19 +343,19 @@ describe('chromedash-enterprise-release-notes-page', () => {
assert.exists(component);
assert.instanceOf(component, ChromedashEnterpriseReleaseNotesPage);
const releaseNotes = [...component.shadowRoot.querySelectorAll('.note-section')];
const releaseNotes = Array.from(component.shadowRoot!.querySelectorAll('.note-section'));
assert.equal(2, releaseNotes.length);
// Test Chrome browser updates
{
assert.equal('Chrome browser updates', releaseNotes[0].querySelector('h2').textContent);
const features = [...releaseNotes[0].querySelectorAll('.feature')];
assert.equal('Chrome browser updates', releaseNotes[0].querySelector('h2')!.textContent);
const features = Array.from(releaseNotes[0].querySelectorAll('.feature'));
// Test feature 1
{
assert.equal(
'feature with two consecutive rollout stages',
features[0].querySelector('strong').textContent);
features[0].querySelector('strong')!.textContent);
assert.equal(
'< To remove - Feature details - ' +
'Owners: owner1 - Editors: editor1 - First Notice: n_milestone_feat_4 - ' +
@ -363,15 +363,15 @@ describe('chromedash-enterprise-release-notes-page', () => {
normalizedTextContent(features[0].querySelector('.toremove')));
assert.equal(
'feature 4 summary',
features[0].querySelector('.summary').textContent);
const stages = [...features[0].querySelectorAll('li')];
features[0].querySelector('.summary')!.textContent);
const stages = Array.from(features[0].querySelectorAll('li'));
assert.equal(2, stages.length);
assert.include(stages[0].textContent, 'Chrome 100');
assert.include(stages[0].textContent, 'fake rollout details 100');
assert.include(stages[1].textContent, 'Chrome 101');
assert.include(stages[1].textContent, 'fake rollout details 101');
const screenshots = [...features[0].querySelectorAll('.screenshots img')];
const screenshots: HTMLImageElement[] = Array.from(features[0].querySelectorAll('.screenshots img'));
assert.lengthOf(screenshots, 2);
assert.equal(screenshots[0].src, 'https://example.com/screenshot1');
assert.equal(screenshots[0].alt, 'Feature screenshot 1');
@ -383,7 +383,7 @@ describe('chromedash-enterprise-release-notes-page', () => {
{
assert.equal(
'feature with one rollout stages',
features[1].querySelector('strong').textContent);
features[1].querySelector('strong')!.textContent);
assert.equal(
'< To remove - Feature details - ' +
'Owners: owner - Editors: editor1, editor2 - First Notice: n_milestone_feat_3 - ' +
@ -391,13 +391,13 @@ describe('chromedash-enterprise-release-notes-page', () => {
normalizedTextContent(features[1].querySelector('.toremove')));
assert.equal(
'feature 3 summary',
features[1].querySelector('.summary').textContent);
const stages = [...features[1].querySelectorAll('li')];
features[1].querySelector('.summary')!.textContent);
const stages = Array.from(features[1].querySelectorAll('li'));
assert.equal(1, stages.length);
assert.include(stages[0].textContent, 'Chrome 100');
assert.include(stages[0].textContent, 'fake rollout details 100');
const screenshots = [...features[1].querySelectorAll('.screenshots img')];
const screenshots: HTMLImageElement[] = Array.from(features[1].querySelectorAll('.screenshots img'));
assert.lengthOf(screenshots, 1);
assert.equal(screenshots[0].src, 'https://example.com/screenshot1');
assert.equal(screenshots[0].alt, 'Feature screenshot 1');
@ -407,7 +407,7 @@ describe('chromedash-enterprise-release-notes-page', () => {
{
assert.equal(
'normal feature with shipping stage',
features[2].querySelector('strong').textContent);
features[2].querySelector('strong')!.textContent);
assert.equal(
'< To remove - Feature details - ' +
'Owners: owner - Editors: editor1, editor2 - First Notice: n_milestone_feat_7 - ' +
@ -415,15 +415,15 @@ describe('chromedash-enterprise-release-notes-page', () => {
normalizedTextContent(features[2].querySelector('.toremove')));
assert.equal(
'normal feature summary',
features[2].querySelector('.summary').textContent);
const stages = [...features[2].querySelectorAll('li')];
features[2].querySelector('.summary')!.textContent);
const stages = Array.from(features[2].querySelectorAll('li'));
assert.equal(4, stages.length);
assert.include(stages[0].textContent, 'Chrome 100 on Windows, Mac, Linux, Android');
assert.include(stages[1].textContent, 'Chrome 101 on Windows, Mac, Linux, Android');
assert.include(stages[2].textContent, 'Chrome 102 on iOS, Android');
assert.include(stages[3].textContent, 'Chrome 103 on iOS');
const screenshots = [...features[1].querySelectorAll('.screenshots img')];
const screenshots: HTMLImageElement[] = Array.from(features[1].querySelectorAll('.screenshots img'));
assert.lengthOf(screenshots, 1);
assert.equal(screenshots[0].src, 'https://example.com/screenshot1');
assert.equal(screenshots[0].alt, 'Feature screenshot 1');
@ -434,14 +434,14 @@ describe('chromedash-enterprise-release-notes-page', () => {
{
assert.equal(
'Upcoming Chrome browser updates',
releaseNotes[1].querySelector('h2').textContent);
const features = [...releaseNotes[1].querySelectorAll('.feature')];
releaseNotes[1].querySelector('h2')!.textContent);
const features = Array.from(releaseNotes[1].querySelectorAll('.feature'));
// Test feature 1
{
assert.equal(
'feature with upcoming rollout stages',
features[0].querySelector('strong').textContent);
features[0].querySelector('strong')!.textContent);
assert.equal(
'< To remove - Feature details - ' +
'Owners: owner - Editors: editor1, editor2 - First Notice: n_milestone_feat_6 - ' +
@ -449,13 +449,13 @@ describe('chromedash-enterprise-release-notes-page', () => {
normalizedTextContent(features[0].querySelector('.toremove')));
assert.equal(
'feature 6 summary',
features[0].querySelector('.summary').textContent);
const stages = [...features[0].querySelectorAll('li')];
features[0].querySelector('.summary')!.textContent);
const stages = Array.from(features[0].querySelectorAll('li'));
assert.equal(1, stages.length);
assert.include(stages[0].textContent, 'Chrome 999');
assert.include(stages[0].textContent, 'fake rollout details 999');
const screenshots = [...features[0].querySelectorAll('.screenshots img')];
const screenshots = Array.from(features[0].querySelectorAll('.screenshots img'));
assert.isEmpty(screenshots);
}
@ -463,7 +463,7 @@ describe('chromedash-enterprise-release-notes-page', () => {
{
assert.equal(
'feature with past and future rollout stages',
features[1].querySelector('strong').textContent);
features[1].querySelector('strong')!.textContent);
assert.equal(
'< To remove - Feature details - ' +
'Owners: owner - Editors: editor1, editor2 - First Notice: n_milestone_feat_5 - ' +
@ -471,15 +471,15 @@ describe('chromedash-enterprise-release-notes-page', () => {
normalizedTextContent(features[1].querySelector('.toremove')));
assert.equal(
'feature 5 summary',
features[1].querySelector('.summary').textContent);
const stages = [...features[1].querySelectorAll('li')];
features[1].querySelector('.summary')!.textContent);
const stages = Array.from(features[1].querySelectorAll('li'));
assert.equal(2, stages.length);
assert.include(stages[0].textContent, 'Chrome 1');
assert.include(stages[0].textContent, 'fake rollout details 1');
assert.include(stages[1].textContent, 'Chrome 1000');
assert.include(stages[1].textContent, 'fake rollout details 1000');
const screenshots = [...features[1].querySelectorAll('.screenshots img')];
const screenshots: HTMLImageElement[] = Array.from(features[1].querySelectorAll('.screenshots img'));
assert.lengthOf(screenshots, 1);
assert.equal(screenshots[0].src, 'https://example.com/screenshot1');
assert.equal(screenshots[0].alt, 'Feature screenshot 1');
@ -499,8 +499,8 @@ describe('chromedash-enterprise-release-notes-page', () => {
await nextFrame();
// Tests summary
const releaseNotesSummary = component.shadowRoot.querySelector('#release-notes-summary');
const children = [...releaseNotesSummary.querySelectorAll('tr > *')];
const releaseNotesSummary = component.renderRoot.querySelector('#release-notes-summary');
const children = Array.from(releaseNotesSummary!.querySelectorAll('tr > *'));
// Validate first headers
assert.equal(children[0].textContent, 'Chrome browser updates');
@ -521,13 +521,13 @@ describe('chromedash-enterprise-release-notes-page', () => {
assert.equal(children[9].textContent, 'Nothing');
// Tests release notes
const releaseNotes = [...component.shadowRoot.querySelectorAll('.note-section')];
const releaseNotes = Array.from(component.renderRoot.querySelectorAll('.note-section'));
assert.equal(2, releaseNotes.length);
// Test Chrome browser updates
{
assert.equal('Chrome browser updates', releaseNotes[0].querySelector('h2').textContent);
const features = [...releaseNotes[0].querySelectorAll('.feature')];
assert.equal('Chrome browser updates', releaseNotes[0].querySelector('h2')!.textContent);
const features = Array.from(releaseNotes[0].querySelectorAll('.feature'));
assert.equal(0, features.length);
}
@ -535,8 +535,8 @@ describe('chromedash-enterprise-release-notes-page', () => {
{
assert.equal(
'Upcoming Chrome browser updates',
releaseNotes[1].querySelector('h2').textContent);
const features = [...releaseNotes[1].querySelectorAll('.feature')];
releaseNotes[1].querySelector('h2')!.textContent);
const features = Array.from(releaseNotes[1].querySelectorAll('.feature'));
assert.equal(0, features.length);
}
});

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

@ -85,7 +85,7 @@ class ChromedashFeatureDetail extends LitElement {
canEdit = false;
@property({attribute: false})
feature!: Feature;
@property({type: Array, attribute: false})
@property({attribute: false})
gates!: GateDict[];
@property({attribute: false})
process!: Process;
@ -93,7 +93,6 @@ class ChromedashFeatureDetail extends LitElement {
progress!: ProgressItem;
@property({type: Number})
selectedGateId = 0;
@state()
anyCollapsed = true;
@state()
@ -268,7 +267,7 @@ class ChromedashFeatureDetail extends LitElement {
if (!rawQuery.hasOwnProperty('gate')) {
return;
}
const gateVal = rawQuery['gate'];
const gateVal = Number(rawQuery['gate']);
const foundGates = this.gates.filter(g => g.id == gateVal);
if (!foundGates.length) {
return;

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

@ -408,9 +408,9 @@ export interface RawQuery {
/**
* Parses URL query strings into a dict.
* @param {string} rawQuery a raw URL query string, e.g. q=abc&num=1;
* @return {Object} A key-value pair dictionary for the query string.
* @return {Record<string, string>} A key-value pair dictionary for the query string.
*/
export function parseRawQuery(rawQuery) {
export function parseRawQuery(rawQuery): Record<string, string> {
const params = new URLSearchParams(rawQuery);
const result = {};
for (const param of params.keys()) {