Skip to content

Commit 996312f

Browse files
authored
Showcase: convert AdvancedTable page to gts (#3198)
1 parent bdc7f3d commit 996312f

27 files changed

+4009
-3267
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { array, hash } from '@ember/helper';
8+
import { deepTracked } from 'ember-deep-tracked';
9+
import { eq, notEq } from 'ember-truth-helpers';
10+
import { guidFor } from '@ember/object/internals';
11+
import { on } from '@ember/modifier';
12+
import { tracked } from '@glimmer/tracking';
13+
14+
import USERS from 'showcase/mocks/user-data';
15+
import type { User } from 'showcase/mocks/user-data';
16+
17+
import {
18+
HdsAdvancedTable,
19+
HdsPaginationNumbered,
20+
} from '@hashicorp/design-system-components/components';
21+
import type { HdsAdvancedTableOnSelectionChangeSignature } from '@hashicorp/design-system-components/components/hds/advanced-table/types';
22+
23+
const updateModelWithSelectAllState = (
24+
modelData: User[],
25+
selectAllState: boolean,
26+
) => {
27+
modelData.forEach((modelRow) => {
28+
if (modelRow instanceof Object) {
29+
// Always set isSelected, adding it if missing
30+
(modelRow as { isSelected: boolean }).isSelected = selectAllState;
31+
}
32+
});
33+
};
34+
35+
function updateModelWithSelectableRowsStates<
36+
T extends { id: number; isSelected?: boolean },
37+
>(
38+
modelData: T[],
39+
selectableRowsStates: HdsAdvancedTableOnSelectionChangeSignature['selectableRowsStates'],
40+
): void {
41+
// Create a map from id to row for quick lookup
42+
const modelDataMap: Map<string, T> = new Map(
43+
modelData.map((modelRow) => [String(modelRow.id), modelRow]),
44+
);
45+
46+
selectableRowsStates.forEach((row) => {
47+
const record = modelDataMap.get(row.selectionKey);
48+
if (record) {
49+
record.isSelected = row.isSelected;
50+
}
51+
});
52+
}
53+
54+
export interface CodeFragmentWithDebugSelectSignature {
55+
Args: {
56+
hasPagination?: boolean;
57+
shouldHideSelectionDebugControls?: boolean;
58+
};
59+
Blocks: {
60+
topbarAction?: [
61+
{
62+
model: User[];
63+
setModel: (newModel: User[]) => void;
64+
},
65+
];
66+
};
67+
Element: HTMLDivElement;
68+
}
69+
70+
export default class CodeFragmentWithDebugSelect extends Component<CodeFragmentWithDebugSelectSignature> {
71+
uuid = guidFor(this);
72+
73+
@tracked scope: 'visible-rows' | 'all-rows' = 'visible-rows';
74+
@tracked showDebug = false;
75+
@tracked currentPageSize = 4;
76+
@tracked currentPage = 1;
77+
78+
@deepTracked model = this.args.hasPagination
79+
? structuredClone(USERS.slice(0, 16))
80+
: structuredClone(USERS.slice(0, 4));
81+
82+
// for paginated examples, need a getter to return the visible rows only
83+
get paginatedModel() {
84+
const visibleRows = this.model.filter((user) => !user.isHidden);
85+
86+
if (!this.args.hasPagination) {
87+
return visibleRows;
88+
}
89+
90+
const start = (this.currentPage - 1) * this.currentPageSize;
91+
const end = this.currentPage * this.currentPageSize;
92+
return visibleRows.slice(start, end);
93+
}
94+
95+
// there are demos where we want to be able to update the full model, not just the visible rows
96+
setModel = (newModel: User[]) => {
97+
this.model = [...newModel];
98+
};
99+
100+
toggleScope = () => {
101+
this.scope = this.scope === 'visible-rows' ? 'all-rows' : 'visible-rows';
102+
};
103+
104+
toggleShowDebug = () => {
105+
this.showDebug = !this.showDebug;
106+
};
107+
108+
onPageChange = (page: number) => {
109+
this.currentPage = page;
110+
};
111+
112+
onPageSizeChange = (pageSize: number) => {
113+
// we agreed to reset the pagination to the first element (any alternative would result in an unpredictable UX)
114+
this.currentPage = 1;
115+
this.currentPageSize = pageSize;
116+
};
117+
118+
onSelectionChange = ({
119+
selectionKey,
120+
selectionCheckboxElement,
121+
selectableRowsStates,
122+
}: HdsAdvancedTableOnSelectionChangeSignature) => {
123+
console.group('onSelectionChange');
124+
console.log('Selection Key:', selectionKey);
125+
console.log('Checkbox Element:', selectionCheckboxElement);
126+
console.log('Selectable Rows States:', selectableRowsStates);
127+
console.groupEnd();
128+
129+
if (selectionKey === 'all' && this.scope === 'all-rows') {
130+
updateModelWithSelectAllState(
131+
this.model,
132+
selectionCheckboxElement ? selectionCheckboxElement.checked : false,
133+
);
134+
} else {
135+
updateModelWithSelectableRowsStates(this.model, selectableRowsStates);
136+
}
137+
};
138+
139+
<template>
140+
<div class="shw-component-advanced-table-demo-topbar">
141+
{{#if (notEq @shouldHideSelectionDebugControls true)}}
142+
<div class="shw-component-advanced-table-demo-topbar__toggle">
143+
<input
144+
id="{{this.uuid}}-scope-toggle"
145+
type="checkbox"
146+
checked={{if (eq this.scope "all-rows") true false}}
147+
{{on "change" this.toggleScope}}
148+
/>
149+
<label for="{{this.uuid}}-scope-toggle">Extend "Select All" scope to
150+
non-displayed rows</label>
151+
</div>
152+
<div class="shw-component-advanced-table-demo-topbar__toggle">
153+
<input
154+
id="{{this.uuid}}-debug-toggle"
155+
type="checkbox"
156+
checked={{this.showDebug}}
157+
{{on "change" this.toggleShowDebug}}
158+
/>
159+
<label for="{{this.uuid}}-debug-toggle">Show all rows' state</label>
160+
</div>
161+
{{/if}}
162+
<div class="shw-component-advanced-table-demo-topbar__action">
163+
{{yield
164+
(hash model=this.model setModel=this.setModel)
165+
to="topbarAction"
166+
}}
167+
</div>
168+
</div>
169+
170+
<div
171+
class={{if
172+
@hasPagination
173+
"shw-component-advanced-table-with-pagination-demo-wrapper"
174+
}}
175+
>
176+
<HdsAdvancedTable
177+
@isSelectable={{true}}
178+
@onSelectionChange={{this.onSelectionChange}}
179+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
180+
@model={{this.paginatedModel}}
181+
@columns={{array
182+
(hash key="id" label="ID")
183+
(hash key="name" label="Name")
184+
(hash key="email" label="Email")
185+
(hash key="role" label="Role")
186+
}}
187+
>
188+
<:body as |B|>
189+
<B.Tr
190+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
191+
@selectionKey="{{B.data.id}}"
192+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
193+
@isSelected={{B.data.isSelected}}
194+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
195+
@selectionAriaLabelSuffix="row #{{B.data.id}}"
196+
>
197+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
198+
<B.Td>{{B.data.id}}</B.Td>
199+
<B.Td>
200+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
201+
{{#let B.data.isAnimated as |isAnimated|}}
202+
<span
203+
class={{if
204+
isAnimated
205+
"shw-component-advanced-table-animate-user"
206+
}}
207+
>
208+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
209+
{{B.data.name}}
210+
</span>
211+
{{/let}}
212+
</B.Td>
213+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
214+
<B.Td>{{B.data.email}}</B.Td>
215+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
216+
<B.Td>{{B.data.role}}</B.Td>
217+
</B.Tr>
218+
</:body>
219+
</HdsAdvancedTable>
220+
{{#if @hasPagination}}
221+
<HdsPaginationNumbered
222+
@totalItems={{this.model.length}}
223+
@currentPageSize={{this.currentPageSize}}
224+
@pageSizes={{array 4 8}}
225+
@currentPage={{this.currentPage}}
226+
@onPageChange={{this.onPageChange}}
227+
@onPageSizeChange={{this.onPageSizeChange}}
228+
@ariaLabel="Pagination for multi-select {{this.uuid}}"
229+
/>
230+
{{/if}}
231+
{{#if this.showDebug}}
232+
{{#each this.model as |row|}}
233+
<pre>row{{row.id}} = {{if row.isSelected ""}}</pre>
234+
{{/each}}
235+
{{/if}}
236+
</div>
237+
</template>
238+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { array, hash } from '@ember/helper';
8+
import { on } from '@ember/modifier';
9+
import { tracked } from '@glimmer/tracking';
10+
11+
import MUSIC from 'showcase/mocks/folk-music-data';
12+
13+
import {
14+
HdsAdvancedTable,
15+
HdsBadge,
16+
HdsButton,
17+
HdsButtonSet,
18+
HdsIcon,
19+
HdsLinkInline,
20+
} from '@hashicorp/design-system-components/components';
21+
22+
export interface CodeFragmentWithDynamicCellContentSignature {
23+
Element: HTMLDivElement;
24+
}
25+
26+
export default class CodeFragmentWithDynamicCellContent extends Component<CodeFragmentWithDynamicCellContentSignature> {
27+
@tracked showAllButtons = false;
28+
29+
toggleElementsVisibility = () => {
30+
this.showAllButtons = !this.showAllButtons;
31+
};
32+
33+
<template>
34+
<HdsAdvancedTable
35+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
36+
@model={{MUSIC}}
37+
@columns={{array
38+
(hash key="artist" label="Artist")
39+
(hash key="album" label="Album")
40+
(hash key="year" label="Release Year")
41+
(hash key="other" label="Additional Actions")
42+
}}
43+
>
44+
<:body as |B|>
45+
{{! @glint-expect-error - this argument shouldn't be required, will be fixed by https://hashicorp.atlassian.net/browse/HDS-5167}}
46+
<B.Tr @selectionKey="{{B.data.id}}">
47+
<B.Th @scope="row">
48+
<HdsLinkInline @href="#showcase">
49+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
50+
{{B.data.artist}}
51+
</HdsLinkInline>
52+
</B.Th>
53+
<B.Td>
54+
<div class="shw-component-advanced-table-cell-content-div">
55+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
56+
<HdsIcon @name={{B.data.icon}} @isInline={{true}} />
57+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
58+
{{B.data.album}}
59+
</div>
60+
</B.Td>
61+
<B.Td>
62+
<HdsBadge
63+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
64+
@text={{B.data.year}}
65+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
66+
@type={{B.data.badge-type}}
67+
{{! @glint-expect-error - will be fixed by https://hashicorp.atlassian.net/browse/HDS-5090}}
68+
@color={{B.data.badge-color.name}}
69+
/>
70+
</B.Td>
71+
<B.Td>
72+
<HdsButtonSet>
73+
<HdsButton
74+
@text="Show more buttons"
75+
@icon="plus"
76+
@size="small"
77+
aria-pressed={{this.showAllButtons}}
78+
{{on "click" this.toggleElementsVisibility}}
79+
/>
80+
{{#if this.showAllButtons}}
81+
<HdsButton
82+
@text="Add"
83+
@isIconOnly={{true}}
84+
@icon="plus"
85+
@size="small"
86+
/>
87+
<HdsButton
88+
@text="Edit"
89+
@isIconOnly={{true}}
90+
@icon="edit"
91+
@size="small"
92+
@color="secondary"
93+
/>
94+
<HdsButton
95+
@text="Delete"
96+
@isIconOnly={{true}}
97+
@icon="trash"
98+
@size="small"
99+
@color="critical"
100+
/>
101+
{{/if}}
102+
</HdsButtonSet>
103+
</B.Td>
104+
</B.Tr>
105+
</:body>
106+
</HdsAdvancedTable>
107+
</template>
108+
}

0 commit comments

Comments
 (0)