Typescript Migration: roadmap (#4097)
roadmap-milestone-card roadmap roadmap-page and test file
This commit is contained in:
Родитель
13183fd910
Коммит
16498d279b
|
@ -1,5 +1,7 @@
|
|||
import {SlPopup} from '@shoelace-style/shoelace';
|
||||
import {LitElement, html, nothing} from 'lit';
|
||||
import {ref, createRef} from 'lit/directives/ref.js';
|
||||
import {customElement, property} from 'lit/decorators.js';
|
||||
import {createRef, ref} from 'lit/directives/ref.js';
|
||||
import {ROADMAP_MILESTONE_CARD_CSS} from '../css/elements/chromedash-roadmap-milestone-card-css.js';
|
||||
|
||||
const REMOVED_STATUS = ['Removed'];
|
||||
|
@ -8,33 +10,37 @@ const ORIGIN_TRIAL = ['Origin trial'];
|
|||
const BROWSER_INTERVENTION = ['Browser Intervention'];
|
||||
const NO_FEATURE_STRING = 'NO FEATURES ARE PLANNED FOR THIS MILESTONE YET';
|
||||
|
||||
export interface TemplateContent {
|
||||
channelLabel: string;
|
||||
h1Class: string;
|
||||
channelTag?: string;
|
||||
dateText: string;
|
||||
featureHeader: string;
|
||||
}
|
||||
|
||||
@customElement('chromedash-roadmap-milestone-card')
|
||||
class ChromedashRoadmapMilestoneCard extends LitElement {
|
||||
infoPopupRef = createRef();
|
||||
infoPopupRef = createRef<SlPopup>();
|
||||
|
||||
static styles = ROADMAP_MILESTONE_CARD_CSS;
|
||||
static get properties() {
|
||||
return {
|
||||
starredFeatures: {type: Object},
|
||||
highlightFeature: {type: Number},
|
||||
templateContent: {type: Object},
|
||||
channel: {type: Object},
|
||||
showDates: {type: Boolean},
|
||||
signedIn: {type: Boolean},
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.starredFeatures = new Set();
|
||||
}
|
||||
@property({attribute: false})
|
||||
starredFeatures = new Set<number>();
|
||||
@property({attribute: false})
|
||||
highlightFeature!: number;
|
||||
@property({attribute: false})
|
||||
templateContent!: TemplateContent;
|
||||
@property({attribute: false})
|
||||
channel; //TODO(markxiong0122): Type this as Channel when PR#4085 is merged
|
||||
@property({type: Boolean})
|
||||
showDates = false;
|
||||
@property({type: Boolean})
|
||||
signedIn = false;
|
||||
|
||||
/**
|
||||
* Returns the number of days between a and b.
|
||||
* @param {!Date} a
|
||||
* @param {!Date} b
|
||||
* @return {!{days: number, future: boolean}}
|
||||
*/
|
||||
_dateDiffInDays(a, b) {
|
||||
_dateDiffInDays(a: Date, b: Date): {days: number; future: boolean} {
|
||||
// Discard time and time-zone information.
|
||||
const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
||||
const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
||||
|
@ -45,7 +51,7 @@ class ChromedashRoadmapMilestoneCard extends LitElement {
|
|||
}
|
||||
|
||||
_computeDate(dateStr, addYear = false) {
|
||||
const opts = {month: 'short', day: 'numeric'};
|
||||
const opts: Intl.DateTimeFormatOptions = {month: 'short', day: 'numeric'};
|
||||
if (addYear) {
|
||||
opts.year = 'numeric';
|
||||
}
|
||||
|
@ -109,7 +115,7 @@ class ChromedashRoadmapMilestoneCard extends LitElement {
|
|||
|
||||
_computeDaysUntil(dateStr) {
|
||||
const date = new Date(dateStr);
|
||||
if (isNaN(date)) {
|
||||
if (isNaN(date.getTime())) {
|
||||
return nothing;
|
||||
}
|
||||
const today = new Date();
|
||||
|
@ -134,7 +140,7 @@ class ChromedashRoadmapMilestoneCard extends LitElement {
|
|||
if (
|
||||
e.relatedTarget != this.renderRoot.querySelector('#detailed-info-link')
|
||||
) {
|
||||
this.infoPopupRef.value.active = null;
|
||||
this.infoPopupRef.value!.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +150,7 @@ class ChromedashRoadmapMilestoneCard extends LitElement {
|
|||
name="info-circle"
|
||||
id="info-button"
|
||||
@click=${() =>
|
||||
(this.infoPopupRef.value.active = !this.infoPopupRef.value.active)}
|
||||
(this.infoPopupRef.value!.active = !this.infoPopupRef.value!.active)}
|
||||
@focusout=${this.hidePopup}
|
||||
></sl-icon-button>
|
||||
|
||||
|
@ -388,8 +394,3 @@ class ChromedashRoadmapMilestoneCard extends LitElement {
|
|||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(
|
||||
'chromedash-roadmap-milestone-card',
|
||||
ChromedashRoadmapMilestoneCard
|
||||
);
|
|
@ -1,11 +1,15 @@
|
|||
import {LitElement, css, html} from 'lit';
|
||||
import {ref, createRef} from 'lit/directives/ref.js';
|
||||
import './chromedash-roadmap';
|
||||
import {customElement, property, state} from 'lit/decorators.js';
|
||||
import {createRef, ref} from 'lit/directives/ref.js';
|
||||
import {SHARED_STYLES} from '../css/shared-css.js';
|
||||
import {User} from '../js-src/cs-client';
|
||||
import './chromedash-roadmap';
|
||||
import {ChromedashRoadmap} from './chromedash-roadmap';
|
||||
|
||||
@customElement('chromedash-roadmap-page')
|
||||
export class ChromedashRoadmapPage extends LitElement {
|
||||
sectionRef = createRef();
|
||||
roadmapRef = createRef();
|
||||
sectionRef = createRef<HTMLElement>();
|
||||
roadmapRef = createRef<ChromedashRoadmap>();
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
|
@ -27,23 +31,16 @@ export class ChromedashRoadmapPage extends LitElement {
|
|||
];
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
user: {type: Object},
|
||||
cardWidth: {type: Number},
|
||||
numColumns: {type: Number},
|
||||
viewOffset: {type: Number},
|
||||
};
|
||||
}
|
||||
@property({type: Object, attribute: false})
|
||||
user!: User;
|
||||
@state()
|
||||
cardWidth = 0;
|
||||
@state()
|
||||
numColumns = 0;
|
||||
@state()
|
||||
viewOffset = 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.user = {};
|
||||
this.cardWidth = 0;
|
||||
this.numColumns = 0;
|
||||
this.viewOffset = 0;
|
||||
this.boundHandleResize = this.handleResize.bind(this);
|
||||
}
|
||||
boundHandleResize = this.handleResize.bind(this);
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
@ -60,7 +57,7 @@ export class ChromedashRoadmapPage extends LitElement {
|
|||
}
|
||||
|
||||
handleResize() {
|
||||
const containerWidth = this.sectionRef.value.offsetWidth;
|
||||
const containerWidth = this.sectionRef.value!.offsetWidth;
|
||||
const margin = 16;
|
||||
|
||||
let numColumns = 3;
|
||||
|
@ -70,14 +67,16 @@ export class ChromedashRoadmapPage extends LitElement {
|
|||
numColumns = 2;
|
||||
}
|
||||
this.numColumns = numColumns;
|
||||
this.cardWidth = containerWidth / numColumns - margin;
|
||||
if (containerWidth) {
|
||||
this.cardWidth = containerWidth / numColumns - margin;
|
||||
}
|
||||
|
||||
this.updateRoadmapMargin(false);
|
||||
}
|
||||
|
||||
handleMove(e) {
|
||||
const roadmap = this.roadmapRef.value;
|
||||
if (!roadmap.lastFutureFetchedOn) return;
|
||||
if (!roadmap?.lastFutureFetchedOn) return;
|
||||
|
||||
if (e.target.id == 'next-button') {
|
||||
this.viewOffset -= 1; // move to newer version
|
||||
|
@ -99,6 +98,7 @@ export class ChromedashRoadmapPage extends LitElement {
|
|||
|
||||
updateRoadmapMargin(animated) {
|
||||
const roadmap = this.roadmapRef.value;
|
||||
if (!roadmap) return;
|
||||
if (animated) {
|
||||
roadmap.classList.add('animate');
|
||||
} else {
|
||||
|
@ -147,5 +147,3 @@ export class ChromedashRoadmapPage extends LitElement {
|
|||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('chromedash-roadmap-page', ChromedashRoadmapPage);
|
|
@ -1,8 +1,8 @@
|
|||
import {html} from 'lit';
|
||||
import {assert, fixture} from '@open-wc/testing';
|
||||
import {ChromedashRoadmapPage} from './chromedash-roadmap-page';
|
||||
import {ChromeStatusClient} from '../js-src/cs-client';
|
||||
import {html} from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import {ChromeStatusClient} from '../js-src/cs-client';
|
||||
import {ChromedashRoadmapPage} from './chromedash-roadmap-page';
|
||||
|
||||
describe('chromedash-roadmap-page', () => {
|
||||
const starsPromise = Promise.resolve([123456]);
|
||||
|
@ -100,11 +100,11 @@ describe('chromedash-roadmap-page', () => {
|
|||
assert.instanceOf(component, ChromedashRoadmapPage);
|
||||
|
||||
// subheader exists
|
||||
const subheaderDiv = component.shadowRoot.querySelector('div#subheader');
|
||||
const subheaderDiv = component.renderRoot.querySelector('div#subheader');
|
||||
assert.exists(subheaderDiv);
|
||||
|
||||
// releases-section exists and contains the previous and next buttons
|
||||
const releasesSec = component.shadowRoot.querySelector(
|
||||
const releasesSec = component.renderRoot.querySelector(
|
||||
'section#releases-section'
|
||||
);
|
||||
assert.exists(releasesSec);
|
||||
|
@ -112,7 +112,7 @@ describe('chromedash-roadmap-page', () => {
|
|||
assert.include(releasesSec.innerHTML, 'button id="next-button"');
|
||||
|
||||
// chromedash-roadmap component exists
|
||||
const roadmap = component.shadowRoot.querySelector('chromedash-roadmap');
|
||||
const roadmap = component.renderRoot.querySelector('chromedash-roadmap');
|
||||
assert.exists(roadmap);
|
||||
});
|
||||
});
|
|
@ -1,9 +1,43 @@
|
|||
import {LitElement, html, css} from 'lit';
|
||||
import {showToastMessage} from './utils.js';
|
||||
import '@polymer/iron-icon';
|
||||
import {LitElement, css, html} from 'lit';
|
||||
import {customElement, property, state} from 'lit/decorators.js';
|
||||
import {SHARED_STYLES} from '../css/shared-css.js';
|
||||
import {Feature} from '../js-src/cs-client.js';
|
||||
import {TemplateContent} from './chromedash-roadmap-milestone-card.js';
|
||||
import {showToastMessage} from './utils.js';
|
||||
|
||||
const TEMPLATE_CONTENT = {
|
||||
//TODO(markxiong0122): move this to cs-client.js after converting it to TypeScript
|
||||
interface MilestoneDetails {
|
||||
branch_point: string;
|
||||
earliest_beta: string;
|
||||
earliest_beta_chromeos: string;
|
||||
earliest_beta_ios: string;
|
||||
feature_freeze: string;
|
||||
final_beta: string;
|
||||
final_beta_cut: string;
|
||||
late_stable_date: string;
|
||||
latest_beta: string;
|
||||
ldaps: Record<string, string>;
|
||||
ltc_date: string;
|
||||
ltr_date: string;
|
||||
ltr_last_refresh_date: string;
|
||||
mstone: number;
|
||||
owners: Record<string, string>;
|
||||
stable_cut: string;
|
||||
stable_cut_ios: string;
|
||||
stable_date: string;
|
||||
stable_refresh_first: string;
|
||||
stable_refresh_second: string;
|
||||
stable_refresh_third: string;
|
||||
version: number;
|
||||
features: Feature[];
|
||||
}
|
||||
|
||||
interface MilestoneInfo {
|
||||
[milestone: number]: MilestoneDetails;
|
||||
}
|
||||
|
||||
const TEMPLATE_CONTENT: Record<string, TemplateContent> = {
|
||||
stable_minus_one: {
|
||||
channelLabel: 'Released',
|
||||
h1Class: '',
|
||||
|
@ -49,7 +83,8 @@ const SHOW_DATES = true;
|
|||
const compareFeatures = (a, b) =>
|
||||
a.name.localeCompare(b.name, 'fr', {ignorePunctuation: true}); // comparator for sorting milestone features
|
||||
|
||||
class ChromedashRoadmap extends LitElement {
|
||||
@customElement('chromedash-roadmap')
|
||||
export class ChromedashRoadmap extends LitElement {
|
||||
static get styles() {
|
||||
return [
|
||||
...SHARED_STYLES,
|
||||
|
@ -63,37 +98,58 @@ class ChromedashRoadmap extends LitElement {
|
|||
`,
|
||||
];
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
channels: {attribute: false},
|
||||
signedIn: {type: Boolean},
|
||||
starredFeatures: {type: Object}, // will contain a set of starred features
|
||||
numColumns: {type: Number},
|
||||
cardWidth: {type: Number}, // width of each milestone card
|
||||
lastFutureFetchedOn: {type: Number}, // milestone number rendering of which caused fetching of next milestones
|
||||
lastPastFetchedOn: {type: Number}, // milestone number rendering of which caused fetching of previous milestones
|
||||
lastMilestoneVisible: {type: Number}, // milestone number visible on screen to the user
|
||||
futureMilestoneArray: {type: Array}, // array to store the milestone numbers fetched after dev channel
|
||||
pastMilestoneArray: {type: Array}, // array to store the milestone numbers fetched before stable channel
|
||||
milestoneInfo: {type: Object}, // object to store milestone details (features version etc.) fetched after dev channel
|
||||
highlightFeature: {type: Number}, // feature to highlight
|
||||
cardOffset: {type: Number}, // left margin value
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.channels = {};
|
||||
this.shownChannelNames = [];
|
||||
this.numColumns = 0;
|
||||
this.cardWidth = 0;
|
||||
this.starredFeatures = new Set();
|
||||
this.futureMilestoneArray = [];
|
||||
this.pastMilestoneArray = [];
|
||||
this.milestoneInfo = {};
|
||||
this.cardOffset = 0;
|
||||
}
|
||||
@property({type: Boolean})
|
||||
signedIn;
|
||||
@property({type: Number, attribute: false})
|
||||
numColumns = 0;
|
||||
@property({type: Number, attribute: false})
|
||||
cardWidth = 0;
|
||||
@state()
|
||||
channels; //TODO(markxiong0122): Type this as Channel when PR#4085 is merged
|
||||
@state()
|
||||
starredFeatures = new Set<number>();
|
||||
/**
|
||||
* The timestamp of the last fetched future milestone.
|
||||
*/
|
||||
@state()
|
||||
lastFutureFetchedOn!: number;
|
||||
/**
|
||||
* The timestamp of the last fetched past milestone.
|
||||
*/
|
||||
@state()
|
||||
lastPastFetchedOn!: number;
|
||||
/**
|
||||
* The milestone number currently visible on the screen to the user.
|
||||
*/
|
||||
@state()
|
||||
lastMilestoneVisible!: number;
|
||||
/**
|
||||
* Array to store the milestone numbers fetched after the dev channel.
|
||||
*/
|
||||
@state()
|
||||
futureMilestoneArray: number[] = [];
|
||||
/**
|
||||
* Array to store the milestone numbers fetched before the stable channel.
|
||||
*/
|
||||
@state()
|
||||
pastMilestoneArray: number[] = [];
|
||||
/**
|
||||
* Object to store milestone details (features, version, etc.) fetched after the dev channel.
|
||||
*/
|
||||
@state()
|
||||
milestoneInfo!: MilestoneInfo;
|
||||
/**
|
||||
* The feature to highlight.
|
||||
*/
|
||||
@state()
|
||||
highlightFeature: number | undefined = undefined;
|
||||
/**
|
||||
* The left margin value.
|
||||
*/
|
||||
@state()
|
||||
cardOffset = 0;
|
||||
@state()
|
||||
shownChannelNames: string[] = [];
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
@ -305,5 +361,3 @@ class ChromedashRoadmap extends LitElement {
|
|||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('chromedash-roadmap', ChromedashRoadmap);
|
Загрузка…
Ссылка в новой задаче