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

Bookmark sorting UI follow-up #992

Merged
merged 10 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
renderDesktopAvailablity,
renderChromiumUsage,
renderHeaderCell,
renderUnsortableHeaderCell,
CELL_DEFS,
calcColGroupSpans,
renderColgroups,
Expand Down Expand Up @@ -660,7 +661,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.include('sortable');
expect(th!.getAttribute('class')).to.include('unsortable');
});
it('renders the name header cell for query order', async () => {
const result = renderUnsortableHeaderCell(
ColumnKey.Name,
'bookmark1 query order',
);
render(result, container);
const el = await fixture(container);
const th = el.querySelector('th');
expect(th).to.exist;
expect(th!.getAttribute('title')).to.equal('bookmark1 query order');
expect(th!.getAttribute('class')).to.include('unsortable');
});
it('renders a header cell with a cell class', async () => {
CELL_DEFS[ColumnKey.BaselineStatus].cellClass = 'cell-class';
Expand All @@ -675,4 +688,13 @@ describe('renderHeaderCell', () => {
expect(th).to.exist;
expect(th!.getAttribute('class')).to.include('cell-class');
});
it('renders a non-name header cell for query order', async () => {
const result = renderUnsortableHeaderCell(ColumnKey.BaselineStatus);
render(result, container);
const el = await fixture(container);
const th = el.querySelector('th');
expect(th).to.exist;
expect(th!.getAttribute('title')).to.not.exist;
expect(th!.getAttribute('class')).to.include('unsortable');
});
});
56 changes: 47 additions & 9 deletions frontend/src/static/js/components/webstatus-overview-cells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getColumnOptions,
} from '../utils/urls.js';
import {FeatureSortOrderType} from '../api/client.js';
import {ifDefined} from 'lit/directives/if-defined.js';

const MISSING_VALUE = html``;

Expand Down Expand Up @@ -529,10 +530,36 @@ export function renderGroupsRow(columns: ColumnKey[]): TemplateResult {
`;
}

export function renderBookmarkHeaderCells(
bookmarkName: string,
columns: ColumnKey[],
): TemplateResult[] {
const headerCells: TemplateResult[] = columns.map(col => {
if (col === ColumnKey.Name) {
const title = `Sorted by ${bookmarkName} query order`;
return html`${renderUnsortableHeaderCell(col, title)}`;
} else {
return html`${renderUnsortableHeaderCell(col)}`;
}
});
return headerCells;
}

export function renderHeaderCell(
routerLocation: {search: string},
column: ColumnKey,
sortSpec: string,
): TemplateResult {
if (CELL_DEFS[column].unsortable) {
return renderUnsortableHeaderCell(column);
}
return renderSortableHeaderCell(routerLocation, column, sortSpec);
}

function renderSortableHeaderCell(
routerLocation: {search: string},
column: ColumnKey,
sortSpec: string,
): TemplateResult {
let sortIndicator = html``;
let urlWithSort = formatOverviewPageUrl(routerLocation, {
Expand All @@ -550,15 +577,26 @@ export function renderHeaderCell(
}

const colDef = CELL_DEFS[column];
if (colDef.unsortable) {
return html`<th class=${colDef.cellClass || ''}>${colDef?.headerHtml}</th>`;
} else {
return html`
<th title="Click to sort" class="${colDef.cellClass || ''} sortable">
<a href=${urlWithSort}> ${sortIndicator} ${colDef?.headerHtml} </a>
</th>
`;
}
return html`
<th title="Click to sort" class="${colDef?.cellClass || ''} sortable">
<a href=${urlWithSort}> ${sortIndicator} ${colDef?.headerHtml} </a>
</th>
`;
}

export function renderUnsortableHeaderCell(
column: ColumnKey,
customTitle?: string,
): TemplateResult {
const colDef = CELL_DEFS[column];
return html`
<th
title=${ifDefined(customTitle)}
class="${colDef?.cellClass || ''} unsortable"
>
${colDef?.headerHtml}
</th>
`;
}

export function renderFeatureCell(
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 @@ -30,6 +30,7 @@ import {
renderColgroups,
renderGroupsRow,
renderHeaderCell,
renderBookmarkHeaderCells,
} from './webstatus-overview-cells.js';
import {TaskTracker} from '../utils/task-tracker.js';
import {ApiError, BadRequestError} from '../api/errors.js';
Expand Down Expand Up @@ -175,15 +176,22 @@ export class WebstatusOverviewTable extends LitElement {
const sortSpec: string =
getSortSpec(this.location) || (DEFAULT_SORT_SPEC as string);

let headerCells: TemplateResult[] = [];
if (this.bookmark?.is_ordered) {
headerCells = renderBookmarkHeaderCells(this.bookmark.name, columns);
} else {
headerCells = columns.map(
col => html`${renderHeaderCell(this.location, col, sortSpec)}`,
);
}

return html`
<table class="data-table">
${renderColgroups(columns)}
<thead>
${renderGroupsRow(columns)}
<tr class="header-row">
${columns.map(
col => html`${renderHeaderCell(this.location, col, sortSpec)}`,
)}
${headerCells}
</tr>
</thead>
<tbody>
Expand Down
18 changes: 14 additions & 4 deletions frontend/src/static/js/components/webstatus-sidebar-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,20 @@ export class WebstatusSidebarMenu extends LitElement {
const bookmarkId = `bookmark${index}`;
const currentLocation = this.getLocation();
const currentURL = new URL(currentLocation.href);
const bookmarkUrl = formatOverviewPageUrl(currentURL, {
q: bookmark.query,
start: 0,
});

let bookmarkUrl;
if (bookmark.override_num_param) {
bookmarkUrl = formatOverviewPageUrl(currentURL, {
q: bookmark.query,
start: 0,
num: bookmark.override_num_param,
});
} else {
bookmarkUrl = formatOverviewPageUrl(currentURL, {
q: bookmark.query,
start: 0,
});
}
// The bookmark should only be active when the path is the FEATURES path
// and the query is set to the active query.
const isQueryActive =
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/static/js/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface Bookmark {
description?: string;
// Should display query results in query's order.
is_ordered?: boolean;
// Override the num parameter value, if provided.
override_num_param?: number;
}

export const DEFAULT_BOOKMARKS: Bookmark[] = [
Expand All @@ -44,5 +46,7 @@ export const DEFAULT_BOOKMARKS: Bookmark[] = [
'id:anchor-positioning OR id:container-queries OR id:has OR id:nesting OR id:view-transitions OR id:subgrid OR id:grid OR name:scrollbar OR id:scroll-driven-animations OR id:scope',
description:
"This list reflects the top 10 interoperability pain points identified by developers in the State of CSS 2024 survey. We have also included their implementation status across Baseline browsers. You will notice that in some cases the items are already Baseline features, but may not have have been Baseline for long enough for developers to use with their target audience's browser support requirements. Since some voted-on pain points involve multiple web features, the list extends beyond 10 individual items for clarity and comprehensive coverage.",
is_ordered: true,
override_num_param: 25,
},
];
Loading