@centreon/ui 23.10.39 → 23.10.41

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 (68) hide show
  1. package/package.json +3 -1
  2. package/src/Listing/Cell/DataCell.tsx +16 -4
  3. package/src/Listing/Cell/index.tsx +82 -2
  4. package/src/Listing/Listing.cypress.spec.tsx +120 -0
  5. package/src/Listing/Listing.styles.ts +2 -2
  6. package/src/Listing/ListingDocs.mdx +61 -0
  7. package/src/Listing/Row/Row.tsx +5 -2
  8. package/src/Listing/index.stories.tsx +104 -31
  9. package/src/Listing/index.tsx +103 -33
  10. package/src/Listing/models.ts +1 -0
  11. package/src/Listing/tableAtoms.ts +2 -0
  12. package/src/Panel/index.tsx +1 -1
  13. package/src/ThemeProvider/index.tsx +0 -24
  14. package/src/ThemeProvider/palettes.ts +36 -6
  15. package/src/api/useMutationQuery/index.ts +16 -6
  16. package/src/components/Form/AccessRights/AccessRights.resource.ts +45 -0
  17. package/src/components/Form/AccessRights/AccessRightsForm.stories.tsx +59 -0
  18. package/src/components/Form/AccessRights/AccessRightsForm.styles.ts +21 -0
  19. package/src/components/Form/AccessRights/AccessRightsForm.tsx +67 -0
  20. package/src/components/Form/AccessRights/AccessRightsFormActions.tsx +80 -0
  21. package/src/components/Form/AccessRights/Input/AddAction.tsx +31 -0
  22. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.stories.tsx +54 -0
  23. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.tsx +72 -0
  24. package/src/components/Form/AccessRights/Input/ContactAccessRightsInput.styles.ts +22 -0
  25. package/src/components/Form/AccessRights/Input/ContactInputField.tsx +105 -0
  26. package/src/components/Form/AccessRights/Input/RoleInputField.tsx +29 -0
  27. package/src/components/Form/AccessRights/List/ContactAccessRightsList.stories.tsx +97 -0
  28. package/src/components/Form/AccessRights/List/ContactAccessRightsList.styles.ts +71 -0
  29. package/src/components/Form/AccessRights/List/ContactAccessRightsList.tsx +51 -0
  30. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.stories.tsx +116 -0
  31. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.tsx +118 -0
  32. package/src/components/Form/AccessRights/List/ContactAccessRightsListItemSkeleton.tsx +26 -0
  33. package/src/components/Form/AccessRights/List/ContactAccessRightsListSkeleton.tsx +28 -0
  34. package/src/components/Form/AccessRights/Stats/AccessRightsStats.styles.ts +18 -0
  35. package/src/components/Form/AccessRights/Stats/AccessRightsStats.tsx +41 -0
  36. package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +52 -0
  37. package/src/components/Form/AccessRights/common/GroupLabel.styles.ts +18 -0
  38. package/src/components/Form/AccessRights/common/GroupLabel.tsx +15 -0
  39. package/src/components/Form/AccessRights/common/Input.styles.ts +48 -0
  40. package/src/components/Form/AccessRights/common/RoleInputSelect.styles.ts +11 -0
  41. package/src/components/Form/AccessRights/common/RoleInputSelect.tsx +57 -0
  42. package/src/components/Form/AccessRights/index.ts +3 -0
  43. package/src/components/Form/AccessRights/useAccessRightsForm.test.tsx +531 -0
  44. package/src/components/Form/AccessRights/useAccessRightsForm.tsx +282 -0
  45. package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +41 -0
  46. package/src/components/Form/Dashboard/DashboardForm.styles.ts +1 -7
  47. package/src/components/Form/Dashboard/DashboardForm.tsx +9 -12
  48. package/src/components/Form/Form.resource.ts +1 -0
  49. package/src/components/Form/Form.styles.ts +17 -0
  50. package/src/components/Form/{Dashboard/DashboardFormActions.tsx → FormActions.tsx} +17 -16
  51. package/src/components/Form/index.ts +1 -0
  52. package/src/components/Header/PageHeader/PageHeader.stories.tsx +9 -0
  53. package/src/components/List/Item/Avatar.tsx +21 -0
  54. package/src/components/List/Item/AvatarSkeleton.tsx +17 -0
  55. package/src/components/List/Item/ListItem.stories.tsx +41 -0
  56. package/src/components/List/Item/ListItem.styles.ts +57 -0
  57. package/src/components/List/Item/ListItem.tsx +32 -0
  58. package/src/components/List/Item/Text.tsx +25 -0
  59. package/src/components/List/Item/TextSkeleton.tsx +22 -0
  60. package/src/components/List/Item/index.ts +14 -0
  61. package/src/components/List/List.stories.tsx +70 -0
  62. package/src/components/List/List.styles.ts +8 -0
  63. package/src/components/List/List.tsx +19 -0
  64. package/src/components/List/index.ts +6 -0
  65. package/src/components/Modal/ModalActions.tsx +4 -1
  66. package/src/components/index.ts +1 -0
  67. package/src/utils/index.ts +1 -0
  68. package/src/utils/useInfiniteScrollListing.ts +106 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "23.10.39",
