@databiosphere/findable-ui 32.1.1 → 34.0.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 (185) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +27 -0
  3. package/jest.config.js +4 -0
  4. package/lib/common/categories/config/utils.d.ts +1 -1
  5. package/lib/common/categories/config/utils.js +5 -1
  6. package/lib/common/entities.d.ts +4 -4
  7. package/lib/components/DataDictionary/components/Entities/entities.d.ts +1 -1
  8. package/lib/components/DataDictionary/components/Entities/entities.js +3 -2
  9. package/lib/components/DataDictionary/components/Entities/types.d.ts +3 -4
  10. package/lib/components/DataDictionary/components/Entity/entity.d.ts +1 -1
  11. package/lib/components/DataDictionary/components/Entity/entity.js +12 -6
  12. package/lib/components/DataDictionary/components/Entity/entity.styles.js +7 -1
  13. package/lib/components/DataDictionary/components/Entity/types.d.ts +4 -4
  14. package/lib/components/DataDictionary/components/Entity/utils.d.ts +9 -0
  15. package/lib/components/DataDictionary/components/Entity/utils.js +18 -0
  16. package/lib/components/DataDictionary/components/Filters/components/ColumnFilters/columnFilters.d.ts +4 -0
  17. package/lib/components/DataDictionary/components/Filters/components/ColumnFilters/columnFilters.js +9 -0
  18. package/lib/components/DataDictionary/components/Filters/components/ColumnFilters/types.d.ts +5 -0
  19. package/lib/components/DataDictionary/components/Filters/components/ColumnFilters/types.js +1 -0
  20. package/lib/components/DataDictionary/components/Filters/filters.d.ts +4 -0
  21. package/lib/components/DataDictionary/components/Filters/filters.js +7 -0
  22. package/lib/components/DataDictionary/components/Filters/filters.styles.d.ts +7 -0
  23. package/lib/components/DataDictionary/components/Filters/filters.styles.js +13 -0
  24. package/lib/components/DataDictionary/components/Filters/stories/constants.d.ts +4 -0
  25. package/lib/components/DataDictionary/components/Filters/stories/constants.js +25 -0
  26. package/lib/components/DataDictionary/components/Filters/stories/filters.stories.d.ts +6 -0
  27. package/lib/components/DataDictionary/components/Filters/stories/filters.stories.js +31 -0
  28. package/lib/components/DataDictionary/components/Filters/stories/hook.d.ts +5 -0
  29. package/lib/components/DataDictionary/components/Filters/stories/hook.js +5 -0
  30. package/lib/components/DataDictionary/components/Filters/stories/types.d.ts +4 -0
  31. package/lib/components/DataDictionary/components/Filters/stories/types.js +1 -0
  32. package/lib/components/DataDictionary/components/Filters/types.d.ts +5 -0
  33. package/lib/components/DataDictionary/components/Filters/types.js +1 -0
  34. package/lib/components/DataDictionary/components/Layout/components/EntitiesLayout/entitiesLayout.styles.js +3 -1
  35. package/lib/components/DataDictionary/components/Layout/components/FiltersLayout/filtersLayout.d.ts +2 -0
  36. package/lib/components/DataDictionary/components/Layout/components/FiltersLayout/filtersLayout.js +5 -0
  37. package/lib/components/DataDictionary/components/Layout/components/FiltersLayout/filtersLayout.styles.d.ts +5 -0
  38. package/lib/components/DataDictionary/components/Layout/components/FiltersLayout/filtersLayout.styles.js +24 -0
  39. package/lib/components/DataDictionary/components/Layout/components/FiltersLayout/types.d.ts +5 -0
  40. package/lib/components/DataDictionary/components/Layout/components/FiltersLayout/types.js +1 -0
  41. package/lib/components/DataDictionary/components/Layout/components/OutlineLayout/outlineLayout.styles.js +1 -1
  42. package/lib/components/DataDictionary/components/Layout/components/TitleLayout/titleLayout.styles.js +1 -0
  43. package/lib/components/DataDictionary/components/Layout/constants.d.ts +4 -0
  44. package/lib/components/DataDictionary/components/Layout/constants.js +4 -0
  45. package/lib/components/DataDictionary/components/Outline/utils.d.ts +5 -5
  46. package/lib/components/DataDictionary/components/Outline/utils.js +23 -6
  47. package/lib/components/DataDictionary/components/Table/hook.d.ts +3 -3
  48. package/lib/components/DataDictionary/components/Table/hook.js +11 -3
  49. package/lib/components/DataDictionary/components/Table/options/columnFilters/constants.d.ts +2 -0
  50. package/lib/components/DataDictionary/components/Table/options/columnFilters/constants.js +8 -0
  51. package/lib/components/DataDictionary/components/Table/options/columnFilters/hook.d.ts +6 -0
  52. package/lib/components/DataDictionary/components/Table/options/columnFilters/hook.js +14 -0
  53. package/lib/components/DataDictionary/components/Table/options/expanded/constants.d.ts +2 -0
  54. package/lib/components/DataDictionary/components/Table/options/expanded/constants.js +5 -0
  55. package/lib/components/DataDictionary/components/Table/options/faceted/constants.d.ts +2 -0
  56. package/lib/components/DataDictionary/components/Table/options/faceted/constants.js +6 -0
  57. package/lib/components/DataDictionary/components/Table/options/grouping/constants.d.ts +2 -0
  58. package/lib/components/DataDictionary/components/Table/options/grouping/constants.js +5 -0
  59. package/lib/components/DataDictionary/components/Table/options/hook.d.ts +1 -1
  60. package/lib/components/DataDictionary/components/Table/options/hook.js +17 -0
  61. package/lib/components/DataDictionary/components/Table/options/visibility/constants.d.ts +2 -0
  62. package/lib/components/DataDictionary/components/Table/options/visibility/constants.js +3 -0
  63. package/lib/components/DataDictionary/components/Table/table.d.ts +1 -1
  64. package/lib/components/DataDictionary/components/Table/table.js +2 -2
  65. package/lib/components/DataDictionary/components/Table/types.d.ts +4 -1
  66. package/lib/components/DataDictionary/components/Table/utils.d.ts +18 -0
  67. package/lib/components/DataDictionary/components/Table/utils.js +27 -0
  68. package/lib/components/DataDictionary/dataDictionary.d.ts +1 -1
  69. package/lib/components/DataDictionary/dataDictionary.js +9 -7
  70. package/lib/components/DataDictionary/hooks/UseDataDictionary/hook.js +16 -4
  71. package/lib/components/DataDictionary/hooks/UseDataDictionary/types.d.ts +6 -4
  72. package/lib/components/DataDictionary/types.d.ts +1 -0
  73. package/lib/components/Detail/components/Table/components/TableBody/tableBody.d.ts +8 -2
  74. package/lib/components/Detail/components/Table/components/TableBody/tableBody.js +2 -2
  75. package/lib/components/Detail/components/Table/components/TableRows/components/CollapsableRows/collapsableRows.d.ts +8 -2
  76. package/lib/components/Detail/components/Table/components/TableRows/components/CollapsableRows/collapsableRows.js +2 -2
  77. package/lib/components/Detail/components/Table/components/TableRows/tableRows.d.ts +8 -2
  78. package/lib/components/Detail/components/Table/components/TableRows/tableRows.js +2 -2
  79. package/lib/components/Filter/components/FilterLabel/filterLabel.styles.d.ts +1 -1
  80. package/lib/components/Filter/components/FilterList/filterList.styles.d.ts +2 -0
  81. package/lib/components/Filter/components/FilterList/filterList.styles.js +28 -15
  82. package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.d.ts +1 -1
  83. package/lib/components/Layout/components/Header/components/Content/components/Actions/components/Authentication/components/Button/button.styles.d.ts +1 -1
  84. package/lib/components/Layout/components/Header/components/Content/components/Actions/components/Search/components/Button/button.styles.d.ts +1 -1
  85. package/lib/components/Layout/components/Header/header.styles.js +4 -1
  86. package/lib/components/Layout/components/Outline/components/ContentsTab/contentsTab.styles.d.ts +1 -1
  87. package/lib/components/Layout/components/Outline/outline.styles.d.ts +1 -1
  88. package/lib/components/Login/components/Button/button.styles.d.ts +1 -1
  89. package/lib/components/Table/common/utils.d.ts +6 -0
  90. package/lib/components/Table/common/utils.js +14 -0
  91. package/lib/components/Table/components/TableFeatures/ColumnFilter/columnFilter.d.ts +7 -0
  92. package/lib/components/Table/components/TableFeatures/ColumnFilter/columnFilter.js +33 -0
  93. package/lib/components/Table/components/TableFeatures/ColumnFilter/columnFilter.styles.d.ts +3 -0
  94. package/lib/components/Table/components/TableFeatures/ColumnFilter/columnFilter.styles.js +19 -0
  95. package/lib/components/Table/components/TableFeatures/ColumnFilter/constants.d.ts +2 -0
  96. package/lib/components/Table/components/TableFeatures/ColumnFilter/constants.js +14 -0
  97. package/lib/components/Table/components/TableFeatures/ColumnFilter/types.d.ts +7 -0
  98. package/lib/components/Table/components/TableFeatures/ColumnFilter/types.js +1 -0
  99. package/lib/components/Table/components/TableFeatures/ColumnFilter/utils.d.ts +6 -0
  100. package/lib/components/Table/components/TableFeatures/ColumnFilter/utils.js +23 -0
  101. package/lib/components/Table/featureOptions/facetedColumn/utils.d.ts +6 -0
  102. package/lib/components/Table/featureOptions/facetedColumn/utils.js +9 -0
  103. package/lib/components/common/ButtonGroup/constants.d.ts +2 -0
  104. package/lib/components/common/ButtonGroup/constants.js +11 -0
  105. package/lib/components/common/Tabs/tabs.styles.d.ts +1 -1
  106. package/lib/mocks/@storybook/addon-actions.d.ts +9 -0
  107. package/lib/mocks/@storybook/addon-actions.js +9 -0
  108. package/lib/styles/common/mui/buttonGroup.d.ts +13 -0
  109. package/lib/styles/common/mui/buttonGroup.js +34 -0
  110. package/lib/styles/common/mui/typography.js +2 -0
  111. package/lib/tests/mui/constants.d.ts +1 -0
  112. package/lib/tests/mui/constants.js +1 -0
  113. package/lib/tests/utils.d.ts +6 -0
  114. package/lib/tests/utils.js +8 -0
  115. package/lib/theme/common/components.d.ts +0 -6
  116. package/lib/theme/common/components.js +17 -31
  117. package/lib/theme/components/index.d.ts +1 -0
  118. package/lib/theme/components/index.js +1 -0
  119. package/lib/theme/components/muiButtonGroup.d.ts +2 -0
  120. package/lib/theme/components/muiButtonGroup.js +76 -0
  121. package/lib/theme/theme.js +1 -1
  122. package/package.json +1 -1
  123. package/src/common/categories/config/utils.ts +6 -3
  124. package/src/common/entities.ts +5 -4
  125. package/src/components/DataDictionary/components/Entities/entities.tsx +5 -9
  126. package/src/components/DataDictionary/components/Entities/types.ts +3 -4
  127. package/src/components/DataDictionary/components/Entity/entity.styles.ts +9 -1
  128. package/src/components/DataDictionary/components/Entity/entity.tsx +18 -8
  129. package/src/components/DataDictionary/components/Entity/types.ts +4 -4
  130. package/src/components/DataDictionary/components/Entity/utils.ts +25 -0
  131. package/src/components/DataDictionary/components/Filters/components/ColumnFilters/columnFilters.tsx +21 -0
  132. package/src/components/DataDictionary/components/Filters/components/ColumnFilters/types.ts +6 -0
  133. package/src/components/DataDictionary/components/Filters/filters.styles.ts +14 -0
  134. package/src/components/DataDictionary/components/Filters/filters.tsx +16 -0
  135. package/src/components/DataDictionary/components/Filters/stories/constants.ts +31 -0
  136. package/src/components/DataDictionary/components/Filters/stories/filters.stories.tsx +42 -0
  137. package/src/components/DataDictionary/components/Filters/stories/hook.ts +9 -0
  138. package/src/components/DataDictionary/components/Filters/stories/types.ts +3 -0
  139. package/src/components/DataDictionary/components/Filters/types.ts +6 -0
  140. package/src/components/DataDictionary/components/Layout/components/EntitiesLayout/entitiesLayout.styles.ts +4 -1
  141. package/src/components/DataDictionary/components/Layout/components/FiltersLayout/filtersLayout.styles.ts +27 -0
  142. package/src/components/DataDictionary/components/Layout/components/FiltersLayout/filtersLayout.tsx +10 -0
  143. package/src/components/DataDictionary/components/Layout/components/FiltersLayout/types.ts +6 -0
  144. package/src/components/DataDictionary/components/Layout/components/OutlineLayout/outlineLayout.styles.ts +1 -1
  145. package/src/components/DataDictionary/components/Layout/components/TitleLayout/titleLayout.styles.ts +1 -0
  146. package/src/components/DataDictionary/components/Layout/constants.ts +4 -0
  147. package/src/components/DataDictionary/components/Outline/utils.ts +35 -13
  148. package/src/components/DataDictionary/components/Table/hook.ts +17 -5
  149. package/src/components/DataDictionary/components/Table/options/columnFilters/constants.ts +16 -0
  150. package/src/components/DataDictionary/components/Table/options/columnFilters/hook.ts +32 -0
  151. package/src/components/DataDictionary/components/Table/options/expanded/constants.ts +13 -0
  152. package/src/components/DataDictionary/components/Table/options/faceted/constants.ts +14 -0
  153. package/src/components/DataDictionary/components/Table/options/grouping/constants.ts +9 -0
  154. package/src/components/DataDictionary/components/Table/options/hook.ts +26 -3
  155. package/src/components/DataDictionary/components/Table/options/visibility/constants.ts +5 -0
  156. package/src/components/DataDictionary/components/Table/table.tsx +2 -0
  157. package/src/components/DataDictionary/components/Table/types.ts +8 -1
  158. package/src/components/DataDictionary/components/Table/utils.ts +40 -0
  159. package/src/components/DataDictionary/dataDictionary.tsx +10 -6
  160. package/src/components/DataDictionary/hooks/UseDataDictionary/hook.ts +19 -4
  161. package/src/components/DataDictionary/hooks/UseDataDictionary/types.ts +6 -4
  162. package/src/components/DataDictionary/types.ts +1 -0
  163. package/src/components/Detail/components/Table/components/TableBody/tableBody.tsx +14 -3
  164. package/src/components/Detail/components/Table/components/TableRows/components/CollapsableRows/collapsableRows.tsx +9 -2
  165. package/src/components/Detail/components/Table/components/TableRows/tableRows.tsx +9 -2
  166. package/src/components/Filter/components/FilterList/filterList.styles.ts +34 -15
  167. package/src/components/Layout/components/Header/header.styles.ts +6 -1
  168. package/src/components/Table/common/utils.ts +16 -0
  169. package/src/components/Table/components/TableFeatures/ColumnFilter/columnFilter.styles.ts +23 -0
  170. package/src/components/Table/components/TableFeatures/ColumnFilter/columnFilter.tsx +98 -0
  171. package/src/components/Table/components/TableFeatures/ColumnFilter/constants.ts +16 -0
  172. package/src/components/Table/components/TableFeatures/ColumnFilter/types.ts +10 -0
  173. package/src/components/Table/components/TableFeatures/ColumnFilter/utils.ts +27 -0
  174. package/src/components/Table/featureOptions/facetedColumn/utils.ts +14 -0
  175. package/src/components/common/ButtonGroup/constants.ts +13 -0
  176. package/src/mocks/@storybook/addon-actions.ts +10 -0
  177. package/src/styles/common/mui/buttonGroup.ts +46 -0
  178. package/src/styles/common/mui/typography.ts +2 -0
  179. package/src/tests/mui/constants.ts +1 -0
  180. package/src/tests/utils.ts +9 -0
  181. package/src/theme/common/components.ts +17 -32
  182. package/src/theme/components/index.ts +1 -0
  183. package/src/theme/components/muiButtonGroup.ts +79 -0
  184. package/src/theme/theme.ts +1 -1
  185. package/tests/dataDictionaryColumnFilters.test.tsx +101 -0
