@firecms/data_import_export 3.0.0-canary.80 → 3.0.0-canary.82
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/LICENSE +2 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.es.js +12 -1364
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +29 -2
- package/dist/index.umd.js.map +1 -1
- package/dist/useImportExportPlugin.d.ts +5 -3
- package/package.json +5 -7
- package/src/index.ts +2 -5
- package/src/useImportExportPlugin.tsx +9 -5
- package/dist/components/DataNewPropertiesMapping.d.ts +0 -13
- package/dist/components/ImportFileUpload.d.ts +0 -3
- package/dist/components/ImportNewPropertyFieldPreview.d.ts +0 -10
- package/dist/components/ImportSaveInProgress.d.ts +0 -8
- package/dist/components/index.d.ts +0 -4
- package/dist/export_import/BasicExportAction.d.ts +0 -7
- package/dist/export_import/ExportCollectionAction.d.ts +0 -11
- package/dist/export_import/ImportCollectionAction.d.ts +0 -15
- package/dist/export_import/export.d.ts +0 -21
- package/dist/export_import/index.d.ts +0 -4
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/useImportConfig.d.ts +0 -2
- package/dist/types/column_mapping.d.ts +0 -20
- package/dist/types/index.d.ts +0 -1
- package/dist/utils/data.d.ts +0 -4
- package/dist/utils/file_headers.d.ts +0 -1
- package/dist/utils/file_to_json.d.ts +0 -16
- package/dist/utils/get_import_inference_type.d.ts +0 -2
- package/dist/utils/get_properties_mapping.d.ts +0 -0
- package/dist/utils/index.d.ts +0 -3
- package/src/components/DataNewPropertiesMapping.tsx +0 -241
- package/src/components/ImportFileUpload.tsx +0 -42
- package/src/components/ImportNewPropertyFieldPreview.tsx +0 -60
- package/src/components/ImportSaveInProgress.tsx +0 -122
- package/src/components/index.ts +0 -4
- package/src/export_import/BasicExportAction.tsx +0 -147
- package/src/export_import/ExportCollectionAction.tsx +0 -288
- package/src/export_import/ImportCollectionAction.tsx +0 -442
- package/src/export_import/export.ts +0 -234
- package/src/export_import/index.ts +0 -4
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useImportConfig.tsx +0 -34
- package/src/types/column_mapping.ts +0 -32
- package/src/types/index.ts +0 -1
- package/src/utils/data.ts +0 -133
- package/src/utils/file_headers.ts +0 -90
- package/src/utils/file_to_json.ts +0 -106
- package/src/utils/get_import_inference_type.ts +0 -27
- package/src/utils/get_properties_mapping.ts +0 -63
- package/src/utils/index.ts +0 -3
@@ -1,288 +0,0 @@
|
|
1
|
-
import React, { useCallback } from "react";
|
2
|
-
|
3
|
-
import {
|
4
|
-
CollectionActionsProps,
|
5
|
-
Entity,
|
6
|
-
EntityCollection,
|
7
|
-
ExportConfig,
|
8
|
-
getDefaultValuesFor,
|
9
|
-
resolveCollection,
|
10
|
-
ResolvedEntityCollection,
|
11
|
-
useCustomizationController,
|
12
|
-
useDataSource,
|
13
|
-
useFireCMSContext,
|
14
|
-
useNavigationController,
|
15
|
-
User
|
16
|
-
} from "@firecms/core";
|
17
|
-
import {
|
18
|
-
Alert,
|
19
|
-
BooleanSwitchWithLabel,
|
20
|
-
Button,
|
21
|
-
CircularProgress,
|
22
|
-
cls,
|
23
|
-
Dialog,
|
24
|
-
DialogActions,
|
25
|
-
DialogContent,
|
26
|
-
focusedMixin,
|
27
|
-
GetAppIcon,
|
28
|
-
IconButton,
|
29
|
-
Tooltip,
|
30
|
-
Typography
|
31
|
-
} from "@firecms/ui";
|
32
|
-
import { downloadEntitiesExport } from "./export";
|
33
|
-
|
34
|
-
const DOCS_LIMIT = 500;
|
35
|
-
|
36
|
-
export function ExportCollectionAction<M extends Record<string, any>, UserType extends User>({
|
37
|
-
collection: inputCollection,
|
38
|
-
path: inputPath,
|
39
|
-
collectionEntitiesCount,
|
40
|
-
onAnalyticsEvent,
|
41
|
-
exportAllowed,
|
42
|
-
notAllowedView
|
43
|
-
}: CollectionActionsProps<M, UserType, EntityCollection<M, any>> & {
|
44
|
-
exportAllowed?: (props: { collectionEntitiesCount: number, path: string, collection: EntityCollection }) => boolean;
|
45
|
-
notAllowedView?: React.ReactNode;
|
46
|
-
onAnalyticsEvent?: (event: string, params?: any) => void;
|
47
|
-
}) {
|
48
|
-
|
49
|
-
const customizationController = useCustomizationController();
|
50
|
-
|
51
|
-
const exportConfig = typeof inputCollection.exportable === "object" ? inputCollection.exportable : undefined;
|
52
|
-
|
53
|
-
const dateRef = React.useRef<Date>(new Date());
|
54
|
-
|
55
|
-
const [includeUndefinedValues, setIncludeUndefinedValues] = React.useState<boolean>(false);
|
56
|
-
const [flattenArrays, setFlattenArrays] = React.useState<boolean>(true);
|
57
|
-
const [exportType, setExportType] = React.useState<"csv" | "json">("csv");
|
58
|
-
const [dateExportType, setDateExportType] = React.useState<"timestamp" | "string">("string");
|
59
|
-
|
60
|
-
const context = useFireCMSContext<UserType>();
|
61
|
-
const dataSource = useDataSource();
|
62
|
-
const navigationController = useNavigationController();
|
63
|
-
|
64
|
-
const path = navigationController.resolveAliasesFrom(inputPath);
|
65
|
-
|
66
|
-
const canExport = !exportAllowed || exportAllowed({
|
67
|
-
collectionEntitiesCount,
|
68
|
-
path,
|
69
|
-
collection: inputCollection
|
70
|
-
});
|
71
|
-
|
72
|
-
const collection: ResolvedEntityCollection<M> = React.useMemo(() => resolveCollection({
|
73
|
-
collection: inputCollection,
|
74
|
-
path,
|
75
|
-
fields: customizationController.propertyConfigs
|
76
|
-
}), [inputCollection, path]);
|
77
|
-
|
78
|
-
const [dataLoading, setDataLoading] = React.useState<boolean>(false);
|
79
|
-
const [dataLoadingError, setDataLoadingError] = React.useState<Error | undefined>();
|
80
|
-
|
81
|
-
const [open, setOpen] = React.useState(false);
|
82
|
-
|
83
|
-
const handleClickOpen = useCallback(() => {
|
84
|
-
setOpen(true);
|
85
|
-
}, [setOpen]);
|
86
|
-
|
87
|
-
const handleClose = useCallback(() => {
|
88
|
-
setOpen(false);
|
89
|
-
}, [setOpen]);
|
90
|
-
|
91
|
-
const fetchAdditionalFields = useCallback(async (entities: Entity<M>[]) => {
|
92
|
-
|
93
|
-
const additionalExportFields = exportConfig?.additionalFields;
|
94
|
-
const additionalFields = collection.additionalFields;
|
95
|
-
|
96
|
-
const resolvedExportColumnsValues: Record<string, any>[] = additionalExportFields
|
97
|
-
? await Promise.all(entities.map(async (entity) => {
|
98
|
-
return (await Promise.all(additionalExportFields.map(async (column) => {
|
99
|
-
return {
|
100
|
-
[column.key]: await column.builder({
|
101
|
-
entity,
|
102
|
-
context
|
103
|
-
})
|
104
|
-
};
|
105
|
-
}))).reduce((a, b) => ({ ...a, ...b }), {});
|
106
|
-
}))
|
107
|
-
: [];
|
108
|
-
|
109
|
-
const resolvedColumnsValues: Record<string, any>[] = additionalFields
|
110
|
-
? await Promise.all(entities.map(async (entity) => {
|
111
|
-
return (await Promise.all(additionalFields
|
112
|
-
.map(async (field) => {
|
113
|
-
if (!field.value)
|
114
|
-
return {};
|
115
|
-
return {
|
116
|
-
[field.key]: await field.value({
|
117
|
-
entity,
|
118
|
-
context
|
119
|
-
})
|
120
|
-
};
|
121
|
-
}))).reduce((a, b) => ({ ...a, ...b }), {});
|
122
|
-
}))
|
123
|
-
: [];
|
124
|
-
return [...resolvedExportColumnsValues, ...resolvedColumnsValues];
|
125
|
-
}, [exportConfig?.additionalFields]);
|
126
|
-
|
127
|
-
const doDownload = useCallback(async (collection: ResolvedEntityCollection<M>,
|
128
|
-
exportConfig: ExportConfig<any> | undefined) => {
|
129
|
-
|
130
|
-
onAnalyticsEvent?.("export_collection", {
|
131
|
-
collection: collection.path
|
132
|
-
});
|
133
|
-
setDataLoading(true);
|
134
|
-
dataSource.fetchCollection<M>({
|
135
|
-
path,
|
136
|
-
collection
|
137
|
-
})
|
138
|
-
.then(async (data) => {
|
139
|
-
setDataLoadingError(undefined);
|
140
|
-
const additionalData = await fetchAdditionalFields(data);
|
141
|
-
const additionalHeaders = [
|
142
|
-
...exportConfig?.additionalFields?.map(column => column.key) ?? [],
|
143
|
-
...collection.additionalFields?.map(field => field.key) ?? []
|
144
|
-
];
|
145
|
-
|
146
|
-
const dataWithDefaults = includeUndefinedValues
|
147
|
-
? data.map(entity => {
|
148
|
-
const defaultValues = getDefaultValuesFor(collection.properties);
|
149
|
-
return {
|
150
|
-
...entity,
|
151
|
-
values: { ...defaultValues, ...entity.values }
|
152
|
-
};
|
153
|
-
})
|
154
|
-
: data;
|
155
|
-
downloadEntitiesExport({
|
156
|
-
data: dataWithDefaults,
|
157
|
-
additionalData,
|
158
|
-
properties: collection.properties,
|
159
|
-
propertiesOrder: collection.propertiesOrder,
|
160
|
-
name: collection.name,
|
161
|
-
flattenArrays,
|
162
|
-
additionalHeaders,
|
163
|
-
exportType,
|
164
|
-
dateExportType
|
165
|
-
});
|
166
|
-
onAnalyticsEvent?.("export_collection_success", {
|
167
|
-
collection: collection.path
|
168
|
-
});
|
169
|
-
})
|
170
|
-
.catch((e) => {
|
171
|
-
console.error("Error loading export data", e);
|
172
|
-
setDataLoadingError(e);
|
173
|
-
})
|
174
|
-
.finally(() => setDataLoading(false));
|
175
|
-
|
176
|
-
}, [onAnalyticsEvent, dataSource, path, fetchAdditionalFields, includeUndefinedValues, flattenArrays, exportType, dateExportType]);
|
177
|
-
|
178
|
-
const onOkClicked = useCallback(() => {
|
179
|
-
doDownload(collection, exportConfig);
|
180
|
-
handleClose();
|
181
|
-
}, [doDownload, collection, exportConfig, handleClose]);
|
182
|
-
|
183
|
-
return <>
|
184
|
-
|
185
|
-
<Tooltip title={"Export"}>
|
186
|
-
<IconButton color={"primary"} onClick={handleClickOpen}>
|
187
|
-
<GetAppIcon/>
|
188
|
-
</IconButton>
|
189
|
-
</Tooltip>
|
190
|
-
|
191
|
-
<Dialog
|
192
|
-
open={open}
|
193
|
-
onOpenChange={setOpen}
|
194
|
-
maxWidth={"xl"}>
|
195
|
-
<DialogContent className={"flex flex-col gap-4 my-4"}>
|
196
|
-
|
197
|
-
<Typography variant={"h6"}>Export data</Typography>
|
198
|
-
|
199
|
-
<div>Download the the content of this table as a CSV</div>
|
200
|
-
|
201
|
-
{collectionEntitiesCount > DOCS_LIMIT &&
|
202
|
-
<Alert color={"warning"}>
|
203
|
-
<div>
|
204
|
-
This collections has a large number
|
205
|
-
of documents ({collectionEntitiesCount}).
|
206
|
-
</div>
|
207
|
-
</Alert>}
|
208
|
-
|
209
|
-
<div className={"flex flex-row gap-4"}>
|
210
|
-
<div className={"p-4 flex flex-col"}>
|
211
|
-
<div className="flex items-center">
|
212
|
-
<input id="radio-csv" type="radio" value="csv" name="exportType"
|
213
|
-
checked={exportType === "csv"}
|
214
|
-
onChange={() => setExportType("csv")}
|
215
|
-
className={cls(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
|
216
|
-
<label htmlFor="radio-csv"
|
217
|
-
className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">CSV</label>
|
218
|
-
</div>
|
219
|
-
<div className="flex items-center">
|
220
|
-
<input id="radio-json" type="radio" value="json" name="exportType"
|
221
|
-
checked={exportType === "json"}
|
222
|
-
onChange={() => setExportType("json")}
|
223
|
-
className={cls(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
|
224
|
-
<label htmlFor="radio-json"
|
225
|
-
className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">JSON</label>
|
226
|
-
</div>
|
227
|
-
</div>
|
228
|
-
|
229
|
-
<div className={"p-4 flex flex-col"}>
|
230
|
-
<div className="flex items-center">
|
231
|
-
<input id="radio-timestamp" type="radio" value="timestamp" name="dateExportType"
|
232
|
-
checked={dateExportType === "timestamp"}
|
233
|
-
onChange={() => setDateExportType("timestamp")}
|
234
|
-
className={cls(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
|
235
|
-
<label htmlFor="radio-timestamp"
|
236
|
-
className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">Dates as
|
237
|
-
timestamps ({dateRef.current.getTime()})</label>
|
238
|
-
</div>
|
239
|
-
<div className="flex items-center">
|
240
|
-
<input id="radio-string" type="radio" value="string" name="dateExportType"
|
241
|
-
checked={dateExportType === "string"}
|
242
|
-
onChange={() => setDateExportType("string")}
|
243
|
-
className={cls(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
|
244
|
-
<label htmlFor="radio-string"
|
245
|
-
className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">Dates as
|
246
|
-
strings ({dateRef.current.toISOString()})</label>
|
247
|
-
</div>
|
248
|
-
</div>
|
249
|
-
</div>
|
250
|
-
|
251
|
-
<BooleanSwitchWithLabel
|
252
|
-
size={"small"}
|
253
|
-
disabled={exportType !== "csv"}
|
254
|
-
value={flattenArrays}
|
255
|
-
onValueChange={setFlattenArrays}
|
256
|
-
label={"Flatten arrays"}/>
|
257
|
-
|
258
|
-
<BooleanSwitchWithLabel
|
259
|
-
size={"small"}
|
260
|
-
value={includeUndefinedValues}
|
261
|
-
onValueChange={setIncludeUndefinedValues}
|
262
|
-
label={"Include undefined values"}/>
|
263
|
-
|
264
|
-
{!canExport && notAllowedView}
|
265
|
-
|
266
|
-
</DialogContent>
|
267
|
-
|
268
|
-
<DialogActions>
|
269
|
-
|
270
|
-
{dataLoading && <CircularProgress size={"small"}/>}
|
271
|
-
|
272
|
-
<Button onClick={handleClose}
|
273
|
-
variant={"text"}>
|
274
|
-
Cancel
|
275
|
-
</Button>
|
276
|
-
|
277
|
-
<Button variant="filled"
|
278
|
-
onClick={onOkClicked}
|
279
|
-
disabled={dataLoading || !canExport}>
|
280
|
-
Download
|
281
|
-
</Button>
|
282
|
-
|
283
|
-
</DialogActions>
|
284
|
-
|
285
|
-
</Dialog>
|
286
|
-
|
287
|
-
</>;
|
288
|
-
}
|