3
+ "version": "23.10.41",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -48,6 +48,7 @@
48
48
  "devDependencies": {
49
49
  "@cypress/react": "^7.0.2",
50
50
  "@cypress/webpack-dev-server": "^3.2.3",
51
+ "@faker-js/faker": "^8.0.2",
51
52
  "@mdx-js/react": "^2.1.4",
52
53
  "@simonsmith/cypress-image-snapshot": "^6.1.0",
53
54
  "@storybook/addon-a11y": "^7.0.9",
@@ -55,6 +56,7 @@
55
56
  "@storybook/addon-essentials": "^7.0.9",
56
57
  "@storybook/addon-interactions": "^7.0.9",
57
58
  "@storybook/addon-styling": "^1.0.6",
59
+ "@storybook/blocks": "^7.0.26",
58
60
  "@storybook/builder-vite": "^7.0.9",
59
61
  "@storybook/jest": "^0.1.0",
60
62
  "@storybook/manager-api": "^7.0.9",
@@ -25,8 +25,11 @@ interface Props {
25
25
  getHighlightRowCondition?: (row) => boolean;
26
26
  isRowHovered: boolean;
27
27
  isRowSelected: boolean;
28
+ labelCollapse?: string;
29
+ labelExpand?: string;
28
30
  row?;
29
31
  rowColorConditions?: Array<RowColorCondition>;
32
+ subItemsRowProperty?: string;
30
33
  viewMode?: ListingVariant;
31
34
  }
32
35
 
@@ -38,16 +41,23 @@ const DataCell = ({
38
41
  rowColorConditions,
39
42
  disableRowCondition,
40
43
  viewMode,
41
- getHighlightRowCondition
44
+ getHighlightRowCondition,
45
+ subItemsRowProperty,
46
+ labelCollapse,
47
+ labelExpand
42
48
  }: Props): JSX.Element | null => {
43
49
  const { classes } = useStyles();
44
50
  const { dataStyle } = useStyleTable({ viewMode });
45
51
 
46
52
  const commonCellProps = {
47
53
  disableRowCondition,
54
+ displaySubItemsCaret: column.displaySubItemsCaret,
48
55
  isRowHovered,
56
+ labelCollapse,
57
+ labelExpand,
49
58
  row,
50
- rowColorConditions
59
+ rowColorConditions,
60
+ subItemsRowProperty
51
61
  };
52
62
 
53
63
  const isRowHighlighted = getHighlightRowCondition?.(row);
@@ -106,7 +116,7 @@ const DataCell = ({
106
116
  isRowHighlighted={isRowHighlighted}
107
117
  viewMode={viewMode}
108
118
  onClick={(e): void => {
109
- if (!clickable) {
119
+ if (!clickable || !column.displaySubItemsCaret) {
110
120
  return;
111
121
  }
112
122
  e.preventDefault();
@@ -223,6 +233,7 @@ const MemoizedDataCell = memo<Props>(
223
233
  : nextProps.row;
224
234
 
225
235
  return (
236
+ equals(prevProps.row, nextProps.row) &&
226
237
  equals(previousIsComponentHovered, nextIsComponentHovered) &&
227
238
  equals(prevProps.isRowHovered, nextProps.isRowHovered) &&
228
239
  equals(previousFormattedString, nextFormattedString) &&
@@ -244,7 +255,8 @@ const MemoizedDataCell = memo<Props>(
244
255
  nextProps.disableRowCondition(nextProps.row)
245
256
  ) &&
246
257
  equals(previousIsRowHighlighted, nextIsRowHighlighted) &&
247
- equals(prevProps.viewMode, nextProps.viewMode) // &&
258
+ equals(prevProps.viewMode, nextProps.viewMode) &&
259
+ equals(prevProps.subItemsRowProperty, nextProps.subItemsRowProperty)
248
260
  );
249
261
  }
250
262
  );
@@ -1,9 +1,11 @@
1
1
  import * as React from 'react';
2
2
 
3
- import { isNil, omit } from 'ramda';
3
+ import { append, equals, includes, isNil, omit, reject } from 'ramda';
4
4
  import { makeStyles } from 'tss-react/mui';
5
5
  import { CSSObject } from 'tss-react';
6
+ import { useAtom } from 'jotai';
6
7
 
8
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
7
9
  import {
8
10
  alpha,
9
11
  TableCell,
@@ -14,7 +16,9 @@ import {
14
16
 
15
17
  import { ListingVariant } from '@centreon/ui-context';
16
18
 
19
+ import { IconButton } from '../..';
17
20
  import { getTextStyleByViewMode } from '../useStyleTable';
21
+ import { subItemsPivotsAtom } from '../tableAtoms';
18
22
 
19
23
  import { Props as DataCellProps } from './DataCell';
20
24
 
@@ -80,6 +84,20 @@ const useStyles = makeStyles<StylesProps>()(
80
84
  viewMode
81
85
  }
82
86
  ) => ({
87
+ caret: {
88
+ transition: theme.transitions.create('transform', {
89
+ duration: theme.transitions.duration.short
90
+ })
91
+ },
92
+ caretLess: {
93
+ transform: 'rotate3d(0,0,1,180deg)'
94
+ },
95
+ caretMore: {
96
+ transform: 'rotate3d(0,0,1,0deg)'
97
+ },
98
+ fakeCaret: {
99
+ marginLeft: theme.spacing(3)
100
+ },
83
101
  root: {
84
102
  alignItems: 'center',
85
103
  backgroundColor: getBackgroundColor({
@@ -111,15 +129,57 @@ interface Props
111
129
  'isRowHovered' | 'row' | 'rowColorConditions' | 'disableRowCondition'
112
130
  >,
113
131
  TableCellProps {
132
+ displaySubItemsCaret?: boolean;
114
133
  isRowHighlighted?: boolean;
134
+ labelCollapse?: string;
135
+ labelExpand?: string;
136
+ subItemsRowProperty?: string;
115
137
  viewMode?: ListingVariant;
116
138
  }
117
139
 
118
- const Cell = (props: Props): JSX.Element => {
140
+ const isPivotExistInTheList = (
141
+ id
142
+ ): ((list: Array<number | string>) => boolean) => includes(id);
143
+
144
+ const handleSubItems = ({
145
+ currentSubItemsPivots,
146
+ id
147
+ }): Array<number | string> => {
148
+ if (isPivotExistInTheList(id)(currentSubItemsPivots)) {
149
+ return reject(equals(id), currentSubItemsPivots);
150
+ }
151
+
152
+ return append(id, currentSubItemsPivots);
153
+ };
154
+
155
+ const Cell = ({
156
+ displaySubItemsCaret,
157
+ subItemsRowProperty,
158
+ labelCollapse,
159
+ labelExpand,
160
+ ...props
161
+ }: Props): JSX.Element => {
119
162
  const { classes, cx } = useStyles(props);
120
163
 
164
+ const [subItemsPivots, setSubItemsPivots] = useAtom(subItemsPivotsAtom);
165
+
121
166
  const { children } = props;
122
167
 
168
+ const rowId = props.row?.id;
169
+
170
+ const click = (e): void => {
171
+ e.preventDefault();
172
+ e.stopPropagation();
173
+
174
+ setSubItemsPivots((currentSubItemsPivots) =>
175
+ handleSubItems({ currentSubItemsPivots, id: rowId })
176
+ );
177
+ };
178
+
179
+ const isSubItemsExpanded = isPivotExistInTheList(rowId)(subItemsPivots);
180
+
181
+ const hasSubItems = subItemsRowProperty && props.row[subItemsRowProperty];
182
+
123
183
  return (
124
184
  <TableCell
125
185
  classes={{
@@ -138,6 +198,26 @@ const Cell = (props: Props): JSX.Element => {
138
198
  props
139
199
  )}
140
200
  >
201
+ {displaySubItemsCaret &&
202
+ (hasSubItems ? (
203
+ <IconButton
204
+ ariaLabel={`${isSubItemsExpanded ? labelCollapse : labelExpand} ${
205
+ props.row.id
206
+ }`}
207
+ size="small"
208
+ onClick={click}
209
+ >
210
+ <ExpandMoreIcon
211
+ className={cx(
212
+ classes.caret,
213
+ isSubItemsExpanded ? classes.caretMore : classes.caretLess
214
+ )}
215
+ fontSize="small"
216
+ />
217
+ </IconButton>
218
+ ) : (
219
+ <div className={classes.fakeCaret} />
220
+ ))}
141
221
  {children}
142
222
  </TableCell>
143
223
  );
@@ -0,0 +1,120 @@
1
+ import { Button } from '@mui/material';
2
+
3
+ import { ColumnType } from './models';
4
+
5
+ import Listing from '.';
6
+
7
+ interface Props {
8
+ row: { name: string };
9
+ }
10
+
11
+ const ButtonColumn = ({ row }: Props): JSX.Element => (
12
+ <Button size="small">Click to reveal details about {row.name}</Button>
13
+ );
14
+
15
+ const generateSubItems = (parentIndex: number): Array<unknown> => {
16
+ return tenElements.map((__, subIndex) => ({
17
+ active: false,
18
+ description: `Sub item ${subIndex + (parentIndex + 10) * 10} description`,
19
+ disableCheckbox: false,
20
+ disableRow: false,
21
+ id: subIndex + (parentIndex + 10) * 10,
22
+ name: `Sub Item ${subIndex + (parentIndex + 10) * 10}`,
23
+ selected: false
24
+ }));
25
+ };
26
+
27
+ const tenElements = new Array(10).fill(0);
28
+
29
+ const listingWithSubItems = tenElements.map((_, index) => ({
30
+ active: false,
31
+ description: `Entity ${index}`,
32
+ disableCheckbox: false,
33
+ disableRow: false,
34
+ id: index,
35
+ name: `E${index}`,
36
+ selected: false,
37
+ subItems: index % 2 === 0 ? generateSubItems(index) : undefined
38
+ }));
39
+
40
+ const columnsWithSubItems = [
41
+ {
42
+ getFormattedString: ({ name }): string => name,
43
+ id: 'name',
44
+ label: 'Name',
45
+ type: ColumnType.string
46
+ },
47
+ {
48
+ getFormattedString: ({ description }): string => description,
49
+ id: 'description',
50
+ label: 'Description',
51
+ type: ColumnType.string
52
+ },
53
+ {
54
+ Component: ButtonColumn,
55
+ displaySubItemsCaret: true,
56
+ id: '#',
57
+ label: 'Custom',
58
+ type: ColumnType.component,
59
+ width: '350px'
60
+ }
61
+ ];
62
+
63
+ const expandedItems = [0, 8];
64
+
65
+ const mountListing = (): void => {
66
+ cy.viewport('macbook-13');
67
+
68
+ cy.mount({
69
+ Component: (
70
+ <Listing
71
+ checkable
72
+ columns={columnsWithSubItems}
73
+ currentPage={1}
74
+ limit={10}
75
+ rows={listingWithSubItems}
76
+ subItems={{
77
+ canCheckSubItems: false,
78
+ enable: true,
79
+ labelCollapse: 'Collapse',
80
+ labelExpand: 'Expand',
81
+ rowProperty: 'subItems'
82
+ }}
83
+ totalRows={10}
84
+ />
85
+ )
86
+ });
87
+ };
88
+
89
+ describe('Listing', () => {
90
+ beforeEach(mountListing);
91
+
92
+ it('expands the row when the corresponding icon si clicked', () => {
93
+ cy.contains('E0').should('be.visible');
94
+
95
+ expandedItems.forEach((index) => {
96
+ const subItems = generateSubItems(index);
97
+
98
+ cy.findByLabelText(`Expand ${index}`).click();
99
+
100
+ cy.findByLabelText(`Collapse ${index}`).should('exist');
101
+
102
+ subItems.forEach(({ name, description }) => {
103
+ cy.contains(name).should('exist');
104
+ cy.contains(description).should('exist');
105
+ });
106
+ });
107
+
108
+ cy.matchImageSnapshot();
109
+ });
110
+
111
+ it('collapses the row when the corresponding icon si clicked', () => {
112
+ cy.contains('Sub item 100').should('be.visible');
113
+
114
+ cy.findByLabelText('Collapse 0').click();
115
+
116
+ cy.contains('Sub item 100').should('not.exist');
117
+
118
+ cy.matchImageSnapshot();
119
+ });
120
+ });
@@ -14,7 +14,7 @@ interface StylesProps {
14
14
  viewMode: ListingVariant;
15
15
  }
16
16
 
17
- const useStyles = makeStyles<StylesProps>()(
17
+ const useListingStyles = makeStyles<StylesProps>()(
18
18
  (theme, { dataStyle, getGridTemplateColumn, rows, limit }) => ({
19
19
  actionBar: {
20
20
  alignItems: 'center',
@@ -73,4 +73,4 @@ const useStyles = makeStyles<StylesProps>()(
73
73
  })
74
74
  );
75
75
 
76
- export { useStyles, loadingIndicatorHeight };
76
+ export { useListingStyles, loadingIndicatorHeight };
@@ -0,0 +1,61 @@
1
+ {/* ListingDocs.mdx */}
2
+
3
+ import { Meta, Story } from '@storybook/blocks';
4
+ import * as ListingStories from './index.stories';
5
+
6
+ <Meta of={ListingStories} />
7
+
8
+ # Listing
9
+
10
+ ## Expand/collapse rows
11
+
12
+ The listing supports rows expanding and collapsing.
13
+
14
+ In order to use this feature, please follow the instructions:
15
+ - (pre-requisite): Your data should have a child property that contains sub-items.
16
+ ```javascript
17
+ [
18
+ {
19
+ "id": 1,
20
+ "festival": "Test",
21
+ "name": "Tom",
22
+ "counter": 3,
23
+ "description": "My description of Tom"
24
+ },
25
+ {
26
+ "id": 2,
27
+ "name": "Jane's group",
28
+ "festival": "fest",
29
+ "counter": 5,
30
+ "description": "My description of Jane's group",
31
+ "subItems": [
32
+ {
33
+ "id": 3,
34
+ "name": "Jane",
35
+ "counter": 0,
36
+ "description": "My description of Jane"
37
+ },
38
+ ]
39
+ }
40
+ ]
41
+ ```
42
+ - Use the `subItems` property to configure how the component will handle your sub-items
43
+ ```javascript
44
+ subItems={{
45
+ canCheckSubItems: false, // Display checkbox on sub items. Default: false
46
+ enable: true, // It enables or disable the row expand/collapse feature. Default: false
47
+ rowProperty: 'subItems' // Which property should be used to detect sub-items. Default: ''
48
+ labelExpand: 'Expand',
49
+ labelCollapse: 'Collapse'
50
+ }}
51
+ ```
52
+ - Finally, update the column configuration in order to display the expand/collapse caret
53
+ ```javascript
54
+ {
55
+ Component: ButtonColumn,
56
+ displaySubItemsCaret: true, // Add this property
57
+ id: '#',
58
+ label: 'Custom',
59
+ type: ColumnType.component
60
+ }
61
+ ```
@@ -49,6 +49,7 @@ type Props = {
49
49
  row;
50
50
  rowColorConditions: Array<RowColorCondition>;
51
51
  shiftKeyDownRowPivot: number | null;
52
+ subItemsPivots: Array<number | string>;
52
53
  viewMode?: ListingVariant;
53
54
  visibleColumns: Array<Column>;
54
55
  } & TableRowProps;
@@ -174,7 +175,8 @@ const Row = memo<RowProps>(
174
175
  equals(prevProps.row, nextProps.row) &&
175
176
  equals(previousRowConditions, nextRowConditions) &&
176
177
  equals(previousRowColors, nextRowColors) &&
177
- equals(prevProps.className, nextProps.className)
178
+ equals(prevProps.className, nextProps.className) &&
179
+ equals(prevProps.subItemsPivots, nextProps.subItemsPivots)
178
180
  );
179
181
  }
180
182
 
@@ -189,7 +191,8 @@ const Row = memo<RowProps>(
189
191
  equals(prevIsShiftKeyDown, nextIsShiftKeyDown) &&
190
192
  equals(prevShiftKeyDownRowPivot, nextShiftKeyDownRowPivot) &&
191
193
  equals(prevLastSelectionIndex, nextLastSelectionIndex) &&
192
- equals(prevViewMode, nextViewMode)
194
+ equals(prevViewMode, nextViewMode) &&
195
+ equals(prevProps.subItemsPivots, nextProps.subItemsPivots)
193
196
  );
194
197
  }
195
198
  );
@@ -1,7 +1,8 @@
1
+ /* eslint-disable no-alert */
1
2
  /* eslint-disable react/prop-types */
2
3
  import { useState } from 'react';
3
4
 
4
- import { ComponentMeta, ComponentStory } from '@storybook/react';
5
+ import { Meta, StoryObj } from '@storybook/react';
5
6
  import { equals, prop } from 'ramda';
6
7
  import { makeStyles } from 'tss-react/mui';
7
8
 
@@ -16,7 +17,7 @@ import { Column, ColumnType, SortOrder } from './models';
16
17
 
17
18
  import Listing from '.';
18
19
 
19
- export default {
20
+ const meta: Meta<typeof Listing> = {
20
21
  argTypes: {
21
22
  checkable: { control: 'boolean' },
22
23
  currentPage: { control: 'number' },
@@ -26,7 +27,10 @@ export default {
26
27
  },
27
28
  component: Listing,
28
29
  title: 'Listing'
29
- } as ComponentMeta<typeof Listing>;
30
+ };
31
+ export default meta;
32
+
33
+ type Story = StoryObj<typeof Listing>;
30
34
 
31
35
  const useStyles = makeStyles()((theme) => ({
32
36
  listing: {
@@ -48,6 +52,12 @@ const ComponentColumn = ({ row, isSelected }): JSX.Element => (
48
52
  </>
49
53
  );
50
54
 
55
+ const ButtonColumn = ({ row }): JSX.Element => (
56
+ <Button size="small" onClick={() => alert(JSON.stringify(row))}>
57
+ Click to reveal details about {row.name}
58
+ </Button>
59
+ );
60
+
51
61
  const defaultColumns = [
52
62
  {
53
63
  getFormattedString: ({ name }): string => name,
@@ -131,7 +141,7 @@ const predefinedRowsSelection = [
131
141
  }
132
142
  ];
133
143
 
134
- const Story = ({
144
+ const StoryTemplate = ({
135
145
  columns = defaultColumns,
136
146
  checkable = true,
137
147
  viewerModeConfiguration,
@@ -164,7 +174,7 @@ const Story = ({
164
174
  );
165
175
  };
166
176
 
167
- export const normal = (): JSX.Element => <Story />;
177
+ export const normal = (): JSX.Element => <StoryTemplate />;
168
178
 
169
179
  export const WithSpecifiedViewMode = (): JSX.Element => {
170
180
  const [viewMode, setViewMode] = useState(ListingVariant.extended);
@@ -173,7 +183,7 @@ export const WithSpecifiedViewMode = (): JSX.Element => {
173
183
  : ListingVariant.compact;
174
184
 
175
185
  return (
176
- <Story
186
+ <StoryTemplate
177
187
  viewMode={viewMode}
178
188
  viewerModeConfiguration={{
179
189
  onClick: () => setViewMode(newViewMode),
@@ -184,15 +194,15 @@ export const WithSpecifiedViewMode = (): JSX.Element => {
184
194
  };
185
195
 
186
196
  export const loadingWithNoData = (): JSX.Element => {
187
- return <Story loading rows={[]} totalRows={0} />;
197
+ return <StoryTemplate loading rows={[]} totalRows={0} />;
188
198
  };
189
199
 
190
200
  export const loadingWithData = (): JSX.Element => {
191
- return <Story loading />;
201
+ return <StoryTemplate loading />;
192
202
  };
193
203
 
194
204
  export const asEmptyState = (): JSX.Element => {
195
- return <Story rows={[]} />;
205
+ return <StoryTemplate rows={[]} />;
196
206
  };
197
207
 
198
208
  const actions = (
@@ -201,12 +211,16 @@ const actions = (
201
211
  </Button>
202
212
  );
203
213
 
204
- export const withActions = (): JSX.Element => <Story actions={actions} />;
214
+ export const withActions = (): JSX.Element => (
215
+ <StoryTemplate actions={actions} />
216
+ );
205
217
 
206
- export const withoutCheckboxes = (): JSX.Element => <Story checkable={false} />;
218
+ export const withoutCheckboxes = (): JSX.Element => (
219
+ <StoryTemplate checkable={false} />
220
+ );
207
221
 
208
222
  export const withShortLabelColumns = (): JSX.Element => (
209
- <Story columns={columnsWithShortLabel} />
223
+ <StoryTemplate columns={columnsWithShortLabel} />
210
224
  );
211
225
 
212
226
  const editableColumns = [
@@ -270,7 +284,7 @@ const ListingWithEditableColumns = (): JSX.Element => {
270
284
  };
271
285
 
272
286
  return (
273
- <Story
287
+ <StoryTemplate
274
288
  columnConfiguration={{
275
289
  selectedColumnIds,
276
290
  sortable: true
@@ -290,23 +304,82 @@ export const withEditableAndSortableColumns = (): JSX.Element => (
290
304
  <ListingWithEditableColumns />
291
305
  );
292
306
 
293
- const TemplateListing: ComponentStory<typeof Listing> = (args) => (
294
- <Listing
295
- {...args}
296
- columns={editableColumns}
297
- disableRowCheckCondition={(row): boolean => row.disableCheckbox}
298
- disableRowCondition={(row): boolean => row.disableRow}
299
- predefinedRowsSelection={predefinedRowsSelection}
300
- rowColorConditions={rowColorConditions}
301
- rows={listing}
302
- />
303
- );
307
+ export const PlaygroundListing: Story = {
308
+ args: {
309
+ checkable: true,
310
+ columns: editableColumns,
311
+ currentPage: 1,
312
+ disableRowCheckCondition: (row): boolean => row.disableCheckbox,
313
+ disableRowCondition: (row): boolean => row.disableRow,
314
+ limit: 10,
315
+ loading: false,
316
+ predefinedRowsSelection,
317
+ rowColorConditions,
318
+ rows: listing,
319
+ totalRows: 10
320
+ }
321
+ };
322
+
323
+ const listingWithSubItems = [...tenElements].map((_, index) => ({
324
+ active: false,
325
+ description: `Entity ${index}`,
326
+ disableCheckbox: false,
327
+ disableRow: false,
328
+ id: index,
329
+ name: `E${index}`,
330
+ selected: false,
331
+ subItems:
332
+ index % 2 === 0
333
+ ? [...tenElements].map((__, subIndex) => ({
334
+ active: false,
335
+ description: `Sub item ${subIndex + (index + 10) * 10} description`,
336
+ disableCheckbox: false,
337
+ disableRow: false,
338
+ id: subIndex + (index + 10) * 10,
339
+ name: `Sub Item ${subIndex + (index + 10) * 10}`,
340
+ selected: false
341
+ }))
342
+ : undefined
343
+ }));
344
+
345
+ const columnsWithSubItems = [
346
+ {
347
+ getFormattedString: ({ name }): string => name,
348
+ id: 'name',
349
+ label: 'Name',
350
+ type: ColumnType.string
351
+ },
352
+ {
353
+ getFormattedString: ({ description }): string => description,
354
+ id: 'description',
355
+ label: 'Description',
356
+ type: ColumnType.string
357
+ },
358
+ {
359
+ Component: ButtonColumn,
360
+ displaySubItemsCaret: true,
361
+ id: '#',
362
+ label: 'Custom',
363
+ type: ColumnType.component,
364
+ width: '350px'
365
+ }
366
+ ];
304
367
 
305
- export const PlaygroundListing = TemplateListing.bind({});
306
- PlaygroundListing.args = {
307
- checkable: true,
308
- currentPage: 1,
309
- limit: 10,
310
- loading: false,
311
- totalRows: 10
368
+ export const ListingWithSubItems = {
369
+ args: {
370
+ checkable: true,
371
+ columns: columnsWithSubItems,
372
+ currentPage: 1,
373
+ limit: 10,
374
+ loading: false,
375
+ rows: listingWithSubItems,
376
+ subItems: {
377
+ canCheckSubItems: false,
378
+ enable: true,
379
+ labelCollapse: 'Collapse',
380
+ labelExpand: 'Expand',
381
+ rowProperty: 'subItems'
382
+ },
383
+ totalRows: 10
384
+ }
312
385
  };