Skip to content

Commit

Permalink
Implementation UI warnings for outdated shipped feature (#4506)
Browse files Browse the repository at this point in the history
* Implementation

* Fix comments, pending tests

* Finish tests

* Ignore old shipped feature
  • Loading branch information
KyleJu authored Oct 31, 2024
1 parent 5c49495 commit 9a6b2f6
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 29 deletions.
148 changes: 142 additions & 6 deletions client-src/elements/chromedash-feature-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export class ChromedashFeaturePage extends LitElement {
@state()
isUpcoming = false;
@state()
hasShipped = false;
@state()
currentDate: number = Date.now();
@state()
// The closest milestone shipping date as an ISO string.
Expand All @@ -128,11 +130,29 @@ export class ChromedashFeaturePage extends LitElement {
return this.feature && Object.keys(this.feature).length !== 0;
}

async fetchClosestShippingDate(milestone: number): Promise<string> {
if (milestone === 0) {
return '';
}
try {
const newMilestonesInfo = await window.csClient.getSpecifiedChannels(
milestone,
milestone
);
return newMilestonesInfo[milestone]?.final_beta;
} catch {
showToastMessage(
'Some errors occurred. Please refresh the page or try again later.'
);
return '';
}
}

/**
* Determine if this feature is upcoming - scheduled to ship
* within two milestones, and find the closest shipping date
* for that milestone.*/
calcUpcoming(channels, stages: Array<StageDict>) {
* within two milestones, then find the closest shipping date
* for that upcoming milestone or an already shipped milestone.*/
async findClosestShippingDate(channels, stages: Array<StageDict>) {
const latestStableVersion = channels['stable']?.version;
if (!latestStableVersion || !stages) {
return;
Expand Down Expand Up @@ -164,13 +184,76 @@ export class ChromedashFeaturePage extends LitElement {
this.closestShippingDate = channels[key].final_beta;
}
});
} else {
// If not upcoming, find the closest milestone that has shipped.
let latestMilestone = 0;
for (const ms of shippingMilestones) {
if (ms && ms <= latestStableVersion) {
latestMilestone = Math.max(latestMilestone, ms);
}
}

if (latestMilestone === latestStableVersion) {
this.closestShippingDate = channels['stable']?.final_beta;
this.hasShipped = true;
} else {
this.closestShippingDate =
await this.fetchClosestShippingDate(latestMilestone);
this.hasShipped = true;
}
}
}

/**
* Determine if it should show warnings to a feature author, if
* a shipped feature is outdated, and it has edit access.*/
isShippedFeatureOutdatedForAuthor() {
return this.userCanEdit() && this.isShippedFeatureOutdated();
}

/**
* Determine if it should show warnings to all readers, if
* a shipped feature is outdated, and last update was > 2 months.*/
isShippedFeatureOutdatedForAll() {
if (!this.isShippedFeatureOutdated()) {
return false;
}

// Represent two months grace period.
const nineWeekPeriod = 9 * 7 * 24 * 60 * 60 * 1000;
const isVerified = isVerifiedWithinGracePeriod(
this.feature.accurate_as_of,
this.currentDate,
nineWeekPeriod
);
return !isVerified;
}

/**
* A feature is outdated if it has shipped, and its
* accurate_as_of is before its latest shipping date before today.*/
isShippedFeatureOutdated(): boolean {
// Check if a feature has shipped.
if (!this.hasShipped) {
return false;
}

// If accurate_as_of is missing from a shipped feature, it is likely
// an old feature. Treat it as not oudated.
if (!this.feature.accurate_as_of) {
return false;
}

return (
Date.parse(this.feature.accurate_as_of) <
Date.parse(this.closestShippingDate)
);
}

/**
* A feature is outdated if it is scheduled to ship in the next 2 milestones,
* and its accurate_as_of date is at least 4 weeks ago.*/
isFeatureOutdated(): boolean {
isUpcomingFeatureOutdated(): boolean {
if (!this.isUpcoming) {
return false;
}
Expand Down Expand Up @@ -214,7 +297,7 @@ export class ChromedashFeaturePage extends LitElement {
if (this.feature.name) {
document.title = `${this.feature.name} - ${this.appTitle}`;
}
this.calcUpcoming(channels, feature.stages);
this.findClosestShippingDate(channels, feature.stages);
this.loading = false;
}
)
Expand Down Expand Up @@ -486,7 +569,7 @@ export class ChromedashFeaturePage extends LitElement {
</div>
`);
}
if (this.isFeatureOutdated()) {
if (this.isUpcomingFeatureOutdated()) {
if (this.userCanEdit()) {
warnings.push(html`
<div class="warning layout horizontal center">
Expand Down Expand Up @@ -530,6 +613,59 @@ export class ChromedashFeaturePage extends LitElement {
`);
}
}

if (this.isShippedFeatureOutdated()) {
if (this.isShippedFeatureOutdatedForAuthor()) {
warnings.push(html`
<div class="warning layout horizontal center">
<span
class="tooltip"
id="shipped-outdated-author"
title="Feature outdated "
>
<iron-icon icon="chromestatus:error" data-tooltip></iron-icon>
</span>
<span>
Your feature hasn't been verified as accurate since&nbsp;
<sl-relative-time
date=${this.feature.accurate_as_of}
></sl-relative-time
>, but it claims to have shipped&nbsp;
<sl-relative-time
date=${this.closestShippingDate}
></sl-relative-time
>. Please
<a href="/guide/verify_accuracy/${this.featureId}"
>verify that your feature is accurate</a
>.
</span>
</div>
`);
} else if (this.isShippedFeatureOutdatedForAll()) {
warnings.push(html`
<div class="warning layout horizontal center">
<span
class="tooltip"
id="shipped-outdated-all"
title="Feature outdated "
>
<iron-icon icon="chromestatus:error" data-tooltip></iron-icon>
</span>
<span>
This feature hasn't been verified as accurate since&nbsp;
<sl-relative-time
date=${this.feature.accurate_as_of}
></sl-relative-time
>, but it claims to have shipped&nbsp;
<sl-relative-time
date=${this.closestShippingDate}
></sl-relative-time
>.
</span>
</div>
`);
}
}
return warnings;
}

Expand Down
Loading

0 comments on commit 9a6b2f6

Please sign in to comment.