@firecms/core 3.0.0-alpha.24 → 3.0.0-alpha.26
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/core/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +2 -1
- package/dist/core/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
- package/dist/core/components/VirtualTable/VirtualTableProps.d.ts +3 -1
- package/dist/index.es.js +6405 -6353
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +14 -14
- package/dist/index.umd.js.map +1 -1
- package/dist/types/plugins.d.ts +1 -1
- package/package.json +2 -2
- package/src/components/TextField.tsx +2 -2
- package/src/core/components/EntityCollectionTable/EntityCollectionTable.tsx +16 -13
- package/src/core/components/EntityCollectionTable/EntityCollectionTableProps.tsx +3 -1
- package/src/core/components/EntityCollectionView/EntityCollectionView.tsx +58 -4
- package/src/core/components/VirtualTable/VirtualTableHeader.tsx +11 -13
- package/src/core/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
- package/src/core/components/VirtualTable/VirtualTableProps.tsx +1 -1
- package/src/types/plugins.tsx +1 -1
package/dist/types/plugins.d.ts
CHANGED
|
@@ -92,9 +92,9 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any> = {
|
|
|
92
92
|
HeaderAction?: React.ComponentType<{
|
|
93
93
|
property: ResolvedProperty;
|
|
94
94
|
propertyKey: string;
|
|
95
|
-
onHover: boolean;
|
|
96
95
|
fullPath: string;
|
|
97
96
|
parentPathSegments: string[];
|
|
97
|
+
onHover: boolean;
|
|
98
98
|
}>;
|
|
99
99
|
/**
|
|
100
100
|
* If you add this callback to your plugin, an add button will be added to the collection table.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.26",
|
|
4
4
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
5
5
|
"funding": {
|
|
6
6
|
"url": "https://github.com/sponsors/firecmsco"
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"dist",
|
|
134
134
|
"src"
|
|
135
135
|
],
|
|
136
|
-
"gitHead": "
|
|
136
|
+
"gitHead": "6cf98e00ea1eee087526615c741eeeedfaf400b7",
|
|
137
137
|
"publishConfig": {
|
|
138
138
|
"access": "public"
|
|
139
139
|
}
|
|
@@ -89,7 +89,7 @@ export function TextField<T extends string | number>({
|
|
|
89
89
|
? <TextareaAutosize
|
|
90
90
|
{...inputProps as any}
|
|
91
91
|
ref={inputRef}
|
|
92
|
-
placeholder={
|
|
92
|
+
placeholder={focused || hasValue || !label ? placeholder : undefined}
|
|
93
93
|
autoFocus={autoFocus}
|
|
94
94
|
rows={rows}
|
|
95
95
|
// onFocus={() => setFocused(true)}
|
|
@@ -121,7 +121,7 @@ export function TextField<T extends string | number>({
|
|
|
121
121
|
disabled && "border border-transparent outline-none opacity-50 dark:opacity-50 text-gray-800 dark:text-gray-200",
|
|
122
122
|
inputClassName
|
|
123
123
|
)}
|
|
124
|
-
placeholder={
|
|
124
|
+
placeholder={focused || hasValue || !label ? placeholder : undefined}
|
|
125
125
|
autoFocus={autoFocus}
|
|
126
126
|
onFocus={() => setFocused(true)}
|
|
127
127
|
onBlur={() => setFocused(false)}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
AdditionalFieldDelegate,
|
|
6
6
|
CollectionSize,
|
|
7
7
|
Entity,
|
|
8
|
+
EntityCollection,
|
|
8
9
|
FilterValues,
|
|
9
10
|
FireCMSContext,
|
|
10
11
|
ResolvedProperty,
|
|
@@ -102,13 +103,14 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
|
|
|
102
103
|
pageSize = 50,
|
|
103
104
|
paginationEnabled,
|
|
104
105
|
checkFilterCombination,
|
|
105
|
-
setPopupCell
|
|
106
|
+
setPopupCell
|
|
106
107
|
},
|
|
107
108
|
filterable = true,
|
|
108
109
|
sortable = true,
|
|
109
110
|
endAdornment,
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
AddColumnComponent,
|
|
112
|
+
AdditionalHeaderWidget,
|
|
113
|
+
additionalIDHeaderWidget
|
|
112
114
|
}: EntityCollectionTableProps<M>) {
|
|
113
115
|
|
|
114
116
|
const largeLayout = useLargeLayout();
|
|
@@ -270,7 +272,7 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
|
|
|
270
272
|
|
|
271
273
|
}, [additionalFieldsMap, size, selectedEntityIds]);
|
|
272
274
|
|
|
273
|
-
const
|
|
275
|
+
const collectionColumns: VirtualTableColumn[] = useMemo(() => {
|
|
274
276
|
const columnsResult: VirtualTableColumn[] = Object.entries<ResolvedProperty>(properties)
|
|
275
277
|
.flatMap(([key, property]) => getColumnKeysForProperty(property, key))
|
|
276
278
|
.map(({
|
|
@@ -294,11 +296,9 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
|
|
|
294
296
|
resolvedProperty: property,
|
|
295
297
|
disabled
|
|
296
298
|
},
|
|
297
|
-
|
|
298
|
-
property
|
|
299
|
-
|
|
300
|
-
onHover
|
|
301
|
-
})
|
|
299
|
+
AdditionalHeaderWidget: ({ onHover }) => AdditionalHeaderWidget
|
|
300
|
+
? <AdditionalHeaderWidget property={property} propertyKey={key} onHover={onHover}/>
|
|
301
|
+
: undefined
|
|
302
302
|
};
|
|
303
303
|
});
|
|
304
304
|
|
|
@@ -322,16 +322,18 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
|
|
|
322
322
|
title: "ID",
|
|
323
323
|
resizable: false,
|
|
324
324
|
frozen: largeLayout,
|
|
325
|
-
headerAlign: "center"
|
|
325
|
+
headerAlign: "center",
|
|
326
|
+
align: "center",
|
|
327
|
+
AdditionalHeaderWidget: () => additionalIDHeaderWidget
|
|
326
328
|
}), [largeLayout])
|
|
327
329
|
|
|
328
330
|
const columns: VirtualTableColumn[] = useMemo(() => [
|
|
329
331
|
idColumn,
|
|
330
332
|
...displayedColumnIds
|
|
331
333
|
.map((p) => {
|
|
332
|
-
return
|
|
334
|
+
return collectionColumns.find(c => c.key === p.key);
|
|
333
335
|
}).filter(Boolean) as VirtualTableColumn[]
|
|
334
|
-
], [
|
|
336
|
+
], [collectionColumns, displayedColumnIds, idColumn]);
|
|
335
337
|
|
|
336
338
|
const cellRenderer = useCallback((props: CellRendererParams<any>) => {
|
|
337
339
|
const column = props.column;
|
|
@@ -373,7 +375,7 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
|
|
|
373
375
|
onValueChange,
|
|
374
376
|
size,
|
|
375
377
|
selectedCell,
|
|
376
|
-
selectedEntityIds
|
|
378
|
+
selectedEntityIds
|
|
377
379
|
}}
|
|
378
380
|
>
|
|
379
381
|
|
|
@@ -503,3 +505,4 @@ function filterableProperty(property: ResolvedProperty, partOfArray = false): bo
|
|
|
503
505
|
}
|
|
504
506
|
return ["string", "number", "boolean", "date", "reference", "array"].includes(property.dataType);
|
|
505
507
|
}
|
|
508
|
+
|
|
@@ -119,7 +119,7 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
|
|
|
119
119
|
|
|
120
120
|
endAdornment?: React.ReactNode;
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
AdditionalHeaderWidget?: (props: {
|
|
123
123
|
property: ResolvedProperty,
|
|
124
124
|
propertyKey: string,
|
|
125
125
|
onHover: boolean,
|
|
@@ -127,6 +127,8 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
|
|
|
127
127
|
|
|
128
128
|
AddColumnComponent?: React.ComponentType;
|
|
129
129
|
|
|
130
|
+
additionalIDHeaderWidget?: React.ReactNode;
|
|
131
|
+
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
export type GetPropertyForProps<M extends Record<string, any>> = {
|
|
@@ -46,12 +46,12 @@ import {
|
|
|
46
46
|
import { useUserConfigurationPersistence } from "../../../hooks/useUserConfigurationPersistence";
|
|
47
47
|
import { EntityCollectionViewActions } from "./EntityCollectionViewActions";
|
|
48
48
|
import { useEntityCollectionTableController } from "../EntityCollectionTable/useEntityCollectionTableController";
|
|
49
|
-
import { Button, cn, Typography } from "../../../components";
|
|
49
|
+
import { Button, cn, IconButton, TextField, Tooltip, Typography } from "../../../components";
|
|
50
50
|
import { Popover } from "../../../components/Popover";
|
|
51
51
|
import { Skeleton } from "../../../components/Skeleton";
|
|
52
52
|
import { setIn } from "formik";
|
|
53
53
|
import { getSubcollectionColumnId } from "../EntityCollectionTable/internal/common";
|
|
54
|
-
import { KeyboardTabIcon } from "../../../icons";
|
|
54
|
+
import { KeyboardTabIcon, SearchIcon } from "../../../icons";
|
|
55
55
|
import { useColumnIds } from "./useColumnsIds";
|
|
56
56
|
import { PopupFormField } from "../EntityCollectionTable/internal/popup_field/PopupFormField";
|
|
57
57
|
import { GetPropertyForProps } from "../EntityCollectionTable/EntityCollectionTableProps";
|
|
@@ -517,10 +517,10 @@ export const EntityCollectionView = React.memo(
|
|
|
517
517
|
.map((plugin, i) => {
|
|
518
518
|
const HeaderAction = plugin.collectionView!.HeaderAction!;
|
|
519
519
|
return <HeaderAction
|
|
520
|
+
onHover={onHover}
|
|
520
521
|
key={`plugin_header_action_${i}`}
|
|
521
522
|
propertyKey={propertyKey}
|
|
522
523
|
property={property}
|
|
523
|
-
onHover={onHover}
|
|
524
524
|
fullPath={fullPath}
|
|
525
525
|
parentPathSegments={parentPathSegments ?? []}/>;
|
|
526
526
|
})}
|
|
@@ -571,8 +571,11 @@ export const EntityCollectionView = React.memo(
|
|
|
571
571
|
/>}
|
|
572
572
|
hoverRow={hoverRow}
|
|
573
573
|
inlineEditing={checkInlineEditing()}
|
|
574
|
-
|
|
574
|
+
AdditionalHeaderWidget={buildAdditionalHeaderWidget}
|
|
575
575
|
AddColumnComponent={addColumnComponentInternal}
|
|
576
|
+
additionalIDHeaderWidget={<EntityIdHeaderWidget
|
|
577
|
+
path={fullPath}
|
|
578
|
+
collection={collection}/>}
|
|
576
579
|
/>
|
|
577
580
|
|
|
578
581
|
<PopupFormField
|
|
@@ -686,3 +689,54 @@ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityC
|
|
|
686
689
|
}
|
|
687
690
|
return { properties: { [key]: { columnWidth: width } } } as PartialEntityCollection;
|
|
688
691
|
}
|
|
692
|
+
|
|
693
|
+
function EntityIdHeaderWidget({ collection, path }: {
|
|
694
|
+
collection: EntityCollection,
|
|
695
|
+
path: string
|
|
696
|
+
}) {
|
|
697
|
+
const [openPopup, setOpenPopup] = React.useState(false);
|
|
698
|
+
const [searchString, setSearchString] = React.useState("");
|
|
699
|
+
const sideEntityController = useSideEntityController();
|
|
700
|
+
return (
|
|
701
|
+
<Tooltip title={!openPopup ? "Find by ID" : undefined}>
|
|
702
|
+
<Popover
|
|
703
|
+
open={openPopup}
|
|
704
|
+
onOpenChange={setOpenPopup}
|
|
705
|
+
trigger={
|
|
706
|
+
<IconButton size={"small"}>
|
|
707
|
+
<SearchIcon size={"small"}/>
|
|
708
|
+
</IconButton>
|
|
709
|
+
}
|
|
710
|
+
>
|
|
711
|
+
<form noValidate={true}
|
|
712
|
+
onSubmit={(e) => {
|
|
713
|
+
e.preventDefault();
|
|
714
|
+
if (!searchString) return;
|
|
715
|
+
setOpenPopup(false);
|
|
716
|
+
return sideEntityController.open({
|
|
717
|
+
entityId: searchString,
|
|
718
|
+
path,
|
|
719
|
+
collection,
|
|
720
|
+
updateUrl: true
|
|
721
|
+
});
|
|
722
|
+
}}
|
|
723
|
+
className={"text-gray-900 dark:text-white w-96 max-w-full"}>
|
|
724
|
+
|
|
725
|
+
<div className="flex p-4 w-full gap-4">
|
|
726
|
+
<TextField
|
|
727
|
+
placeholder={"Find entity by ID"}
|
|
728
|
+
size={"small"}
|
|
729
|
+
onChange={(e) => setSearchString(e.target.value)}
|
|
730
|
+
value={searchString}
|
|
731
|
+
className={"flex-grow"}/>
|
|
732
|
+
<Button variant={"outlined"}
|
|
733
|
+
disabled={!searchString}
|
|
734
|
+
type={"submit"}
|
|
735
|
+
>Go</Button>
|
|
736
|
+
</div>
|
|
737
|
+
</form>
|
|
738
|
+
</Popover>
|
|
739
|
+
|
|
740
|
+
</Tooltip>
|
|
741
|
+
);
|
|
742
|
+
}
|
|
@@ -5,7 +5,7 @@ import { VirtualTableColumn, VirtualTableSort, VirtualTableWhereFilterOp } from
|
|
|
5
5
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
6
6
|
import { Badge, Button, cn, IconButton, Popover } from "../../../components";
|
|
7
7
|
import { defaultBorderMixin } from "../../../styles";
|
|
8
|
-
import { ArrowUpwardIcon,
|
|
8
|
+
import { ArrowUpwardIcon, FilterListIcon } from "../../../icons";
|
|
9
9
|
|
|
10
10
|
interface FilterFormProps<T> {
|
|
11
11
|
column: VirtualTableColumn<T>;
|
|
@@ -37,7 +37,7 @@ type VirtualTableHeaderProps<M extends Record<string, any>> = {
|
|
|
37
37
|
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, any]) => void;
|
|
38
38
|
onClickResizeColumn?: (columnIndex: number, column: VirtualTableColumn) => void;
|
|
39
39
|
createFilterField?: (props: FilterFormFieldProps<any>) => React.ReactNode;
|
|
40
|
-
|
|
40
|
+
AdditionalHeaderWidget?: (props: { onHover: boolean }) => React.ReactNode;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
@@ -52,7 +52,7 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
52
52
|
column,
|
|
53
53
|
onClickResizeColumn,
|
|
54
54
|
createFilterField,
|
|
55
|
-
|
|
55
|
+
AdditionalHeaderWidget
|
|
56
56
|
}: VirtualTableHeaderProps<M>) {
|
|
57
57
|
|
|
58
58
|
const [onHover, setOnHover] = useState(false);
|
|
@@ -112,10 +112,12 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
112
112
|
|
|
113
113
|
</div>
|
|
114
114
|
</div>
|
|
115
|
+
<>
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
{AdditionalHeaderWidget &&
|
|
118
|
+
<AdditionalHeaderWidget onHover={onHover || openFilter}/>}
|
|
119
|
+
|
|
120
|
+
{column.sortable && (sort || hovered || openFilter) &&
|
|
119
121
|
<Badge color="secondary"
|
|
120
122
|
invisible={!sort}>
|
|
121
123
|
<IconButton
|
|
@@ -133,8 +135,8 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
133
135
|
<ArrowUpwardIcon className={"rotate-180"}/>}
|
|
134
136
|
</IconButton>
|
|
135
137
|
</Badge>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
}
|
|
139
|
+
</>
|
|
138
140
|
|
|
139
141
|
{column.filter && createFilterField && <div>
|
|
140
142
|
<Badge color="secondary"
|
|
@@ -220,11 +222,7 @@ function FilterForm<M>({
|
|
|
220
222
|
|
|
221
223
|
if (!filterField) return null;
|
|
222
224
|
return (
|
|
223
|
-
<div className={
|
|
224
|
-
cn(
|
|
225
|
-
"text-gray-900 dark:text-white",
|
|
226
|
-
)
|
|
227
|
-
}>
|
|
225
|
+
<div className={"text-gray-900 dark:text-white"}>
|
|
228
226
|
<div
|
|
229
227
|
className={cn(defaultBorderMixin, "py-4 px-6 text-xs font-semibold uppercase border-b")}>
|
|
230
228
|
{column.title ?? id}
|
|
@@ -121,7 +121,7 @@ export const VirtualTableHeaderRow = ({
|
|
|
121
121
|
onClickResizeColumn={onClickResizeColumn}
|
|
122
122
|
column={column}
|
|
123
123
|
createFilterField={createFilterField}
|
|
124
|
-
|
|
124
|
+
AdditionalHeaderWidget={column.AdditionalHeaderWidget}/>
|
|
125
125
|
</ErrorBoundary>;
|
|
126
126
|
})}
|
|
127
127
|
|
|
@@ -220,7 +220,7 @@ export interface VirtualTableColumn<CustomProps extends any = any> {
|
|
|
220
220
|
/**
|
|
221
221
|
* Additional children to be rendered in the header when hovering
|
|
222
222
|
*/
|
|
223
|
-
|
|
223
|
+
AdditionalHeaderWidget?: (props: { onHover: boolean }) => React.ReactNode;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/**
|
package/src/types/plugins.tsx
CHANGED
|
@@ -112,9 +112,9 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any> = {
|
|
|
112
112
|
HeaderAction?: React.ComponentType<{
|
|
113
113
|
property: ResolvedProperty,
|
|
114
114
|
propertyKey: string,
|
|
115
|
-
onHover: boolean,
|
|
116
115
|
fullPath: string,
|
|
117
116
|
parentPathSegments: string[],
|
|
117
|
+
onHover: boolean,
|
|
118
118
|
}>;
|
|
119
119
|
|
|
120
120
|
/**
|