@firecms/data_import_export 3.0.0-canary.42 → 3.0.0-canary.44

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.
@@ -4,7 +4,6 @@ import {
4
4
  EntityReference,
5
5
  getArrayValuesCount,
6
6
  getValueInPath,
7
- ResolvedEntityCollection,
8
7
  ResolvedProperties,
9
8
  ResolvedProperty
10
9
  } from "@firecms/core";
@@ -14,37 +13,43 @@ interface Header {
14
13
  label: string;
15
14
  }
16
15
 
17
- export function downloadExport<M extends Record<string, any>>(data: Entity<M>[],
18
- additionalData: Record<string, any>[] | undefined,
19
- collection: ResolvedEntityCollection<M>,
20
- flattenArrays: boolean,
21
- additionalHeaders: string[] | undefined,
22
- exportType: "csv" | "json",
23
- dateExportType: "timestamp" | "string"
16
+ export function downloadEntitiesExport<M extends Record<string, any>>(data: Entity<M>[],
17
+ additionalData: Record<string, any>[] | undefined,
18
+ properties: ResolvedProperties<M>,
19
+ propertiesOrder: string[] | undefined,
20
+ name: string,
21
+ flattenArrays: boolean,
22
+ additionalHeaders: string[] | undefined,
23
+ exportType: "csv" | "json",
24
+ dateExportType: "timestamp" | "string"
24
25
  ) {
25
26
 
26
- console.debug("Downloading export", { dataLength: data.length, collection, exportType, dateExportType });
27
- const properties = collection.properties;
27
+ console.debug("Downloading export", {
28
+ dataLength: data.length,
29
+ properties,
30
+ exportType,
31
+ dateExportType
32
+ });
28
33
 
29
34
  if (exportType === "csv") {
30
35
  const arrayValuesCount = flattenArrays ? getArrayValuesCount(data.map(d => d.values)) : {};
31
- const headers = getExportHeaders(properties, additionalHeaders, arrayValuesCount);
32
- const exportableData = getCSVExportableData(data, additionalData, properties, headers, dateExportType);
36
+ const headers = getExportHeaders(properties, propertiesOrder, additionalHeaders, arrayValuesCount);
37
+ const exportableData = getEntityCSVExportableData(data, additionalData, properties, headers, dateExportType);
33
38
  const headersData = entryToCSVRow(headers.map(h => h.label));
34
39
  const csvData = exportableData.map(entry => entryToCSVRow(entry));
35
- downloadBlob([headersData, ...csvData], `${collection.name}.csv`, "text/csv");
40
+ downloadBlob([headersData, ...csvData], `${name}.csv`, "text/csv");
36
41
  } else {
37
- const exportableData = getJsonExportableData(data, additionalData, properties, dateExportType);
42
+ const exportableData = getEntityJsonExportableData(data, additionalData, properties, dateExportType);
38
43
  const json = JSON.stringify(exportableData, null, 2);
39
- downloadBlob([json], `${collection.name}.json`, "application/json");
44
+ downloadBlob([json], `${name}.json`, "application/json");
40
45
  }
41
46
  }
42
47
 
43
- export function getCSVExportableData(data: Entity<any>[],
44
- additionalData: Record<string, any>[] | undefined,
45
- properties: ResolvedProperties,
46
- headers: Header[],
47
- dateExportType: "timestamp" | "string"
48
+ export function getEntityCSVExportableData(data: Entity<any>[],
49
+ additionalData: Record<string, any>[] | undefined,
50
+ properties: ResolvedProperties,
51
+ headers: Header[],
52
+ dateExportType: "timestamp" | "string"
48
53
  ) {
49
54
 
50
55
  const mergedData: any[] = data.map(e => ({
@@ -63,10 +68,10 @@ export function getCSVExportableData(data: Entity<any>[],
63
68
  });
64
69
  }
65
70
 
66
- export function getJsonExportableData(data: Entity<any>[],
67
- additionalData: Record<string, any>[] | undefined,
68
- properties: ResolvedProperties,
69
- dateExportType: "timestamp" | "string"
71
+ export function getEntityJsonExportableData(data: Entity<any>[],
72
+ additionalData: Record<string, any>[] | undefined,
73
+ properties: ResolvedProperties,
74
+ dateExportType: "timestamp" | "string"
70
75
  ) {
71
76
 
72
77
  const mergedData: any[] = data.map(e => ({
@@ -84,13 +89,18 @@ export function getJsonExportableData(data: Entity<any>[],
84
89
  }
85
90
 
86
91
  function getExportHeaders<M extends Record<string, any>>(properties: ResolvedProperties<M>,
92
+ propertiesOrder: string[] | undefined,
87
93
  additionalHeaders: string[] | undefined,
88
94
  arrayValuesCount?: ArrayValuesCount): Header[] {
89
95
 
90
96
  const headers: Header[] = [
91
- { label: "id", key: "id" },
92
- ...Object.entries(properties)
93
- .flatMap(([childKey, property]) => {
97
+ {
98
+ label: "id",
99
+ key: "id"
100
+ },
101
+ ...(propertiesOrder ?? Object.keys(properties))
102
+ .flatMap((childKey) => {
103
+ const property = properties[childKey];
94
104
  if (arrayValuesCount && arrayValuesCount[childKey] > 1) {
95
105
  return Array.from({ length: arrayValuesCount[childKey] },
96
106
  (_, i) => getHeaders(property as ResolvedProperty, `${childKey}[${i}]`, ""))
@@ -102,7 +112,10 @@ function getExportHeaders<M extends Record<string, any>>(properties: ResolvedPro
102
112
  ];
103
113
 
104
114
  if (additionalHeaders) {
105
- headers.push(...additionalHeaders.map(h => ({ label: h, key: h })));
115
+ headers.push(...additionalHeaders.map(h => ({
116
+ label: h,
117
+ key: h
118
+ })));
106
119
  }
107
120
 
108
121
  return headers;
@@ -121,7 +134,10 @@ function getHeaders(property: ResolvedProperty, propertyKey: string, prefix = ""
121
134
  .map(([childKey, p]) => getHeaders(p, childKey, currentKey))
122
135
  .flat();
123
136
  } else {
124
- return [{ label: currentKey, key: currentKey }];
137
+ return [{
138
+ label: currentKey,
139
+ key: currentKey
140
+ }];
125
141
  }
126
142
  }
127
143
 
@@ -0,0 +1,4 @@
1
+ export * from "./export";
2
+ export * from "./BasicExportAction";
3
+ export * from "./ExportCollectionAction";
4
+ export * from "./ImportCollectionAction";
@@ -5,6 +5,7 @@ import { ImportConfig } from "../types";
5
5
  export const useImportConfig = (): ImportConfig => {
6
6
 
7
7
  const [inUse, setInUse] = useState<boolean>(false);
8
+ const [defaultValues, setDefaultValues] = useState<Record<string, any>>({});
8
9
  const [idColumn, setIdColumn] = useState<string | undefined>();
9
10
  const [importData, setImportData] = useState<object[]>([]);
10
11
  const [entities, setEntities] = useState<Entity<any>[]>([]);
@@ -27,5 +28,7 @@ export const useImportConfig = (): ImportConfig => {
27
28
  setHeadersMapping,
28
29
  originProperties,
29
30
  setOriginProperties,
31
+ defaultValues,
32
+ setDefaultValues
30
33
  };
31
34
  };
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from "./components";
3
3
  export * from "./types";
4
4
  export * from "./utils";
5
5
  export * from "./hooks";
6
+ export * from "./export_import";
@@ -26,11 +26,7 @@ export type ImportConfig = {
26
26
  headingsOrder: string[];
27
27
  setHeadingsOrder: React.Dispatch<React.SetStateAction<string[]>>;
28
28
 
29
- }
29
+ defaultValues: Record<string, any>;
30
+ setDefaultValues: React.Dispatch<React.SetStateAction<Record<string, any>>>;
30
31
 
31
- export type DataTypeMapping = {
32
- from: DataType;
33
- fromSubtype?: DataType;
34
- to: DataType;
35
- toSubtype?: DataType;
36
32
  }
@@ -19,7 +19,7 @@ export function useImportExportPlugin(props?: ImportExportPluginProps): FireCMSP
19
19
 
20
20
  export type ImportExportPluginProps = {
21
21
  exportAllowed?: (props: ExportAllowedParams) => boolean;
22
- notAllowedView: React.ReactNode;
22
+ notAllowedView?: React.ReactNode;
23
23
  onAnalyticsEvent?: (event: string, params?: any) => void;
24
24
  }
25
25
  export type ExportAllowedParams = { collectionEntitiesCount: number, path: string, collection: EntityCollection };
package/src/utils/data.ts CHANGED
@@ -1,41 +1,44 @@
1
- import { DataType, Entity, EntityReference, getPropertyInPath, Properties } from "@firecms/core";
1
+ import {
2
+ Entity,
3
+ EntityReference,
4
+ getPropertyInPath,
5
+ isPropertyBuilder,
6
+ mergeDeep,
7
+ Properties,
8
+ Property,
9
+ PropertyOrBuilder,
10
+ ResolvedProperty,
11
+ resolveProperty
12
+ } from "@firecms/core";
2
13
  import { unflattenObject } from "./file_to_json";
3
-
4
- type DataTypeMapping = {
5
- from: DataType;
6
- fromSubtype?: DataType;
7
- to: DataType;
8
- toSubtype?: DataType;
9
- }
14
+ import { getIn } from "@firecms/formex";
15
+ import { inferTypeFromValue } from "@firecms/schema_inference";
10
16
 
11
17
  export function convertDataToEntity(data: Record<any, any>,
12
18
  idColumn: string | undefined,
13
19
  headersMapping: Record<string, string | null>,
14
20
  properties: Properties,
15
- propertiesMapping: Record<string, DataTypeMapping>,
16
- path: string): Entity<any> {
21
+ path: string,
22
+ defaultValues: Record<string, any>): Entity<any> {
17
23
  const flatObject = flattenEntry(data);
18
24
  if (idColumn)
19
25
  delete flatObject[idColumn];
20
26
  const mappedKeysObject = Object.entries(flatObject)
21
27
  .map(([key, value]) => {
22
- const mappedKey = headersMapping[key] ?? key;
28
+ const mappedKey = getIn(headersMapping, key) ?? key;
23
29
 
24
30
  const mappedProperty = getPropertyInPath(properties, mappedKey);
25
- if (!mappedProperty)
31
+ if (!mappedProperty) {
26
32
  return {};
27
-
28
- const propertyMapping = propertiesMapping[mappedKey];
29
- let valueResult = value;
30
- if (propertyMapping) {
31
- valueResult = processValueMapping(value, propertyMapping);
32
33
  }
34
+ const processedValue = processValueMapping(value, mappedProperty);
33
35
  return ({
34
- [mappedKey]: valueResult
36
+ [mappedKey]: processedValue
35
37
  });
36
38
  })
37
39
  .reduce((acc, curr) => ({ ...acc, ...curr }), {});
38
- const values = unflattenObject(mappedKeysObject);
40
+
41
+ const values = mergeDeep(defaultValues ?? {}, unflattenObject(mappedKeysObject));
39
42
  let id = idColumn ? data[idColumn] : undefined;
40
43
  if (typeof id === "string") {
41
44
  id = id.trim();
@@ -60,7 +63,7 @@ export function flattenEntry(obj: any, parent = ""): any {
60
63
  return Object.keys(obj).reduce((acc, key) => {
61
64
  const prefixedKey = parent ? `${parent}.${key}` : key;
62
65
 
63
- if (typeof obj[key] === "object" && obj[key] !== null && !Array.isArray(obj[key])) {
66
+ if (typeof obj[key] === "object" && !(obj[key] instanceof Date) && obj[key] !== null && !Array.isArray(obj[key])) {
64
67
  Object.assign(acc, flattenEntry(obj[key], prefixedKey));
65
68
  } else {
66
69
  // @ts-ignore
@@ -71,116 +74,24 @@ export function flattenEntry(obj: any, parent = ""): any {
71
74
  }, {});
72
75
  }
73
76
 
74
- // export function convertDataEntryValue({
75
- // key,
76
- // fullKey,
77
- // value,
78
- // idColumn,
79
- // headersMapping,
80
- // properties,
81
- // propertiesMapping
82
- // }: {
83
- // key?: string,
84
- // fullKey: string,
85
- // value: any,
86
- // idColumn?: string,
87
- // headersMapping: Record<string, string | null>,
88
- // properties: Properties,
89
- // propertiesMapping: Record<string, DataTypeMapping>
90
- // }): any {
91
- //
92
- // if (value === undefined) return value;
93
- // if (value === null) return value;
94
- //
95
- // if (Array.isArray(value)) {
96
- // const mappedKey = headersMapping[fullKey] || fullKey;
97
- // const valueMapping = propertiesMapping[mappedKey];
98
- // return processValueMapping(value, valueMapping);
99
- // // return value.map(v => convertDataEntryValue({ value: v, fullKey, idColumn, headersMapping, propertiesMapping }));
100
- // } else if (typeof value === "object") {
101
- // return convertDataObjectValue({
102
- // key,
103
- // fullKey,
104
- // value,
105
- // idColumn,
106
- // headersMapping,
107
- // properties,
108
- // propertiesMapping
109
- // });
110
- // } else {
111
- // const mappedKey = headersMapping[fullKey] || fullKey;
112
- // const valueMapping = propertiesMapping[mappedKey];
113
- // return processValueMapping(value, valueMapping);
114
- // }
115
- // }
77
+ export function processValueMapping(value: any, property?: PropertyOrBuilder): any {
78
+ if (value === null) return null;
116
79
 
117
- // export function convertDataObjectValue({
118
- // key,
119
- // fullKey,
120
- // value,
121
- // idColumn,
122
- // headersMapping,
123
- // properties,
124
- // propertiesMapping
125
- // }: {
126
- // key?: string,
127
- // fullKey?: string,
128
- // value: object,
129
- // idColumn?: string,
130
- // headersMapping: Record<string, string | null>,
131
- // properties: Properties,
132
- // propertiesMapping: Record<string, DataTypeMapping>
133
- // }): object {
134
- //
135
- // if (value instanceof Date) {
136
- // const mappedKey = fullKey ? headersMapping[fullKey] || fullKey : undefined;
137
- // const valueMapping = mappedKey ? propertiesMapping[mappedKey] : undefined;
138
- // return processValueMapping(value, valueMapping);
139
- // }
140
- //
141
- // return Object.entries(value)
142
- // .map(([childKey, childValue]) => {
143
- // const childFullKey = fullKey ? `${fullKey}.${childKey}` : childKey;
144
- // const mappedKey = headersMapping[childFullKey] ?? childFullKey;
145
- // const mappedKeyLastPart = mappedKey.split(".").slice(-1)[0];
146
- // const property = getPropertyInPath(properties, mappedKey);
147
- // // if (!property) {
148
- // // console.log("ppp", { properties, mappedKey, })
149
- // // return {};
150
- // // }
151
- // return ({
152
- // [mappedKeyLastPart]: convertDataEntryValue({
153
- // key: childKey,
154
- // fullKey: childFullKey,
155
- // value: childValue,
156
- // idColumn,
157
- // headersMapping,
158
- // properties,
159
- // propertiesMapping
160
- // })
161
- // });
162
- // })
163
- // .reduce((acc, curr) => ({ ...acc, ...curr }), {});
164
- // }
80
+ if (property === undefined) return value;
81
+ const usedProperty: ResolvedProperty | null = resolveProperty({
82
+ propertyOrBuilder: property,
83
+ propertyValue: value
84
+ })
85
+ if (usedProperty === null) return value;
86
+ const from = inferTypeFromValue(value);
87
+ const to = usedProperty.dataType;
165
88
 
166
- export function processValueMapping(value: any, valueMapping?: DataTypeMapping): any {
167
- if (valueMapping === undefined) return value;
168
- const {
169
- from,
170
- to
171
- } = valueMapping;
172
- if (from === "array" && to === "array" && valueMapping.fromSubtype && valueMapping.toSubtype && Array.isArray(value)) {
173
- return value.map(v => processValueMapping(v, {
174
- from: valueMapping.fromSubtype!,
175
- to: valueMapping.toSubtype!
176
- }));
89
+ if (from === "array" && to === "array" && Array.isArray(value) && usedProperty.of && !isPropertyBuilder(usedProperty.of as PropertyOrBuilder)) {
90
+ return value.map(v => processValueMapping(v, usedProperty.of as Property));
177
91
  } else if (from === "string" && to === "number" && typeof value === "string") {
178
92
  return Number(value);
179
- } else if (from === "string" && to === "array" && valueMapping.toSubtype && typeof value === "string") {
180
- return value.split(",").map((v: string) => processValueMapping(v, {
181
- from: "string",
182
- to: valueMapping.toSubtype!
183
- }));
93
+ } else if (from === "string" && to === "array" && typeof value === "string" && usedProperty.of && !isPropertyBuilder(usedProperty.of as PropertyOrBuilder)) {
94
+ return value.split(",").map((v: string) => processValueMapping(v, usedProperty.of));
184
95
  } else if (from === "string" && to === "boolean") {
185
96
  return value === "true";
186
97
  } else if (from === "number" && to === "boolean") {
@@ -1,59 +1,63 @@
1
- import { DataType, getPropertyInPath, Properties, Property } from "@firecms/core";
2
- import { DataTypeMapping } from "../types";
3
-
4
- export function getPropertiesMapping(originProperties: Properties, newProperties: Properties): Record<string, DataTypeMapping> {
5
-
6
- function updateMapping(properties: Record<string, Property>, namespace?: string): Record<string, DataTypeMapping> {
7
-
8
- const dataMapping: Record<string, DataTypeMapping> = {};
9
-
10
- Object.keys(properties).forEach((key) => {
11
-
12
- const currentKey = namespace ? `${namespace}.${key}` : key;
13
-
14
- const property = getPropertyInPath(properties, key) as Property;
15
- const inferredProperty = getPropertyInPath(originProperties, currentKey) as Property;
16
-
17
- if (property) {
18
- if (property.dataType === "map" && property.properties) {
19
- const nestedMapping = updateMapping(property.properties as Record<string, Property>, currentKey);
20
- Object.keys(nestedMapping).forEach((nestedKey) => {
21
- dataMapping[`${currentKey}.${nestedKey}`] = nestedMapping[nestedKey];
22
- });
23
- return;
24
- }
25
-
26
- if (inferredProperty) {
27
-
28
- const from = inferredProperty.dataType;
29
- const to = property.dataType;
30
- let fromSubtype: DataType | undefined;
31
- let toSubtype: DataType | undefined;
32
-
33
- if (property.dataType === "array" && property.of) {
34
- toSubtype = (property.of as Property).dataType;
35
- }
36
-
37
- if (inferredProperty?.dataType === "array" && inferredProperty?.of) {
38
- fromSubtype = (inferredProperty.of as Property).dataType;
39
- }
40
-
41
- if (from !== to || fromSubtype !== toSubtype) {
42
- dataMapping[key] = {
43
- from,
44
- to,
45
- fromSubtype,
46
- toSubtype
47
- };
48
- }
49
- }
50
-
51
- }
52
-
53
- });
54
-
55
- return dataMapping;
56
- }
57
-
58
- return updateMapping(newProperties);
59
- }
1
+ // import { DataType, getPropertyInPath, Properties, Property } from "@firecms/core";
2
+ // import { DataTypeMapping } from "../types";
3
+ //
4
+ // export function getPropertiesMapping(originProperties: Properties,
5
+ // newProperties: Properties,
6
+ // headersMapping: Record<string, string | null>): Record<string, DataTypeMapping> {
7
+ //
8
+ // function updateMapping(properties: Record<string, Property>, namespace?: string): Record<string, DataTypeMapping> {
9
+ //
10
+ // const dataMapping: Record<string, DataTypeMapping> = {};
11
+ //
12
+ // Object.keys(properties).forEach((key) => {
13
+ //
14
+ // const currentKey = namespace ? `${namespace}.${key}` : key;
15
+ //
16
+ // const property = getPropertyInPath(properties, key) as Property;
17
+ // // reverse lookup
18
+ // const mappedKey = Object.entries(headersMapping).find(([_, value]) => value === currentKey)?.[0];
19
+ // const inferredProperty = mappedKey ? getPropertyInPath(originProperties, mappedKey) as Property : null;
20
+ //
21
+ // if (property) {
22
+ // if (property.dataType === "map" && property.properties) {
23
+ // const nestedMapping = updateMapping(property.properties as Record<string, Property>, currentKey);
24
+ // Object.keys(nestedMapping).forEach((nestedKey) => {
25
+ // dataMapping[`${currentKey}.${nestedKey}`] = nestedMapping[nestedKey];
26
+ // });
27
+ // return;
28
+ // }
29
+ //
30
+ // if (inferredProperty) {
31
+ //
32
+ // const from = inferredProperty.dataType;
33
+ // const to = property.dataType;
34
+ // let fromSubtype: DataType | undefined;
35
+ // let toSubtype: DataType | undefined;
36
+ //
37
+ // if (property.dataType === "array" && property.of) {
38
+ // toSubtype = (property.of as Property).dataType;
39
+ // }
40
+ //
41
+ // if (inferredProperty?.dataType === "array" && inferredProperty?.of) {
42
+ // fromSubtype = (inferredProperty.of as Property).dataType;
43
+ // }
44
+ //
45
+ // if (from !== to || fromSubtype !== toSubtype) {
46
+ // dataMapping[currentKey] = {
47
+ // from,
48
+ // to,
49
+ // fromSubtype,
50
+ // toSubtype
51
+ // };
52
+ // }
53
+ // }
54
+ //
55
+ // }
56
+ //
57
+ // });
58
+ //
59
+ // return dataMapping;
60
+ // }
61
+ //
62
+ // return updateMapping(newProperties);
63
+ // }
@@ -1,4 +1,3 @@
1
1
  export * from "./file_to_json";
2
2
  export * from "./data";
3
3
  export * from "./get_import_inference_type";
4
- export * from "./get_properties_mapping";