Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
djhi committed Apr 29, 2021
1 parent eb47868 commit 429825a
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 30 deletions.
2 changes: 1 addition & 1 deletion packages/ra-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
},
"dependencies": {
"classnames": "~2.2.5",
"date-fns": "^1.29.0",
"date-fns": "^2.21.1",
"eventemitter3": "^3.0.0",
"inflection": "~1.12.0",
"lodash": "~4.17.5",
Expand Down
5 changes: 3 additions & 2 deletions packages/ra-core/src/inference/assertions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import parseDate from 'date-fns/parse';
import isValid from 'date-fns/isValid';
import parseDate from 'date-fns/parseISO';

export const isNumeric = (value: any) =>
!isNaN(parseFloat(value)) && isFinite(value);
Expand Down Expand Up @@ -45,7 +46,7 @@ export const isDate = (value: any) => !value || value instanceof Date;
export const valuesAreDate = (values: any[]) => values.every(isDate);

export const isDateString = (value: any) =>
!value || (typeof value === 'string' && !isNaN(parseDate(value).getDate()));
!value || (typeof value === 'string' && isValid(parseDate(value)));
export const valuesAreDateString = (values: any[]) =>
values.every(isDateString);

Expand Down
17 changes: 13 additions & 4 deletions packages/ra-core/src/inference/inferTypeFromValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const InferenceTypes = [
'richText',
'string',
'url',
'object',
] as const;

export type PossibleInferredElementTypes = typeof InferenceTypes[number];
Expand Down Expand Up @@ -170,10 +171,18 @@ export const inferTypeFromValues = (
}
if (valuesAreObject(values)) {
// we need to go deeper
// Arbitrarily, choose the first prop of the first object
const propName = Object.keys(values[0]).shift();
const leafValues = values.map(v => v[propName]);
return inferTypeFromValues(`${name}.${propName}`, leafValues);
// Arbitrarily, choose the first object
// FIXME bad visual representation
return {
type: 'object',
props: { source: name },
children: Object.keys(values[0]).map(leafName =>
inferTypeFromValues(
leafName,
values.map(value => value[leafName])
)
),
};
}
return { type: 'string', props: { source: name } };
};
2 changes: 1 addition & 1 deletion packages/ra-no-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
},
"dependencies": {
"classnames": "~2.2.5",
"date-fns": "^1.29.0",
"date-fns": "^2.21.1",
"inflection": "~1.12.0",
"lodash": "~4.17.5",
"react-admin": "^3.14.5",
Expand Down
26 changes: 18 additions & 8 deletions packages/ra-no-code/src/builders/getInputFromFieldDefinition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,68 @@ import {
} from 'ra-ui-materialui';

export const getInputFromFieldDefinition = (
definition: InferredElementDescription
definition: InferredElementDescription,
keyPrefix?: string
) => {
switch (definition.type) {
case 'date':
return (
<DateInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
{...definition.props}
/>
);
case 'email':
return (
<TextInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
validate={email()}
{...definition.props}
/>
);
case 'boolean':
return (
<BooleanInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
{...definition.props}
/>
);
case 'number':
return (
<NumberInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
{...definition.props}
/>
);
case 'image':
return (
<ImageInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
{...definition.props}
/>
);
case 'url':
return (
<TextInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
{...definition.props}
/>
);
case 'object':
if (Array.isArray(definition.children)) {
return definition.children.map((child, index) =>
getInputFromFieldDefinition(child, index.toString())
);
}
return <>{getInputFromFieldDefinition(definition.children)}</>;
default:
return (
<TextInput
key={definition.props.source}
key={getKey(keyPrefix, definition.props.source)}
{...definition.props}
/>
);
}
};

const getKey = (prefix, source) => (prefix ? `${prefix}_${source}` : source);
61 changes: 48 additions & 13 deletions packages/ra-no-code/src/ui/useImportResourceFromCsv.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from 'react';
import { parse } from 'papaparse';
import { Record, useDataProvider } from 'ra-core';
import { getValuesFromRecords, Record, useDataProvider } from 'ra-core';
import set from 'lodash/set';

import {
useResourcesConfiguration,
Expand All @@ -24,23 +25,23 @@ export const useImportResourceFromCsv = (
setParsing(true);
parse<Record>(file, {
header: true,
complete: async ({ data }) => {
skipEmptyLines: true,
complete: async ({ data, meta }) => {
const resourceAlreadyExists = !!resources[resource];

const records = sanitizeRecords(
data.filter(record => !!record.id),
meta
);
console.log({ records });
await Promise.all(
data.map(record => {
if (record.id) {
return dataProvider
.create(resource, {
data: record,
})
.catch(error => console.error(error));
}
return Promise.resolve();
records.map(record => {
return dataProvider.create(resource, {
data: record,
});
})
);
setParsing(false);
const fields = getFieldDefinitionsFromRecords(data);
const fields = getFieldDefinitionsFromRecords(records);
addResource({ name: resource, fields });
onImportCompleted({ resource, resourceAlreadyExists });
},
Expand All @@ -58,3 +59,37 @@ type ImportCompletedHandler = ({
resourceAlreadyExists: boolean;
resource: string;
}) => void;

const sanitizeRecords = (
records: Record[],
{ fields }: { fields: string[] }
): Record[] => {
const values = getValuesFromRecords(records);
return fields.reduce(
(newRecords, field) => sanitizeRecord(newRecords, values, field),
[...records]
);
};

const sanitizeRecord = (records, values, field) => {
if (field.split('.').length > 1) {
return records.map(record => {
let { [field]: pathField, ...newRecord } = record;
return set(newRecord, field, record[field]);
});
}

const fieldValues = values[field];

if (
fieldValues.some(value =>
['false', 'true'].includes(value.toString().toLowerCase())
)
) {
return records.map(record =>
set(record, field, Boolean(record[field]))
);
}

return records;
};
7 changes: 6 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6592,7 +6592,7 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"

date-fns@^1.27.2, date-fns@^1.29.0:
date-fns@^1.27.2:
version "1.30.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
Expand All @@ -6602,6 +6602,11 @@ date-fns@^2.0.1:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.9.0.tgz#d0b175a5c37ed5f17b97e2272bbc1fa5aec677d2"
integrity sha512-khbFLu/MlzLjEzy9Gh8oY1hNt/Dvxw3J6Rbc28cVoYWQaC1S3YI4xwkF9ZWcjDLscbZlY9hISMr66RFzZagLsA==

date-fns@^2.21.1:
version "2.21.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.21.1.tgz#679a4ccaa584c0706ea70b3fa92262ac3009d2b0"
integrity sha512-m1WR0xGiC6j6jNFAyW4Nvh4WxAi4JF4w9jRJwSI8nBmNcyZXPcP9VUQG+6gHQXAmqaGEKDKhOqAtENDC941UkA==

date-fns@~1.29.0:
version "1.29.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
Expand Down

0 comments on commit 429825a

Please sign in to comment.