@firecms/core 3.0.0-canary.120 → 3.0.0-canary.121
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/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
- package/dist/form/index.d.ts +2 -2
- package/dist/index.es.js +68 -52
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +68 -52
- package/dist/index.umd.js.map +1 -1
- package/dist/types/storage.d.ts +75 -0
- package/package.json +5 -5
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +18 -20
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +55 -7
- package/src/components/VirtualTable/VirtualTableCell.tsx +0 -8
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +14 -26
- package/src/core/field_configs.tsx +3 -3
- package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +17 -16
- package/src/form/index.tsx +2 -2
- package/src/internal/useBuildDataSource.ts +4 -10
- package/src/types/storage.ts +82 -0
package/dist/types/storage.d.ts
CHANGED
|
@@ -87,4 +87,79 @@ export interface StorageSource {
|
|
|
87
87
|
* @param bucket
|
|
88
88
|
*/
|
|
89
89
|
getFile: (path: string, bucket?: string) => Promise<File | null>;
|
|
90
|
+
/**
|
|
91
|
+
* Delete a file.
|
|
92
|
+
* @param path
|
|
93
|
+
* @param bucket
|
|
94
|
+
*/
|
|
95
|
+
deleteFile: (path: string, bucket?: string) => Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* List the contents of a path.
|
|
98
|
+
* @param path
|
|
99
|
+
* @param options
|
|
100
|
+
*/
|
|
101
|
+
list: (path: string, options?: {
|
|
102
|
+
bucket?: string;
|
|
103
|
+
maxResults?: number;
|
|
104
|
+
pageToken?: string;
|
|
105
|
+
}) => Promise<StorageListResult>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Result returned by list().
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
export declare interface StorageListResult {
|
|
112
|
+
/**
|
|
113
|
+
* References to prefixes (sub-folders). You can call list() on them to
|
|
114
|
+
* get its contents.
|
|
115
|
+
*
|
|
116
|
+
* Folders are implicit based on '/' in the object paths.
|
|
117
|
+
* For example, if a bucket has two objects '/a/b/1' and '/a/b/2', list('/a')
|
|
118
|
+
* will return '/a/b' as a prefix.
|
|
119
|
+
*/
|
|
120
|
+
prefixes: StorageReference[];
|
|
121
|
+
/**
|
|
122
|
+
* Objects in this directory.
|
|
123
|
+
* You can call getMetadata() and getDownloadUrl() on them.
|
|
124
|
+
*/
|
|
125
|
+
items: StorageReference[];
|
|
126
|
+
/**
|
|
127
|
+
* If set, there might be more results for this list. Use this token to resume the list.
|
|
128
|
+
*/
|
|
129
|
+
nextPageToken?: string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Represents a reference to a Google Cloud Storage object. Developers can
|
|
133
|
+
* upload, download, and delete objects, as well as get/set object metadata.
|
|
134
|
+
* @public
|
|
135
|
+
*/
|
|
136
|
+
export declare interface StorageReference {
|
|
137
|
+
/**
|
|
138
|
+
* Returns a gs:// URL for this object in the form
|
|
139
|
+
* `gs://<bucket>/<path>/<to>/<object>`
|
|
140
|
+
* @returns The gs:// URL.
|
|
141
|
+
*/
|
|
142
|
+
toString(): string;
|
|
143
|
+
/**
|
|
144
|
+
* A reference to the root of this object's bucket.
|
|
145
|
+
*/
|
|
146
|
+
root: StorageReference;
|
|
147
|
+
/**
|
|
148
|
+
* The name of the bucket containing this reference's object.
|
|
149
|
+
*/
|
|
150
|
+
bucket: string;
|
|
151
|
+
/**
|
|
152
|
+
* The full path of this object.
|
|
153
|
+
*/
|
|
154
|
+
fullPath: string;
|
|
155
|
+
/**
|
|
156
|
+
* The short name of this object, which is the last component of the full path.
|
|
157
|
+
* For example, if fullPath is 'full/path/image.png', name is 'image.png'.
|
|
158
|
+
*/
|
|
159
|
+
name: string;
|
|
160
|
+
/**
|
|
161
|
+
* A reference pointing to the parent location of this reference, or null if
|
|
162
|
+
* this reference is the root.
|
|
163
|
+
*/
|
|
164
|
+
parent: StorageReference | null;
|
|
90
165
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-canary.
|
|
4
|
+
"version": "3.0.0-canary.121",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/firecmsco"
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"./package.json": "./package.json"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@firecms/editor": "^3.0.0-canary.
|
|
50
|
-
"@firecms/formex": "^3.0.0-canary.
|
|
51
|
-
"@firecms/ui": "^3.0.0-canary.
|
|
49
|
+
"@firecms/editor": "^3.0.0-canary.121",
|
|
50
|
+
"@firecms/formex": "^3.0.0-canary.121",
|
|
51
|
+
"@firecms/ui": "^3.0.0-canary.121",
|
|
52
52
|
"@hello-pangea/dnd": "^16.6.0",
|
|
53
53
|
"@radix-ui/react-portal": "^1.1.1",
|
|
54
54
|
"clsx": "^2.1.1",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"dist",
|
|
101
101
|
"src"
|
|
102
102
|
],
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "b24af22a548699c954b226b60e55001473654948",
|
|
104
104
|
"publishConfig": {
|
|
105
105
|
"access": "public"
|
|
106
106
|
},
|
|
@@ -45,22 +45,21 @@ const TableCellInner = ({
|
|
|
45
45
|
children
|
|
46
46
|
}: TableCellInnerProps) => {
|
|
47
47
|
return (
|
|
48
|
-
<div
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}}
|
|
48
|
+
<div className={cls("flex flex-col max-h-full w-full",
|
|
49
|
+
{
|
|
50
|
+
"items-start": faded || scrollable
|
|
51
|
+
})}
|
|
52
|
+
style={{
|
|
53
|
+
justifyContent,
|
|
54
|
+
height: fullHeight ? "100%" : undefined,
|
|
55
|
+
overflow: scrollable ? "auto" : undefined,
|
|
56
|
+
WebkitMaskImage: faded
|
|
57
|
+
? "linear-gradient(to bottom, black 60%, transparent 100%)"
|
|
58
|
+
: undefined,
|
|
59
|
+
maskImage: faded
|
|
60
|
+
? "linear-gradient(to bottom, black 60%, transparent 100%)"
|
|
61
|
+
: undefined
|
|
62
|
+
}}
|
|
64
63
|
>
|
|
65
64
|
{children}
|
|
66
65
|
</div>
|
|
@@ -156,8 +155,9 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
|
|
|
156
155
|
}, [ref, onSelect, selected, disabled]);
|
|
157
156
|
|
|
158
157
|
const onFocus = useCallback((event: React.SyntheticEvent<HTMLDivElement>) => {
|
|
159
|
-
onSelectCallback();
|
|
160
158
|
event.stopPropagation();
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
onSelectCallback();
|
|
161
161
|
}, [onSelectCallback]);
|
|
162
162
|
|
|
163
163
|
const isOverflowing = useMemo(() => {
|
|
@@ -203,11 +203,9 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
|
|
|
203
203
|
}}
|
|
204
204
|
tabIndex={selected || disabled ? undefined : 0}
|
|
205
205
|
onFocus={onFocus}
|
|
206
|
-
// onClick={onClick}
|
|
207
206
|
onMouseEnter={setOnHoverTrue}
|
|
208
207
|
onMouseMove={setOnHoverTrue}
|
|
209
208
|
onMouseLeave={setOnHoverFalse}
|
|
210
|
-
// contain={scrollable ? "content" : "size"}
|
|
211
209
|
>
|
|
212
210
|
|
|
213
211
|
<ErrorBoundary>
|
|
@@ -237,7 +235,7 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
|
|
|
237
235
|
|
|
238
236
|
{disabled && onHover && disabledTooltip &&
|
|
239
237
|
<div className="absolute top-1 right-1 text-xs">
|
|
240
|
-
<Tooltip title={disabledTooltip}
|
|
238
|
+
<Tooltip title={disabledTooltip}>
|
|
241
239
|
<RemoveCircleIcon size={"smallest"} color={"disabled"} className={"text-gray-500"}/>
|
|
242
240
|
</Tooltip>
|
|
243
241
|
</div>}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { EnumValuesChip } from "../../../preview";
|
|
3
3
|
import { VirtualTableWhereFilterOp } from "../../VirtualTable";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Checkbox,
|
|
6
|
+
ClearIcon,
|
|
7
|
+
IconButton,
|
|
8
|
+
Label,
|
|
9
|
+
MultiSelect,
|
|
10
|
+
MultiSelectItem,
|
|
11
|
+
Select,
|
|
12
|
+
SelectItem,
|
|
13
|
+
TextField
|
|
14
|
+
} from "@firecms/ui";
|
|
5
15
|
import { EnumValueConfig } from "../../../types";
|
|
6
16
|
|
|
7
17
|
interface StringNumberFilterFieldProps {
|
|
@@ -82,6 +92,8 @@ export function StringNumberFilterField({
|
|
|
82
92
|
}
|
|
83
93
|
|
|
84
94
|
const multiple = multipleSelectOperations.includes(operation);
|
|
95
|
+
|
|
96
|
+
console.log("internalValue", { internalValue });
|
|
85
97
|
return (
|
|
86
98
|
|
|
87
99
|
<div className="flex w-[440px]">
|
|
@@ -117,17 +129,14 @@ export function StringNumberFilterField({
|
|
|
117
129
|
</IconButton>}
|
|
118
130
|
/>}
|
|
119
131
|
|
|
120
|
-
{enumValues &&
|
|
132
|
+
{enumValues && !multiple &&
|
|
121
133
|
<Select
|
|
122
134
|
position={"item-aligned"}
|
|
123
|
-
value={internalValue
|
|
124
|
-
? (Array.isArray(internalValue) ? internalValue.map(e => String(e)) : String(internalValue))
|
|
125
|
-
: isArray ? [] : ""}
|
|
135
|
+
value={typeof internalValue === "string" ? internalValue : ""}
|
|
126
136
|
onValueChange={(value) => {
|
|
127
137
|
if (value !== "")
|
|
128
138
|
updateFilter(operation, dataType === "number" ? parseInt(value as string) : value as string)
|
|
129
139
|
}}
|
|
130
|
-
multiple={multiple}
|
|
131
140
|
endAdornment={internalValue && <IconButton
|
|
132
141
|
className="absolute right-2 top-3"
|
|
133
142
|
onClick={(e) => updateFilter(operation, undefined)}>
|
|
@@ -136,6 +145,8 @@ export function StringNumberFilterField({
|
|
|
136
145
|
renderValue={(enumKey) => {
|
|
137
146
|
if (enumKey === null)
|
|
138
147
|
return "Filter for null values";
|
|
148
|
+
if (enumKey === undefined)
|
|
149
|
+
return null;
|
|
139
150
|
|
|
140
151
|
return <EnumValuesChip
|
|
141
152
|
key={`select_value_${name}_${enumKey}`}
|
|
@@ -144,7 +155,7 @@ export function StringNumberFilterField({
|
|
|
144
155
|
size={"small"}/>;
|
|
145
156
|
}}>
|
|
146
157
|
{enumValues.map((enumConfig) => (
|
|
147
|
-
<SelectItem key={`
|
|
158
|
+
<SelectItem key={`select_item_${name}_${enumConfig.id}`}
|
|
148
159
|
value={String(enumConfig.id)}>
|
|
149
160
|
<EnumValuesChip
|
|
150
161
|
enumKey={String(enumConfig.id)}
|
|
@@ -155,6 +166,43 @@ export function StringNumberFilterField({
|
|
|
155
166
|
</Select>
|
|
156
167
|
}
|
|
157
168
|
|
|
169
|
+
{enumValues && multiple &&
|
|
170
|
+
<MultiSelect
|
|
171
|
+
position={"item-aligned"}
|
|
172
|
+
value={Array.isArray(internalValue) ? internalValue.map(e => String(e)) : []}
|
|
173
|
+
onValueChange={(value) => {
|
|
174
|
+
updateFilter(operation, dataType === "number" ? value.map(v => parseInt(v)) : value)
|
|
175
|
+
}}
|
|
176
|
+
multiple={multiple}
|
|
177
|
+
endAdornment={internalValue && <IconButton
|
|
178
|
+
className="absolute right-2 top-3"
|
|
179
|
+
onClick={(e) => updateFilter(operation, undefined)}>
|
|
180
|
+
<ClearIcon/>
|
|
181
|
+
</IconButton>}
|
|
182
|
+
// renderValues={(enumKeys) => {
|
|
183
|
+
// console.log("renderValues", enumKeys);
|
|
184
|
+
// if (enumKeys === null)
|
|
185
|
+
// return "Filter for null values";
|
|
186
|
+
//
|
|
187
|
+
// return enumKeys.map(key => <EnumValuesChip
|
|
188
|
+
// key={`select_value_${name}_${enumKeys}`}
|
|
189
|
+
// enumKey={key}
|
|
190
|
+
// enumValues={enumValues}
|
|
191
|
+
// size={"small"}/>);
|
|
192
|
+
// }}
|
|
193
|
+
>
|
|
194
|
+
{enumValues.map((enumConfig) => (
|
|
195
|
+
<MultiSelectItem key={`select_value_${name}_${enumConfig.id}`}
|
|
196
|
+
value={String(enumConfig.id)}>
|
|
197
|
+
<EnumValuesChip
|
|
198
|
+
enumKey={String(enumConfig.id)}
|
|
199
|
+
enumValues={enumValues}
|
|
200
|
+
size={"small"}/>
|
|
201
|
+
</MultiSelectItem>
|
|
202
|
+
))}
|
|
203
|
+
</MultiSelect>
|
|
204
|
+
}
|
|
205
|
+
|
|
158
206
|
{!isArray && <Label
|
|
159
207
|
className="border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-gray-100 dark:[&:has(:checked)]:bg-gray-800"
|
|
160
208
|
htmlFor="null-filter"
|
|
@@ -30,14 +30,6 @@ export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
|
|
|
30
30
|
width: props.column.width
|
|
31
31
|
} as CellRendererParams<T>
|
|
32
32
|
);
|
|
33
|
-
// return props.rowData && <props.cellRenderer
|
|
34
|
-
// rowData={props.rowData}
|
|
35
|
-
// rowIndex={props.rowIndex}
|
|
36
|
-
// isScrolling={false}
|
|
37
|
-
// column={props.column}
|
|
38
|
-
// columns={props.columns}
|
|
39
|
-
// columnIndex={props.columnIndex}
|
|
40
|
-
// width={props.column.width}/>
|
|
41
33
|
},
|
|
42
34
|
(a, b) => {
|
|
43
35
|
return equal(a.rowData, b.rowData) &&
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EnumValueConfig } from "../../../types";
|
|
2
|
-
import {
|
|
2
|
+
import { EnumValuesChip } from "../../../preview";
|
|
3
3
|
import React, { useCallback, useEffect } from "react";
|
|
4
4
|
import { MultiSelect, MultiSelectItem, Select, SelectItem } from "@firecms/ui";
|
|
5
5
|
|
|
@@ -18,9 +18,7 @@ export function VirtualTableSelect(props: {
|
|
|
18
18
|
}) {
|
|
19
19
|
|
|
20
20
|
const {
|
|
21
|
-
name,
|
|
22
21
|
enumValues,
|
|
23
|
-
error,
|
|
24
22
|
internalValue,
|
|
25
23
|
disabled,
|
|
26
24
|
small,
|
|
@@ -41,6 +39,7 @@ export function VirtualTableSelect(props: {
|
|
|
41
39
|
}, [focused, ref]);
|
|
42
40
|
|
|
43
41
|
const onChange = useCallback((updatedValue: string | string[]) => {
|
|
42
|
+
console.trace("onChange");
|
|
44
43
|
if (valueType === "number") {
|
|
45
44
|
if (multiple) {
|
|
46
45
|
const newValue = (updatedValue as string[]).map((v) => parseFloat(v));
|
|
@@ -58,35 +57,27 @@ export function VirtualTableSelect(props: {
|
|
|
58
57
|
}
|
|
59
58
|
}, [multiple, updateValue, valueType]);
|
|
60
59
|
|
|
61
|
-
const renderValue = (enumKey
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
enumValues={enumValues}
|
|
68
|
-
size={small ? "small" : "medium"}/>;
|
|
69
|
-
} else {
|
|
70
|
-
return <EnumValuesChip
|
|
71
|
-
key={`${enumKey}-${index}`}
|
|
72
|
-
enumKey={enumKey}
|
|
73
|
-
enumValues={enumValues}
|
|
74
|
-
size={small ? "small" : "medium"}/>;
|
|
75
|
-
}
|
|
60
|
+
const renderValue = (enumKey?: string | number) => {
|
|
61
|
+
return <EnumValuesChip
|
|
62
|
+
key={`${enumKey}`}
|
|
63
|
+
enumKey={String(enumKey)}
|
|
64
|
+
enumValues={enumValues}
|
|
65
|
+
size={small ? "small" : "medium"}/>;
|
|
76
66
|
};
|
|
67
|
+
|
|
77
68
|
return (
|
|
78
69
|
multiple
|
|
79
70
|
? <MultiSelect
|
|
80
71
|
inputRef={ref}
|
|
81
|
-
containerClassName="w-full h-full"
|
|
82
72
|
className="w-full h-full p-0 bg-transparent"
|
|
83
73
|
position={"item-aligned"}
|
|
84
74
|
disabled={disabled}
|
|
75
|
+
includeClear={false}
|
|
76
|
+
useChips={false}
|
|
85
77
|
value={validValue
|
|
86
78
|
? ((internalValue as any[]).map(v => v.toString()))
|
|
87
79
|
: ([])}
|
|
88
|
-
|
|
89
|
-
renderValue={renderValue}>
|
|
80
|
+
onValueChange={onChange}>
|
|
90
81
|
{enumValues?.map((enumConfig) => (
|
|
91
82
|
<MultiSelectItem
|
|
92
83
|
key={enumConfig.id}
|
|
@@ -103,14 +94,11 @@ export function VirtualTableSelect(props: {
|
|
|
103
94
|
className="w-full h-full p-0 bg-transparent"
|
|
104
95
|
position={"item-aligned"}
|
|
105
96
|
disabled={disabled}
|
|
106
|
-
multiple={multiple}
|
|
107
97
|
padding={false}
|
|
108
|
-
includeFocusOutline={false}
|
|
109
98
|
value={validValue
|
|
110
|
-
?
|
|
111
|
-
:
|
|
99
|
+
? internalValue?.toString()
|
|
100
|
+
: ""}
|
|
112
101
|
onValueChange={onChange}
|
|
113
|
-
onMultiValueChange={onChange}
|
|
114
102
|
renderValue={renderValue}>
|
|
115
103
|
{enumValues?.map((enumConfig) => (
|
|
116
104
|
<SelectItem
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
KeyValueFieldBinding,
|
|
10
10
|
MapFieldBinding,
|
|
11
11
|
MarkdownEditorFieldBinding,
|
|
12
|
-
|
|
12
|
+
MultiSelectFieldBinding,
|
|
13
13
|
ReferenceFieldBinding,
|
|
14
14
|
RepeatFieldBinding,
|
|
15
15
|
SelectFieldBinding,
|
|
@@ -139,7 +139,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
|
|
|
139
139
|
dataType: "string",
|
|
140
140
|
enumValues: [],
|
|
141
141
|
},
|
|
142
|
-
Field:
|
|
142
|
+
Field: MultiSelectFieldBinding
|
|
143
143
|
}
|
|
144
144
|
},
|
|
145
145
|
number_input: {
|
|
@@ -177,7 +177,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
|
|
|
177
177
|
dataType: "number",
|
|
178
178
|
enumValues: [],
|
|
179
179
|
},
|
|
180
|
-
Field:
|
|
180
|
+
Field: MultiSelectFieldBinding
|
|
181
181
|
}
|
|
182
182
|
},
|
|
183
183
|
file_upload: {
|
|
@@ -14,18 +14,18 @@ import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
|
14
14
|
* and tables to the specified properties.
|
|
15
15
|
* @group Form fields
|
|
16
16
|
*/
|
|
17
|
-
export function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
export function MultiSelectFieldBinding({
|
|
18
|
+
propertyKey,
|
|
19
|
+
value,
|
|
20
|
+
setValue,
|
|
21
|
+
error,
|
|
22
|
+
showError,
|
|
23
|
+
disabled,
|
|
24
|
+
property,
|
|
25
|
+
includeDescription,
|
|
26
|
+
size = "medium",
|
|
27
|
+
autoFocus
|
|
28
|
+
}: FieldProps<EnumType[], any, any>) {
|
|
29
29
|
|
|
30
30
|
const of: ResolvedProperty<any> | ResolvedProperty<any>[] = property.of;
|
|
31
31
|
if (!of) {
|
|
@@ -80,19 +80,20 @@ export function MultiSelectBinding({
|
|
|
80
80
|
}, [enumValues, setValue, value]);
|
|
81
81
|
|
|
82
82
|
return (
|
|
83
|
-
|
|
83
|
+
<>
|
|
84
84
|
<MultiSelect
|
|
85
|
+
className={"w-full mt-2"}
|
|
85
86
|
size={size === "medium" ? "medium" : "small"}
|
|
86
87
|
value={validValue ? value.map((v) => v.toString()) : []}
|
|
87
88
|
disabled={disabled}
|
|
89
|
+
modalPopover={true}
|
|
88
90
|
label={<LabelWithIconAndTooltip
|
|
89
91
|
propertyKey={propertyKey}
|
|
90
92
|
icon={getIconForProperty(property, "small")}
|
|
91
93
|
required={property.validation?.required}
|
|
92
94
|
title={property.name}
|
|
93
95
|
className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>}
|
|
94
|
-
|
|
95
|
-
onMultiValueChange={(updatedValue: string[]) => {
|
|
96
|
+
onValueChange={(updatedValue: string[]) => {
|
|
96
97
|
let newValue: EnumType[] | null;
|
|
97
98
|
if (of && (of as ResolvedProperty)?.dataType === "number") {
|
|
98
99
|
newValue = updatedValue ? (updatedValue as string[]).map((e) => parseFloat(e)) : [];
|
|
@@ -113,6 +114,6 @@ export function MultiSelectBinding({
|
|
|
113
114
|
disabled={disabled}
|
|
114
115
|
property={property}/>
|
|
115
116
|
|
|
116
|
-
|
|
117
|
+
</>
|
|
117
118
|
);
|
|
118
119
|
}
|
package/src/form/index.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SelectFieldBinding } from "./field_bindings/SelectFieldBinding";
|
|
2
|
-
import {
|
|
2
|
+
import { MultiSelectFieldBinding } from "./field_bindings/MultiSelectFieldBinding";
|
|
3
3
|
import { ArrayOfReferencesFieldBinding } from "./field_bindings/ArrayOfReferencesFieldBinding";
|
|
4
4
|
import { StorageUploadFieldBinding } from "./field_bindings/StorageUploadFieldBinding";
|
|
5
5
|
import { TextFieldBinding } from "./field_bindings/TextFieldBinding";
|
|
@@ -17,7 +17,7 @@ import { ArrayCustomShapedFieldBinding } from "./field_bindings/ArrayCustomShape
|
|
|
17
17
|
export {
|
|
18
18
|
ArrayCustomShapedFieldBinding,
|
|
19
19
|
RepeatFieldBinding,
|
|
20
|
-
|
|
20
|
+
MultiSelectFieldBinding,
|
|
21
21
|
ArrayOfReferencesFieldBinding,
|
|
22
22
|
BlockFieldBinding,
|
|
23
23
|
DateTimeFieldBinding,
|
|
@@ -204,15 +204,6 @@ export function useBuildDataSource({
|
|
|
204
204
|
const collection = collectionProp ?? navigationController.getCollection(path);
|
|
205
205
|
const usedDelegate = collection?.overrides?.dataSourceDelegate ?? delegate;
|
|
206
206
|
|
|
207
|
-
console.log("useBuildDatasource save", {
|
|
208
|
-
path,
|
|
209
|
-
entityId,
|
|
210
|
-
values,
|
|
211
|
-
collectionProp,
|
|
212
|
-
collection,
|
|
213
|
-
status
|
|
214
|
-
});
|
|
215
|
-
|
|
216
207
|
const resolvedCollection = collection
|
|
217
208
|
? resolveCollection<M>({
|
|
218
209
|
collection,
|
|
@@ -267,7 +258,10 @@ export function useBuildDataSource({
|
|
|
267
258
|
}: DeleteEntityProps<M>
|
|
268
259
|
): Promise<void> => {
|
|
269
260
|
const usedDelegate = collection?.overrides?.dataSourceDelegate ?? delegate;
|
|
270
|
-
return usedDelegate.deleteEntity({
|
|
261
|
+
return usedDelegate.deleteEntity({
|
|
262
|
+
entity,
|
|
263
|
+
collection
|
|
264
|
+
});
|
|
271
265
|
}, [delegate.deleteEntity]),
|
|
272
266
|
|
|
273
267
|
/**
|
package/src/types/storage.ts
CHANGED
|
@@ -102,4 +102,86 @@ export interface StorageSource {
|
|
|
102
102
|
* @param bucket
|
|
103
103
|
*/
|
|
104
104
|
getFile: (path: string, bucket?: string) => Promise<File | null>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Delete a file.
|
|
108
|
+
* @param path
|
|
109
|
+
* @param bucket
|
|
110
|
+
*/
|
|
111
|
+
deleteFile: (path: string, bucket?: string) => Promise<void>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* List the contents of a path.
|
|
115
|
+
* @param path
|
|
116
|
+
* @param options
|
|
117
|
+
*/
|
|
118
|
+
list: (path: string, options?: {
|
|
119
|
+
bucket?: string,
|
|
120
|
+
maxResults?: number,
|
|
121
|
+
pageToken?: string
|
|
122
|
+
}) => Promise<StorageListResult>;
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Result returned by list().
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
130
|
+
export declare interface StorageListResult {
|
|
131
|
+
/**
|
|
132
|
+
* References to prefixes (sub-folders). You can call list() on them to
|
|
133
|
+
* get its contents.
|
|
134
|
+
*
|
|
135
|
+
* Folders are implicit based on '/' in the object paths.
|
|
136
|
+
* For example, if a bucket has two objects '/a/b/1' and '/a/b/2', list('/a')
|
|
137
|
+
* will return '/a/b' as a prefix.
|
|
138
|
+
*/
|
|
139
|
+
prefixes: StorageReference[];
|
|
140
|
+
/**
|
|
141
|
+
* Objects in this directory.
|
|
142
|
+
* You can call getMetadata() and getDownloadUrl() on them.
|
|
143
|
+
*/
|
|
144
|
+
items: StorageReference[];
|
|
145
|
+
/**
|
|
146
|
+
* If set, there might be more results for this list. Use this token to resume the list.
|
|
147
|
+
*/
|
|
148
|
+
nextPageToken?: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Represents a reference to a Google Cloud Storage object. Developers can
|
|
153
|
+
* upload, download, and delete objects, as well as get/set object metadata.
|
|
154
|
+
* @public
|
|
155
|
+
*/
|
|
156
|
+
export declare interface StorageReference {
|
|
157
|
+
/**
|
|
158
|
+
* Returns a gs:// URL for this object in the form
|
|
159
|
+
* `gs://<bucket>/<path>/<to>/<object>`
|
|
160
|
+
* @returns The gs:// URL.
|
|
161
|
+
*/
|
|
162
|
+
toString(): string;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* A reference to the root of this object's bucket.
|
|
166
|
+
*/
|
|
167
|
+
root: StorageReference;
|
|
168
|
+
/**
|
|
169
|
+
* The name of the bucket containing this reference's object.
|
|
170
|
+
*/
|
|
171
|
+
bucket: string;
|
|
172
|
+
/**
|
|
173
|
+
* The full path of this object.
|
|
174
|
+
*/
|
|
175
|
+
fullPath: string;
|
|
176
|
+
/**
|
|
177
|
+
* The short name of this object, which is the last component of the full path.
|
|
178
|
+
* For example, if fullPath is 'full/path/image.png', name is 'image.png'.
|
|
179
|
+
*/
|
|
180
|
+
name: string;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* A reference pointing to the parent location of this reference, or null if
|
|
184
|
+
* this reference is the root.
|
|
185
|
+
*/
|
|
186
|
+
parent: StorageReference | null;
|
|
105
187
|
}
|