@@ -0,0 +1,40 @@
1
+ import { RowData } from "@tanstack/react-table";
2
+ import { Attribute, Class } from "../../../../common/entities";
3
+ import { ClassMeta } from "./types";
4
+
5
+ /**
6
+ * Builds class meta data from classes.
7
+ * Metadata is used to display class title and description above each "grouped" table.
8
+ * @param classes - Class entities.
9
+ * @returns Class meta data.
10
+ */
11
+ export const buildClassMeta = <T extends RowData = Attribute>(
12
+ classes: Class<T>[]
13
+ ): ClassMeta => {
14
+ return Object.fromEntries(
15
+ classes.map(({ description, name, title }) => [
16
+ name,
17
+ { description, title },
18
+ ])
19
+ );
20
+ };
21
+
22
+ /**
23
+ * Builds table data from classes.
24
+ * RowData contains attributes of a class and a classKey property `Class["name"]` to identify the class the row belongs to.
25
+ * `classKey` is used to group rows by class.
26
+ * @param classes - Class entities.
27
+ * @returns Table data.
28
+ */
29
+ export const buildTableData = <T extends RowData = Attribute>(
30
+ classes: Class<T>[]
31
+ ): T[] => {
32
+ return classes
33
+ .map(({ attributes, name: classKey }) =>
34
+ attributes.map((attribute) => ({
35
+ ...(attribute as unknown as Attribute),
36
+ classKey,
37
+ }))
38
+ )
39
+ .flat() as T[];
40
+ };
@@ -1,12 +1,13 @@
1
1
  import { RowData } from "@tanstack/react-table";
