@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.
- package/dist/Admin.d.ts +6 -2
- package/dist/Admin.js +14 -8
- package/dist/RecordLink.js +5 -4
- package/dist/Settings.d.ts +17 -0
- package/dist/Settings.js +14 -0
- package/dist/button/BulkDeleteButton.d.ts +4 -1
- package/dist/button/BulkDeleteButton.js +37 -5
- package/dist/button/Button.d.ts +2 -1
- package/dist/button/CancelButton.d.ts +6 -0
- package/dist/button/CancelButton.js +10 -0
- package/dist/button/CreateButton.js +9 -8
- package/dist/button/DeleteButton.d.ts +13 -0
- package/dist/button/DeleteButton.js +36 -0
- package/dist/button/EditButton.d.ts +1 -1
- package/dist/button/EditButton.js +10 -10
- package/dist/button/SaveButton.js +2 -2
- package/dist/button/index.d.ts +2 -0
- package/dist/button/index.js +2 -0
- package/dist/collection-hooks/interfaces.d.ts +7 -3
- package/dist/collection-hooks/useCollection.d.ts +1 -1
- package/dist/collection-hooks/useCollection.js +15 -10
- package/dist/create/Create.d.ts +9 -17
- package/dist/create/Create.js +40 -12
- package/dist/create/CreateHeader.d.ts +2 -2
- package/dist/create/CreateHeader.js +4 -5
- package/dist/defaults.d.ts +6 -0
- package/dist/defaults.js +21 -0
- package/dist/detail/Detail.d.ts +33 -0
- package/dist/detail/Detail.js +22 -0
- package/dist/detail/DetailHeader.d.ts +11 -0
- package/dist/detail/{ShowHeader.js → DetailHeader.js} +7 -5
- package/dist/detail/DetailHub.d.ts +27 -0
- package/dist/detail/DetailHub.js +63 -0
- package/dist/detail/KeyValuePairs.d.ts +7 -1
- package/dist/detail/KeyValuePairs.js +14 -8
- package/dist/detail/index.d.ts +3 -2
- package/dist/detail/index.js +3 -2
- package/dist/edit/Edit.d.ts +8 -19
- package/dist/edit/Edit.js +48 -12
- package/dist/edit/EditHeader.d.ts +2 -2
- package/dist/edit/EditHeader.js +5 -4
- package/dist/field/ArrayField.d.ts +26 -10
- package/dist/field/ArrayField.js +38 -10
- package/dist/field/BadgeField.d.ts +1 -1
- package/dist/field/BadgeField.js +1 -1
- package/dist/field/BooleanField.d.ts +1 -1
- package/dist/field/BooleanField.js +2 -2
- package/dist/field/CurrencyField.d.ts +1 -1
- package/dist/field/CurrencyField.js +1 -1
- package/dist/field/DateField.d.ts +1 -1
- package/dist/field/DateField.js +1 -1
- package/dist/field/IdField.d.ts +1 -1
- package/dist/field/IdField.js +3 -3
- package/dist/field/NumberField.d.ts +1 -1
- package/dist/field/NumberField.js +1 -1
- package/dist/field/ReferenceField.d.ts +1 -1
- package/dist/field/ReferenceField.js +4 -2
- package/dist/field/ReferenceManyField.d.ts +35 -4
- package/dist/field/ReferenceManyField.js +17 -4
- package/dist/field/StatusIndicatorField.d.ts +1 -1
- package/dist/field/StatusIndicatorField.js +6 -5
- package/dist/field/TextField.d.ts +1 -1
- package/dist/field/TextField.js +1 -1
- package/dist/field/types.d.ts +9 -9
- package/dist/form/Form.d.ts +12 -2
- package/dist/form/Form.js +10 -16
- package/dist/form/index.d.ts +1 -1
- package/dist/form/index.js +1 -1
- package/dist/hooks/useSchemaFields.d.ts +22 -0
- package/dist/hooks/useSchemaFields.js +45 -0
- package/dist/i18n/Message.d.ts +15 -0
- package/dist/i18n/Message.js +19 -0
- package/dist/i18n/RecordMessage.d.ts +14 -0
- package/dist/i18n/RecordMessage.js +16 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/types.d.ts +19 -0
- package/dist/i18n/types.js +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/input/ArrayInput.d.ts +33 -0
- package/dist/input/{AttributeEditor.js → ArrayInput.js} +18 -11
- package/dist/input/AutocompleteInput.d.ts +1 -1
- package/dist/input/AutocompleteInput.js +3 -3
- package/dist/input/BooleanInput.d.ts +6 -0
- package/dist/input/BooleanInput.js +23 -0
- package/dist/input/CommonInputProps.d.ts +6 -0
- package/dist/input/CommonInputProps.js +6 -0
- package/dist/input/FieldTitle.js +4 -4
- package/dist/input/FormField.js +12 -3
- package/dist/input/FormFieldContext.d.ts +1 -1
- package/dist/input/NumberInput.d.ts +1 -1
- package/dist/input/NumberInput.js +3 -3
- package/dist/input/ReferenceInput.d.ts +1 -1
- package/dist/input/ReferenceInput.js +22 -12
- package/dist/input/SelectInput.d.ts +1 -1
- package/dist/input/SelectInput.js +3 -3
- package/dist/input/SliderInput.d.ts +1 -1
- package/dist/input/SliderInput.js +4 -4
- package/dist/input/TextAreaInput.d.ts +1 -1
- package/dist/input/TextAreaInput.js +3 -3
- package/dist/input/TextInput.d.ts +1 -1
- package/dist/input/TextInput.js +6 -12
- package/dist/input/index.d.ts +2 -1
- package/dist/input/index.js +2 -1
- package/dist/input/types.d.ts +33 -2
- package/dist/layout/AppLayout.js +6 -3
- package/dist/layout/Notifications.d.ts +1 -0
- package/dist/layout/Notifications.js +51 -0
- package/dist/layout/Ready.d.ts +6 -0
- package/dist/layout/Ready.js +24 -0
- package/dist/layout/TopNavigation.d.ts +4 -2
- package/dist/layout/TopNavigation.js +7 -7
- package/dist/layout/index.d.ts +2 -0
- package/dist/layout/index.js +2 -0
- package/dist/list/Cards.d.ts +31 -4
- package/dist/list/Cards.js +81 -10
- package/dist/list/List.d.ts +9 -12
- package/dist/list/List.js +41 -11
- package/dist/list/Table.d.ts +8 -4
- package/dist/list/Table.js +55 -55
- package/dist/list/TableHeader.d.ts +2 -2
- package/dist/list/TableHeader.js +4 -5
- package/dist/theme/ThemeManager.js +1 -1
- package/package.json +9 -6
- package/src/Admin.tsx +35 -18
- package/src/RecordLink.stories.tsx +1 -1
- package/src/RecordLink.tsx +5 -4
- package/src/Settings.tsx +16 -0
- package/src/__mocks__/ra-core.tsx +83 -0
- package/src/__mocks__/strato-core.tsx +36 -42
- package/src/button/BulkDeleteButton.test.tsx +45 -8
- package/src/button/BulkDeleteButton.tsx +75 -12
- package/src/button/Button.tsx +31 -2
- package/src/button/CancelButton.tsx +20 -0
- package/src/button/CreateButton.tsx +12 -10
- package/src/button/DeleteButton.tsx +96 -0
- package/src/button/EditButton.tsx +13 -12
- package/src/button/SaveButton.tsx +2 -3
- package/src/button/index.ts +2 -0
- package/src/collection-hooks/interfaces.ts +7 -3
- package/src/collection-hooks/useCollection.test.ts +115 -2
- package/src/collection-hooks/useCollection.ts +15 -10
- package/src/create/Create.test.tsx +3 -3
- package/src/create/Create.tsx +68 -37
- package/src/create/CreateHeader.tsx +6 -10
- package/src/defaults.tsx +28 -0
- package/src/detail/Detail-CollectionFields.test.tsx +84 -0
- package/src/detail/Detail.test.tsx +91 -0
- package/src/detail/Detail.tsx +48 -0
- package/src/detail/{ShowHeader.test.tsx → DetailHeader.test.tsx} +11 -9
- package/src/detail/DetailHeader.tsx +42 -0
- package/src/detail/DetailHub.tsx +88 -0
- package/src/detail/KeyValuePairs.test.tsx +2 -2
- package/src/detail/KeyValuePairs.tsx +25 -18
- package/src/detail/index.ts +3 -2
- package/src/edit/Edit.test.tsx +7 -5
- package/src/edit/Edit.tsx +92 -40
- package/src/edit/EditHeader.tsx +7 -5
- package/src/field/ArrayField.tsx +57 -11
- package/src/field/BadgeField.tsx +2 -3
- package/src/field/BooleanField.test.tsx +2 -3
- package/src/field/BooleanField.tsx +3 -3
- package/src/field/CurrencyField.tsx +1 -1
- package/src/field/DateField.tsx +1 -1
- package/src/field/IdField.test.tsx +8 -20
- package/src/field/IdField.tsx +5 -20
- package/src/field/NumberField.tsx +1 -1
- package/src/field/ReferenceField.test.tsx +15 -6
- package/src/field/ReferenceField.tsx +10 -7
- package/src/field/ReferenceManyField.test.tsx +55 -10
- package/src/field/ReferenceManyField.tsx +84 -13
- package/src/field/StatusIndicatorField.test.tsx +7 -21
- package/src/field/StatusIndicatorField.tsx +8 -20
- package/src/field/TextField.tsx +1 -1
- package/src/field/types.ts +12 -13
- package/src/form/Form.test.tsx +8 -4
- package/src/form/Form.tsx +24 -19
- package/src/form/index.ts +1 -1
- package/src/hooks/useSchemaFields.ts +89 -0
- package/src/i18n/Message.tsx +22 -0
- package/src/i18n/RecordMessage.tsx +22 -0
- package/src/i18n/index.ts +3 -0
- package/src/i18n/types.ts +19 -0
- package/src/index.ts +5 -1
- package/src/input/ArrayInput.test.tsx +81 -0
- package/src/input/{AttributeEditor.tsx → ArrayInput.tsx} +36 -18
- package/src/input/AutocompleteInput.test.tsx +2 -4
- package/src/input/AutocompleteInput.tsx +9 -11
- package/src/input/BooleanInput.tsx +42 -0
- package/src/input/CommonInputProps.tsx +8 -0
- package/src/input/FieldTitle.tsx +3 -15
- package/src/input/FormField.tsx +78 -67
- package/src/input/FormFieldContext.ts +1 -1
- package/src/input/NumberInput.tsx +10 -7
- package/src/input/ReferenceInput.test.tsx +12 -2
- package/src/input/ReferenceInput.tsx +32 -14
- package/src/input/SelectInput.tsx +14 -17
- package/src/input/SliderInput.test.tsx +2 -3
- package/src/input/SliderInput.tsx +48 -38
- package/src/input/TextAreaInput.tsx +10 -6
- package/src/input/TextInput.test.tsx +2 -4
- package/src/input/TextInput.tsx +35 -20
- package/src/input/index.ts +2 -1
- package/src/input/types.ts +40 -8
- package/src/layout/AppLayout.test.tsx +23 -3
- package/src/layout/AppLayout.tsx +11 -8
- package/src/layout/Notifications.test.tsx +102 -0
- package/src/layout/Notifications.tsx +61 -0
- package/src/layout/Ready.tsx +123 -0
- package/src/layout/TopNavigation.test.tsx +2 -3
- package/src/layout/TopNavigation.tsx +9 -8
- package/src/layout/index.ts +2 -0
- package/src/list/Cards.test.tsx +320 -0
- package/src/list/Cards.tsx +146 -16
- package/src/list/List.tsx +87 -26
- package/src/list/Table.test.tsx +40 -5
- package/src/list/Table.tsx +89 -98
- package/src/list/TableHeader.test.tsx +15 -11
- package/src/list/TableHeader.tsx +6 -8
- package/src/theme/ThemeManager.tsx +1 -1
- package/dist/__mocks__/strato-core.js +0 -50
- package/dist/__mocks__to__delete/strato-core.js +0 -50
- package/dist/detail/Show.d.ts +0 -39
- package/dist/detail/Show.js +0 -40
- package/dist/detail/ShowHeader.d.ts +0 -7
- package/dist/input/AttributeEditor.d.ts +0 -25
- package/src/detail/Show.test.tsx +0 -96
- package/src/detail/Show.tsx +0 -104
- package/src/detail/ShowHeader.tsx +0 -35
- package/src/input/AttributeEditor.test.tsx +0 -147
package/src/list/Cards.tsx
CHANGED
|
@@ -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
|
|
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<
|
|
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
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
74
|
+
const finalSelectionType = selectionType ?? (definition?.options?.canDelete ? 'multi' : undefined);
|
|
27
75
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
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) =>
|
|
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,
|
|
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<
|
|
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
|
-
|
|
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
|
|
57
|
-
|
|
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}
|
|
70
|
-
|
|
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
|
);
|
package/src/list/Table.test.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
|
200
|
+
it('should pass display fields to useCollection', () => {
|
|
201
201
|
(useResourceContext as any).mockReturnValue('products');
|
|
202
202
|
|
|
203
203
|
render(
|
|
204
|
-
<Table
|
|
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
|
|
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
|
});
|