@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.149 → 2.0.0-next.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +4443 -3841
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +381 -2
  4. package/dist/components/alert-list-details-experimental/alert-list-details-experimental.css.js +94 -0
  5. package/dist/components/alert-list-details-experimental/alert-list-details-experimental.css.js.map +1 -0
  6. package/dist/components/alert-list-details-experimental/alert-list-details-experimental.d.ts +72 -0
  7. package/dist/components/alert-list-details-experimental/alert-list-details-experimental.d.ts.map +1 -0
  8. package/dist/components/alert-list-details-experimental/alert-list-details-experimental.js +396 -0
  9. package/dist/components/alert-list-details-experimental/alert-list-details-experimental.js.map +1 -0
  10. package/dist/components/table/table.css.js +43 -0
  11. package/dist/components/table/table.css.js.map +1 -1
  12. package/dist/components/table/table.d.ts +31 -1
  13. package/dist/components/table/table.d.ts.map +1 -1
  14. package/dist/components/table/table.js +124 -11
  15. package/dist/components/table/table.js.map +1 -1
  16. package/dist/types.d.ts +2 -0
  17. package/dist/types.d.ts.map +1 -1
  18. package/dist/types.js.map +1 -1
  19. package/package.json +1 -1
  20. package/src/components/alert-list-details-experimental/alert-list-details-experimental.css +70 -0
  21. package/src/components/alert-list-details-experimental/alert-list-details-experimental.stories.ts +510 -0
  22. package/src/components/alert-list-details-experimental/alert-list-details-experimental.ts +457 -0
  23. package/src/components/table/table.css +42 -0
  24. package/src/components/table/table.stories.ts +279 -0
  25. package/src/components/table/table.ts +177 -13
  26. package/src/types.ts +6 -4
@@ -2,6 +2,7 @@ import type {Meta, StoryObj} from '@storybook/web-components-vite';
2
2
  import {
3
3
  ObcTable,
4
4
  ObcTableCellData,
5
+ ObcTableExpandToggleEvent,
5
6
  ObcTableRow,
6
7
  ObcTableCellType,
7
8
  } from './table.js';
