Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move availabity to separate columns #999

Merged
merged 11 commits into from
Dec 20, 2024
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
DEFAULT_COLUMN_OPTIONS,
ColumnOptionKey,
renderBaselineStatus,
renderDesktopAvailablity,
renderChromiumUsage,
renderHeaderCell,
CELL_DEFS,
Expand Down Expand Up @@ -429,6 +430,55 @@ describe('renderBaselineStatus', () => {
});
});

describe('renderDesktopAvailablity', () => {
let container: HTMLElement;
beforeEach(() => {
container = document.createElement('td');
});
it('renders a full-color icon for an available feature', async () => {
const feature: components['schemas']['Feature'] = {
feature_id: 'id',
name: 'name',
browser_implementations: {
chrome: {status: 'available', version: '123'},
},
};
const result = renderDesktopAvailablity(
feature,
{search: ''},
{browser: 'chrome'},
);
render(result, container);
const el = await fixture(container);
const div = el.querySelector('div');
expect(div).to.exist;
expect(div!.getAttribute('class')).to.equal('browser-impl-available');
expect(div!.innerHTML).to.not.include('disabled');
expect(div!.innerHTML).to.include('chrome_24x24.png');
});
it('renders a grayscale icon for an available feature', async () => {
const feature: components['schemas']['Feature'] = {
feature_id: 'id',
name: 'name',
browser_implementations: {
chrome: {status: 'unavailable'},
},
};
const result = renderDesktopAvailablity(
feature,
{search: ''},
{browser: 'chrome'},
);
render(result, container);
const el = await fixture(container);
const div = el.querySelector('div');
expect(div).to.exist;
expect(div!.getAttribute('class')).to.equal('browser-impl-unavailable');
expect(div!.innerHTML).to.include('disabled');
expect(div!.innerHTML).to.include('chrome_24x24.png');
});
});

