@strato-admin/cloudscape 0.1.0 → 0.3.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 (231) hide show
  1. package/dist/Admin.d.ts +6 -2
  2. package/dist/Admin.js +14 -8
  3. package/dist/RecordLink.js +5 -4
  4. package/dist/Settings.d.ts +17 -0
  5. package/dist/Settings.js +14 -0
  6. package/dist/button/BulkDeleteButton.d.ts +4 -1
  7. package/dist/button/BulkDeleteButton.js +37 -5
  8. package/dist/button/Button.d.ts +2 -1
  9. package/dist/button/CancelButton.d.ts +6 -0
  10. package/dist/button/CancelButton.js +10 -0
  11. package/dist/button/CreateButton.js +9 -8
  12. package/dist/button/DeleteButton.d.ts +13 -0
  13. package/dist/button/DeleteButton.js +36 -0
  14. package/dist/button/EditButton.d.ts +1 -1
  15. package/dist/button/EditButton.js +10 -10
  16. package/dist/button/SaveButton.js +2 -2
  17. package/dist/button/index.d.ts +2 -0
  18. package/dist/button/index.js +2 -0
  19. package/dist/collection-hooks/interfaces.d.ts +7 -3
  20. package/dist/collection-hooks/useCollection.d.ts +1 -1
  21. package/dist/collection-hooks/useCollection.js +15 -10
  22. package/dist/create/Create.d.ts +9 -17
  23. package/dist/create/Create.js +40 -12
  24. package/dist/create/CreateHeader.d.ts +2 -2
  25. package/dist/create/CreateHeader.js +4 -5
  26. package/dist/defaults.d.ts +6 -0
  27. package/dist/defaults.js +21 -0
  28. package/dist/detail/Detail.d.ts +33 -0
  29. package/dist/detail/Detail.js +22 -0
  30. package/dist/detail/DetailHeader.d.ts +11 -0
  31. package/dist/detail/{ShowHeader.js → DetailHeader.js} +7 -5
  32. package/dist/detail/DetailHub.d.ts +27 -0
  33. package/dist/detail/DetailHub.js +63 -0
  34. package/dist/detail/KeyValuePairs.d.ts +7 -1
  35. package/dist/detail/KeyValuePairs.js +14 -8
  36. package/dist/detail/index.d.ts +3 -2
  37. package/dist/detail/index.js +3 -2
  38. package/dist/edit/Edit.d.ts +8 -19
  39. package/dist/edit/Edit.js +48 -12
  40. package/dist/edit/EditHeader.d.ts +2 -2
  41. package/dist/edit/EditHeader.js +5 -4
  42. package/dist/field/ArrayField.d.ts +26 -10
  43. package/dist/field/ArrayField.js +38 -10
  44. package/dist/field/BadgeField.d.ts +1 -1
  45. package/dist/field/BadgeField.js +1 -1
  46. package/dist/field/BooleanField.d.ts +1 -1
  47. package/dist/field/BooleanField.js +2 -2
  48. package/dist/field/CurrencyField.d.ts +1 -1
  49. package/dist/field/CurrencyField.js +1 -1
  50. package/dist/field/DateField.d.ts +1 -1
  51. package/dist/field/DateField.js +1 -1
  52. package/dist/field/IdField.d.ts +1 -1
  53. package/dist/field/IdField.js +3 -3
  54. package/dist/field/NumberField.d.ts +1 -1
  55. package/dist/field/NumberField.js +1 -1
  56. package/dist/field/ReferenceField.d.ts +1 -1
  57. package/dist/field/ReferenceField.js +4 -2
  58. package/dist/field/ReferenceManyField.d.ts +35 -4
  59. package/dist/field/ReferenceManyField.js +17 -4
  60. package/dist/field/StatusIndicatorField.d.ts +1 -1
  61. package/dist/field/StatusIndicatorField.js +6 -5
  62. package/dist/field/TextField.d.ts +1 -1
  63. package/dist/field/TextField.js +1 -1
  64. package/dist/field/types.d.ts +9 -9
  65. package/dist/form/Form.d.ts +12 -2
  66. package/dist/form/Form.js +10 -16
  67. package/dist/form/index.d.ts +1 -1
  68. package/dist/form/index.js +1 -1
  69. package/dist/hooks/useSchemaFields.d.ts +22 -0
  70. package/dist/hooks/useSchemaFields.js +45 -0
  71. package/dist/i18n/Message.d.ts +15 -0
  72. package/dist/i18n/Message.js +19 -0
  73. package/dist/i18n/RecordMessage.d.ts +14 -0
  74. package/dist/i18n/RecordMessage.js +16 -0
  75. package/dist/i18n/index.d.ts +3 -0
  76. package/dist/i18n/index.js +2 -0
  77. package/dist/i18n/types.d.ts +19 -0
  78. package/dist/i18n/types.js +1 -0
  79. package/dist/index.d.ts +5 -1
  80. package/dist/index.js +5 -1
  81. package/dist/input/ArrayInput.d.ts +33 -0
  82. package/dist/input/{AttributeEditor.js → ArrayInput.js} +18 -11
  83. package/dist/input/AutocompleteInput.d.ts +1 -1
  84. package/dist/input/AutocompleteInput.js +3 -3
  85. package/dist/input/BooleanInput.d.ts +6 -0
  86. package/dist/input/BooleanInput.js +23 -0
  87. package/dist/input/CommonInputProps.d.ts +6 -0
  88. package/dist/input/CommonInputProps.js +6 -0
  89. package/dist/input/FieldTitle.js +4 -4
  90. package/dist/input/FormField.js +12 -3
  91. package/dist/input/FormFieldContext.d.ts +1 -1
  92. package/dist/input/NumberInput.d.ts +1 -1
  93. package/dist/input/NumberInput.js +3 -3
  94. package/dist/input/ReferenceInput.d.ts +1 -1
  95. package/dist/input/ReferenceInput.js +22 -12
  96. package/dist/input/SelectInput.d.ts +1 -1
  97. package/dist/input/SelectInput.js +3 -3
  98. package/dist/input/SliderInput.d.ts +1 -1
  99. package/dist/input/SliderInput.js +4 -4
  100. package/dist/input/TextAreaInput.d.ts +1 -1
  101. package/dist/input/TextAreaInput.js +3 -3
  102. package/dist/input/TextInput.d.ts +1 -1
  103. package/dist/input/TextInput.js +6 -12
  104. package/dist/input/index.d.ts +2 -1
  105. package/dist/input/index.js +2 -1
  106. package/dist/input/types.d.ts +33 -2
  107. package/dist/layout/AppLayout.js +6 -3
  108. package/dist/layout/Notifications.d.ts +1 -0
  109. package/dist/layout/Notifications.js +51 -0
  110. package/dist/layout/Ready.d.ts +6 -0
  111. package/dist/layout/Ready.js +24 -0
  112. package/dist/layout/TopNavigation.d.ts +4 -2
  113. package/dist/layout/TopNavigation.js +7 -7
  114. package/dist/layout/index.d.ts +2 -0
  115. package/dist/layout/index.js +2 -0
  116. package/dist/list/Cards.d.ts +31 -4
  117. package/dist/list/Cards.js +81 -10
  118. package/dist/list/List.d.ts +9 -12
  119. package/dist/list/List.js +41 -11
  120. package/dist/list/Table.d.ts +8 -4
  121. package/dist/list/Table.js +55 -55
  122. package/dist/list/TableHeader.d.ts +2 -2
  123. package/dist/list/TableHeader.js +4 -5
  124. package/dist/theme/ThemeManager.js +1 -1
  125. package/package.json +9 -6
  126. package/src/Admin.tsx +35 -18
  127. package/src/RecordLink.stories.tsx +1 -1
  128. package/src/RecordLink.tsx +5 -4
  129. package/src/Settings.tsx +16 -0
  130. package/src/__mocks__/ra-core.tsx +83 -0
  131. package/src/__mocks__/strato-core.tsx +36 -42
  132. package/src/button/BulkDeleteButton.test.tsx +45 -8
  133. package/src/button/BulkDeleteButton.tsx +75 -12
  134. package/src/button/Button.tsx +31 -2
  135. package/src/button/CancelButton.tsx +20 -0
  136. package/src/button/CreateButton.tsx +12 -10
  137. package/src/button/DeleteButton.tsx +96 -0
  138. package/src/button/EditButton.tsx +13 -12
  139. package/src/button/SaveButton.tsx +2 -3
  140. package/src/button/index.ts +2 -0
  141. package/src/collection-hooks/interfaces.ts +7 -3
  142. package/src/collection-hooks/useCollection.test.ts +115 -2
  143. package/src/collection-hooks/useCollection.ts +15 -10
  144. package/src/create/Create.test.tsx +3 -3
  145. package/src/create/Create.tsx +68 -37
  146. package/src/create/CreateHeader.tsx +6 -10
  147. package/src/defaults.tsx +28 -0
  148. package/src/detail/Detail-CollectionFields.test.tsx +84 -0
  149. package/src/detail/Detail.test.tsx +91 -0
  150. package/src/detail/Detail.tsx +48 -0
  151. package/src/detail/{ShowHeader.test.tsx → DetailHeader.test.tsx} +11 -9
  152. package/src/detail/DetailHeader.tsx +42 -0
  153. package/src/detail/DetailHub.tsx +88 -0
  154. package/src/detail/KeyValuePairs.test.tsx +2 -2
  155. package/src/detail/KeyValuePairs.tsx +25 -18
  156. package/src/detail/index.ts +3 -2
  157. package/src/edit/Edit.test.tsx +7 -5
  158. package/src/edit/Edit.tsx +92 -40
  159. package/src/edit/EditHeader.tsx +7 -5
  160. package/src/field/ArrayField.tsx +57 -11
  161. package/src/field/BadgeField.tsx +2 -3
  162. package/src/field/BooleanField.test.tsx +2 -3
  163. package/src/field/BooleanField.tsx +3 -3
  164. package/src/field/CurrencyField.tsx +1 -1
  165. package/src/field/DateField.tsx +1 -1
  166. package/src/field/IdField.test.tsx +8 -20
  167. package/src/field/IdField.tsx +5 -20
  168. package/src/field/NumberField.tsx +1 -1
  169. package/src/field/ReferenceField.test.tsx +15 -6
  170. package/src/field/ReferenceField.tsx +10 -7
  171. package/src/field/ReferenceManyField.test.tsx +55 -10
  172. package/src/field/ReferenceManyField.tsx +84 -13
  173. package/src/field/StatusIndicatorField.test.tsx +7 -21
  174. package/src/field/StatusIndicatorField.tsx +8 -20
  175. package/src/field/TextField.tsx +1 -1
  176. package/src/field/types.ts +12 -13
  177. package/src/form/Form.test.tsx +8 -4
  178. package/src/form/Form.tsx +24 -19
  179. package/src/form/index.ts +1 -1
  180. package/src/hooks/useSchemaFields.ts +89 -0
  181. package/src/i18n/Message.tsx +22 -0
  182. package/src/i18n/RecordMessage.tsx +22 -0
  183. package/src/i18n/index.ts +3 -0
  184. package/src/i18n/types.ts +19 -0
  185. package/src/index.ts +5 -1
  186. package/src/input/ArrayInput.test.tsx +81 -0
  187. package/src/input/{AttributeEditor.tsx → ArrayInput.tsx} +36 -18
  188. package/src/input/AutocompleteInput.test.tsx +2 -4
  189. package/src/input/AutocompleteInput.tsx +9 -11
  190. package/src/input/BooleanInput.tsx +42 -0
  191. package/src/input/CommonInputProps.tsx +8 -0
  192. package/src/input/FieldTitle.tsx +3 -15
  193. package/src/input/FormField.tsx +78 -67
  194. package/src/input/FormFieldContext.ts +1 -1
  195. package/src/input/NumberInput.tsx +10 -7
  196. package/src/input/ReferenceInput.test.tsx +12 -2
  197. package/src/input/ReferenceInput.tsx +32 -14
  198. package/src/input/SelectInput.tsx +14 -17
  199. package/src/input/SliderInput.test.tsx +2 -3
  200. package/src/input/SliderInput.tsx +48 -38
  201. package/src/input/TextAreaInput.tsx +10 -6
  202. package/src/input/TextInput.test.tsx +2 -4
  203. package/src/input/TextInput.tsx +35 -20
  204. package/src/input/index.ts +2 -1
  205. package/src/input/types.ts +40 -8
  206. package/src/layout/AppLayout.test.tsx +23 -3
  207. package/src/layout/AppLayout.tsx +11 -8
  208. package/src/layout/Notifications.test.tsx +102 -0
  209. package/src/layout/Notifications.tsx +61 -0
  210. package/src/layout/Ready.tsx +123 -0
  211. package/src/layout/TopNavigation.test.tsx +2 -3
  212. package/src/layout/TopNavigation.tsx +9 -8
  213. package/src/layout/index.ts +2 -0
  214. package/src/list/Cards.test.tsx +320 -0
  215. package/src/list/Cards.tsx +146 -16
  216. package/src/list/List.tsx +87 -26
  217. package/src/list/Table.test.tsx +40 -5
  218. package/src/list/Table.tsx +89 -98
  219. package/src/list/TableHeader.test.tsx +15 -11
  220. package/src/list/TableHeader.tsx +6 -8
  221. package/src/theme/ThemeManager.tsx +1 -1
  222. package/dist/__mocks__/strato-core.js +0 -50
  223. package/dist/__mocks__to__delete/strato-core.js +0 -50
  224. package/dist/detail/Show.d.ts +0 -39
  225. package/dist/detail/Show.js +0 -40
  226. package/dist/detail/ShowHeader.d.ts +0 -7
  227. package/dist/input/AttributeEditor.d.ts +0 -25
  228. package/src/detail/Show.test.tsx +0 -96
  229. package/src/detail/Show.tsx +0 -104
  230. package/src/detail/ShowHeader.tsx +0 -35
  231. package/src/input/AttributeEditor.test.tsx +0 -147
