@@ -14,7 +14,12 @@ import {DETAILS_STYLES} from './chromedash-feature-detail';
1414import './chromedash-feature-highlights.js' ;
1515import { GateDict } from './chromedash-gate-chip.js' ;
1616import { Process , ProgressItem } from './chromedash-gate-column.js' ;
17- import { showToastMessage , isVerifiedWithinGracePeriod } from './utils.js' ;
17+ import {
18+ showToastMessage ,
19+ getFeatureOutdatedBanner ,
20+ findClosestShippingDate ,
21+ closestShippingDateInfo ,
22+ } from './utils.js' ;
1823import {
1924 STAGE_TYPES_SHIPPING ,
2025 STAGE_TYPES_ORIGIN_TRIAL ,
@@ -116,14 +121,14 @@ export class ChromedashFeaturePage extends LitElement {
116121 @state ( )
117122 loading = true ;
118123 @state ( )
119- isUpcoming = false ;
120- @state ( )
121- hasShipped = false ;
122- @state ( )
123124 currentDate : number = Date . now ( ) ;
124125 @state ( )
125- // The closest milestone shipping date as an ISO string.
126- closestShippingDate : string = '' ;
126+ shippingInfo : closestShippingDateInfo = {
127+ // The closest milestone shipping date as an ISO string.
128+ closestShippingDate : '' ,
129+ hasShipped : false ,
130+ isUpcoming : false ,
131+ } ;
127132
128133 connectedCallback ( ) {
129134 super . connectedCallback ( ) ;
@@ -134,155 +139,6 @@ export class ChromedashFeaturePage extends LitElement {
134139 return this . feature && Object . keys ( this . feature ) . length !== 0 ;
135140 }
136141
137- async fetchClosestShippingDate ( milestone : number ) : Promise < string > {
138- if ( milestone === 0 ) {
139- return '' ;
140- }
141- try {
142- const newMilestonesInfo = await window . csClient . getSpecifiedChannels (
143- milestone ,
144- milestone
145- ) ;
146- return newMilestonesInfo [ milestone ] ?. final_beta ;
147- } catch {
148- showToastMessage (
149- 'Some errors occurred. Please refresh the page or try again later.'
150- ) ;
151- return '' ;
152- }
153- }
154-
155- /**
156- * Determine if this feature is upcoming - scheduled to ship
157- * within two milestones, then find the closest shipping date
158- * for that upcoming milestone or an already shipped milestone.*/
159- async findClosestShippingDate ( channels , stages : Array < StageDict > ) {
160- const latestStableVersion = channels [ 'stable' ] ?. version ;
161- if ( ! latestStableVersion || ! stages ) {
162- return ;
163- }
164-
165- const shippingTypeMilestones = new Set < number | undefined > ( ) ;
166- const otTypeMilestones = new Set < number | undefined > ( ) ;
167- for ( const stage of stages ) {
168- if ( STAGE_TYPES_SHIPPING . has ( stage . stage_type ) ) {
169- shippingTypeMilestones . add ( stage . desktop_first ) ;
170- shippingTypeMilestones . add ( stage . android_first ) ;
171- shippingTypeMilestones . add ( stage . ios_first ) ;
172- shippingTypeMilestones . add ( stage . webview_first ) ;
173- }
174- }
175- for ( const stage of stages ) {
176- if ( STAGE_TYPES_ORIGIN_TRIAL . has ( stage . stage_type ) ) {
177- otTypeMilestones . add ( stage . desktop_first ) ;
178- otTypeMilestones . add ( stage . android_first ) ;
179- otTypeMilestones . add ( stage . ios_first ) ;
180- otTypeMilestones . add ( stage . webview_first ) ;
181- }
182- }
183-
184- const upcomingMilestonesTarget = new Set < number | undefined > ( [
185- ...shippingTypeMilestones ,
186- ...otTypeMilestones ,
187- ] ) ;
188- // Check if this feature is shipped within two milestones.
189- let foundMilestone = 0 ;
190- if ( upcomingMilestonesTarget . has ( latestStableVersion + 1 ) ) {
191- foundMilestone = latestStableVersion + 1 ;
192- this . isUpcoming = true ;
193- } else if ( upcomingMilestonesTarget . has ( latestStableVersion + 2 ) ) {
194- foundMilestone = latestStableVersion + 2 ;
195- this . isUpcoming = true ;
196- }
197-
198- if ( this . isUpcoming ) {
199- Object . keys ( channels ) . forEach ( key => {
200- if ( channels [ key ] . version === foundMilestone ) {
201- this . closestShippingDate = channels [ key ] . final_beta ;
202- }
203- } ) ;
204- } else {
205- const shippedMilestonesTarget = shippingTypeMilestones ;
206- // If not upcoming, find the closest milestone that has shipped.
207- let latestMilestone = 0 ;
208- for ( const ms of shippedMilestonesTarget ) {
209- if ( ms && ms <= latestStableVersion ) {
210- latestMilestone = Math . max ( latestMilestone , ms ) ;
211- }
212- }
213-
214- if ( latestMilestone === latestStableVersion ) {
215- this . closestShippingDate = channels [ 'stable' ] ?. final_beta ;
216- this . hasShipped = true ;
217- } else {
218- this . closestShippingDate =
219- await this . fetchClosestShippingDate ( latestMilestone ) ;
220- this . hasShipped = true ;
221- }
222- }
223- }
224-
225- /**
226- * Determine if it should show warnings to a feature author, if
227- * a shipped feature is outdated, and it has edit access.*/
228- isShippedFeatureOutdatedForAuthor ( ) {
229- return this . userCanEdit ( ) && this . isShippedFeatureOutdated ( ) ;
230- }
231-
232- /**
233- * Determine if it should show warnings to all readers, if
234- * a shipped feature is outdated, and last update was > 2 months.*/
235- isShippedFeatureOutdatedForAll ( ) {
236- if ( ! this . isShippedFeatureOutdated ( ) ) {
237- return false ;
238- }
239-
240- // Represent two months grace period.
241- const nineWeekPeriod = 9 * 7 * 24 * 60 * 60 * 1000 ;
242- const isVerified = isVerifiedWithinGracePeriod (
243- this . feature . accurate_as_of ,
244- this . currentDate ,
245- nineWeekPeriod
246- ) ;
247- return ! isVerified ;
248- }
249-
250- /**
251- * A feature is outdated if it has shipped, and its
252- * accurate_as_of is before its latest shipping date before today.*/
253- isShippedFeatureOutdated ( ) : boolean {
254- // Check if a feature has shipped.
255- if ( ! this . hasShipped ) {
256- return false ;
257- }
258-
259- // If accurate_as_of is missing from a shipped feature, it is likely
260- // an old feature. Treat it as not oudated.
261- if ( ! this . feature . accurate_as_of ) {
262- return false ;
263- }
264-
265- return (
266- Date . parse ( this . feature . accurate_as_of ) <
267- Date . parse ( this . closestShippingDate )
268- ) ;
269- }
270-
271- /**
272- * A feature is outdated if it is scheduled to ship in the next 2 milestones,
273- * and its accurate_as_of date is at least 4 weeks ago.*/
274- isUpcomingFeatureOutdated ( ) : boolean {
275- if ( ! this . isUpcoming ) {
276- return false ;
277- }
278-
279- const isVerified = isVerifiedWithinGracePeriod (
280- this . feature . accurate_as_of ,
281- this . currentDate
282- ) ;
283- return ! isVerified ;
284- }
285-
286142 fetchData ( ) {
287143 this . loading = true ;
288144 Promise . all ( [
@@ -295,7 +151,7 @@ export class ChromedashFeaturePage extends LitElement {
295151 window . csClient . getChannels ( ) ,
296152 ] )
297153 . then (
298- ( [
154+ async ( [
299155 feature ,
300156 gatesRes ,
301157 commentRes ,
@@ -315,7 +171,11 @@ export class ChromedashFeaturePage extends LitElement {
315171 if ( this . feature . name ) {
316172 document . title = `${ this . feature . name } - ${ this . appTitle } ` ;
317173 }
318- this . findClosestShippingDate ( channels , feature . stages ) ;
174+ this . shippingInfo = await findClosestShippingDate (
175+ channels ,
176+ feature . stages
177+ ) ;
178+
319179 this . loading = false ;
320180 }
321181 )
@@ -632,103 +492,17 @@ export class ChromedashFeaturePage extends LitElement {
632492 </ div >
633493 ` ) ;
634494 }
635- if ( this . isUpcomingFeatureOutdated ( ) ) {
636- if ( this . userCanEdit ( ) ) {
637- warnings . push ( html `
638- < div class ="warning layout horizontal center ">
639- < span class ="tooltip " id ="outdated-icon " title ="Feature outdated ">
640- < sl-icon name ="exclamation-circle-fill " data-tooltip > </ sl-icon >
641- </ span >
642- < span >
643- Your feature hasn't been verified as accurate since
644- < sl-relative-time
645- date =${ this . feature . accurate_as_of ?? '' }
646- > </ sl-relative-time
647- > , but it is scheduled to ship
648- < sl-relative-time
649- date =${ this . closestShippingDate }
650- > </ sl-relative-time
651- > . Please
652- < a href ="/guide/verify_accuracy/ ${ this . featureId } "
653- > verify that your feature is accurate</ a
654- > .
655- </ span >
656- </ div >
657- ` ) ;
658- } else {
659- warnings . push ( html `
660- < div class ="warning layout horizontal center ">
661- < span class ="tooltip " id ="outdated-icon " title ="Feature outdated ">
662- < sl-icon name ="exclamation-circle-fill " data-tooltip > </ sl-icon >
663- </ span >
664- < span >
665- This feature hasn't been verified as accurate since
666- < sl-relative-time
667- date =${ this . feature . accurate_as_of ?? '' }
668- > </ sl-relative-time
669- > , but it is scheduled to ship
670- < sl-relative-time
671- date =${ this . closestShippingDate }
672- > </ sl-relative-time
673- > .
674- </ span >
675- </ div >
676- ` ) ;
677- }
495+ const userCanEdit = this . userCanEdit ( ) ;
496+ const featureOutdatedBanner = getFeatureOutdatedBanner (
497+ this . feature ,
498+ this . shippingInfo ,
499+ this . currentDate ,
500+ userCanEdit
501+ ) ;
502+ if ( featureOutdatedBanner ) {
503+ warnings . push ( featureOutdatedBanner ) ;
678504 }
679505
680- if ( this . isShippedFeatureOutdated ( ) ) {
681- if ( this . isShippedFeatureOutdatedForAuthor ( ) ) {
682- warnings . push ( html `
683- < div class ="warning layout horizontal center ">
684- < span
685- class ="tooltip "
686- id ="shipped-outdated-author "
687- title ="Feature outdated "
688- >
689- < sl-icon name ="exclamation-circle-fill " data-tooltip > </ sl-icon >
690- </ span >
691- < span >
692- Your feature hasn't been verified as accurate since
693- < sl-relative-time
694- date =${ this . feature . accurate_as_of ?? '' }
695- > </ sl-relative-time
696- > , but it claims to have shipped
697- < sl-relative-time
698- date =${ this . closestShippingDate }
699- > </ sl-relative-time
700- > . Please
701- < a href ="/guide/verify_accuracy/ ${ this . featureId } "
702- > verify that your feature is accurate</ a
703- > .
704- </ span >
705- </ div >
706- ` ) ;
707- } else if ( this . isShippedFeatureOutdatedForAll ( ) ) {
708- warnings . push ( html `
709- < div class ="warning layout horizontal center ">
710- < span
711- class ="tooltip "
712- id ="shipped-outdated-all "
713- title ="Feature outdated "
714- >
715- < sl-icon name ="exclamation-circle-fill " data-tooltip > </ sl-icon >
716- </ span >
717- < span >
718- This feature hasn't been verified as accurate since
719- < sl-relative-time
720- date =${ this . feature . accurate_as_of ?? '' }
721- > </ sl-relative-time
722- > , but it claims to have shipped
723- < sl-relative-time
724- date =${ this . closestShippingDate }
725- > </ sl-relative-time
726- > .
727- </ span >
728- </ div >
729- ` ) ;
730- }
731- }
732506 return warnings ;
733507 }
734508
0 commit comments