describe('calcColGroupSpans', () => {
const TEST_COLS = [
ColumnKey.Name,
Expand Down Expand Up @@ -596,7 +646,7 @@ describe('renderHeaderCell', () => {
const th = el.querySelector('th');
expect(th).to.exist;
expect(th!.getAttribute('title')).to.equal('Click to sort');
expect(th!.getAttribute('class')).to.equal('sortable');
expect('' + th!.getAttribute('class')).to.include('sortable');
});
it('renders an unsortable header cell', async () => {
CELL_DEFS[ColumnKey.BaselineStatus].unsortable = true;
Expand All @@ -610,6 +660,19 @@ describe('renderHeaderCell', () => {
const th = el.querySelector('th');
expect(th).to.exist;
expect(th!.getAttribute('title')).to.not.equal('Click to sort');
expect(th!.getAttribute('class')).to.not.equal('sortable');
expect('' + th!.getAttribute('class')).to.not.include('sortable');
});
it('renders a header cell with a cell class', async () => {
CELL_DEFS[ColumnKey.BaselineStatus].cellClass = 'cell-class';
const result = renderHeaderCell(
{search: '/'},
ColumnKey.BaselineStatus,
'',
);
render(result, container);
const el = await fixture(container);
const th = el.querySelector('th');
expect(th).to.exist;
expect(th!.getAttribute('class')).to.include('cell-class');
});
});
92 changes: 74 additions & 18 deletions frontend/src/static/js/components/webstatus-overview-cells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '../utils/urls.js';
import {FeatureSortOrderType} from '../api/client.js';

const MISSING_VALUE = html`---`;
const MISSING_VALUE = html``;

type CellRenderer = {
(
Expand All @@ -40,6 +40,7 @@ type ColumnDefinition = {
group?: string;
headerHtml: TemplateResult;
cellRenderer: CellRenderer;
cellClass?: string;
unsortable?: boolean;
options: {
browser?: components['parameters']['browserPathParam'];
Expand All @@ -56,6 +57,10 @@ const NEWLY_TO_WIDELY_MONTH_OFFSET = 30;
export enum ColumnKey {
Name = 'name',
BaselineStatus = 'baseline_status',
DesktopAvailabilityChrome = 'desktop_availability_chrome',
DesktopAvailabilityEdge = 'desktop_availability_edge',
DesktopAvailabilityFirefox = 'desktop_availability_firefox',
DesktopAvailabilitySafari = 'desktop_availability_safari',
StableChrome = 'stable_chrome',
StableEdge = 'stable_edge',
StableFirefox = 'stable_firefox',
Expand Down Expand Up @@ -97,6 +102,10 @@ const columnOptionKeyMapping = Object.entries(ColumnOptionKey).reduce(
export const DEFAULT_COLUMNS = [
ColumnKey.Name,
ColumnKey.BaselineStatus,
ColumnKey.DesktopAvailabilityChrome,
ColumnKey.DesktopAvailabilityEdge,
ColumnKey.DesktopAvailabilityFirefox,
ColumnKey.DesktopAvailabilitySafari,
ColumnKey.StableChrome,
ColumnKey.StableEdge,
ColumnKey.StableFirefox,
Expand Down Expand Up @@ -260,12 +269,24 @@ export const renderBaselineStatus: CellRenderer = (
`;
};

const BROWSER_IMPL_ICONS: Record<
NonNullable<components['schemas']['BrowserImplementation']['status']>,
string
> = {
unavailable: 'minus-circle',
available: 'check-circle',
export const renderDesktopAvailablity: CellRenderer = (
feature,
_routerLocation,
{browser},
) => {
const browserImpl = feature.browser_implementations?.[browser!];
const browserImplStatus = browserImpl?.status || 'unavailable';
const browserImplVersion = browserImpl?.version;
return html`
<div class="browser-impl-${browserImplStatus}">
<sl-tooltip
?disabled=${browserImplVersion === undefined}
content="Since version ${browserImplVersion}"
>
<img src="/public/img/${browser}_24x24.png" />
</sl-tooltip>
</div>
`;
};

function renderMissingPercentage(): TemplateResult {
Expand All @@ -292,7 +313,6 @@ export const renderBrowserQuality: CellRenderer = (
let percentage = renderPercentage(score);
const browserImpl = feature.browser_implementations?.[browser!];
const browserImplStatus = browserImpl?.status || 'unavailable';
const browserImplVersion = browserImpl?.version;
if (browserImplStatus === 'unavailable') {
percentage = renderMissingPercentage();
}
Expand All @@ -305,15 +325,7 @@ export const renderBrowserQuality: CellRenderer = (
if (didFeatureCrash(feature.wpt?.stable?.[browser!]?.metadata)) {
percentage = renderFeatureCrash();
}
const iconName = BROWSER_IMPL_ICONS[browserImplStatus];
return html`
<div class="browser-impl-${browserImplStatus}">
<sl-tooltip
?disabled=${browserImplVersion === undefined}
content="Since version ${browserImplVersion}"
>
<sl-icon name="${iconName}" library="custom"></sl-icon>
</sl-tooltip>
${percentage}
</div>
`;
Expand Down Expand Up @@ -370,59 +382,103 @@ export const CELL_DEFS: Record<ColumnKey, ColumnDefinition> = {
],
},
},
[ColumnKey.DesktopAvailabilityChrome]: {
nameInDialog: 'Availibility in desktop Chrome',
group: 'Availability',
headerHtml: html``,
unsortable: true,
cellClass: 'centered',
cellRenderer: renderDesktopAvailablity,
options: {browser: 'chrome'},
},
[ColumnKey.DesktopAvailabilityEdge]: {
nameInDialog: 'Availibility in desktop Edge',
group: 'Availability',
headerHtml: html``,
unsortable: true,
cellClass: 'centered',
cellRenderer: renderDesktopAvailablity,
options: {browser: 'edge'},
},
[ColumnKey.DesktopAvailabilityFirefox]: {
nameInDialog: 'Availibility in desktop Firefox',
group: 'Availability',
headerHtml: html``,
unsortable: true,
cellClass: 'centered',
cellRenderer: renderDesktopAvailablity,
options: {browser: 'firefox'},
},
[ColumnKey.DesktopAvailabilitySafari]: {
nameInDialog: 'Availibility in desktop Safari',
group: 'Availability',
headerHtml: html``,
cellClass: 'centered',
unsortable: true,
cellRenderer: renderDesktopAvailablity,
options: {browser: 'safari'},
},
[ColumnKey.StableChrome]: {
nameInDialog: 'Browser Implementation in Chrome',
group: 'WPT',
headerHtml: html`<img src="/public/img/chrome_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQuality,
options: {browser: 'chrome', channel: 'stable'},
},
[ColumnKey.StableEdge]: {
nameInDialog: 'Browser Implementation in Edge',
group: 'WPT',
headerHtml: html`<img src="/public/img/edge_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQuality,
options: {browser: 'edge', channel: 'stable'},
},
[ColumnKey.StableFirefox]: {
nameInDialog: 'Browser Implementation in Firefox',
group: 'WPT',
headerHtml: html`<img src="/public/img/firefox_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQuality,
options: {browser: 'firefox', channel: 'stable'},
},
[ColumnKey.StableSafari]: {
nameInDialog: 'Browser Implementation in Safari',
group: 'WPT',
headerHtml: html`<img src="/public/img/safari_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQuality,
options: {browser: 'safari', channel: 'stable'},
},
[ColumnKey.ExpChrome]: {
nameInDialog: 'Browser Implementation in Chrome Experimental',
group: 'WPT Experimental',
headerHtml: html`<img src="/public/img/chrome-canary_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQualityExp,
options: {browser: 'chrome', channel: 'experimental'},
},
[ColumnKey.ExpEdge]: {
nameInDialog: 'Browser Implementation in Edge Experimental',
group: 'WPT Experimental',
headerHtml: html`<img src="/public/img/edge-dev_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQualityExp,
options: {browser: 'edge', channel: 'experimental'},
},
[ColumnKey.ExpFirefox]: {
nameInDialog: 'Browser Implementation in Firefox Experimental',
group: 'WPT Experimental',
headerHtml: html`<img src="/public/img/firefox-nightly_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQualityExp,
options: {browser: 'firefox', channel: 'experimental'},
},
[ColumnKey.ExpSafari]: {
nameInDialog: 'Browser Implementation in Safari Experimental',
group: 'WPT Experimental',
headerHtml: html`<img src="/public/img/safari-preview_24x24.png" />`,
cellClass: 'centered',
cellRenderer: renderBrowserQualityExp,
options: {browser: 'safari', channel: 'experimental'},
},
Expand Down Expand Up @@ -495,10 +551,10 @@ export function renderHeaderCell(

const colDef = CELL_DEFS[column];
if (colDef.unsortable) {
return html`<th>${colDef?.headerHtml}</th>`;
return html`<th class=${colDef.cellClass || ''}>${colDef?.headerHtml}</th>`;
} else {
return html`
<th title="Click to sort" class="sortable">
<th title="Click to sort" class="${colDef.cellClass || ''} sortable">
<a href=${urlWithSort}> ${sortIndicator} ${colDef?.headerHtml} </a>
</th>
`;
Expand Down
14 changes: 11 additions & 3 deletions frontend/src/static/js/components/webstatus-overview-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {getColumnsSpec, getSortSpec} from '../utils/urls.js';
import {
ColumnKey,
DEFAULT_SORT_SPEC,
CELL_DEFS,
parseColumnsSpec,
renderFeatureCell,
renderColgroups,
Expand Down Expand Up @@ -61,6 +62,9 @@ export class WebstatusOverviewTable extends LitElement {
.data-table {
margin: var(--content-padding) 0;
}
.data-table th {
padding: var(--content-padding-quarter) var(--content-padding);
}
.header-row th {
border-left: var(--default-border);
border-right: var(--default-border);
Expand All @@ -72,14 +76,16 @@ export class WebstatusOverviewTable extends LitElement {
padding-top: var(--content-padding-quarter);
}
.browser-impl-unavailable {
color: var(--icon-color-avail-unavailable);
filter: grayscale(1);
opacity: 50%;
}
.percent {
display: inline-block;
width: 6ex;
text-align: right;
}
.missing.percent {
.missing.percent,
tr .centered {
text-align: center;
}

Expand Down Expand Up @@ -290,7 +296,9 @@ export class WebstatusOverviewTable extends LitElement {
<tr>
${columns.map(
col => html`
<td>${renderFeatureCell(feature, this.location, col)}</td>
<td class=${CELL_DEFS[col].cellClass ?? ''}>
${renderFeatureCell(feature, this.location, col)}
</td>
`,
)}
</tr>
Expand Down
Loading