@firecms/core 3.0.0-alpha.21 → 3.0.0-alpha.24
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/components/TextareaAutosize.d.ts +2 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/core/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +7 -1
- package/dist/core/components/EntityCollectionTable/useEntityCollectionTableController.d.ts +1 -1
- package/dist/core/components/VirtualTable/VirtualTableHeader.d.ts +1 -0
- package/dist/core/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
- package/dist/core/components/VirtualTable/VirtualTableProps.d.ts +12 -0
- package/dist/core/components/VirtualTable/types.d.ts +2 -0
- package/dist/core/form_field_configs.d.ts +1 -1
- package/dist/core/util/make_properties_editable.d.ts +2 -1
- package/dist/core/util/property_utils.d.ts +2 -1
- package/dist/index.es.js +7987 -7905
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +105 -105
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collections.d.ts +1 -0
- package/dist/types/plugins.d.ts +22 -0
- package/package.json +137 -136
- package/src/components/BooleanSwitch.tsx +1 -1
- package/src/components/BooleanSwitchWithLabel.tsx +2 -2
- package/src/components/CircularProgress.tsx +1 -1
- package/src/components/TextField.tsx +5 -6
- package/src/components/TextareaAutosize.tsx +8 -4
- package/src/components/index.tsx +2 -0
- package/src/core/components/EntityCollectionTable/EntityCollectionTable.tsx +11 -3
- package/src/core/components/EntityCollectionTable/EntityCollectionTableProps.tsx +11 -1
- package/src/core/components/EntityCollectionTable/internal/PropertyTableCell.tsx +4 -2
- package/src/core/components/EntityCollectionTable/useEntityCollectionTableController.tsx +1 -1
- package/src/core/components/EntityCollectionView/EntityCollectionView.tsx +55 -3
- package/src/core/components/VirtualTable/VirtualTable.tsx +19 -7
- package/src/core/components/VirtualTable/VirtualTableHeader.tsx +26 -24
- package/src/core/components/VirtualTable/VirtualTableHeaderRow.tsx +7 -2
- package/src/core/components/VirtualTable/VirtualTableProps.tsx +14 -0
- package/src/core/components/VirtualTable/VirtualTableRow.tsx +1 -1
- package/src/core/components/VirtualTable/types.tsx +2 -0
- package/src/core/util/make_properties_editable.ts +18 -1
- package/src/core/util/property_utils.tsx +6 -1
- package/src/form/components/LabelWithIcon.tsx +2 -3
- package/src/form/field_bindings/TextFieldBinding.tsx +1 -2
- package/src/types/collections.ts +2 -0
- package/src/types/plugins.tsx +24 -1
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
FilterValues,
|
|
11
11
|
PartialEntityCollection,
|
|
12
12
|
PropertyOrBuilder,
|
|
13
|
+
ResolvedProperty,
|
|
13
14
|
SaveEntityProps,
|
|
14
15
|
SelectionController
|
|
15
16
|
} from "../../../types";
|
|
@@ -228,6 +229,17 @@ export const EntityCollectionView = React.memo(
|
|
|
228
229
|
setLastDeleteTimestamp(Date.now());
|
|
229
230
|
}, [setSelectedEntities]);
|
|
230
231
|
|
|
232
|
+
let AddColumnComponent: React.ComponentType<{
|
|
233
|
+
fullPath: string,
|
|
234
|
+
parentPathSegments: string[],
|
|
235
|
+
collection: EntityCollection;
|
|
236
|
+
}> | undefined
|
|
237
|
+
|
|
238
|
+
// we are only using the first plugin that implements this
|
|
239
|
+
if (context?.plugins) {
|
|
240
|
+
AddColumnComponent = context.plugins.find(plugin => plugin.collectionView?.AddColumnComponent)?.collectionView?.AddColumnComponent;
|
|
241
|
+
}
|
|
242
|
+
|
|
231
243
|
const onCollectionModifiedForUser = useCallback((path: string, partialCollection: PartialEntityCollection<M>) => {
|
|
232
244
|
if (userConfigPersistence) {
|
|
233
245
|
const currentStoredConfig = userConfigPersistence.getCollectionConfig(path);
|
|
@@ -305,7 +317,11 @@ export const EntityCollectionView = React.memo(
|
|
|
305
317
|
fields: context.fields
|
|
306
318
|
}), [collection, fullPath]);
|
|
307
319
|
|
|
308
|
-
const getPropertyFor = useCallback(({
|
|
320
|
+
const getPropertyFor = useCallback(({
|
|
321
|
+
propertyKey,
|
|
322
|
+
propertyValue,
|
|
323
|
+
entity
|
|
324
|
+
}: GetPropertyForProps<M>) => {
|
|
309
325
|
let propertyOrBuilder: PropertyOrBuilder<any, M> | undefined = getPropertyInPath<M>(collection.properties, propertyKey);
|
|
310
326
|
|
|
311
327
|
// we might not find the property in the collection if combining property builders and map spread
|
|
@@ -485,6 +501,42 @@ export const EntityCollectionView = React.memo(
|
|
|
485
501
|
|
|
486
502
|
</Popover>;
|
|
487
503
|
|
|
504
|
+
function buildAdditionalHeaderWidget({
|
|
505
|
+
property,
|
|
506
|
+
propertyKey,
|
|
507
|
+
onHover
|
|
508
|
+
}: {
|
|
509
|
+
property: ResolvedProperty,
|
|
510
|
+
propertyKey: string,
|
|
511
|
+
onHover: boolean
|
|
512
|
+
}) {
|
|
513
|
+
if (!context.plugins)
|
|
514
|
+
return null;
|
|
515
|
+
return <>
|
|
516
|
+
{context.plugins.filter(plugin => plugin.collectionView?.HeaderAction)
|
|
517
|
+
.map((plugin, i) => {
|
|
518
|
+
const HeaderAction = plugin.collectionView!.HeaderAction!;
|
|
519
|
+
return <HeaderAction
|
|
520
|
+
key={`plugin_header_action_${i}`}
|
|
521
|
+
propertyKey={propertyKey}
|
|
522
|
+
property={property}
|
|
523
|
+
onHover={onHover}
|
|
524
|
+
fullPath={fullPath}
|
|
525
|
+
parentPathSegments={parentPathSegments ?? []}/>;
|
|
526
|
+
})}
|
|
527
|
+
</>;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const addColumnComponentInternal = AddColumnComponent
|
|
531
|
+
? function () {
|
|
532
|
+
if (typeof AddColumnComponent === "function")
|
|
533
|
+
return <AddColumnComponent fullPath={fullPath}
|
|
534
|
+
parentPathSegments={parentPathSegments ?? []}
|
|
535
|
+
collection={collection}/>;
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
: undefined;
|
|
539
|
+
|
|
488
540
|
return (
|
|
489
541
|
<div className={cn("overflow-hidden h-full w-full", className)}
|
|
490
542
|
ref={containerRef}>
|
|
@@ -519,6 +571,8 @@ export const EntityCollectionView = React.memo(
|
|
|
519
571
|
/>}
|
|
520
572
|
hoverRow={hoverRow}
|
|
521
573
|
inlineEditing={checkInlineEditing()}
|
|
574
|
+
additionalHeaderWidget={buildAdditionalHeaderWidget}
|
|
575
|
+
AddColumnComponent={addColumnComponentInternal}
|
|
522
576
|
/>
|
|
523
577
|
|
|
524
578
|
<PopupFormField
|
|
@@ -632,5 +686,3 @@ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityC
|
|
|
632
686
|
}
|
|
633
687
|
return { properties: { [key]: { columnWidth: width } } } as PartialEntityCollection;
|
|
634
688
|
}
|
|
635
|
-
|
|
636
|
-
|
|
@@ -26,7 +26,10 @@ import { AssignmentIcon } from "../../../icons";
|
|
|
26
26
|
const VirtualListContext = createContext<VirtualTableContextProps<any>>({} as any);
|
|
27
27
|
VirtualListContext.displayName = "VirtualListContext";
|
|
28
28
|
|
|
29
|
-
type InnerElementProps = {
|
|
29
|
+
type InnerElementProps = {
|
|
30
|
+
children: React.ReactNode,
|
|
31
|
+
style: any
|
|
32
|
+
};
|
|
30
33
|
|
|
31
34
|
// eslint-disable-next-line react/display-name
|
|
32
35
|
const innerElementType = forwardRef<HTMLDivElement, InnerElementProps>(({
|
|
@@ -107,7 +110,8 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
107
110
|
createFilterField,
|
|
108
111
|
rowClassName,
|
|
109
112
|
className,
|
|
110
|
-
endAdornment
|
|
113
|
+
endAdornment,
|
|
114
|
+
AddColumnComponent
|
|
111
115
|
}: VirtualTableProps<T>) {
|
|
112
116
|
|
|
113
117
|
const sortByProperty: string | undefined = sortBy ? sortBy[0] : undefined;
|
|
@@ -186,11 +190,11 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
186
190
|
|
|
187
191
|
const maxScroll = Math.max((data?.length ?? 0) * getRowHeight(size) - bounds.height, 0);
|
|
188
192
|
const onEndReachedInternal = useCallback((scrollOffset: number) => {
|
|
189
|
-
if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current +
|
|
193
|
+
if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current + 600) {
|
|
190
194
|
endReachCallbackThreshold.current = scrollOffset;
|
|
191
195
|
onEndReached();
|
|
192
196
|
}
|
|
193
|
-
}, [data, onEndReached]);
|
|
197
|
+
}, [data?.length, onEndReached]);
|
|
194
198
|
|
|
195
199
|
const onScroll = useCallback(({
|
|
196
200
|
scrollOffset,
|
|
@@ -200,7 +204,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
200
204
|
scrollOffset: number,
|
|
201
205
|
scrollUpdateWasRequested: boolean;
|
|
202
206
|
}) => {
|
|
203
|
-
if (!scrollUpdateWasRequested && (scrollOffset >= maxScroll -
|
|
207
|
+
if (!scrollUpdateWasRequested && (scrollOffset >= maxScroll - 600))
|
|
204
208
|
onEndReachedInternal(scrollOffset);
|
|
205
209
|
}, [maxScroll, onEndReachedInternal]);
|
|
206
210
|
|
|
@@ -278,7 +282,8 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
278
282
|
hoverRow: hoverRow ?? false,
|
|
279
283
|
createFilterField,
|
|
280
284
|
rowClassName,
|
|
281
|
-
endAdornment
|
|
285
|
+
endAdornment,
|
|
286
|
+
AddColumnComponent
|
|
282
287
|
}}>
|
|
283
288
|
|
|
284
289
|
<MemoizedList
|
|
@@ -288,6 +293,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
288
293
|
height={bounds.height}
|
|
289
294
|
itemCount={(data?.length ?? 0) + (endAdornment ? 1 : 0)}
|
|
290
295
|
onScroll={onScroll}
|
|
296
|
+
includeAddColumn={Boolean(AddColumnComponent)}
|
|
291
297
|
itemSize={getRowHeight(size)}/>
|
|
292
298
|
|
|
293
299
|
</VirtualListContext.Provider>
|
|
@@ -303,7 +309,8 @@ function MemoizedList({
|
|
|
303
309
|
height,
|
|
304
310
|
itemCount,
|
|
305
311
|
onScroll,
|
|
306
|
-
itemSize
|
|
312
|
+
itemSize,
|
|
313
|
+
includeAddColumn
|
|
307
314
|
}: {
|
|
308
315
|
outerRef: RefObject<HTMLDivElement>;
|
|
309
316
|
width: number;
|
|
@@ -315,6 +322,7 @@ function MemoizedList({
|
|
|
315
322
|
scrollUpdateWasRequested: boolean;
|
|
316
323
|
}) => void;
|
|
317
324
|
itemSize: number;
|
|
325
|
+
includeAddColumn?: boolean;
|
|
318
326
|
}) {
|
|
319
327
|
|
|
320
328
|
const Row = useCallback(({
|
|
@@ -360,6 +368,7 @@ function MemoizedList({
|
|
|
360
368
|
top: `calc(${style.top}px + 48px)`
|
|
361
369
|
}}
|
|
362
370
|
size={size}>
|
|
371
|
+
|
|
363
372
|
{columns.map((column: VirtualTableColumn, columnIndex: number) => {
|
|
364
373
|
const cellData = rowData && rowData[column.key];
|
|
365
374
|
return <VirtualTableCell
|
|
@@ -373,6 +382,9 @@ function MemoizedList({
|
|
|
373
382
|
rowIndex={index}
|
|
374
383
|
columnIndex={columnIndex}/>;
|
|
375
384
|
})}
|
|
385
|
+
|
|
386
|
+
{includeAddColumn && <div className={"w-20"}/>}
|
|
387
|
+
|
|
376
388
|
</VirtualTableRow>
|
|
377
389
|
);
|
|
378
390
|
}}
|
|
@@ -3,12 +3,9 @@ import equal from "react-fast-compare";
|
|
|
3
3
|
|
|
4
4
|
import { VirtualTableColumn, VirtualTableSort, VirtualTableWhereFilterOp } from "./VirtualTableProps";
|
|
5
5
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
6
|
-
import { Button, IconButton } from "../../../components";
|
|
6
|
+
import { Badge, Button, cn, IconButton, Popover } from "../../../components";
|
|
7
7
|
import { defaultBorderMixin } from "../../../styles";
|
|
8
|
-
import { ArrowUpwardIcon, ExpandMoreIcon } from "../../../icons";
|
|
9
|
-
import { Popover } from "../../../components/Popover";
|
|
10
|
-
import { Badge } from "../../../components/Badge";
|
|
11
|
-
import { cn } from "../../../components/util/cn";
|
|
8
|
+
import { ArrowUpwardIcon, ExpandMoreIcon, FilterIcon, FilterListIcon } from "../../../icons";
|
|
12
9
|
|
|
13
10
|
interface FilterFormProps<T> {
|
|
14
11
|
column: VirtualTableColumn<T>;
|
|
@@ -40,6 +37,7 @@ type VirtualTableHeaderProps<M extends Record<string, any>> = {
|
|
|
40
37
|
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, any]) => void;
|
|
41
38
|
onClickResizeColumn?: (columnIndex: number, column: VirtualTableColumn) => void;
|
|
42
39
|
createFilterField?: (props: FilterFormFieldProps<any>) => React.ReactNode;
|
|
40
|
+
additionalHeaderWidget?: (onHover: boolean) => React.ReactNode;
|
|
43
41
|
};
|
|
44
42
|
|
|
45
43
|
export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
@@ -53,7 +51,8 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
53
51
|
filter,
|
|
54
52
|
column,
|
|
55
53
|
onClickResizeColumn,
|
|
56
|
-
createFilterField
|
|
54
|
+
createFilterField,
|
|
55
|
+
additionalHeaderWidget
|
|
57
56
|
}: VirtualTableHeaderProps<M>) {
|
|
58
57
|
|
|
59
58
|
const [onHover, setOnHover] = useState(false);
|
|
@@ -115,23 +114,26 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
115
114
|
</div>
|
|
116
115
|
|
|
117
116
|
{column.sortable && (sort || hovered || openFilter) &&
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
<>
|
|
118
|
+
{additionalHeaderWidget && additionalHeaderWidget(hovered || openFilter)}
|
|
119
|
+
<Badge color="secondary"
|
|
120
|
+
invisible={!sort}>
|
|
121
|
+
<IconButton
|
|
122
|
+
size={"small"}
|
|
123
|
+
className={onHover || openFilter ? "bg-white dark:bg-gray-950" : undefined}
|
|
124
|
+
onClick={() => {
|
|
125
|
+
onColumnSort(column.key as Extract<keyof M, string>);
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
{!sort &&
|
|
129
|
+
<ArrowUpwardIcon/>}
|
|
130
|
+
{sort === "asc" &&
|
|
131
|
+
<ArrowUpwardIcon/>}
|
|
132
|
+
{sort === "desc" &&
|
|
133
|
+
<ArrowUpwardIcon className={"rotate-180"}/>}
|
|
134
|
+
</IconButton>
|
|
135
|
+
</Badge>
|
|
136
|
+
</>
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
{column.filter && createFilterField && <div>
|
|
@@ -146,7 +148,7 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
146
148
|
className={onHover || openFilter ? "bg-white dark:bg-gray-950" : undefined}
|
|
147
149
|
size={"small"}
|
|
148
150
|
onClick={handleSettingsClick}>
|
|
149
|
-
<
|
|
151
|
+
<FilterListIcon size={"small"}/>
|
|
150
152
|
</IconButton>}
|
|
151
153
|
>
|
|
152
154
|
{column.filter &&
|
|
@@ -16,7 +16,8 @@ export const VirtualTableHeaderRow = ({
|
|
|
16
16
|
filter,
|
|
17
17
|
onColumnResize,
|
|
18
18
|
onColumnResizeEnd,
|
|
19
|
-
createFilterField
|
|
19
|
+
createFilterField,
|
|
20
|
+
AddColumnComponent
|
|
20
21
|
}: VirtualTableContextProps<any>) => {
|
|
21
22
|
|
|
22
23
|
const columnRefs = columns.map(() => createRef<HTMLDivElement>());
|
|
@@ -119,9 +120,13 @@ export const VirtualTableHeaderRow = ({
|
|
|
119
120
|
onColumnSort={onColumnSort}
|
|
120
121
|
onClickResizeColumn={onClickResizeColumn}
|
|
121
122
|
column={column}
|
|
122
|
-
createFilterField={createFilterField}
|
|
123
|
+
createFilterField={createFilterField}
|
|
124
|
+
additionalHeaderWidget={column.additionalHeaderWidget}/>
|
|
123
125
|
</ErrorBoundary>;
|
|
124
126
|
})}
|
|
127
|
+
|
|
128
|
+
{AddColumnComponent && <AddColumnComponent/>}
|
|
129
|
+
|
|
125
130
|
</div>
|
|
126
131
|
);
|
|
127
132
|
};
|
|
@@ -136,6 +136,12 @@ export interface VirtualTableProps<T extends Record<string, any>> {
|
|
|
136
136
|
*/
|
|
137
137
|
endAdornment?: React.ReactNode;
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* If adding this callback, a button to add a new column is displayed.
|
|
141
|
+
* @param column
|
|
142
|
+
*/
|
|
143
|
+
AddColumnComponent?: React.ComponentType;
|
|
144
|
+
|
|
139
145
|
}
|
|
140
146
|
|
|
141
147
|
export type CellRendererParams<T extends any> = {
|
|
@@ -206,7 +212,15 @@ export interface VirtualTableColumn<CustomProps extends any = any> {
|
|
|
206
212
|
*/
|
|
207
213
|
resizable?: boolean;
|
|
208
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Custom props passed to the cell renderer
|
|
217
|
+
*/
|
|
209
218
|
custom?: CustomProps;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Additional children to be rendered in the header when hovering
|
|
222
|
+
*/
|
|
223
|
+
additionalHeaderWidget?: (onHover:boolean) => React.ReactNode;
|
|
210
224
|
}
|
|
211
225
|
|
|
212
226
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import {
|
|
2
3
|
CellRendererParams,
|
|
3
4
|
OnRowClickParams,
|
|
@@ -39,4 +40,5 @@ export type VirtualTableContextProps<T extends any> = {
|
|
|
39
40
|
createFilterField?: (props: FilterFormFieldProps<any>) => React.ReactNode;
|
|
40
41
|
rowClassName?: (rowData: T) => string | undefined;
|
|
41
42
|
endAdornment?: React.ReactNode;
|
|
43
|
+
AddColumnComponent?: React.ComponentType;
|
|
42
44
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Properties } from "../../types";
|
|
1
|
+
import { Properties, PropertiesOrBuilders } from "../../types";
|
|
2
|
+
import { isPropertyBuilder } from "./entities";
|
|
2
3
|
|
|
3
4
|
export function makePropertiesEditable(properties: Properties) {
|
|
4
5
|
Object.keys(properties).forEach((key) => {
|
|
@@ -9,3 +10,19 @@ export function makePropertiesEditable(properties: Properties) {
|
|
|
9
10
|
}
|
|
10
11
|
});
|
|
11
12
|
}
|
|
13
|
+
|
|
14
|
+
export function makePropertiesNonEditable(properties: PropertiesOrBuilders): PropertiesOrBuilders {
|
|
15
|
+
return Object.entries(properties).reduce((acc, [key, property]) => {
|
|
16
|
+
if (!isPropertyBuilder(property) && property.dataType === "map" && property.properties) {
|
|
17
|
+
const updated = { ...property, properties: makePropertiesNonEditable(property.properties as PropertiesOrBuilders) };
|
|
18
|
+
acc[key] = updated;
|
|
19
|
+
}
|
|
20
|
+
if (isPropertyBuilder(property)) {
|
|
21
|
+
acc[key] = property;
|
|
22
|
+
} else {
|
|
23
|
+
acc[key] = { ...property, editable: false };
|
|
24
|
+
}
|
|
25
|
+
return acc;
|
|
26
|
+
}, {} as PropertiesOrBuilders);
|
|
27
|
+
|
|
28
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { FieldConfig, PropertiesOrBuilders, PropertyOrBuilder, ResolvedProperty } from "../../types";
|
|
3
|
+
import { EntityCollection, FieldConfig, PropertiesOrBuilders, PropertyOrBuilder, ResolvedProperty } from "../../types";
|
|
4
4
|
import { getFieldConfig } from "../form_field_configs";
|
|
5
5
|
import { isPropertyBuilder } from "./entities";
|
|
6
6
|
import { resolveProperty } from "./resolutions";
|
|
@@ -123,3 +123,8 @@ export function getPropertiesWithPropertiesOrder<M extends Record<string, any>>(
|
|
|
123
123
|
});
|
|
124
124
|
return result;
|
|
125
125
|
}
|
|
126
|
+
|
|
127
|
+
export function getDefaultPropertiesOrder(collection: EntityCollection<any>): string[] {
|
|
128
|
+
if (collection.propertiesOrder) return collection.propertiesOrder;
|
|
129
|
+
return [...Object.keys(collection.properties), ...(collection.additionalFields ?? []).map(field => field.id)];
|
|
130
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Typography } from "../../components/Typography";
|
|
3
2
|
|
|
4
3
|
interface LabelWithIconProps {
|
|
5
4
|
icon: React.ReactNode;
|
|
@@ -27,8 +26,8 @@ export function LabelWithIcon({
|
|
|
27
26
|
|
|
28
27
|
{icon}
|
|
29
28
|
|
|
30
|
-
<
|
|
31
|
-
|
|
29
|
+
<span
|
|
30
|
+
className={`font-medium text-${small ? "base" : "sm"} origin-top-left transform ${small ? "translate-x-2 scale-75" : ""}`}>{(title ?? "") + (required ? " *" : "")}</span>
|
|
32
31
|
|
|
33
32
|
</span>
|
|
34
33
|
);
|
|
@@ -4,9 +4,8 @@ import { FieldProps, PreviewType } from "../../types";
|
|
|
4
4
|
import { FieldHelperText, LabelWithIcon } from "../components";
|
|
5
5
|
import { useClearRestoreValue } from "../../hooks";
|
|
6
6
|
import { getIconForProperty } from "../../core";
|
|
7
|
-
import { IconButton, TextField } from "../../components";
|
|
7
|
+
import { Collapse, IconButton, TextField } from "../../components";
|
|
8
8
|
import { PropertyPreview } from "../../preview";
|
|
9
|
-
import { Collapse } from "../../components/Collapse";
|
|
10
9
|
import { ClearIcon } from "../../icons";
|
|
11
10
|
|
|
12
11
|
interface TextFieldProps<T extends string | number> extends FieldProps<T> {
|
package/src/types/collections.ts
CHANGED
|
@@ -477,6 +477,8 @@ export type TableController<M extends Record<string, any> = any> = {
|
|
|
477
477
|
sortBy?: [string, "asc" | "desc"]) => boolean;
|
|
478
478
|
popupCell?: SelectedCellProps<M>;
|
|
479
479
|
setPopupCell?: (popupCell?: SelectedCellProps<M>) => void;
|
|
480
|
+
|
|
481
|
+
onAddColumn?: (column: string) => void;
|
|
480
482
|
}
|
|
481
483
|
|
|
482
484
|
export type SelectedCellProps<M extends Record<string, any>> = {
|
package/src/types/plugins.tsx
CHANGED
|
@@ -3,7 +3,6 @@ import React, { PropsWithChildren } from "react";
|
|
|
3
3
|
import { FireCMSContext } from "./firecms_context";
|
|
4
4
|
import { CollectionActionsProps, EntityCollection } from "./collections";
|
|
5
5
|
import { User } from "./user";
|
|
6
|
-
import { FieldConfigId } from "./field_config";
|
|
7
6
|
import { FieldProps, FormContext } from "./fields";
|
|
8
7
|
import { CMSType, Property } from "./properties";
|
|
9
8
|
import { EntityStatus } from "./entities";
|
|
@@ -105,6 +104,30 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any> = {
|
|
|
105
104
|
|
|
106
105
|
}
|
|
107
106
|
|
|
107
|
+
collectionView?: {
|
|
108
|
+
/**
|
|
109
|
+
* Use this method to inject widgets to the entity collections header
|
|
110
|
+
* @param props
|
|
111
|
+
*/
|
|
112
|
+
HeaderAction?: React.ComponentType<{
|
|
113
|
+
property: ResolvedProperty,
|
|
114
|
+
propertyKey: string,
|
|
115
|
+
onHover: boolean,
|
|
116
|
+
fullPath: string,
|
|
117
|
+
parentPathSegments: string[],
|
|
118
|
+
}>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* If you add this callback to your plugin, an add button will be added to the collection table.
|
|
122
|
+
* TODO: Only the first plugin that defines this callback will be used, at the moment.
|
|
123
|
+
*/
|
|
124
|
+
AddColumnComponent?: React.ComponentType<{
|
|
125
|
+
fullPath: string,
|
|
126
|
+
parentPathSegments: string[],
|
|
127
|
+
collection: EntityCollection;
|
|
128
|
+
}>;
|
|
129
|
+
}
|
|
130
|
+
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
/**
|