@@ -689,3 +690,281 @@ export const Interactive: Story = {
689
690
  `;
690
691
  },
691
692
  };
693
+
694
+ interface HierarchyNode {
695
+ id: string;
696
+ system: string;
697
+ location: string;
698
+ state: string;
699
+ members?: HierarchyNode[];
700
+ }
701
+
702
+ const systemTree: HierarchyNode[] = [
703
+ {
704
+ id: 'propulsion',
705
+ system: 'Propulsion',
706
+ location: 'Engine room',
707
+ state: 'Running',
708
+ members: [
709
+ {
710
+ id: 'main-engine',
711
+ system: 'Main engine',
712
+ location: 'Engine room',
713
+ state: 'Running',
714
+ members: [
715
+ {
716
+ id: 'lube-oil',
717
+ system: 'Lube oil',
718
+ location: 'Engine room',
719
+ state: 'Nominal',
720
+ },
721
+ {
722
+ id: 'cooling-water',
723
+ system: 'Cooling water',
724
+ location: 'Engine room',
725
+ state: 'Nominal',
726
+ },
727
+ ],
728
+ },
729
+ {
730
+ id: 'shaft-generator',
731
+ system: 'Shaft generator',
732
+ location: 'Engine room',
733
+ state: 'Standby',
734
+ },
735
+ ],
736
+ },
737
+ {
738
+ id: 'power',
739
+ system: 'Power',
740
+ location: 'Switchboard',
741
+ state: 'Running',
742
+ members: [
743
+ {
744
+ id: 'aux-engine-1',
745
+ system: 'Aux engine 1',
746
+ location: 'Switchboard',
747
+ state: 'Running',
748
+ },
749
+ {
750
+ id: 'aux-engine-2',
751
+ system: 'Aux engine 2',
752
+ location: 'Switchboard',
753
+ state: 'Stopped',
754
+ },
755
+ ],
756
+ },
757
+ {
758
+ id: 'ballast',
759
+ system: 'Ballast',
760
+ location: 'Pump room',
761
+ state: 'Idle',
762
+ },
763
+ ];
764
+
765
+ const collapsedRowIds = new Set<string>(['power']);
766
+
767
+ const hierarchyRows = (
768
+ nodes: HierarchyNode[],
769
+ level = 0,
770
+ parentId?: string
771
+ ): ObcTableRow[] => {
772
+ const rows: ObcTableRow[] = [];
773
+ for (const node of nodes) {
774
+ const expanded = !collapsedRowIds.has(node.id);
775
+ rows.push({
776
+ id: node.id,
777
+ parentId,
778
+ level,
779
+ expandable: (node.members?.length ?? 0) > 0,
780
+ expanded,
781
+ system: {type: ObcTableCellType.Regular, text: node.system},
782
+ location: {type: ObcTableCellType.Regular, text: node.location},
783
+ state: {type: ObcTableCellType.Regular, text: node.state, neutral: true},
784
+ });
785
+ if (expanded && node.members) {
786
+ rows.push(...hierarchyRows(node.members, level + 1, node.id));
787
+ }
788
+ }
789
+ return rows;
790
+ };
791
+
792
+ const compareCellText = (a: ObcTableCellData, b: ObcTableCellData) => {
793
+ const text = (value: ObcTableCellData) =>
794
+ value?.type === ObcTableCellType.Regular ? String(value.text ?? '') : '';
795
+ return text(a).localeCompare(text(b));
796
+ };
797
+
798
+ export const Hierarchy: Story = {
799
+ args: {
800
+ width: 700,
801
+ columns: [
802
+ {
803
+ label: 'System',
804
+ key: 'system',
805
+ sortable: true,
806
+ compareFunction: compareCellText,
807
+ },
808
+ {label: 'Location', key: 'location'},
809
+ {label: 'State', key: 'state'},
810
+ ],
811
+ },
812
+ parameters: {
813
+ docs: {
814
+ description: {
815
+ story:
816
+ 'Rows form a tree through `parentId` and `level`. The table draws the indent and the chevron and reports `expand-toggle`; the story owns which rows are collapsed and passes only the visible ones. Sorting the System column reorders each sibling set on its own, so a child never leaves its parent.',
817
+ },
818
+ },
819
+ },
820
+ render: (args) => {
821
+ return html`<obc-table
822
+ .data=${hierarchyRows(systemTree)}
823
+ .columns=${args.columns}
824
+ .striped=${true}
825
+ @expand-toggle=${(e: ObcTableExpandToggleEvent) => {
826
+ if (e.detail.expanded) {
827
+ collapsedRowIds.delete(e.detail.rowId);
828
+ } else {
829
+ collapsedRowIds.add(e.detail.rowId);
830
+ }
831
+ (e.target as ObcTable).data = hierarchyRows(systemTree);
832
+ }}
833
+ ></obc-table>`;
834
+ },
835
+ };
836
+
837
+ const cyclicRows = (): ObcTableRow[] => [
838
+ {
839
+ id: 'standalone',
840
+ level: 0,
841
+ system: {type: ObcTableCellType.Regular, text: 'Ballast'},
842
+ parent: {type: ObcTableCellType.Regular, text: '—', neutral: true},
843
+ },
844
+ {
845
+ id: 'pump-a',
846
+ parentId: 'pump-b',
847
+ level: 1,
848
+ system: {type: ObcTableCellType.Regular, text: 'Pump A'},
849
+ parent: {type: ObcTableCellType.Regular, text: 'pump-b', neutral: true},
850
+ },
851
+ {
852
+ id: 'pump-b',
853
+ parentId: 'pump-a',
854
+ level: 1,
855
+ system: {type: ObcTableCellType.Regular, text: 'Pump B'},
856
+ parent: {type: ObcTableCellType.Regular, text: 'pump-a', neutral: true},
857
+ },
858
+ ];
859
+
860
+ export const CyclicHierarchy: Story = {
861
+ args: {width: 700},
862
+ parameters: {
863
+ docs: {
864
+ description: {
865
+ story:
866
+ 'Regression guard. Both tables get the same three rows, two of which name each other as `parentId`. `sortWithinSiblings()` walks down from rows whose `parentId` is absent from the data, so the cycle yields no root; the rows it cannot reach are re-entered as a top-level sibling set instead of being dropped. Both tables list all three rows, in the sort order each is given. Make all three rows cyclic and all three still render.',
867
+ },
868
+ },
869
+ },
870
+ render: (args) => {
871
+ const columns = (sorted: boolean) => [
872
+ {
873
+ label: 'System',
874
+ key: 'system',
875
+ ...(sorted
876
+ ? {
877
+ sortable: true as const,
878
+ sortDirection: 'asc' as const,
879
+ compareFunction: compareCellText,
880
+ }
881
+ : {}),
882
+ },
883
+ {label: 'Declared parentId', key: 'parent'},
884
+ ];
885
+ return html`<div style="display: grid; gap: 24px; width: ${args.width}px;">
886
+ <div>
887
+ <p>Unsorted</p>
888
+ <obc-table .data=${cyclicRows()} .columns=${columns(false)}></obc-table>
889
+ </div>
890
+ <div>
891
+ <p>Sorted on System — the cyclic rows are recovered</p>
892
+ <obc-table .data=${cyclicRows()} .columns=${columns(true)}></obc-table>
893
+ </div>
894
+ </div>`;
895
+ },
896
+ };
897
+
898
+ const cycleWithDescendantRows = (): ObcTableRow[] => [
899
+ {
900
+ id: 'standalone',
901
+ level: 0,
902
+ system: {type: ObcTableCellType.Regular, text: 'Ballast'},
903
+ parent: {type: ObcTableCellType.Regular, text: '—', neutral: true},
904
+ },
905
+ {
906
+ id: 'pump-a',
907
+ parentId: 'pump-b',
908
+ level: 1,
909
+ system: {type: ObcTableCellType.Regular, text: 'Pump A'},
910
+ parent: {type: ObcTableCellType.Regular, text: 'pump-b', neutral: true},
911
+ },
912
+ {
913
+ id: 'pump-b',
914
+ parentId: 'pump-a',
915
+ level: 1,
916
+ system: {type: ObcTableCellType.Regular, text: 'Pump B'},
917
+ parent: {type: ObcTableCellType.Regular, text: 'pump-a', neutral: true},
918
+ },
919
+ {
920
+ id: 'pump-sensor',
921
+ parentId: 'pump-a',
922
+ level: 2,
923
+ system: {type: ObcTableCellType.Regular, text: 'Pump sensor'},
924
+ parent: {type: ObcTableCellType.Regular, text: 'pump-a', neutral: true},
925
+ },
926
+ ];
927
+
928
+ export const CycleWithDescendants: Story = {
929
+ args: {width: 700},
930
+ parameters: {
931
+ docs: {
932
+ description: {
933
+ story:
934
+ 'Regression guard for the blast radius of a cycle. Pump sensor has one ordinary parent and is in no cycle, but its parent sits in one, so recovering only the cycle members would still lose it. All four rows render in both tables; Pump sensor stays under Pump A, because the recovered rows are walked, not flattened.',
935
+ },
936
+ },
937
+ },
938
+ render: (args) => {
939
+ const columns = (sorted: boolean) => [
940
+ {
941
+ label: 'System',
942
+ key: 'system',
943
+ ...(sorted
944
+ ? {
945
+ sortable: true as const,
946
+ sortDirection: 'asc' as const,
947
+ compareFunction: compareCellText,
948
+ }
949
+ : {}),
950
+ },
951
+ {label: 'Declared parentId', key: 'parent'},
952
+ ];
953
+ return html`<div style="display: grid; gap: 24px; width: ${args.width}px;">
954
+ <div>
955
+ <p>Unsorted</p>
956
+ <obc-table
957
+ .data=${cycleWithDescendantRows()}
958
+ .columns=${columns(false)}
959
+ ></obc-table>
960
+ </div>
961
+ <div>
962
+ <p>Sorted on System — the cycle and its descendant are recovered</p>
963
+ <obc-table
964
+ .data=${cycleWithDescendantRows()}
965
+ .columns=${columns(true)}
966
+ ></obc-table>
967
+ </div>
968
+ </div>`;
969
+ },
970
+ };
@@ -13,6 +13,7 @@ import '../table-header-item/table-header-item.js';
13
13
  import {ObcTableHeaderItemType} from '../table-header-item/table-header-item.js';
14
14
  import {classMap} from 'lit/directives/class-map.js';
15
15
  import '../button/button.js';
16
+ import '../../icons/icon-chevron-right-google.js';
16
17
  import {CheckboxStatus, ObcCheckboxChangeEvent} from '../checkbox/checkbox.js';
17
18
  import {TagColor} from '../tag/tag.js';
18
19
  import '../../building-blocks/bar-horizontal/bar-horizontal.js';
@@ -130,7 +131,11 @@ export type ObcTableCellData =
130
131
  export interface ObcTableRow {
131
132
  selected?: boolean;
132
133
  id: string;
133
- [key: string]: ObcTableCellData | boolean | undefined | string;
134
+ parentId?: string;
135
+ level?: number;
136
+ expandable?: boolean;
137
+ expanded?: boolean;
138
+ [key: string]: ObcTableCellData | boolean | undefined | string | number;
134
139
  }
135
140
 
136
141
  export interface ObcTableColumnUnsortable<
@@ -187,6 +192,11 @@ export type ObcTableRowClickEvent = CustomEvent<{
187
192
  row: ObcTableRow;
188
193
  }>;
189
194
 
195
+ export type ObcTableExpandToggleEvent = CustomEvent<{
196
+ rowId: string;
197
+ expanded: boolean;
198
+ }>;
199
+
190
200
  function cssPart(value: ObcTableCellData, subpart: string): string | undefined {
191
201
  if (value.cssPart) {
192
202
  return `${value.cssPart} ${subpart}`;
@@ -206,11 +216,17 @@ function cssPart(value: ObcTableCellData, subpart: string): string | undefined {
206
216
  * - Cell rendering variants: `checkbox`, `tag`, `horizontal-bar`, and `button` cell types.
207
217
  * - Visual variants: `rowDivider`, `striped`, `narrowHeader`, and `showHeader`.
208
218
  * - Sorting support for sortable columns via column definitions.
219
+ * - Hierarchical rows via `parentId`, `level`, `expandable` and `expanded`.
209
220
  *
210
221
  * Usage Guidelines
211
222
  * - Controlled selection: pass `selectedRowIds` and update it on `selection-change`.
212
223
  * - Uncontrolled selection: pass `defaultSelectedRowIds` and listen to `selection-change`.
213
224
  * - Use `selectAllAriaLabel` to customize the header checkbox accessibility label.
225
+ * - Hierarchy is controlled, and flat: pass only the rows that are currently
226
+ * visible, each with the `parentId` of its parent row, and drop a collapsed
227
+ * group's descendants from `data` on `expand-toggle`. The table draws the
228
+ * indent and the chevron, keeps each sibling set sorted within its parent,
229
+ * and owns no expansion state of its own.
214
230
  *
215
231
  * Slots/Content
216
232
  * - This component does not expose public slots. Provide content via `data` and `columns`.
@@ -221,6 +237,15 @@ function cssPart(value: ObcTableCellData, subpart: string): string | undefined {
221
237
  * - `cell-checkbox-change` fires when a checkbox cell changes.
222
238
  * - `cell-tag-click` fires when a tag inside a cell is clicked.
223
239
  * - `selection-change` fires when row selection changes (source: `row` or `header`).
240
+ * - `expand-toggle` fires when a group row's chevron or expand key is used.
241
+ *
242
+ * Accessibility
243
+ * A table with hierarchical rows renders as a
244
+ * [treegrid](https://www.w3.org/WAI/ARIA/apg/patterns/treegrid/): rows carry
245
+ * `aria-level`, and group rows `aria-expanded`. Right expands a collapsed
246
+ * group, Left collapses an expanded one or moves to the parent row. Cell-level
247
+ * arrow navigation, which the full pattern also specifies, is out of scope —
248
+ * arrow keys move between rows, matching the flat table.
224
249
  *
225
250
  * Best Practices
226
251
  * - Keep column `key` values stable across renders to avoid selection or sorting resets.
@@ -247,6 +272,7 @@ function cssPart(value: ObcTableCellData, subpart: string): string | undefined {
247
272
  * @fires {ObcTableCellCheckboxChangeEvent} cell-checkbox-change - Fired when a cell checkbox is changed.
248
273
  * @fires {ObcTableCellTagClickEvent} cell-tag-click - Fired when a tag inside a cell is clicked.
249
274
  * @fires {ObcTableSelectionChangeEvent} selection-change - Fired when row selection changes.
275
+ * @fires {ObcTableExpandToggleEvent} expand-toggle - Fired when a group row is expanded or collapsed.
250
276
  * @beta
251
277
  */
252
278
  @customElement('obc-table')
@@ -273,6 +299,50 @@ export class ObcTable extends LitElement {
273
299
 
274
300
  private _previousPositions: {top: number; index: string}[] = [];
275
301
 
302
+ private get hasHierarchy() {
303
+ return this.data.some(
304
+ (row) =>
305
+ row.parentId !== undefined ||
306
+ (row.level ?? 0) > 0 ||
307
+ row.expandable === true
308
+ );
309
+ }
310
+
311
+ private sortWithinSiblings(
312
+ rows: ObcTableRow[],
313
+ compare: (a: ObcTableRow, b: ObcTableRow) => number
314
+ ) {
315
+ const ids = new Set(rows.map((row) => row.id));
316
+ const childrenByParent = new Map<string, ObcTableRow[]>();
317
+ const roots: ObcTableRow[] = [];
318
+ for (const row of rows) {
319
+ const parentId = row.parentId;
320
+ if (parentId !== undefined && parentId !== row.id && ids.has(parentId)) {
321
+ const siblings = childrenByParent.get(parentId) ?? [];
322
+ siblings.push(row);
323
+ childrenByParent.set(parentId, siblings);
324
+ } else {
325
+ roots.push(row);
326
+ }
327
+ }
328
+
329
+ const sorted: ObcTableRow[] = [];
330
+ const visited = new Set<string>();
331
+ const visit = (siblings: ObcTableRow[]) => {
332
+ for (const row of [...siblings].sort(compare)) {
333
+ if (visited.has(row.id)) {
334
+ continue;
335
+ }
336
+ visited.add(row.id);
337
+ sorted.push(row);
338
+ visit(childrenByParent.get(row.id) ?? []);
339
+ }
340
+ };
341
+ visit(roots);
342
+ visit(rows.filter((row) => !visited.has(row.id)));
343
+ return sorted;
344
+ }
345
+
276
346
  get sortedData() {
277
347
  if (this._sortByColumnIdx === undefined) {
278
348
  return this.data;
@@ -285,8 +355,7 @@ export class ObcTable extends LitElement {
285
355
  return this.data;
286
356
  }
287
357
  const sortDirection = this._sortDirection;
288
- const sortedData = [...this.data];
289
- sortedData.sort((a, b) => {
358
+ const compare = (a: ObcTableRow, b: ObcTableRow) => {
290
359
  const aValue = a[sortByColumn.key];
291
360
  const bValue = b[sortByColumn.key];
292
361
  if (sortDirection === 'asc') {
@@ -304,7 +373,12 @@ export class ObcTable extends LitElement {
304
373
  a
305
374
  );
306
375
  }
307
- });
376
+ };
377
+ if (this.hasHierarchy) {
378
+ return this.sortWithinSiblings(this.data, compare);
379
+ }
380
+ const sortedData = [...this.data];
381
+ sortedData.sort(compare);
308
382
  return sortedData;
309
383
  }
310
384
 
@@ -329,6 +403,42 @@ export class ObcTable extends LitElement {
329
403
  );
330
404
  }
331
405
 
406
+ private _handleExpandToggle(row: ObcTableRow, expanded: boolean) {
407
+ if (!row.expandable) {
408
+ return;
409
+ }
410
+ this.dispatchEvent(
411
+ new CustomEvent('expand-toggle', {
412
+ detail: {rowId: row.id, expanded},
413
+ }) as ObcTableExpandToggleEvent
414
+ );
415
+ }
416
+
417
+ private _renderRowExpander(row: ObcTableRow) {
418
+ if (!this.hasHierarchy) {
419
+ return nothing;
420
+ }
421
+ const level = row.level ?? 0;
422
+ return html`<span
423
+ class="row-expander"
424
+ style="--row-level: ${level}"
425
+ aria-hidden="true"
426
+ >
427
+ ${row.expandable
428
+ ? html`<span
429
+ class=${classMap({chevron: true, expanded: row.expanded ?? false})}
430
+ @click=${(event: MouseEvent) => {
431
+ event.preventDefault();
432
+ event.stopPropagation();
433
+ this._handleExpandToggle(row, !(row.expanded ?? false));
434
+ }}
435
+ >
436
+ <obi-chevron-right-google></obi-chevron-right-google>
437
+ </span>`
438
+ : nothing}
439
+ </span>`;
440
+ }
441
+
332
442
  private _focusFirstRow() {
333
443
  const firstRow = this.renderRoot.querySelector<HTMLButtonElement>(
334
444
  'button[role="row"].grid-row'
@@ -393,6 +503,13 @@ export class ObcTable extends LitElement {
393
503
 
394
504
  private _handleRowKeyDown(event: KeyboardEvent) {
395
505
  const key = event.key;
506
+ if (
507
+ this.hasHierarchy &&
508
+ (key === 'ArrowRight' || key === 'ArrowLeft') &&
509
+ this._handleRowExpandKey(event, key)
510
+ ) {
511
+ return;
512
+ }
396
513
  if (
397
514
  key !== 'ArrowDown' &&
398
515
  key !== 'ArrowUp' &&
@@ -447,6 +564,37 @@ export class ObcTable extends LitElement {
447
564
  }
448
565
  }
449
566
 
567
+ private _handleRowExpandKey(
568
+ event: KeyboardEvent,
569
+ key: 'ArrowRight' | 'ArrowLeft'
570
+ ) {
571
+ const target = event.currentTarget as HTMLButtonElement | null;
572
+ const rowId = target?.dataset.rowId;
573
+ const row = this.sortedData.find((candidate) => candidate.id === rowId);
574
+ if (!row) return false;
575
+
576
+ const expanded = row.expanded ?? false;
577
+ if (key === 'ArrowRight' && row.expandable && !expanded) {
578
+ this._handleExpandToggle(row, true);
579
+ } else if (key === 'ArrowLeft' && row.expandable && expanded) {
580
+ this._handleExpandToggle(row, false);
581
+ } else if (key === 'ArrowLeft') {
582
+ const parent = this.renderRoot.querySelector<HTMLButtonElement>(
583
+ `button[role="row"].grid-row[data-row-id="${CSS.escape(
584
+ row.parentId ?? ''
585
+ )}"]`
586
+ );
587
+ if (!parent) return false;
588
+ parent.focus();
589
+ } else {
590
+ return false;
591
+ }
592
+
593
+ event.preventDefault();
594
+ event.stopPropagation();
595
+ return true;
596
+ }
597
+
450
598
  private _getAllPositions(): {
451
599
  top: number;
452
600
  height: number;
@@ -459,7 +607,6 @@ export class ObcTable extends LitElement {
459
607
  )
460
608
  );
