@orchestrator-ui/orchestrator-ui-components 1.38.2 → 2.1.0

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 (113) hide show
  1. package/.turbo/turbo-build.log +11 -9
  2. package/.turbo/turbo-lint.log +5 -2
  3. package/.turbo/turbo-test.log +14 -14
  4. package/CHANGELOG.md +30 -0
  5. package/dist/index.d.ts +329 -172
  6. package/dist/index.js +6152 -5545
  7. package/dist/index.js.map +1 -0
  8. package/package.json +2 -2
  9. package/src/components/WfoContentHeader/WfoContentHeader.tsx +55 -0
  10. package/src/components/WfoContentHeader/index.ts +1 -0
  11. package/src/components/WfoForms/formFields/SubscriptionSummaryField.tsx +6 -5
  12. package/src/components/WfoInlineNoteEdit/WfoInlineNoteEdit.tsx +105 -0
  13. package/src/components/WfoInlineNoteEdit/index.ts +1 -0
  14. package/src/components/WfoPageTemplate/WfoPageHeader/WfoPageHeader.tsx +3 -1
  15. package/src/components/WfoPageTemplate/WfoSidebar/WfoCopyright.tsx +1 -1
  16. package/src/components/WfoPageTemplate/WfoSidebar/WfoSidebar.tsx +6 -6
  17. package/src/components/WfoProcessList/WfoProcessesList.tsx +52 -51
  18. package/src/components/WfoRadioDropdown/WfoRadioDropdown.tsx +88 -0
  19. package/src/components/WfoRadioDropdown/index.ts +1 -0
  20. package/src/components/WfoRenderElementOrString/WfoRenderElementOrString.tsx +16 -0
  21. package/src/components/WfoRenderElementOrString/index.ts +1 -0
  22. package/src/components/WfoSubscription/WfoInSyncField.tsx +13 -9
  23. package/src/components/WfoSubscription/WfoInUseByRelations.tsx +4 -2
  24. package/src/components/WfoSubscription/WfoProcessesTimeline.tsx +76 -29
  25. package/src/components/WfoSubscription/WfoRelatedSubscriptions.tsx +92 -84
  26. package/src/components/WfoSubscription/WfoSubscription.tsx +19 -37
  27. package/src/components/WfoSubscription/WfoSubscriptionDetailTree.tsx +17 -9
  28. package/src/components/WfoSubscription/WfoSubscriptionGeneral.tsx +18 -156
  29. package/src/components/WfoSubscription/WfoSubscriptionGeneralSections/WfoSubscriptionDetailSection.tsx +119 -0
  30. package/src/components/WfoSubscription/WfoSubscriptionGeneralSections/WfoSubscriptionFixedInputSection.tsx +28 -0
  31. package/src/components/WfoSubscription/WfoSubscriptionGeneralSections/WfoSubscriptionMetadataSection.tsx +29 -0
  32. package/src/components/WfoSubscription/WfoSubscriptionGeneralSections/WfoSubscriptionProductInfoSection.tsx +55 -0
  33. package/src/components/WfoSubscription/WfoSubscriptionGeneralSections/index.ts +4 -0
  34. package/src/components/WfoSubscription/index.ts +3 -0
  35. package/src/components/WfoSubscription/overrides/index.ts +1 -0
  36. package/src/components/WfoSubscription/styles.ts +4 -1
  37. package/src/components/WfoSubscription/utils/relatedSubscriptionsListItemsObjectMappers.ts +62 -0
  38. package/src/components/WfoSubscription/utils/utils.spec.ts +0 -13
  39. package/src/components/WfoSubscription/utils/utils.ts +18 -5
  40. package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +105 -100
  41. package/src/components/WfoTable/{WfoTableWithFilter/WfoTableWithFilter.tsx → WfoAdvancedTable/WfoAdvancedTable.tsx} +65 -123
  42. package/src/components/WfoTable/WfoAdvancedTable/getRowDetailData.tsx +55 -0
  43. package/src/components/WfoTable/WfoAdvancedTable/index.ts +4 -0
  44. package/src/components/WfoTable/WfoAdvancedTable/toSortedTableColumnConfig.ts +12 -0
  45. package/src/components/WfoTable/WfoAdvancedTable/types.ts +23 -0
  46. package/src/components/WfoTable/WfoStatusColorField/WfoStatusColorField.tsx +16 -0
  47. package/src/components/WfoTable/WfoStatusColorField/index.ts +1 -0
  48. package/src/components/WfoTable/WfoStatusColorField/styles.ts +20 -0
  49. package/src/components/WfoTable/WfoTable/WfoExpandedRow.tsx +33 -0
  50. package/src/components/WfoTable/WfoTable/WfoGroupedTable/WfoExpandableRow.tsx +48 -0
  51. package/src/components/WfoTable/WfoTable/WfoGroupedTable/WfoExpandedGroupRow.tsx +71 -0
  52. package/src/components/WfoTable/WfoTable/WfoGroupedTable/WfoGroupedTable.tsx +100 -0
  53. package/src/components/WfoTable/WfoTable/WfoGroupedTable/WfoGroupedTableGroups.tsx +74 -0
  54. package/src/components/WfoTable/WfoTable/WfoGroupedTable/styles.ts +39 -0
  55. package/src/components/WfoTable/WfoTable/WfoGroupedTable/useGroupedTableConfig.tsx +184 -0
  56. package/src/components/WfoTable/WfoTable/WfoGroupedTable/utils.spec.ts +133 -0
  57. package/src/components/WfoTable/WfoTable/WfoGroupedTable/utils.ts +41 -0
  58. package/src/components/WfoTable/WfoTable/WfoMultilineCell.tsx +13 -0
  59. package/src/components/WfoTable/WfoTable/WfoTable.tsx +201 -0
  60. package/src/components/WfoTable/WfoTable/WfoTableDataRows.tsx +112 -0
  61. package/src/components/WfoTable/{WfoBasicTable → WfoTable/WfoTableHeaderCell}/WfoSortDirectionIcon.tsx +3 -3
  62. package/src/components/WfoTable/{WfoBasicTable → WfoTable/WfoTableHeaderCell}/WfoTableHeaderCell.tsx +4 -3
  63. package/src/components/WfoTable/WfoTable/WfoTableHeaderCell/index.ts +2 -0
  64. package/src/components/WfoTable/WfoTable/WfoTableHeaderRow.tsx +114 -0
  65. package/src/components/WfoTable/WfoTable/WfoTruncateCell.tsx +23 -0
  66. package/src/components/WfoTable/WfoTable/constants.ts +1 -0
  67. package/src/components/WfoTable/WfoTable/index.ts +14 -0
  68. package/src/components/WfoTable/WfoTable/styles.ts +117 -0
  69. package/src/components/WfoTable/WfoTable/utils.spec.ts +79 -0
  70. package/src/components/WfoTable/WfoTable/utils.ts +78 -0
  71. package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.tsx +13 -12
  72. package/src/components/WfoTable/WfoTableWithFilter/index.ts +1 -1
  73. package/src/components/WfoTable/index.ts +4 -5
  74. package/src/components/WfoTable/utils/columns.ts +1 -48
  75. package/src/components/WfoTable/utils/tableUtils.ts +13 -10
  76. package/src/components/WfoTree/WfoTreeBranch.tsx +10 -1
  77. package/src/components/WfoTree/WfoTreeNode.tsx +8 -57
  78. package/src/components/WfoTree/WfoTreeNodeListItem.tsx +65 -0
  79. package/src/components/WfoTree/styles.ts +28 -4
  80. package/src/components/index.ts +4 -0
  81. package/src/configuration/policy-resources.ts +1 -0
  82. package/src/configuration/version.ts +1 -1
  83. package/src/icons/WfoXMarkSmall.tsx +29 -0
  84. package/src/messages/en-GB.json +4 -0
  85. package/src/messages/nl-NL.json +4 -0
  86. package/src/pages/metadata/WfoMetadataPageLayout.tsx +4 -4
  87. package/src/pages/metadata/WfoProductBlocksPage.tsx +42 -59
  88. package/src/pages/metadata/WfoProductsPage.tsx +41 -47
  89. package/src/pages/metadata/WfoResourceTypesPage.tsx +26 -35
  90. package/src/pages/metadata/WfoTasksPage.tsx +35 -33
  91. package/src/pages/metadata/WfoWorkflowsPage.tsx +33 -29
  92. package/src/pages/processes/WfoProcessDetail.tsx +47 -55
  93. package/src/pages/settings/WfoSettingsPage.tsx +9 -4
  94. package/src/pages/startPage/WfoStartPage.tsx +17 -1
  95. package/src/pages/subscriptions/WfoSubscriptionsListPage.tsx +4 -5
  96. package/src/pages/tasks/WfoTasksListPage.tsx +44 -52
  97. package/src/pages/workflows/WfoWorkflowsListPage.tsx +4 -5
  98. package/src/rtk/endpoints/index.ts +1 -0
  99. package/src/rtk/endpoints/relatedSubscriptions.ts +5 -4
  100. package/src/rtk/endpoints/subscriptionActions.ts +11 -1
  101. package/src/utils/getObjectKeys.ts +3 -0
  102. package/src/utils/index.ts +5 -3
  103. package/tsup.config.ts +10 -0
  104. package/src/components/WfoTable/WfoBasicTable/WfoBasicTable.tsx +0 -194
  105. package/src/components/WfoTable/WfoBasicTable/WfoStatusColorField.tsx +0 -21
  106. package/src/components/WfoTable/WfoBasicTable/index.ts +0 -5
  107. package/src/components/WfoTable/WfoDataGridTable/WfoDataGridTable.stories.tsx +0 -136
  108. package/src/components/WfoTable/WfoDataGridTable/WfoDataGridTable.tsx +0 -146
  109. package/src/components/WfoTable/WfoDataGridTable/WfodataGridColumns.spec.ts +0 -113
  110. package/src/components/WfoTable/WfoDataGridTable/WfodataGridColumns.ts +0 -81
  111. package/src/components/WfoTable/utils/mapSortableAndFilterableValuesToTableColumnConfig.spec.ts +0 -52
  112. package/src/components/WfoTable/utils/mapSortableAndFilterableValuesToTableColumnConfig.ts +0 -23
  113. /package/src/components/WfoTable/{WfoBasicTable → WfoTable/WfoTableHeaderCell}/styles.ts +0 -0
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+
3
+ import { getWfoStatusColorFieldStyles } from '@/components/WfoTable/WfoStatusColorField/styles';
4
+ import { useWithOrchestratorTheme } from '@/hooks';
5
+
6
+ export type WfoStatusColorFieldProps = {
7
+ color: string;
8
+ };
9
+
10
+ export const WfoStatusColorField = ({ color }: WfoStatusColorFieldProps) => {
11
+ const { getStatusColorFieldStyle } = useWithOrchestratorTheme(
12
+ getWfoStatusColorFieldStyles,
13
+ );
14
+
15
+ return <div css={getStatusColorFieldStyle(color)}></div>;
16
+ };
@@ -0,0 +1 @@
1
+ export * from './WfoStatusColorField';
@@ -0,0 +1,20 @@
1
+ import { tint } from '@elastic/eui';
2
+ import { css } from '@emotion/react';
3
+
4
+ import { TABLE_ROW_HEIGHT } from '@/components';
5
+ import { WfoTheme } from '@/hooks';
6
+
7
+ export const getWfoStatusColorFieldStyles = ({ theme }: WfoTheme) => {
8
+ const toStatusColorFieldColor = (color: string) => tint(color, 0.3);
9
+
10
+ const getStatusColorFieldStyle = (color: string) =>
11
+ css({
12
+ backgroundColor: toStatusColorFieldColor(color),
13
+ height: TABLE_ROW_HEIGHT,
14
+ width: theme.size.xs,
15
+ });
16
+
17
+ return {
18
+ getStatusColorFieldStyle,
19
+ };
20
+ };
@@ -0,0 +1,33 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ import { WfoTableProps } from './WfoTable';
4
+
5
+ export type WfoExpandedRowProps<T extends object> = Pick<
6
+ WfoTableProps<T>,
7
+ 'rowExpandingConfiguration'
8
+ > & {
9
+ rowData: T;
10
+ };
11
+
12
+ export const WfoExpandedRow = <T extends object>({
13
+ rowExpandingConfiguration,
14
+ rowData,
15
+ }: WfoExpandedRowProps<T>) => {
16
+ if (!rowExpandingConfiguration) {
17
+ return null;
18
+ }
19
+
20
+ return Object.entries(rowExpandingConfiguration.uniqueRowIdToExpandedRowMap)
21
+ .map(([key, value]): [key: string, value: ReactNode] => [
22
+ key.toLowerCase(),
23
+ value,
24
+ ])
25
+ .filter(
26
+ ([key]) =>
27
+ key ===
28
+ (
29
+ rowData[rowExpandingConfiguration.uniqueRowId] as string
30
+ ).toLowerCase(),
31
+ )
32
+ .map(([, expandedRowComponent]) => expandedRowComponent);
33
+ };
@@ -0,0 +1,48 @@
1
+ import React, { FC } from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import { EuiButtonIcon, EuiText } from '@elastic/eui';
6
+
7
+ import { useWithOrchestratorTheme } from '@/hooks';
8
+
9
+ import { getWfoGroupedTableStyles } from './styles';
10
+
11
+ export type WfoExpandableRowProps = {
12
+ isExpanded: boolean;
13
+ groupName: string;
14
+ updateExpandedRows: (groupName: string) => void;
15
+ numberOfRowsInGroup: number;
16
+ };
17
+
18
+ export const WfoExpandableRow: FC<WfoExpandableRowProps> = ({
19
+ groupName,
20
+ numberOfRowsInGroup,
21
+ updateExpandedRows,
22
+ isExpanded,
23
+ }) => {
24
+ const { expandableRowContainerStyle, expandableRowTextStyle } =
25
+ useWithOrchestratorTheme(getWfoGroupedTableStyles);
26
+ const t = useTranslations('wfoComponents');
27
+
28
+ const hasData = numberOfRowsInGroup > 0;
29
+
30
+ return (
31
+ <div css={expandableRowContainerStyle}>
32
+ <EuiButtonIcon
33
+ disabled={!hasData}
34
+ aria-label={isExpanded ? t('collapse') : t('expand')}
35
+ iconType={hasData && isExpanded ? 'arrowDown' : 'arrowRight'}
36
+ onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
37
+ updateExpandedRows(groupName);
38
+ event.stopPropagation();
39
+ }}
40
+ />
41
+
42
+ <EuiText
43
+ size="s"
44
+ css={expandableRowTextStyle}
45
+ >{`${groupName} (${numberOfRowsInGroup})`}</EuiText>
46
+ </div>
47
+ );
48
+ };
@@ -0,0 +1,71 @@
1
+ import React, { Ref } from 'react';
2
+
3
+ import { useWithOrchestratorTheme } from '@/hooks';
4
+
5
+ import { WfoTableDataRows } from '../WfoTableDataRows';
6
+ import { WfoTableHeaderRow } from '../WfoTableHeaderRow';
7
+ import { getWfoTableStyles } from '../styles';
8
+ import { GroupedData } from './WfoGroupedTable';
9
+ import {
10
+ WfoGroupedTableGroups,
11
+ WfoGroupedTableGroupsProps,
12
+ WfoGroupedTableGroupsRef,
13
+ } from './WfoGroupedTableGroups';
14
+ import { getWfoGroupedTableStyles } from './styles';
15
+
16
+ export type WfoExpandedGroupRowProps<T extends object> = Pick<
17
+ WfoGroupedTableGroupsProps<T>,
18
+ 'columnConfig' | 'nestingLevel' | 'groupNameLabel'
19
+ > & {
20
+ data: GroupedData<T> | T[];
21
+ onExpandRowChange: (isAllExpanded: boolean) => void;
22
+ };
23
+
24
+ export const WfoExpandedGroupRow = React.forwardRef(
25
+ <T extends object>(
26
+ {
27
+ data,
28
+ columnConfig,
29
+ nestingLevel = 1,
30
+ groupNameLabel,
31
+ onExpandRowChange,
32
+ }: WfoExpandedGroupRowProps<T>,
33
+ reference: Ref<WfoGroupedTableGroupsRef>,
34
+ ) => {
35
+ const { expandedRowStyle } =
36
+ useWithOrchestratorTheme(getWfoTableStyles);
37
+ const { innerTableHeaderStyle, getNestingStyle } =
38
+ useWithOrchestratorTheme(getWfoGroupedTableStyles);
39
+
40
+ if (Array.isArray(data)) {
41
+ return (
42
+ <>
43
+ <WfoTableHeaderRow
44
+ css={[
45
+ innerTableHeaderStyle,
46
+ getNestingStyle(nestingLevel),
47
+ ]}
48
+ columnConfig={columnConfig}
49
+ />
50
+ <WfoTableDataRows
51
+ css={[expandedRowStyle, getNestingStyle(nestingLevel)]}
52
+ data={data}
53
+ columnConfig={columnConfig}
54
+ />
55
+ </>
56
+ );
57
+ }
58
+
59
+ return (
60
+ <WfoGroupedTableGroups
61
+ ref={reference}
62
+ data={data}
63
+ columnConfig={columnConfig}
64
+ groupNameLabel={groupNameLabel}
65
+ nestingLevel={nestingLevel}
66
+ onExpandRowChange={onExpandRowChange}
67
+ />
68
+ );
69
+ },
70
+ );
71
+ WfoExpandedGroupRow.displayName = 'WfoExpandedGroupRow';
@@ -0,0 +1,100 @@
1
+ import React from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import { EuiButtonEmpty, EuiFlexGroup, EuiSpacer } from '@elastic/eui';
6
+
7
+ import { useWithOrchestratorTheme } from '@/hooks';
8
+
9
+ import { WfoTable, WfoTableProps } from '../WfoTable';
10
+ import { getWfoTableStyles } from '../styles';
11
+ import { useGroupedTableConfig } from './useGroupedTableConfig';
12
+
13
+ export type GroupType = {
14
+ groupName: string;
15
+ };
16
+
17
+ export type GroupedData<T> = {
18
+ [Key: string]: T[] | GroupedData<T>;
19
+ };
20
+
21
+ export type WfoGroupedTableProps<T extends object> = Pick<
22
+ WfoTableProps<T>,
23
+ 'columnConfig' | 'isLoading' | 'className'
24
+ > & {
25
+ data: GroupedData<T>;
26
+ groupNameLabel: string;
27
+ };
28
+
29
+ export const WfoGroupedTable = <T extends object>({
30
+ data,
31
+ columnConfig,
32
+ groupNameLabel,
33
+ isLoading,
34
+ className,
35
+ }: WfoGroupedTableProps<T>) => {
36
+ const { headerStyle, rowStyle, cellStyle } =
37
+ useWithOrchestratorTheme(getWfoTableStyles);
38
+
39
+ const t = useTranslations('wfoComponents.wfoGroupedTable');
40
+
41
+ const {
42
+ groups,
43
+ groupColumnConfig,
44
+ numberOfColumnsInnerTable,
45
+ uniqueRowIdToExpandedRowMap,
46
+ isAllGroupsAndSubgroupsExpanded,
47
+ toggleExpandedRow,
48
+ expandAllRows,
49
+ collapseAllRows,
50
+ } = useGroupedTableConfig({
51
+ data,
52
+ groupNameLabel,
53
+ columnConfig,
54
+ });
55
+
56
+ return (
57
+ <>
58
+ <EuiFlexGroup justifyContent="flexEnd">
59
+ <EuiButtonEmpty
60
+ size="xs"
61
+ onClick={() =>
62
+ isAllGroupsAndSubgroupsExpanded
63
+ ? collapseAllRows()
64
+ : expandAllRows()
65
+ }
66
+ >
67
+ {isAllGroupsAndSubgroupsExpanded
68
+ ? t('collapse')
69
+ : t('expand')}
70
+ </EuiButtonEmpty>
71
+ </EuiFlexGroup>
72
+
73
+ <EuiSpacer size="xs" />
74
+
75
+ <WfoTable
76
+ className={className}
77
+ data={groups}
78
+ columnConfig={groupColumnConfig}
79
+ isLoading={isLoading}
80
+ overrideHeader={() => (
81
+ <thead css={headerStyle}>
82
+ <tr css={rowStyle}>
83
+ <th
84
+ colSpan={numberOfColumnsInnerTable}
85
+ css={cellStyle}
86
+ >
87
+ {groupNameLabel}
88
+ </th>
89
+ </tr>
90
+ </thead>
91
+ )}
92
+ rowExpandingConfiguration={{
93
+ uniqueRowId: 'groupName',
94
+ uniqueRowIdToExpandedRowMap,
95
+ }}
96
+ onRowClick={({ groupName }) => toggleExpandedRow(groupName)}
97
+ />
98
+ </>
99
+ );
100
+ };
@@ -0,0 +1,74 @@
1
+ import React, { Ref, useImperativeHandle } from 'react';
2
+
3
+ import { useWithOrchestratorTheme } from '@/hooks';
4
+
5
+ import { WfoTableDataRows } from '../WfoTableDataRows';
6
+ import { getWfoTableStyles } from '../styles';
7
+ import { WfoGroupedTableProps } from './WfoGroupedTable';
8
+ import { getWfoGroupedTableStyles } from './styles';
9
+ import { useGroupedTableConfig } from './useGroupedTableConfig';
10
+
11
+ export type WfoGroupedTableGroupsRef = {
12
+ expandAllRows: () => void;
13
+ };
14
+
15
+ export type WfoGroupedTableGroupsProps<T extends object> = Pick<
16
+ WfoGroupedTableProps<T>,
17
+ 'columnConfig' | 'data' | 'groupNameLabel'
18
+ > & {
19
+ nestingLevel?: number;
20
+ onExpandRowChange: (isAllExpanded: boolean) => void;
21
+ };
22
+
23
+ export const WfoGroupedTableGroups = React.forwardRef(
24
+ <T extends object>(
25
+ {
26
+ data,
27
+ groupNameLabel,
28
+ columnConfig,
29
+ nestingLevel = 1,
30
+ onExpandRowChange,
31
+ }: WfoGroupedTableGroupsProps<T>,
32
+ reference: Ref<WfoGroupedTableGroupsRef>,
33
+ ) => {
34
+ const { expandedRowStyle } =
35
+ useWithOrchestratorTheme(getWfoTableStyles);
36
+ const { getNestingStyle } = useWithOrchestratorTheme(
37
+ getWfoGroupedTableStyles,
38
+ );
39
+
40
+ const {
41
+ groups,
42
+ groupColumnConfig,
43
+ uniqueRowIdToExpandedRowMap,
44
+ toggleExpandedRow,
45
+ expandAllRows,
46
+ } = useGroupedTableConfig({
47
+ data,
48
+ groupNameLabel,
49
+ columnConfig,
50
+ nestingLevel,
51
+ notifyParent: onExpandRowChange,
52
+ });
53
+
54
+ useImperativeHandle(reference, () => ({
55
+ expandAllRows: () => {
56
+ expandAllRows();
57
+ },
58
+ }));
59
+
60
+ return (
61
+ <WfoTableDataRows
62
+ css={[expandedRowStyle, getNestingStyle(nestingLevel)]}
63
+ data={groups}
64
+ columnConfig={groupColumnConfig}
65
+ onRowClick={(row) => toggleExpandedRow(row.groupName)}
66
+ rowExpandingConfiguration={{
67
+ uniqueRowId: 'groupName',
68
+ uniqueRowIdToExpandedRowMap,
69
+ }}
70
+ />
71
+ );
72
+ },
73
+ );
74
+ WfoGroupedTableGroups.displayName = 'WfoGroupedTableGroups';
@@ -0,0 +1,39 @@
1
+ import { css } from '@emotion/react';
2
+
3
+ import { WfoTheme } from '@/hooks';
4
+
5
+ export const getWfoGroupedTableStyles = ({ theme }: WfoTheme) => {
6
+ // Matches the default width of a EuiButtonIcon component
7
+ const expandRowButtonWidth = '24px';
8
+ const marginBetweenButtonAndGroupLabel = theme.size.m;
9
+
10
+ const innerTableHeaderStyle = css({
11
+ fontSize: theme.size.m,
12
+ textAlign: 'left',
13
+ backgroundColor: theme.colors.lightestShade,
14
+ });
15
+
16
+ const expandableRowContainerStyle = css({
17
+ display: 'flex',
18
+ alignItems: 'center',
19
+ });
20
+
21
+ const expandableRowTextStyle = css({
22
+ marginLeft: marginBetweenButtonAndGroupLabel,
23
+ fontWeight: theme.font.weight.medium,
24
+ });
25
+
26
+ const getNestingStyle = (nestingLevel: number) =>
27
+ css({
28
+ 'th:first-child > *:first-child, td:first-child > *:first-child': {
29
+ marginLeft: `calc(${nestingLevel} * (${expandRowButtonWidth} + ${marginBetweenButtonAndGroupLabel}))`,
30
+ },
31
+ });
32
+
33
+ return {
34
+ innerTableHeaderStyle,
35
+ expandableRowContainerStyle,
36
+ expandableRowTextStyle,
37
+ getNestingStyle,
38
+ };
39
+ };
@@ -0,0 +1,184 @@
1
+ import React, { ReactNode, useEffect, useRef, useState } from 'react';
2
+
3
+ import { getObjectKeys } from '@/utils';
4
+
5
+ import { ColumnType, WfoTableColumnConfig } from '../WfoTable';
6
+ import { WfoExpandableRow } from './WfoExpandableRow';
7
+ import { WfoExpandedGroupRow } from './WfoExpandedGroupRow';
8
+ import { GroupType, WfoGroupedTableProps } from './WfoGroupedTable';
9
+ import { WfoGroupedTableGroupsRef } from './WfoGroupedTableGroups';
10
+ import { getTotalNumberOfRows } from './utils';
11
+
12
+ export type UseGroupedTableConfigProps<T extends object> = Pick<
13
+ WfoGroupedTableProps<T>,
14
+ 'columnConfig' | 'data' | 'groupNameLabel'
15
+ > & {
16
+ nestingLevel?: number;
17
+ notifyParent?: (meAndAllMySubgroupsAreExpanded: boolean) => void;
18
+ };
19
+
20
+ export const useGroupedTableConfig = <T extends object>({
21
+ data,
22
+ columnConfig,
23
+ groupNameLabel,
24
+ nestingLevel = 0,
25
+ notifyParent,
26
+ }: UseGroupedTableConfigProps<T>) => {
27
+ const groupReferences = useRef(new Map<string, WfoGroupedTableGroupsRef>());
28
+
29
+ const [expandedRowIds, setExpandedRowIds] = useState<string[]>([]);
30
+ const [isAllGroupsExpanded, setIsAllGroupsExpanded] = useState(false);
31
+ const [isAllSubgroupsExpanded, setIsAllSubgroupsExpanded] = useState<
32
+ string[]
33
+ >([]);
34
+
35
+ // Expanding all children needs another render cycle, because they do not exist in the DOM yet
36
+ const [isExpanding, setIsExpanding] = useState(false);
37
+
38
+ useEffect(() => {
39
+ if (isExpanding) {
40
+ groupReferences.current.forEach((ref) => {
41
+ ref.expandAllRows();
42
+ });
43
+ setIsExpanding(false);
44
+ }
45
+ }, [isExpanding]);
46
+
47
+ useEffect(() => {
48
+ if (notifyParent) {
49
+ notifyParent(
50
+ isAllGroupsExpanded &&
51
+ groups.every(({ groupName }) =>
52
+ isAllSubgroupsExpanded.includes(groupName),
53
+ ),
54
+ );
55
+ }
56
+ }, [isAllSubgroupsExpanded, isAllGroupsExpanded]);
57
+
58
+ const groups: GroupType[] = getObjectKeys(data).map((key) => ({
59
+ groupName: key.toString(),
60
+ }));
61
+ const numberOfColumnsInnerTable = Object.keys(columnConfig).length;
62
+
63
+ const groupColumnConfig: WfoTableColumnConfig<GroupType> = {
64
+ groupName: {
65
+ columnType: ColumnType.CONTROL,
66
+ label: groupNameLabel,
67
+ numberOfColumnsToSpan: numberOfColumnsInnerTable,
68
+ renderControl: ({ groupName }) => {
69
+ const isExpanded = expandedRowIds.includes(groupName);
70
+ const groupData = data[groupName];
71
+
72
+ const numberOfRowsInGroup = Array.isArray(groupData)
73
+ ? groupData.length
74
+ : getTotalNumberOfRows(groupData);
75
+
76
+ return (
77
+ <WfoExpandableRow
78
+ groupName={groupName}
79
+ isExpanded={isExpanded}
80
+ updateExpandedRows={toggleExpandedRow}
81
+ numberOfRowsInGroup={numberOfRowsInGroup}
82
+ />
83
+ );
84
+ },
85
+ },
86
+ };
87
+
88
+ const getReferenceCallbackForRow = (groupName: string) => {
89
+ return (ref: WfoGroupedTableGroupsRef | null) => {
90
+ if (ref) {
91
+ groupReferences.current.set(groupName, ref);
92
+ } else if (groupName && groupReferences.current.has(groupName)) {
93
+ groupReferences.current.delete(groupName);
94
+ }
95
+ };
96
+ };
97
+
98
+ const uniqueRowIdToExpandedRowMap = expandedRowIds.reduce<
99
+ Record<string, ReactNode>
100
+ >((accumulator, groupName) => {
101
+ const groupData = data[groupName];
102
+
103
+ accumulator[groupName] = (
104
+ <WfoExpandedGroupRow
105
+ key={groupName}
106
+ ref={getReferenceCallbackForRow(groupName)}
107
+ data={groupData}
108
+ columnConfig={columnConfig}
109
+ groupNameLabel={groupNameLabel}
110
+ nestingLevel={nestingLevel + 1}
111
+ onExpandRowChange={(isAllSubgroupsExpanded) =>
112
+ setIsAllSubgroupsExpanded((prevState) => {
113
+ if (isAllSubgroupsExpanded) {
114
+ return [...prevState, groupName];
115
+ }
116
+
117
+ return prevState.filter((id) => id !== groupName);
118
+ })
119
+ }
120
+ />
121
+ );
122
+
123
+ return accumulator;
124
+ }, {});
125
+
126
+ const toggleExpandedRow = (groupName: string) => {
127
+ const groupData = data[groupName];
128
+ const groupHasData = Array.isArray(groupData)
129
+ ? groupData.length > 0
130
+ : Object.keys(groupData).length > 0;
131
+
132
+ if (groupHasData) {
133
+ setExpandedRowIds((prevState) => {
134
+ // Collapse group
135
+ if (prevState.includes(groupName)) {
136
+ setIsAllGroupsExpanded(false);
137
+ return prevState.filter((value) => value !== groupName);
138
+ }
139
+
140
+ // Expand group
141
+ if (prevState.length + 1 >= groups.length) {
142
+ setIsAllGroupsExpanded(true);
143
+ }
144
+ if (Array.isArray(groupData)) {
145
+ setIsAllSubgroupsExpanded((prevState) => {
146
+ return [...prevState, groupName];
147
+ });
148
+ }
149
+ return [...prevState, groupName];
150
+ });
151
+ }
152
+ };
153
+
154
+ const expandAllRows = () => {
155
+ setExpandedRowIds(() => groups.map(({ groupName }) => groupName));
156
+ setIsExpanding(true);
157
+ setIsAllGroupsExpanded(true);
158
+ setIsAllSubgroupsExpanded(() =>
159
+ groups.map(({ groupName }) => groupName),
160
+ );
161
+ };
162
+
163
+ const collapseAllRows = () => {
164
+ setExpandedRowIds([]);
165
+ setIsAllGroupsExpanded(false);
166
+ };
167
+
168
+ const isAllGroupsAndSubgroupsExpanded =
169
+ isAllGroupsExpanded &&
170
+ groups.every(({ groupName }) =>
171
+ isAllSubgroupsExpanded.includes(groupName),
172
+ );
173
+
174
+ return {
175
+ groups,
176
+ numberOfColumnsInnerTable,
177
+ groupColumnConfig,
178
+ uniqueRowIdToExpandedRowMap,
179
+ isAllGroupsAndSubgroupsExpanded,
180
+ toggleExpandedRow,
181
+ expandAllRows,
182
+ collapseAllRows,
183
+ };
184
+ };