@@ -1,47 +1,145 @@
1
1
  import React from 'react';
2
2
  import CloudscapeCards, { CardsProps } from '@cloudscape-design/components/cards';
3
3
  import Pagination from '@cloudscape-design/components/pagination';
4
- import { RaRecord, RecordContextProvider, useFieldSchema } from '@strato-admin/core';
4
+ import TextFilter from '@cloudscape-design/components/text-filter';
5
+ import CollectionPreferences from '@cloudscape-design/components/collection-preferences';
6
+ import { RaRecord, RecordContextProvider, useTranslateLabel, useTranslate } from '@strato-admin/ra-core';
7
+ import { useResourceSchema, useSettings } from '@strato-admin/core';
5
8
  import { useCollection } from '../collection-hooks';
9
+ import { useSchemaFields } from '../hooks/useSchemaFields';
6
10
  import KeyValuePairs from '../detail/KeyValuePairs';
11
+ import TableHeader from './TableHeader';
7
12
 
8
- export interface ListCardsProps<T extends RaRecord = any> extends Omit<CardsProps<T>, 'items' | 'cardDefinition'> {
13
+ export interface ListCardsProps<T extends RaRecord = any> extends Omit<
14
+ CardsProps<T>,
15
+ 'items' | 'cardDefinition' | 'preferences'
16
+ > {
9
17
  renderItem?: (item: T) => React.ReactNode;
10
18
  include?: string[];
11
19
  exclude?: string[];
20
+ children?: React.ReactNode;
21
+ title?: React.ReactNode;
22
+ description?: string;
23
+ actions?: React.ReactNode;
24
+ selectionType?: 'single' | 'multi';
25
+ /**
26
+ * Whether to enable text filtering.
27
+ * @default true
28
+ */
29
+ filtering?: boolean;
30
+ /**
31
+ * Placeholder text for the filter input.
32
+ * @default "Search..."
33
+ */
34
+ filteringPlaceholder?: string;
35
+ /**
36
+ * Options for the page size selector.
37
+ */
38
+ pageSizeOptions?: ReadonlyArray<{ value: number; label?: string }>;
39
+ /**
40
+ * Whether to show the preferences button or custom preferences content.
41
+ * @default true
42
+ */
43
+ preferences?: boolean | React.ReactNode;
12
44
  }
13
45
 
14
- export const ListCards = <T extends RaRecord = any>({
15
- renderItem,
46
+ export const ListCards = <T extends RaRecord = any>({
47
+ renderItem,
16
48
  include,
17
49
  exclude,
18
- ...props
50
+ children,
51
+ title,
52
+ description,
53
+ actions,
54
+ selectionType,
55
+ filtering = true,
56
+ filteringPlaceholder,
57
+ pageSizeOptions,
58
+ preferences = true,
59
+ ...props
19
60
  }: ListCardsProps<T>) => {
20
- const { items, paginationProps, collectionProps } = useCollection<T>({
21
- filtering: {},
22
- pagination: {},
23
- sorting: {},
24
- });
61
+ const translate = useTranslate();
62
+ const { listPageSizes, listPageSizeLabel } = useSettings();
63
+
64
+ const resolvedPageSizeOptions =
65
+ pageSizeOptions ??
66
+ (listPageSizes && listPageSizeLabel
67
+ ? listPageSizes.map((value) => ({ value, label: listPageSizeLabel(value) }))
68
+ : undefined);
69
+ const translateLabel = useTranslateLabel();
70
+ const { resource, label: schemaLabel, definition } = useResourceSchema();
71
+
72
+ const { getListFields } = useSchemaFields();
25
73
 
26
- const schemaChildren = useFieldSchema();
74
+ const finalSelectionType = selectionType ?? (definition?.options?.canDelete ? 'multi' : undefined);
27
75
 
28
- const defaultRenderItem = (_item: T) => (
29
- <KeyValuePairs include={include} exclude={exclude}>
30
- {schemaChildren}
31
- </KeyValuePairs>
76
+ const finalChildren = React.useMemo(
77
+ () => getListFields(children, { include, exclude }),
78
+ [getListFields, children, include, exclude],
32
79
  );
33
80
 
81
+ const visibleContentOptions = React.useMemo(() => {
82
+ const options: { id: string; label: string }[] = [];
83
+ finalChildren.forEach((child, index) => {
84
+ if (!React.isValidElement(child)) return;
85
+ const { source, label } = child.props as any;
86
+ const headerLabel = translateLabel({ label, resource, source });
87
+ if (typeof headerLabel === 'string') {
88
+ options.push({
89
+ id: source || `section-${index}`,
90
+ label: headerLabel,
91
+ });
92
+ }
93
+ });
94
+ return options;
95
+ }, [finalChildren, resource, translateLabel]);
96
+
97
+ const { items, paginationProps, collectionProps, filterProps, preferencesProps } = useCollection<T>({
98
+ preferences: {
99
+ pageSizeOptions: resolvedPageSizeOptions as any,
100
+ visibleContentOptions: visibleContentOptions.length > 0 ? visibleContentOptions : undefined,
101
+ },
102
+ });
103
+
104
+ const displayedChildren = React.useMemo(() => {
105
+ const { visibleContent } = preferencesProps.preferences;
106
+ if (!visibleContent) return finalChildren;
107
+
108
+ return finalChildren.filter((child) => {
109
+ if (!React.isValidElement(child)) return true;
110
+ const { source } = child.props as any;
111
+ // If the child doesn't have a source, we don't know how to toggle it, so we keep it.
112
+ if (!source) return true;
113
+ // If it's not in the options, it's not toggleable, so we keep it.
114
+ if (!visibleContentOptions.some((opt) => opt.id === source)) return true;
115
+
116
+ return visibleContent.includes(source);
117
+ });
118
+ }, [finalChildren, preferencesProps.preferences.visibleContent, visibleContentOptions]);
119
+
120
+ const defaultRenderItem = (_item: T) => <KeyValuePairs>{displayedChildren}</KeyValuePairs>;
121
+
34
122
  const finalRenderItem = renderItem || defaultRenderItem;
35
123
 
36
124
  const cardDefinition: CardsProps.CardDefinition<T> = {
37
125
  sections: [
38
126
  {
39
127
  id: 'main',
40
- content: (item: T) => <RecordContextProvider value={item}>{finalRenderItem(item) as any}</RecordContextProvider>,
128
+ content: (item: T) => (
129
+ <RecordContextProvider value={item}>{finalRenderItem(item) as any}</RecordContextProvider>
130
+ ),
41
131
  },
42
132
  ],
43
133
  };
44
134
 
135
+ const cardsHeader = React.useMemo(() => {
136
+ if (React.isValidElement(title)) {
137
+ return title;
138
+ }
139
+ const finalTitle = title !== undefined ? title : schemaLabel;
140
+ return <TableHeader title={finalTitle} description={description} actions={actions} />;
141
+ }, [title, description, actions, schemaLabel]);
142
+
45
143
  return (
46
144
  <CloudscapeCards
47
145
  {...collectionProps}
@@ -49,6 +147,38 @@ export const ListCards = <T extends RaRecord = any>({
49
147
  items={items || []}
50
148
  cardDefinition={cardDefinition}
51
149
  pagination={<Pagination {...paginationProps} />}
150
+ header={cardsHeader}
151
+ selectionType={finalSelectionType}
152
+ filter={filtering && <TextFilter {...filterProps} filteringPlaceholder={filteringPlaceholder} />}
153
+ preferences={
154
+ preferences === true || resolvedPageSizeOptions ? (
155
+ <CollectionPreferences
156
+ {...preferencesProps}
157
+ pageSizePreference={
158
+ resolvedPageSizeOptions
159
+ ? {
160
+ options: resolvedPageSizeOptions as any,
161
+ }
162
+ : undefined
163
+ }
164
+ visibleContentPreference={
165
+ visibleContentOptions.length > 0
166
+ ? {
167
+ title: translate('strato.action.select_sections', { _: 'Select visible sections' }),
168
+ options: [
169
+ {
170
+ label: translate('strato.action.select_sections', { _: 'Select visible sections' }),
171
+ options: visibleContentOptions,
172
+ },
173
+ ],
174
+ }
175
+ : undefined
176
+ }
177
+ />
178
+ ) : React.isValidElement(preferences) ? (
179
+ preferences
180
+ ) : undefined
181
+ }
52
182
  />
53
183
  );
54
184
  };
package/src/list/List.tsx CHANGED
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
- import { ListBase, type RaRecord, ResourceSchemaProvider } from '@strato-admin/core';
2
+ import { ListBase, type RaRecord, type ListBaseProps, useTranslate } from '@strato-admin/ra-core';
3
+ import { ResourceSchemaProvider, useResourceSchema, useConstructedPageTitle, useSettings } from '@strato-admin/core';
3
4
  import Table from './Table';
4
5
 
5
- export interface ListProps<_RecordType extends RaRecord = any> {
6
+ export interface ListProps<RecordType extends RaRecord = any> extends ListBaseProps<RecordType> {
6
7
  children?: React.ReactNode;
7
- fieldSchema?: React.ReactNode;
8
8
  include?: string[];
9
9
  exclude?: string[];
10
- title?: React.ReactNode;
10
+ title?: React.ReactNode | (() => React.ReactNode);
11
+ description?: React.ReactNode | (() => React.ReactNode);
11
12
  actions?: React.ReactNode;
12
13
  /**
13
14
  * Whether to enable text filtering in the implicit Table.
@@ -19,9 +20,71 @@ export interface ListProps<_RecordType extends RaRecord = any> {
19
20
  * @default true
20
21
  */
21
22
  preferences?: boolean | React.ReactNode;
22
- [key: string]: any;
23
+ /**
24
+ * The fields to display by default.
25
+ */
26
+ display?: string[];
23
27
  }
24
28
 
29
+ const ListUI = ({
30
+ children,
31
+ title,
32
+ actions,
33
+ description,
34
+ include,
35
+ exclude,
36
+ filtering,
37
+ preferences,
38
+ display,
39
+ }: {
40
+ children?: React.ReactNode;
41
+ title?: React.ReactNode | (() => React.ReactNode);
42
+ actions?: React.ReactNode;
43
+ description?: React.ReactNode | (() => React.ReactNode);
44
+ include?: string[];
45
+ exclude?: string[];
46
+ filtering?: boolean;
47
+ preferences?: boolean | React.ReactNode;
48
+ display?: string[];
49
+ }) => {
50
+ const { label, listTitle, listDescription, listComponent: ListComponent = Table } = useResourceSchema();
51
+ const translate = useTranslate();
52
+ const constructedTitle = useConstructedPageTitle('list', label);
53
+
54
+ const finalTitle = React.useMemo(() => {
55
+ if (typeof title === 'function') return title();
56
+ if (React.isValidElement(title)) return title;
57
+ if (title) return translate(title as string);
58
+ if (React.isValidElement(listTitle)) return listTitle;
59
+ if (listTitle) return translate(listTitle as string);
60
+ return constructedTitle;
61
+ }, [title, listTitle, translate, constructedTitle]);
62
+
63
+ const finalDescription = React.useMemo(() => {
64
+ if (typeof description === 'function') return description();
65
+ if (React.isValidElement(description)) return description;
66
+ if (description) return translate(description as string);
67
+ if (React.isValidElement(listDescription)) return listDescription;
68
+ if (listDescription) return translate(listDescription as string);
69
+ return undefined;
70
+ }, [description, listDescription, translate]);
71
+
72
+ const finalChildren = children || (
73
+ <ListComponent
74
+ include={include}
75
+ exclude={exclude}
76
+ display={display}
77
+ title={finalTitle}
78
+ description={finalDescription}
79
+ actions={actions}
80
+ filtering={filtering}
81
+ preferences={preferences}
82
+ />
83
+ );
84
+
85
+ return <>{finalChildren}</>;
86
+ };
87
+
25
88
  /**
26
89
  * A List component that provides a list context and a Cloudscape Table.
27
90
  *
@@ -31,43 +94,41 @@ export interface ListProps<_RecordType extends RaRecord = any> {
31
94
  * <Table.Column source="name" />
32
95
  * </Table>
33
96
  * </List>
34
- *
97
+ *
35
98
  * @example
36
99
  * // Using FieldSchema from context
37
100
  * <List include={['name', 'price']} />
38
- *
39
- * @example
40
- * // Passing a custom field schema
41
- * <List fieldSchema={<FieldSchema>...</FieldSchema>}>
42
- * <Table />
43
- * </List>
44
101
  */
45
102
  export const List = <RecordType extends RaRecord = any>({
46
103
  children,
47
- fieldSchema,
48
104
  include,
49
105
  exclude,
50
106
  title,
51
107
  actions,
108
+ description,
52
109
  filtering = true,
53
110
  preferences = true,
111
+ display,
54
112
  ...props
55
113
  }: ListProps<RecordType>) => {
56
- const finalChildren = children || (
57
- <Table
58
- include={include}
59
- exclude={exclude}
60
- title={title}
61
- actions={actions}
62
- filtering={filtering}
63
- preferences={preferences}
64
- />
65
- );
114
+ const { queryOptions } = useResourceSchema(props.resource);
115
+ const { listPageSize } = useSettings();
66
116
 
67
117
  return (
68
- <ListBase {...props}>
69
- <ResourceSchemaProvider resource={props.resource} fieldSchema={fieldSchema}>
70
- {finalChildren as any}
118
+ <ListBase queryOptions={queryOptions} {...props} perPage={props.perPage ?? listPageSize}>
119
+ <ResourceSchemaProvider resource={props.resource}>
120
+ <ListUI
121
+ title={title}
122
+ actions={actions}
123
+ description={description}
124
+ include={include}
125
+ exclude={exclude}
126
+ filtering={filtering}
127
+ preferences={preferences}
128
+ display={display}
129
+ >
130
+ {children}
131
+ </ListUI>
71
132
  </ResourceSchemaProvider>
72
133
  </ListBase>
73
134
  );
@@ -1,12 +1,12 @@
1
1
  import React from 'react';
2
2
  import { render, cleanup } from '@testing-library/react';
3
3
  import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
4
- import { useResourceContext, useListContext, useResourceDefinitions } from '@strato-admin/core';
4
+ import { useResourceContext, useListContext, useResourceDefinitions } from '@strato-admin/ra-core';
5
5
  import { useCollection } from '../collection-hooks';
6
6
  import Table from './Table';
7
7
  import CloudscapeTable from '@cloudscape-design/components/table';
8
8
 
9
- // Mock ra-core
9
+ vi.mock('@strato-admin/ra-core', () => import('../__mocks__/ra-core'));
10
10
  vi.mock('@strato-admin/core', () => import('../__mocks__/strato-core'));
11
11
 
12
12
  // Mock react-router-dom
@@ -197,11 +197,11 @@ describe('DataTable', () => {
197
197
  expect(tableProps.selectionType).toBe('multi');
198
198
  });
199
199
 
200
- it('should pass default visible fields to useCollection', () => {
200
+ it('should pass display fields to useCollection', () => {
201
201
  (useResourceContext as any).mockReturnValue('products');
202
202
 
203
203
  render(
204
- <Table defaultVisibleFields={['name', 'price']}>
204
+ <Table display={['name', 'price']}>
205
205
  <Table.Column source="id" label="ID" />
206
206
  <Table.Column source="name" label="Name" />
207
207
  <Table.Column source="price" label="Price" />
@@ -219,7 +219,7 @@ describe('DataTable', () => {
219
219
  ]);
220
220
  });
221
221
 
222
- it('should default to first 5 columns if defaultVisibleFields is not provided', () => {
222
+ it('should default to first 5 columns if display is not provided', () => {
223
223
  (useResourceContext as any).mockReturnValue('products');
224
224
 
225
225
  render(
@@ -252,4 +252,39 @@ describe('DataTable', () => {
252
252
 
253
253
  expect(queryByTestId('table-header')).toBeNull();
254
254
  });
255
+
256
+ it('should hide collection fields by default', () => {
257
+ (useResourceContext as any).mockReturnValue('products');
258
+ const CollectionField = () => <div />;
259
+ (CollectionField as any).isCollectionField = true;
260
+
261
+ render(
262
+ <Table>
263
+ <Table.Column source="name" />
264
+ <CollectionField key="collection" source="items" />
265
+ </Table>,
266
+ );
267
+
268
+ const tableProps = (CloudscapeTable as any).mock.calls[0][0];
269
+ expect(tableProps.columnDefinitions).toHaveLength(1);
270
+ expect(tableProps.columnDefinitions[0].id).toBe('products___name');
271
+ });
272
+
273
+ it('should show collection fields when explicitly included', () => {
274
+ (useResourceContext as any).mockReturnValue('products');
275
+ const CollectionField = () => <div />;
276
+ (CollectionField as any).isCollectionField = true;
277
+
278
+ render(
279
+ <Table include={['name', 'items']}>
280
+ <Table.Column source="name" />
281
+ <CollectionField key="collection" source="items" />
282
+ </Table>,
283
+ );
284
+
285
+ const tableProps = (CloudscapeTable as any).mock.calls[0][0];
286
+ expect(tableProps.columnDefinitions).toHaveLength(2);
287
+ expect(tableProps.columnDefinitions[0].id).toBe('products___name');
288
+ expect(tableProps.columnDefinitions[1].id).toBe('products___items');
289
+ });
255
290
  });