2
- import React, { useMemo } from "react";
2
+ import React from "react";
3
3
  import { Attribute } from "../../common/entities";
4
4
  import { Entities } from "./components/Entities/entities";
5
+ import { Filters } from "./components/Filters/filters";
5
6
  import { EntitiesLayout as DefaultEntitiesLayout } from "./components/Layout/components/EntitiesLayout/entitiesLayout";
7
+ import { FiltersLayout as DefaultFiltersLayout } from "./components/Layout/components/FiltersLayout/filtersLayout";
6
8
  import { OutlineLayout as DefaultOutlineLayout } from "./components/Layout/components/OutlineLayout/outlineLayout";
7
9
  import { TitleLayout as DefaultTitleLayout } from "./components/Layout/components/TitleLayout/titleLayout";
8
10
  import { Outline as DefaultOutline } from "./components/Outline/outline";
9
- import { buildClassesOutline } from "./components/Outline/utils";
10
11
  import { Title as DefaultTitle } from "./components/Title/title";
11
12
  import { View } from "./dataDictionary.styles";
12
13
  import { useDataDictionary } from "./hooks/UseDataDictionary/hook";
@@ -16,24 +17,27 @@ import { DataDictionaryProps } from "./types";
16
17
  export const DataDictionary = <T extends RowData = Attribute>({
17
18
  className,
18
19
  EntitiesLayout = DefaultEntitiesLayout,
20
+ FiltersLayout = DefaultFiltersLayout,
19
21
  Outline = DefaultOutline,
20
22
  OutlineLayout = DefaultOutlineLayout,
21
23
  Title = DefaultTitle,
22
24
  TitleLayout = DefaultTitleLayout,
23
25
  }: DataDictionaryProps): JSX.Element => {
24
- const { classes, columnDefs } = useDataDictionary<T>();
26
+ const { outline, table, title } = useDataDictionary<T>();
25
27
  const { spacing } = useLayoutSpacing();
26
- const outline = useMemo(() => buildClassesOutline(classes), [classes]);
27
28
  return (
28
29
  <View className={className}>
29
30
  <TitleLayout {...spacing}>
30
- <Title />
31
+ <Title title={title} />
31
32
  </TitleLayout>
32
33
  <OutlineLayout {...spacing}>
33
34
  <Outline outline={outline} />
34
35
  </OutlineLayout>
36
+ <FiltersLayout {...spacing}>
37
+ <Filters table={table} />
38
+ </FiltersLayout>
35
39
  <EntitiesLayout {...spacing}>
36
- <Entities classes={classes} columnDefs={columnDefs} spacing={spacing} />
40
+ <Entities spacing={spacing} table={table} />
37
41
  </EntitiesLayout>
38
42
  </View>
39
43
  );
@@ -2,6 +2,8 @@ import { RowData } from "@tanstack/react-table";
2
2
  import { useMemo } from "react";
3
3
  import { Attribute, DataDictionaryConfig } from "../../../../common/entities";
4
4
  import { useConfig } from "../../../../hooks/useConfig";
5
+ import { buildClassesOutline } from "../../components/Outline/utils";
6
+ import { useTable } from "../../components/Table/hook";
5
7
  import { UseDataDictionary } from "./types";
6
8
 
7
9
  export const useDataDictionary = <
@@ -11,13 +13,26 @@ export const useDataDictionary = <
11
13
  config: { dataDictionaries: dataDictionaryConfigs },
12
14
  } = useConfig();