461
609
 
462
- // Calculate the zoom factor for the first row
463
610
  const firstRow = rows[0];
464
611
  if (!firstRow) {
465
612
  return [];
@@ -609,7 +756,7 @@ export class ObcTable extends LitElement {
609
756
  --grid-columns-rest: ${selectionColumnCount};
610
757
  --selection-column-width: var(--menu-navigation-components-table-item-touch-target-size);
611
758
  "
612
- role="table"
759
+ role=${this.hasHierarchy ? 'treegrid' : 'table'}
613
760
  >
614
761
  ${this.showHeader
615
762
  ? html`
@@ -741,8 +888,18 @@ export class ObcTable extends LitElement {
741
888
  data-row-id=${row.id}
742
889
  style="grid-row: ${rowIndex + 1}"
743
890
  part="row"
891
+ aria-level=${ifDefined(
892
+ this.hasHierarchy ? (row.level ?? 0) + 1 : undefined
893
+ )}
894
+ aria-expanded=${ifDefined(
895
+ row.expandable ? (row.expanded ?? false) : undefined
896
+ )}
744
897
  >
745
- ${map(effectiveColumns, (col) => {
898
+ ${map(effectiveColumns, (col, colIndex) => {
899
+ const expander =
900
+ colIndex === (this.selectable ? 1 : 0)
901
+ ? this._renderRowExpander(row)
902
+ : nothing;
746
903
  if (this.selectable && col.key === '__selection__') {
747
904
  const checked = this._selectedRowIds.has(row.id);
748
905
  return html`<div
@@ -765,7 +922,9 @@ export class ObcTable extends LitElement {
765
922
  }
766
923
  const value = row[col.key];
767
924
  if (value === undefined) {
768
- return html`<div class="grid-cell" role="cell"></div>`;
925
+ return html`<div class="grid-cell" role="cell">
926
+ ${expander}
927
+ </div>`;
769
928
  }
770
929
  if (col.renderCell) {
771
930
  return html`<div
@@ -775,7 +934,7 @@ export class ObcTable extends LitElement {
775
934
  role="cell"
776
935
  part=${ifDefined((value as ObcTableCellData).cssPart)}
777
936
  >
778
- ${col.renderCell(
937
+ ${expander}${col.renderCell(
779
938
  value as ObcTableCellData,
780
939
  row,
781
940
  row.id
@@ -785,7 +944,8 @@ export class ObcTable extends LitElement {
785
944
  return this._renderCell(
786
945
  value as ObcTableCellData,
787
946
  row,
788
- col
947
+ col,
948
+ expander
789
949
  );
790
950
  }
791
951
  })}
@@ -951,7 +1111,8 @@ export class ObcTable extends LitElement {
951
1111
  private _renderCell(
952
1112
  value: ObcTableCellData,
953
1113
  row: ObcTableRow,
954
- column: ObcTableColumn<ObcTableCellData, ObcTableRow>
1114
+ column: ObcTableColumn<ObcTableCellData, ObcTableRow>,
1115
+ expander: HTMLTemplateResult | typeof nothing = nothing
955
1116
  ) {
956
1117
  if (value.type === ObcTableCellType.Regular) {
957
1118
  return html`<div
@@ -968,7 +1129,7 @@ export class ObcTable extends LitElement {
968
1129
  role="cell"
969
1130
  part=${ifDefined(cssPart(value, 'cell'))}
970
1131
  >
971
- ${value.icon3
1132
+ ${expander}${value.icon3
972
1133
  ? html`<span class="icon" part=${ifDefined(cssPart(value, 'icon3'))}
973
1134
  >${value.icon3}</span
974
1135
  >`
@@ -999,6 +1160,7 @@ export class ObcTable extends LitElement {
999
1160
  class="grid-cell button ${column.dividerRight ? 'divider-right' : ''}"
1000
1161
  role="cell"
1001
1162
  >
1163
+ ${expander}
1002
1164
  <obc-button
1003
1165
  variant="normal"
1004
1166
  fullWidth
@@ -1036,6 +1198,7 @@ export class ObcTable extends LitElement {
1036
1198
  role="cell"
1037
1199
  part=${ifDefined(cssPart(value, 'cell'))}
1038
1200
  >
1201
+ ${expander}
1039
1202
  <obc-checkbox
1040
1203
  .status=${value.status ?? CheckboxStatus.unchecked}
1041
1204
  .disabled=${value.disabled ?? false}
@@ -1083,7 +1246,7 @@ export class ObcTable extends LitElement {
1083
1246
  role="cell"
1084
1247
  part=${ifDefined(cssPart(value, 'cell'))}
1085
1248
  >
1086
- ${visibleTags.map((tag) => {
1249
+ ${expander}${visibleTags.map((tag) => {
1087
1250
  const hasIcon = tag.hasIcon ?? tag.icon !== undefined;
1088
1251
  return html`<obc-tag
1089
1252
  .label=${tag.label}
@@ -1122,6 +1285,7 @@ export class ObcTable extends LitElement {
1122
1285
  role="cell"
1123
1286
  part=${ifDefined(cssPart(value, 'cell'))}
1124
1287
  >
1288
+ ${expander}
1125
1289
  <obc-bar-horizontal
1126
1290
  .minValue=${value.minValue ?? 0}
1127
1291
  .maxValue=${value.maxValue ?? 100}
package/src/types.ts CHANGED
@@ -34,11 +34,11 @@ export enum AlertCategory {
34
34
  }
35
35
 
36
36
  export interface Alert {
37
- id: string; // The id of the alert
38
- tagId: string; // The tag ID visible to the user
37
+ id: string;
38
+ tagId: string;
39
39
  source: string;
40
40
  text: string;
41
- note?: string; // The note of the alert, typically by the operator
41
+ note?: string;
42
42
  acknowledged:
43
43
  | false
44
44
  | {
@@ -67,8 +67,10 @@ export interface Alert {
67
67
  blockedEndTime?: Date;
68
68
  blockedBy?: string;
69
69
  };
70
- noAck?: boolean; // If true, the alarm has no ack button
70
+ noAck?: boolean;
71
+ noSilence?: boolean;
71
72
  category?: AlertCategory;
73
+ memberOf?: string[];
72
74
  }
73
75
 
74
76
  export function isActive(alert: Alert) {