@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
@@ -4,28 +4,37 @@ import React from "react";
4
4
  import { Attribute } from "../../../../common/entities";
5
5
  import { TYPOGRAPHY_PROPS } from "../../../../styles/common/mui/typography";
6
6
  import { AnchorLink } from "../../../common/AnchorLink/anchorLink";
7
- import { useTable } from "../Table/hook";
8
7
  import { Table } from "../Table/table";
9
8
  import { GRID_PROPS } from "./constants";
10
9
  import { StyledTypography } from "./entity.styles";
11
10
  import { EntityProps } from "./types";
11
+ import { getClassMeta } from "./utils";
12
12
 
13
13
  export const Entity = <T extends RowData = Attribute>({
14
- class: cls,
15
- columnDefs,
14
+ row,
16
15
  spacing,
17
- }: EntityProps<T>): JSX.Element => {
18
- const table = useTable<T>(cls.attributes, columnDefs);
16
+ table,
17
+ }: EntityProps<T>): JSX.Element | null => {
18
+ // Get class key from row.
19
+ const classKey = row.getValue<string>("classKey");
20
+
21
+ // Get class metadata from table options.
22
+ const cls = getClassMeta<T>(classKey, table);
23
+
24
+ // Class not found in table meta - return null.
25
+ if (!cls) return null;
26
+
19
27
  return (
20
28
  <Grid {...GRID_PROPS} rowGap={4}>
29
+ {/* Class title and description */}
21
30
  <Grid {...GRID_PROPS} rowGap={1}>
22
31
  <StyledTypography
23
32
  component="h3"
24
- id={cls.name}
33
+ id={classKey}
25
34
  variant={TYPOGRAPHY_PROPS.VARIANT.TEXT_HEADING_SMALL}
26
35
  {...spacing}
27
36
  >
28
- {cls.title} <AnchorLink anchorLink={cls.name} />
37
+ {cls.title} <AnchorLink anchorLink={classKey} />
29
38
  </StyledTypography>
30
39
  <Typography
31
40
  color={TYPOGRAPHY_PROPS.COLOR.INK_LIGHT}
@@ -35,7 +44,8 @@ export const Entity = <T extends RowData = Attribute>({
35
44
  {cls.description}
36
45
  </Typography>
37
46
  </Grid>
38
- <Table table={table} />
47
+ {/* Class attributes table */}
48
+ <Table row={row} table={table} />
39
49
  </Grid>
40
50
  );
41
51
  };
@@ -1,9 +1,9 @@
1
- import { ColumnDef, RowData } from "@tanstack/react-table";
2
- import { Attribute, Class } from "../../../../common/entities";
1
+ import { Row, RowData, Table } from "@tanstack/react-table";
2
+ import { Attribute } from "../../../../common/entities";
3
3
  import { LayoutSpacing } from "../../hooks/UseLayoutSpacing/types";
4
4
 
5
5
  export interface EntityProps<T extends RowData = Attribute> {
6
- class: Class<T>;
7
- columnDefs: ColumnDef<T, T[keyof T]>[];
6
+ row: Row<T>;
8
7
  spacing?: LayoutSpacing;
8
+ table: Table<T>;
9
9
  }
@@ -0,0 +1,25 @@
1
+ import { RowData, Table } from "@tanstack/react-table";
2
+ import { Attribute, Class } from "../../../../common/entities";
3
+ import { ClassMeta } from "../Table/types";
4
+
5
+ /**
6
+ * Retrieves class metadata from the table options meta.
7
+ * @param classKey - Class key.
8
+ * @param table - Table instance.
9
+ * @returns Class metadata or undefined.
10
+ */
11
+ export function getClassMeta<T extends RowData = Attribute>(
12
+ classKey: string | undefined,
13
+ table: Table<T>
14
+ ): Pick<Class<T>, "description" | "title"> | undefined {
15
+ if (!classKey) return;
16
+
17
+ // Grab the table meta and return if not defined.
18
+ const meta = table.options.meta;
19
+ if (!meta) return;
20
+
21
+ // Return class metadata if defined.
22
+ if ("classMeta" in meta) {
23
+ return (meta.classMeta as ClassMeta)?.[classKey];
24
+ }
25
+ }
@@ -0,0 +1,21 @@
1
+ import { ButtonGroup } from "@mui/material";
2
+ import { RowData } from "@tanstack/react-table";
3
+ import React from "react";
4
+ import { Attribute } from "../../../../../../common/entities";
5
+ import { BUTTON_GROUP_PROPS } from "../../../../../common/ButtonGroup/constants";
6
+ import { ColumnFilter } from "../../../../../Table/components/TableFeatures/ColumnFilter/columnFilter";
7
+ import { ColumnFiltersProps } from "./types";
8
+
9
+ export const ColumnFilters = <T extends RowData = Attribute>({
10
+ table,
11
+ }: ColumnFiltersProps<T>): JSX.Element => {
12
+ const columns = table.getAllColumns();
13
+ const columnFilters = columns.filter((column) => column.getCanFilter());
14
+ return (
15
+ <ButtonGroup {...BUTTON_GROUP_PROPS.SECONDARY_OUTLINED}>
16
+ {columnFilters.map((column) => (
17
+ <ColumnFilter key={column.id} column={column} />
18
+ ))}
19
+ </ButtonGroup>
20
+ );
21
+ };
@@ -0,0 +1,6 @@
1
+ import { RowData, Table } from "@tanstack/react-table";
2
+ import { Attribute } from "../../../../../../common/entities";
3
+
4
+ export interface ColumnFiltersProps<T extends RowData = Attribute> {
5
+ table: Table<T>;
6
+ }
@@ -0,0 +1,14 @@
1
+ import styled from "@emotion/styled";
2
+ import { Grid } from "@mui/material";
3
+ import { BUTTON_GROUP_PROPS } from "../../../../styles/common/mui/buttonGroup";
4
+
5
+ export const StyledGrid = styled(Grid)`
6
+ align-items: center;
7
+ display: grid;
8
+ gap: 16px;
9
+ grid-template-columns: 1fr auto;
10
+
11
+ .${BUTTON_GROUP_PROPS.CLASSES.ROOT} {
12
+ grid-column: 2;
13
+ }
14
+ `;
@@ -0,0 +1,16 @@
1
+ import { RowData } from "@tanstack/react-table";
2
+ import React from "react";
3
+ import { Attribute } from "../../../../common/entities";
4
+ import { ColumnFilters } from "./components/ColumnFilters/columnFilters";
5
+ import { StyledGrid } from "./filters.styles";
6
+ import { FiltersProps } from "./types";
7
+
8
+ export const Filters = <T extends RowData = Attribute>({
9
+ table,
10
+ }: FiltersProps<T>): JSX.Element => {
11
+ return (
12
+ <StyledGrid>
13
+ <ColumnFilters table={table} />
14
+ </StyledGrid>
15
+ );
16
+ };
@@ -0,0 +1,31 @@
1
+ import { PartialColumn } from "./types";
2
+
3
+ export const BIONETWORK: PartialColumn = {
4
+ columnDef: { header: "BioNetwork" },
5
+ getCanFilter: () => true,
6
+ getFacetedUniqueValues: () =>
7
+ new Map([
8
+ ["Nervous System", 3],
9
+ ["Brain", 2],
10
+ ["Lung", 1],
11
+ ]),
12
+ id: "bioNetwork",
13
+ };
14
+
15
+ export const EXAMPLE: PartialColumn = {
16
+ columnDef: { header: "Example" },
17
+ getCanFilter: () => false,
18
+ getFacetedUniqueValues: () => new Map([["EFO:0008563", 1]]),
19
+ id: "example",
20
+ };
21
+
22
+ export const REQUIRED: PartialColumn = {
23
+ columnDef: { header: "Required" },
24
+ getCanFilter: () => true,
25
+ getFacetedUniqueValues: () =>
26
+ new Map([
27
+ ["Required", 16],
28
+ ["Not Required", 30],
29
+ ]),
30
+ id: "required",
31
+ };
@@ -0,0 +1,42 @@
1
+ import { action } from "@storybook/addon-actions";
2
+ import { Meta, StoryObj } from "@storybook/react";
3
+ import { functionalUpdate, Table } from "@tanstack/react-table";
4
+ import React from "react";
5
+ import { Filters } from "../filters";
6
+ import { BIONETWORK, EXAMPLE, REQUIRED } from "./constants";
7
+ import { useFilterStore } from "./hook";
8
+ import { PartialColumn } from "./types";
9
+
10
+ const meta: Meta<typeof Filters> = {
11
+ component: Filters,
12
+ };
13
+
14
+ export default meta;
15
+
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ const DefaultStory = (): JSX.Element => {
19
+ const { filterStore, setFilterStore } = useFilterStore();
20
+
21
+ const makeColumn = (column: PartialColumn): PartialColumn => ({
22
+ ...column,
23
+ getFilterValue: () => filterStore[column.id],
24
+ getIsFiltered: () => !!filterStore[column.id],
25
+ setFilterValue: (updaterOrValue: unknown): unknown => {
26
+ const next = functionalUpdate(updaterOrValue, filterStore[column.id]);
27
+ setFilterStore({ ...filterStore, [column.id]: next });
28
+ action("setFilterValue")(next);
29
+ return next;
30
+ },
31
+ });
32
+
33
+ const table = {
34
+ getAllColumns: () => [REQUIRED, BIONETWORK, EXAMPLE].map(makeColumn),
35
+ } as Table<unknown>;
36
+
37
+ return <Filters table={table} />;
38
+ };
39
+
40
+ export const Default: Story = {
41
+ render: () => <DefaultStory />,
42
+ };
@@ -0,0 +1,9 @@
1
+ import { Dispatch, SetStateAction, useState } from "react";
2
+
3
+ export function useFilterStore(): {
4
+ filterStore: Record<string, unknown>;
5
+ setFilterStore: Dispatch<SetStateAction<Record<string, unknown>>>;
6
+ } {
7
+ const [filterStore, setFilterStore] = useState<Record<string, unknown>>({});
8
+ return { filterStore, setFilterStore };
9
+ }
@@ -0,0 +1,3 @@
1
+ import { Column } from "@tanstack/react-table";
2
+
3
+ export type PartialColumn = Partial<Column<unknown>> & { id: string };
@@ -0,0 +1,6 @@
1
+ import { RowData, Table } from "@tanstack/react-table";
2
+ import { Attribute } from "../../../../common/entities";
3
+
4
+ export interface FiltersProps<T extends RowData = Attribute> {
5
+ table: Table<T>;
6
+ }
@@ -5,13 +5,16 @@ import { LAYOUT_SPACING } from "../../constants";
5
5
 
6
6
  const PB = LAYOUT_SPACING.CONTENT_PADDING_BOTTOM; /* bottom padding */
7
7
  const PT = LAYOUT_SPACING.CONTENT_PADDING_TOP; /* top padding */
8
+ const FILTERS_HEIGHT =
9
+ LAYOUT_SPACING.FILTERS_HEIGHT +
10
+ LAYOUT_SPACING.FILTERS_PADDING_TOP; /* filters height */
8
11
  const TITLE_HEIGHT = LAYOUT_SPACING.TITLE_HEIGHT; /* title height */
9
12
 
10
13
  export const Layout = styled("div")<LayoutSpacing>`
11
14
  grid-column: 2;
12
15
  grid-row: 1;
13
16
  padding-bottom: ${PB}px;
14
- padding-top: ${({ top }) => top + TITLE_HEIGHT + PT}px;
17
+ padding-top: ${({ top }) => top + TITLE_HEIGHT + FILTERS_HEIGHT + PT}px;
15
18
  z-index: 1; /* not required, but helpful in that the entities are always on top */
16
19
 
17
20
  ${mediaTabletDown} {
@@ -0,0 +1,27 @@
1
+ import styled from "@emotion/styled";
2
+ import { PALETTE } from "../../../../../../styles/common/constants/palette";
3
+ import { mediaTabletDown } from "../../../../../../styles/common/mixins/breakpoints";
4
+ import { LayoutSpacing } from "../../../../hooks/UseLayoutSpacing/types";
5
+ import { LAYOUT_SPACING } from "../../constants";
6
+
7
+ const PB = LAYOUT_SPACING.FILTERS_PADDING_BOTTOM; /* bottom padding */
8
+ const PT = LAYOUT_SPACING.FILTERS_PADDING_TOP; /* top padding */
9
+ const TITLE_HEIGHT = LAYOUT_SPACING.TITLE_HEIGHT; /* title height */
10
+
11
+ export const Layout = styled("div")<LayoutSpacing>`
12
+ align-self: flex-start;
13
+ background-color: ${PALETTE.BACKGROUND_DEFAULT};
14
+ grid-column: 2;
15
+ grid-row: 1;
16
+ margin-bottom: ${PB}px;
17
+ padding-top: ${({ top }) => top + TITLE_HEIGHT + PT}px;
18
+ position: sticky;
19
+ top: 0;
20
+ z-index: 2; /* required, filters should be on top of entities */
21
+
22
+ ${mediaTabletDown} {
23
+ grid-column: 1;
24
+ grid-row: auto;
25
+ padding-top: ${PT}px;
26
+ }
27
+ `;
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { Layout } from "./filtersLayout.styles";
3
+ import { FiltersLayoutProps } from "./types";
4
+
5
+ export const FiltersLayout = ({
6
+ children,
7
+ ...props
8
+ }: FiltersLayoutProps): JSX.Element => {
9
+ return <Layout {...props}>{children}</Layout>;
10
+ };
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from "react";
2
+ import { LayoutSpacing } from "../../../../hooks/UseLayoutSpacing/types";
3
+
4
+ export interface FiltersLayoutProps extends LayoutSpacing {
5
+ children: ReactNode;
6
+ }
@@ -4,7 +4,7 @@ import { LayoutSpacing } from "../../../../hooks/UseLayoutSpacing/types";
4
4
  import { LAYOUT_SPACING } from "../../constants";
5
5
 
6
6
  const PB = LAYOUT_SPACING.CONTENT_PADDING_BOTTOM; /* bottom padding */
7
- const PT = LAYOUT_SPACING.CONTENT_PADDING_TOP; /* top padding */
7
+ const PT = LAYOUT_SPACING.OUTLINE_PADDING_TOP; /* top padding */
8
8
  const TITLE_HEIGHT = LAYOUT_SPACING.TITLE_HEIGHT; /* title height */
9
9
 
10
10
  export const Layout = styled("div")<LayoutSpacing>`
@@ -9,6 +9,7 @@ export const Layout = styled("div")<LayoutSpacing>`
9
9
  padding-top: ${({ top }) => top}px; /* header height */
10
10
  position: sticky;
11
11
  top: 0;
12
+ z-index: 4;
12
13
 
13
14
  ${mediaTabletDown} {
14
15
  grid-column: 1;
@@ -1,5 +1,9 @@
1
1
  export const LAYOUT_SPACING = {
2
2
  CONTENT_PADDING_BOTTOM: 24,
3
3
  CONTENT_PADDING_TOP: 16,
4
+ FILTERS_HEIGHT: 40,
5
+ FILTERS_PADDING_BOTTOM: 16,
6
+ FILTERS_PADDING_TOP: 16,
7
+ OUTLINE_PADDING_TOP: 16,
4
8
  TITLE_HEIGHT: 74,
5
9
  };
@@ -1,21 +1,43 @@
1
- import { 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
3
  import { OutlineItem } from "../../../Layout/components/Outline/types";
4
+ import { ClassMeta } from "../Table/types";
4
5
 
5
6
  /**
6
- * Returns outline items from classes.
7
- * @param classes - Class entities.
7
+ * Returns outline items from class metadata.
8
+ * @param table - Table instance.
8
9
  * @returns Outline items.
9
10
  */
10
11
  export function buildClassesOutline<T extends RowData = Attribute>(
11
- classes: Class<T>[]
12
+ table: Table<T>
12
13
  ): OutlineItem[] {
13
- return classes.map(({ name, title }) => {
14
- return {
15
- depth: 2,
16
- disabled: false,
17
- hash: name,
18
- value: title,
19
- };
20
- });
14
+ const meta = table.options.meta;
15
+ if (!meta) return [];
16
+ if (!("classMeta" in meta)) return [];
17
+ return Object.entries(meta.classMeta as ClassMeta).map(
18
+ ([classKey, { title }]) => {
19
+ return {
20
+ depth: 2,
21
+ disabled: !hasGroupedRow(table, classKey),
22
+ hash: classKey,
23
+ value: title,
24
+ };
25
+ }
26
+ );
27
+ }
28
+
29
+ /**
30
+ * Returns true if a grouped row exists for a class key.
31
+ * @param table - Table instance.
32
+ * @param classKey - Class key.
33
+ * @returns True if a grouped row exists, false otherwise.
34
+ */
35
+ function hasGroupedRow<T extends RowData = Attribute>(
36
+ table: Table<T>,
37
+ classKey: string
38
+ ): boolean {
39
+ const groupRow = table
40
+ .getGroupedRowModel()
41
+ .rows.find((row) => row.getValue("classKey") === classKey);
42
+ return !!groupRow;
21
43
  }
@@ -2,22 +2,34 @@ import {
2
2
  ColumnDef,
3
3
  RowData,
4
4
  Table,
5
+ TableOptions,
5
6
  useReactTable,
6
7
  } from "@tanstack/react-table";
7
- import { Attribute } from "../../../../common/entities";
8
+ import { useMemo } from "react";
9
+ import { Attribute, Class } from "../../../../common/entities";
8
10
  import { useTableOptions } from "./options/hook";
11
+ import { buildClassMeta, buildTableData } from "./utils";
9
12
 
10
13
  export const useTable = <T extends RowData = Attribute>(
11
- data: T[],
12
- columnDefs: ColumnDef<T, T[keyof T]>[]
14
+ classes: Class<T>[],
15
+ columnDefs: ColumnDef<T, T[keyof T]>[],
16
+ tableOptions?: Omit<TableOptions<T>, "columns" | "data" | "getCoreRowModel">
13
17
  ): Table<T> => {
14
- // Table options.
15
- const tableOptions = useTableOptions<T>();
18
+ // Build table data.
19
+ const data = useMemo(() => buildTableData(classes), [classes]);
20
+
21
+ // Default table options.
22
+ const defaultTableOptions = useTableOptions<T>();
23
+
24
+ // Build class meta.
25
+ const classMeta = useMemo(() => buildClassMeta(classes), [classes]);
16
26
 
17
27
  // Table instance.
18
28
  return useReactTable<T>({
29
+ ...defaultTableOptions,
19
30
  ...tableOptions,
20
31
  columns: columnDefs,
21
32
  data,
33
+ meta: { classMeta },
22
34
  });
23
35
  };
@@ -0,0 +1,16 @@
1
+ import {
2
+ ColumnFiltersOptions,
3
+ RowData,
4
+ getFilteredRowModel,
5
+ } from "@tanstack/react-table";
6
+ import { arrIncludesSome } from "../../../../../Table/columnDef/columnFilters/filterFn";
7
+
8
+ export const COLUMN_FILTERS_OPTIONS: Pick<
9
+ ColumnFiltersOptions<RowData>,
10
+ "enableColumnFilters" | "enableFilters" | "filterFns" | "getFilteredRowModel"
11
+ > = {
12
+ enableColumnFilters: true,
13
+ enableFilters: true,
14
+ filterFns: { arrIncludesSome },
15
+ getFilteredRowModel: getFilteredRowModel(),
16
+ };
@@ -0,0 +1,32 @@
1
+ import {
2
+ ColumnFiltersOptions,
3
+ ColumnFiltersState,
4
+ RowData,
5
+ Updater,
6
+ } from "@tanstack/react-table";
7
+ import { Dispatch, SetStateAction, useCallback } from "react";
8
+ import { Attribute } from "../../../../../../common/entities";
9
+ import { resolveUpdater } from "../../../../../Table/options/updater";
10
+ import { COLUMN_FILTERS_OPTIONS } from "./constants";
11
+
12
+ export const useColumnFiltersOptions = <T extends RowData = Attribute>({
13
+ setColumnFilters,
14
+ }: {
15
+ setColumnFilters: Dispatch<SetStateAction<ColumnFiltersState>>;
16
+ }): ColumnFiltersOptions<T> => {
17
+ // Column filters change handler.
18
+ // TODO dispatch to provider with reducer.
19
+ const onColumnFiltersChange = useCallback(
20
+ (updaterOrValue: Updater<ColumnFiltersState>): void => {
21
+ setColumnFilters((old) =>
22
+ resolveUpdater<ColumnFiltersState>(updaterOrValue, old)
23
+ );
24
+ },
25
+ [setColumnFilters]
26
+ );
27
+
28
+ return {
29
+ ...COLUMN_FILTERS_OPTIONS,
30
+ onColumnFiltersChange,
31
+ };
32
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ ExpandedOptions,
3
+ getExpandedRowModel,
4
+ RowData,
5
+ } from "@tanstack/react-table";
6
+
7
+ export const EXPANDED_OPTIONS: Pick<
8
+ ExpandedOptions<RowData>,
9
+ "enableExpanding" | "getExpandedRowModel"
10
+ > = {
11
+ enableExpanding: true,
12
+ getExpandedRowModel: getExpandedRowModel(),
13
+ };
@@ -0,0 +1,14 @@
1
+ import {
2
+ FacetedOptions,
3
+ getFacetedRowModel,
4
+ RowData,
5
+ } from "@tanstack/react-table";
6
+ import { getFacetedUniqueValuesWithArrayValues } from "../../../../../Table/common/utils";
7
+
8
+ export const FACETED_OPTIONS: Pick<
9
+ FacetedOptions<RowData>,
10
+ "getFacetedRowModel" | "getFacetedUniqueValues"
11
+ > = {
12
+ getFacetedRowModel: getFacetedRowModel(),
13
+ getFacetedUniqueValues: getFacetedUniqueValuesWithArrayValues(),
14
+ };
@@ -0,0 +1,9 @@
1
+ import { GroupingOptions, getGroupedRowModel } from "@tanstack/react-table";
2
+
3
+ export const GROUPING_OPTIONS: Pick<
4
+ GroupingOptions,
5
+ "enableGrouping" | "getGroupedRowModel"
6
+ > = {
7
+ enableGrouping: true,
8
+ getGroupedRowModel: getGroupedRowModel(),
9
+ };
@@ -1,14 +1,37 @@
1
- import { RowData, TableOptions } from "@tanstack/react-table";
1
+ import {
2
+ ColumnFiltersState,
3
+ RowData,
4
+ TableOptions,
5
+ } from "@tanstack/react-table";
6
+ import { useState } from "react";
2
7
  import { Attribute } from "../../../../../common/entities";
8
+ import { useColumnFiltersOptions } from "./columnFilters/hook";
3
9
  import { CORE_OPTIONS } from "./core/constants";
10
+ import { EXPANDED_OPTIONS } from "./expanded/constants";
11
+ import { FACETED_OPTIONS } from "./faceted/constants";
12
+ import { GROUPING_OPTIONS } from "./grouping/constants";
4
13
  import { SORTING_OPTIONS } from "./sorting/constants";
14
+ import { VISIBILITY_OPTIONS } from "./visibility/constants";
5
15
 
6
16
  export const useTableOptions = <T extends RowData = Attribute>(): Omit<
7
17
  TableOptions<T>,
8
- "columns" | "data"
18
+ "columns" | "data" | "initialState"
9
19
  > => {
20
+ // Column filters state - to be moved to a provider with a reducer.
21
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
22
+
23
+ // Column filters options.
24
+ const columnFiltersOptions = useColumnFiltersOptions<T>({ setColumnFilters });
25
+
26
+ // Table options.
10
27
  return {
28
+ ...columnFiltersOptions,
11
29
  ...CORE_OPTIONS,
30
+ ...EXPANDED_OPTIONS,
31
+ ...FACETED_OPTIONS,
32
+ ...GROUPING_OPTIONS,
12
33
  ...SORTING_OPTIONS,
13
- };
34
+ ...VISIBILITY_OPTIONS,
35
+ state: { columnFilters },
36
+ } as TableOptions<T>;
14
37
  };
@@ -0,0 +1,5 @@
1
+ import { VisibilityOptions } from "@tanstack/react-table";
2
+
3
+ export const VISIBILITY_OPTIONS: Pick<VisibilityOptions, "enableHiding"> = {
4
+ enableHiding: true,
5
+ };
@@ -11,6 +11,7 @@ import { StyledRoundedPaper } from "./table.styles";
11
11
  import { TableProps } from "./types";
12
12
 
13
13
  export const Table = <T extends RowData>({
14
+ row,
14
15
  table,
15
16
  }: TableProps<T>): JSX.Element => {
16
17
  return (
@@ -28,6 +29,7 @@ export const Table = <T extends RowData>({
28
29
  />
29
30
  <TableBody
30
31
  rowDirection={ROW_DIRECTION.DEFAULT}
32
+ rows={row.getLeafRows()}
31
33
  tableInstance={table}
32
34
  />
33
35
  </GridTable>
@@ -1,5 +1,12 @@
1
- import { RowData, Table } from "@tanstack/react-table";
1
+ import { Row, RowData, Table } from "@tanstack/react-table";
2
+ import { Class } from "common/entities";
3
+
4
+ export type ClassMeta = Record<
5
+ Class["name"],
6
+ Pick<Class, "description" | "title">
7
+ >;
2
8
 
3
9
  export interface TableProps<T extends RowData> {
10
+ row: Row<T>;
4
11
  table: Table<T>;
5
12
  }