13
15
 
16
+ // Get dictionary config.
14
17
  const dataDictionaryConfig = dataDictionaryConfigs?.[0] as
15
18
  | DataDictionaryConfig<T>
16
19
  | undefined; // TODO: Handle multiple data dictionaries
17
20
 
18
- return useMemo(() => {
19
- const classes = dataDictionaryConfig?.dataDictionary?.classes || [];
20
- const columnDefs = dataDictionaryConfig?.columnDefs || [];
21
- return { classes, columnDefs };
21
+ // Get configured dictionary classes, column definitions and table options.
22
+ const { classes, columnDefs, tableOptions, title } = useMemo(() => {
23
+ return {
24
+ classes: dataDictionaryConfig?.dataDictionary?.classes || [],
25
+ columnDefs: dataDictionaryConfig?.columnDefs || [],
26
+ tableOptions: dataDictionaryConfig?.tableOptions || {},
27
+ title: dataDictionaryConfig?.dataDictionary?.title || "",
28
+ };
22
29
  }, [dataDictionaryConfig]);
30
+
31
+ // Build table instance.
32
+ const table = useTable<T>(classes, columnDefs, tableOptions);
33
+
34
+ // Build outline.
35
+ const outline = buildClassesOutline<T>(table);
36
+
37
+ return { outline, table, title };
23
38
  };
@@ -1,7 +1,9 @@
1
- import { ColumnDef, RowData } from "@tanstack/react-table";
2
- import { Attribute, Class } from "../../../../common/entities";
1
+ import { RowData, Table } from "@tanstack/react-table";
2
+ import { Attribute } from "../../../../common/entities";
3
+ import { OutlineItem } from "../../../Layout/components/Outline/types";
3
4
 
4
5
  export interface UseDataDictionary<T extends RowData = Attribute> {
5
- classes: Class<T>[];
6
- columnDefs: ColumnDef<T, T[keyof T]>[];
6
+ outline: OutlineItem[];
7
+ table: Table<T>;
8
+ title: string;
7
9
  }
@@ -3,6 +3,7 @@ import { BaseComponentProps } from "../types";
3
3
 
4
4
  export interface DataDictionaryProps extends BaseComponentProps {
5
5
  EntitiesLayout?: ElementType;
6
+ FiltersLayout?: ElementType;
6
7
  Outline?: ElementType;
7
8
  OutlineLayout?: ElementType;
8
9
  Title?: ElementType;
@@ -1,5 +1,5 @@
1
1
  import { TableBody as MTableBody } from "@mui/material";
2
- import { RowData, Table } from "@tanstack/react-table";
2
+ import { Row, RowData, Table } from "@tanstack/react-table";
3
3
  import React from "react";
4
4
  import { ROW_DIRECTION } from "../../../../../Table/common/entities";
5
5
  import { TableView } from "../../table";
@@ -8,21 +8,32 @@ import { TableRows } from "../TableRows/tableRows";
8
8
 
9
9
  export interface TableBodyProps<T extends RowData> {
10
10
  rowDirection: ROW_DIRECTION;
11
+ /**
12
+ * Optional override for the rows rendered by <TableBody>.
13
+ * - Omit to show the table’s full leaf-level row model.
14
+ * - Pass `group.subRows` (or any other subset) to display a “mini-table” for a single group e.g. the rows that belong to one Data-Dictionary entity.
15
+ */
16
+ rows?: Row<T>[];
11
17
  tableInstance: Table<T>;
12
18
  tableView?: TableView;
13
19
  }
14
20
 
15
21
  export const TableBody = <T extends RowData>({
16
22
  rowDirection,
23
+ rows,
17
24
  tableInstance,
18
25
  tableView,
19
26
  }: TableBodyProps<T>): JSX.Element => {
20
27
  return (
21
28
  <MTableBody>
22
29
  {rowDirection === ROW_DIRECTION.DEFAULT ? (
23
- <TableRows tableInstance={tableInstance} tableView={tableView} />
30
+ <TableRows
31
+ rows={rows}
32
+ tableInstance={tableInstance}
33
+ tableView={tableView}
34
+ />
24
35
  ) : (
25
- <CollapsableRows tableInstance={tableInstance} />
36
+ <CollapsableRows rows={rows} tableInstance={tableInstance} />
26
37
  )}
27
38
  </MTableBody>
28
39
  );
@@ -1,4 +1,4 @@
1
- import { RowData, Table } from "@tanstack/react-table";
1
+ import { Row, RowData, Table } from "@tanstack/react-table";
2
2
  import React, { Fragment } from "react";
3
3
  import { isCollapsableRowDisabled } from "../../../../../../../Table/common/utils";
4
4
  import { CollapsableCell } from "../../../../../../../Table/components/TableCell/components/CollapsableCell/collapsableCell";
@@ -6,10 +6,17 @@ import { TableRow } from "../../../../../../../Table/components/TableRow/tableRo
6
6
  import { useCollapsableRows } from "../../../../../../../Table/components/TableRows/components/CollapsableRows/hook";
7
7
 
8
8
  export interface CollapsableRowsProps<T extends RowData> {
9
+ /**
10
+ * Optional override for the rows rendered by <CollapsableRows>.
11
+ * - Omit to show the table’s full leaf-level row model.
12
+ * - Pass `group.subRows` (or any other subset) to display a “mini-table” for a single group e.g. the rows that belong to one Data-Dictionary entity.
13
+ */
14
+ rows?: Row<T>[];
9
15
  tableInstance: Table<T>;
10
16
  }
11
17
 
12
18
  export const CollapsableRows = <T extends RowData>({
19
+ rows: leafOrSubRows,
13
20
  tableInstance,
14
21
  }: CollapsableRowsProps<T>): JSX.Element => {
15
22
  const { getRowModel } = tableInstance;
@@ -17,7 +24,7 @@ export const CollapsableRows = <T extends RowData>({
17
24
  useCollapsableRows(tableInstance);
18
25
  return (
19
26
  <Fragment>
20
- {rows.map((row) => {
27
+ {(leafOrSubRows || rows).map((row) => {
21
28
  if (row.depth > 0) return null; // Hide sub rows.
22
29
  return (
23
30
  <TableRow key={row.id} isPreview={row.getIsPreview()}>
@@ -1,5 +1,5 @@
1
1
  import { TableCell } from "@mui/material";
2
- import { flexRender, RowData, Table } from "@tanstack/react-table";
2
+ import { flexRender, Row, RowData, Table } from "@tanstack/react-table";
3
3
  import React, { Fragment } from "react";
4
4
  import {
5
5
  getTableCellAlign,
@@ -9,11 +9,18 @@ import { TableRow } from "../../../../../Table/components/TableRow/tableRow.styl
9
9
  import { TableView } from "../../table";
10
10
 
11
11
  export interface TableRowsProps<T extends RowData> {
12
+ /**
13
+ * Optional override for the rows rendered by <TableRows>.
14
+ * - Omit to show the table’s full leaf-level row model.
15
+ * - Pass `group.subRows` (or any other subset) to display a “mini-table” for a single group e.g. the rows that belong to one Data-Dictionary entity.
16
+ */
17
+ rows?: Row<T>[];
12
18
  tableInstance: Table<T>;
13
19
  tableView?: TableView;
14
20
  }
15
21
 
16
22
  export const TableRows = <T extends RowData>({
23
+ rows: leafOrSubRows,
17
24
  tableInstance,
18
25
  tableView,
19
26
  }: TableRowsProps<T>): JSX.Element => {
@@ -23,7 +30,7 @@ export const TableRows = <T extends RowData>({
23
30
  const { size: tableCellSize = "medium" } = tableCell || {};
24
31
  return (
25
32
  <Fragment>
26
- {rows.map((row) => {
33
+ {(leafOrSubRows || rows).map((row) => {
27
34
  return (
28
35
  <TableRow
29
36
  key={row.id}
@@ -1,7 +1,38 @@
1
+ import { css } from "@emotion/react";
1
2
  import styled from "@emotion/styled";
2
- import { List as MList } from "@mui/material";
3
+ import {
4
+ listItemButtonClasses,
5
+ listItemTextClasses,
6
+ List as MList,
7
+ } from "@mui/material";
8
+ import { PALETTE } from "../../../../styles/common/constants/palette";
3
9
  import { LIST_MARGIN } from "../../common/constants";
4
10
 
11
+ export const MuiListItemButtonRoot = css`
12
+ .${listItemButtonClasses.root} {
13
+ gap: 8px;
14
+ padding: 10px 16px;
15
+
16
+ &.Mui-disabled {
17
+ color: ${PALETTE.SMOKE_MAIN};
18
+ opacity: 1;
19
+ }
20
+ }
21
+ `;
22
+
23
+ export const MuiListItemTextRoot = css`
24
+ .${listItemTextClasses.root} {
25
+ align-items: center;
26
+ display: grid;
27
+ gap: 8px;
28
+ grid-template-columns: 1fr auto;
29
+
30
+ > span {
31
+ min-width: 0; /* required; flexbox child min-width property is "auto" by default making overflow-wrap ineffectual */
32
+ }
33
+ }
34
+ `;
35
+
5
36
  export const List = styled(MList)`
6
37
  && {
7
38
  overflow-wrap: break-word;
@@ -20,20 +51,8 @@ export const List = styled(MList)`
20
51
  }
21
52
 
22
53
  // List item
23
- .MuiListItemButton-root {
24
- gap: 8px;
25
- padding: 10px 16px;
26
- }
54
+ ${MuiListItemButtonRoot}
27
55
 
28
56
  // List item text
29
- .MuiListItemText-root {
30
- align-items: center;
31
- display: grid;
32
- gap: 8px;
33
- grid-template-columns: 1fr auto;
34
-
35
- > span {
36
- min-width: 0; /* required; flexbox child min-width property is "auto" by default making overflow-wrap ineffectual */
37
- }
38
- }
57
+ ${MuiListItemTextRoot}
39
58
  `;
@@ -4,6 +4,11 @@ import { AppBar as MAppBar } from "@mui/material";
4
4
  import { smokeMain } from "../../../../styles/common/mixins/colors";
5
5
  import { HEADER_HEIGHT } from "./common/constants";
6
6
 
7
+ // See https://github.com/emotion-js/emotion/issues/1105.
8
+ // See https://github.com/emotion-js/emotion/releases/tag/%40emotion%2Fcache%4011.10.2.
9
+ const ignoreSsrWarning =
10
+ "/* emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason */";
11
+
7
12
  export const AppBar = styled(MAppBar)`
8
13
  border-bottom: 1px solid ${smokeMain};
9
14
 
@@ -34,7 +39,7 @@ export const Left = styled.div`
34
39
  justify-content: flex-start;
35
40
 
36
41
  .MuiButton-navPrimary {
37
- &:first-of-type {
42
+ &:first-child:not(style)${ignoreSsrWarning} { {
38
43
  margin-left: 24px;
39
44
  }
40
45
  }
@@ -84,6 +84,22 @@ export function buildCategoryViews<T extends RowData>(
84
84
  return categoryViews;
85
85
  }
86
86
 
87
+ /**
88
+ * Returns the header for a column as a string.
89
+ * @param column - Column.
90
+ * @returns column header.
91
+ */
92
+ export function getColumnHeader<T extends RowData>(column: Column<T>): string {
93
+ const { columnDef, id = "" } = column;
94
+ const { header, meta } = columnDef;
95
+
96
+ // Return header if it is a string.
97
+ if (typeof header === "string") return header;
98
+
99
+ // Return header from meta or id.
100
+ return meta?.header || id;
101
+ }
102
+
87
103
  /**
88
104
  * Format data to TSV string.
89
105
  * @param data - Table data.
@@ -0,0 +1,23 @@
1
+ import styled from "@emotion/styled";
2
+ import { Menu, menuClasses, paperClasses } from "@mui/material";
3
+ import { MAX_LIST_HEIGHT_PX } from "../../../../Filter/common/constants";
4
+ import {
5
+ MuiListItemButtonRoot,
6
+ MuiListItemTextRoot,
7
+ } from "../../../../Filter/components/FilterList/filterList.styles";
8
+
9
+ export const StyledMenu = styled(Menu)`
10
+ .${paperClasses.root} {
11
+ margin: 4px 0;
12
+ width: 288px;
13
+
14
+ .${menuClasses.list} {
15
+ max-height: ${MAX_LIST_HEIGHT_PX}px;
16
+ overflow-wrap: break-word;
17
+
18
+ ${MuiListItemButtonRoot}
19
+
20
+ ${MuiListItemTextRoot}
21
+ }
22
+ }
23
+ `;
@@ -0,0 +1,98 @@
1
+ import {
2
+ Checkbox,
3
+ ListItemButton,
4
+ ListItemText,
5
+ Button as MButton,
6
+ Typography,
7
+ } from "@mui/material";
8
+ import { RowData } from "@tanstack/react-table";
9
+ import React, { Fragment } from "react";
10
+ import { SVG_ICON_PROPS } from "../../../../../styles/common/mui/svgIcon";
11
+ import { TYPOGRAPHY_PROPS } from "../../../../../styles/common/mui/typography";
12
+ import { CheckedIcon } from "../../../../common/CustomIcon/components/CheckedIcon/checkedIcon";
13
+ import { UncheckedIcon } from "../../../../common/CustomIcon/components/UncheckedIcon/uncheckedIcon";
14
+ import { DropDownIcon } from "../../../../common/Form/components/Select/components/DropDownIcon/dropDownIcon";
15
+ import { useMenu } from "../../../../common/Menu/hooks/useMenu";
16
+ import { getColumnHeader } from "../../../common/utils";
17
+ import { getSortedFacetedValues } from "../../../featureOptions/facetedColumn/utils";
18
+ import { StyledMenu } from "./columnFilter.styles";
19
+ import { MENU_PROPS } from "./constants";
20
+ import { ColumnFilterProps } from "./types";
21
+ import { updater } from "./utils";
22
+
23
+ /**
24
+ * Column filter component with supported filter functions:
25
+ * - `arrIncludesSome`
26
+ */
27
+
28
+ export const ColumnFilter = <T extends RowData>({
29
+ Button = MButton,
30
+ className,
31
+ column,
32
+ ...props /* MuiMenuProps */
33
+ }: ColumnFilterProps<T>): JSX.Element => {
34
+ const { anchorEl, onClose, onOpen, open } = useMenu();
35
+ const facetedUniqueValues = column.getFacetedUniqueValues();
36
+ const sortedValues = getSortedFacetedValues(facetedUniqueValues);
37
+ const filterValue = (column.getFilterValue() || []) as unknown[];
38
+ return (
39
+ <Fragment>
40
+ <Button
41
+ key={column.id}
42
+ endIcon={<DropDownIcon color={SVG_ICON_PROPS.COLOR.INK_LIGHT} />}
43
+ onClick={onOpen}
44
+ >
45
+ {getColumnHeader(column)}
46
+ </Button>
47
+ <StyledMenu
48
+ {...MENU_PROPS}
49
+ {...props}
50
+ className={className}
51
+ anchorEl={anchorEl}
52
+ onClose={onClose}
53
+ open={open}
54
+ >
55
+ {sortedValues.map(([value, occurrence]) => (
56
+ <ListItemButton
57
+ key={String(value)}
58
+ selected={filterValue.includes(value)}
59
+ onClick={() => column.setFilterValue(updater(value))}
60
+ >
61
+ <Checkbox
62
+ checked={filterValue.includes(value)}
63
+ checkedIcon={<CheckedIcon />}
64
+ icon={<UncheckedIcon />}
65
+ />
66
+ <ListItemText
67
+ disableTypography
68
+ primary={<span>{String(value)}</span>}
69
+ secondary={
70
+ <Typography
71
+ color={TYPOGRAPHY_PROPS.COLOR.INK_LIGHT}
72
+ variant={TYPOGRAPHY_PROPS.VARIANT.TEXT_BODY_SMALL_400}
73
+ >
74
+ {occurrence}
75
+ </Typography>
76
+ }
77
+ />
78
+ </ListItemButton>
79
+ ))}
80
+ <ListItemButton
81
+ disabled={!column.getIsFiltered()}
82
+ onClick={() => column.setFilterValue(undefined)}
83
+ >
84
+ <Typography
85
+ color={
86
+ column.getIsFiltered()
87
+ ? TYPOGRAPHY_PROPS.COLOR.PRIMARY
88
+ : TYPOGRAPHY_PROPS.COLOR.INHERIT
89
+ }
90
+ variant={TYPOGRAPHY_PROPS.VARIANT.TEXT_BODY_500}
91
+ >
92
+ Clear All
93
+ </Typography>
94
+ </ListItemButton>
95
+ </StyledMenu>
96
+ </Fragment>
97
+ );
98
+ };
@@ -0,0 +1,16 @@
1
+ import { MenuProps } from "@mui/material";
2
+
3
+ export const MENU_PROPS: Omit<MenuProps, "anchorEl" | "onClose" | "open"> = {
4
+ anchorOrigin: {
5
+ horizontal: "right",
6
+ vertical: "bottom",
7
+ },
8
+ marginThreshold: 8,
9
+ slotProps: {
10
+ paper: { variant: "menu" },
11
+ },
12
+ transformOrigin: {
13
+ horizontal: "right",
14
+ vertical: "top",
15
+ },
16
+ };
@@ -0,0 +1,10 @@
1
+ import { Button, MenuProps } from "@mui/material";
2
+ import { Column, RowData } from "@tanstack/react-table";
3
+ import { BaseComponentProps } from "../../../../types";
4
+
5
+ export interface ColumnFilterProps<T extends RowData>
6
+ extends BaseComponentProps,
7
+ Omit<MenuProps, "anchorEl" | "onClose" | "open"> {
8
+ Button?: typeof Button;
9
+ column: Column<T>;
10
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Returns an updater function for column filter.
3
+ * @param value - Value.
4
+ * @returns An updater function that returns the new filter value.
5
+ */
6
+ export function updater(
7
+ value: unknown
8
+ ): (old: unknown[] | undefined) => unknown[] | undefined {
9
+ return (old: unknown[] | undefined) => {
10
+ // If no old value, return new value.
11
+ if (!old) return [value];
12
+
13
+ // If value already exists, remove it.
14
+ if (old.includes(value)) {
15
+ // Filter out the value.
16
+ const next = old.filter((v) => v !== value);
17
+
18
+ // If no values remain, return undefined.
19
+ if (next.length === 0) return undefined;
20
+
21
+ return next;
22
+ }
23
+
24
+ // Otherwise, add the value.
25
+ return [...old, value];
26
+ };
27
+ }
@@ -0,0 +1,14 @@
1
+ import { COLLATOR_CASE_INSENSITIVE } from "../../../../common/constants";
2
+
3
+ /**
4
+ * Sorts Map entries by key.
5
+ * @param facetedValues - Map of faceted values.
6
+ * @returns Sorted array of [key, value] entries.
7
+ */
8
+ export function getSortedFacetedValues(
9
+ facetedValues: Map<unknown, number>
10
+ ): [unknown, number][] {
11
+ return [...facetedValues].sort((a, b) =>
12
+ COLLATOR_CASE_INSENSITIVE.compare(String(a), String(b))
13
+ );
14
+ }
@@ -0,0 +1,13 @@
1
+ import { ButtonGroupProps } from "@mui/material";
2
+ import { BUTTON_GROUP_PROPS as MUI_BUTTON_GROUP_PROPS } from "../../../styles/common/mui/buttonGroup";
3
+
4
+ export const BUTTON_GROUP_PROPS: Record<string, Partial<ButtonGroupProps>> = {
5
+ PRIMARY_CONTAINED: {
6
+ color: MUI_BUTTON_GROUP_PROPS.COLOR.PRIMARY,
7
+ variant: MUI_BUTTON_GROUP_PROPS.VARIANT.CONTAINED,
8
+ },
9
+ SECONDARY_OUTLINED: {
10
+ color: MUI_BUTTON_GROUP_PROPS.COLOR.SECONDARY,
11
+ variant: MUI_BUTTON_GROUP_PROPS.VARIANT.OUTLINED,
12
+ },
13
+ };
@@ -0,0 +1,10 @@
1
+ import { jest } from "@jest/globals";
2
+
3
+ /**
4
+ * Mock for Storybook's @storybook/addon-actions function.
5
+ * The mock keeps the same function signature as the real Storybook action,
6
+ * does not trigger any Storybook logic, and simply returns a Jest mock function
7
+ * for use in tests.
8
+ * @returns A Jest mock function.
9
+ */
10
+ export const action = (): jest.Mock => jest.fn();
@@ -0,0 +1,46 @@
1
+ import { buttonGroupClasses, ButtonGroupProps } from "@mui/material";
2
+
3
+ type ButtonGroupPropsOptions = {
4
+ CLASSES: typeof CLASSES;
5
+ COLOR: typeof COLOR;
6
+ SIZE: typeof SIZE;
7
+ VARIANT: typeof VARIANT;
8
+ };
9
+
10
+ const CLASSES: Record<string, ButtonGroupProps["classes"]> = {
11
+ COLOR_PRIMARY: buttonGroupClasses.colorPrimary,
12
+ COLOR_SECONDARY: buttonGroupClasses.colorSecondary,
13
+ CONTAINED: buttonGroupClasses.contained,
14
+ GROUPED: buttonGroupClasses.grouped,
15
+ OUTLINED: buttonGroupClasses.outlined,
16
+ ROOT: buttonGroupClasses.root,
17
+ };
18
+
19
+ const COLOR: Record<string, ButtonGroupProps["color"]> = {
20
+ ERROR: "error",
21
+ INFO: "info",
22
+ INHERIT: "inherit",
23
+ PRIMARY: "primary",
24
+ SECONDARY: "secondary",
25
+ SUCCESS: "success",
26
+ WARNING: "warning",
27
+ };
28
+
29
+ const SIZE: Record<string, ButtonGroupProps["size"]> = {
30
+ LARGE: "large",
31
+ MEDIUM: "medium",
32
+ SMALL: "small",
33
+ };
34
+
35
+ const VARIANT: Record<string, ButtonGroupProps["variant"]> = {
36
+ CONTAINED: "contained",
37
+ OUTLINED: "outlined",
38
+ TEXT: "text",
39
+ };
40
+
41
+ export const BUTTON_GROUP_PROPS: ButtonGroupPropsOptions = {
42
+ CLASSES,
43
+ COLOR,
44
+ SIZE,
45
+ VARIANT,
46
+ };
@@ -10,12 +10,14 @@ const COLOR: Record<string, TypographyOwnProps["color"]> = {
10
10
  INHERIT: "inherit",
11
11
  INK_LIGHT: "ink.light",
12
12
  INK_MAIN: "ink.main",
13
+ PRIMARY: "primary",
13
14
  };
14
15
 
15
16
  const VARIANT: Record<string, TypographyOwnProps["variant"]> = {
16
17
  INHERIT: "inherit",
17
18
  TEXT_BODY_400: "text-body-400",
18
19
  TEXT_BODY_400_2_LINES: "text-body-400-2lines",
20
+ TEXT_BODY_500: "text-body-500",
19
21
  TEXT_BODY_SMALL_400: "text-body-small-400",
20
22
  TEXT_HEADING_LARGE: "text-heading-large",
21
23
  TEXT_HEADING_SMALL: "text-heading-small",
@@ -1,5 +1,6 @@
1
1
  export const MUI_CLASSES = {
2
2
  ACTIVE: "Mui-active",
3
3
  COMPLETED: "Mui-completed",
4
+ DISABLED: "Mui-disabled",
4
5
  SELECTED: "Mui-selected",
5
6
  };