Skip to content

Commit

Permalink
Merge pull request #6217 from marmelab/ra-no-code-configuration
Browse files Browse the repository at this point in the history
ra-no-code - Introduce Resource Configuration
  • Loading branch information
fzaninotto authored May 6, 2021
2 parents e42e1e2 + 63fef58 commit f983396
Show file tree
Hide file tree
Showing 24 changed files with 576 additions and 100 deletions.
3 changes: 2 additions & 1 deletion packages/ra-core/src/inference/assertions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import isValid from 'date-fns/is_valid';
import parseDate from 'date-fns/parse';

export const isNumeric = (value: any) =>
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
8 changes: 4 additions & 4 deletions packages/ra-core/src/inference/inferTypeFromValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
valuesAreEmail,
} from './assertions';

const types = [
export const InferenceTypes = [
'array',
'boolean',
'date',
Expand All @@ -33,9 +33,10 @@ const types = [
'richText',
'string',
'url',
'object',
] as const;

export type PossibleInferredElementTypes = typeof types[number];
export type PossibleInferredElementTypes = typeof InferenceTypes[number];

export interface InferredElementDescription {
type: PossibleInferredElementTypes;
Expand Down Expand Up @@ -169,8 +170,7 @@ export const inferTypeFromValues = (
return { type: 'number', props: { source: name } };
}
if (valuesAreObject(values)) {
// we need to go deeper
// Arbitrarily, choose the first prop of the first object
/// 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);
Expand Down
1 change: 0 additions & 1 deletion packages/ra-no-code/src/Admin.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ describe('Admin', () => {
getByText('Date', { selector: 'th *' });
getByText('Customer', { selector: 'th *' });
getByText('Basket.product', { selector: 'th *' });
getByText('Basket.quantity', { selector: 'th *' });
getByText('Total ex taxes', { selector: 'th *' });
getByText('Delivery fees', { selector: 'th *' });
getByText('Tax rate', { selector: 'th *' });
Expand Down
15 changes: 14 additions & 1 deletion packages/ra-no-code/src/Admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,26 @@ import {
Resource,
} from 'react-admin';
import localStorageDataProvider from 'ra-data-local-storage';
import { Create, Edit, List } from './builders';
import { Create, Edit, List, Show } from './builders';
import {
useResourcesConfiguration,
ResourceConfigurationPage,
ResourceConfigurationProvider,
} from './ResourceConfiguration';
import { Layout, Ready } from './ui';
import { Route } from 'react-router';

const dataProvider = localStorageDataProvider();

const customRoutes = [
<Route
path="/configure/:resource"
render={({ match }) => (
<ResourceConfigurationPage resource={match.params.resource} />
)}
/>,
];

export const Admin = (props: AdminProps) => (
<ResourceConfigurationProvider dataProvider={dataProvider}>
<InnerAdmin {...props} />
Expand All @@ -28,6 +39,7 @@ const InnerAdmin = (props: AdminProps) => {
dataProvider={dataProvider}
ready={Ready}
layout={Layout}
customRoutes={customRoutes}
{...props}
>
{hasResources
Expand All @@ -39,6 +51,7 @@ const InnerAdmin = (props: AdminProps) => {
list={List}
edit={Edit}
create={Create}
show={Show}
/>
))
: undefined}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { InferenceTypes } from 'ra-core';
import { FieldProps, SelectInput } from 'ra-ui-materialui';

export const FieldTypeInput = (props: FieldProps) => (
<SelectInput choices={INFERENCE_TYPES} {...props} />
);

const INFERENCE_TYPES = InferenceTypes.map(type => ({
id: type,
name: type,
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';
import { CheckboxGroupInput, FieldProps } from 'ra-ui-materialui';

export const FieldViewsInput = (props: FieldProps) => (
<CheckboxGroupInput
{...props}
choices={VIEWS}
initialValue={VIEWS_INITIAL_VALUE}
/>
);

const VIEWS = [
{
id: 'list',
name: 'List',
},
{
id: 'edit',
name: 'Edit',
},
{
id: 'create',
name: 'Create',
},
{
id: 'show',
name: 'Show',
},
];

const VIEWS_INITIAL_VALUE = ['list', 'edit', 'create', 'show'];
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './FieldTypeInput';
export * from './FieldViewsInput';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from 'react';
import { getFieldLabelTranslationArgs, useTranslate } from 'ra-core';
import { TextInput } from 'ra-ui-materialui';
import { CardContent } from '@material-ui/core';
import { FieldTypeInput } from './FieldConfiguration/FieldTypeInput';
import { FieldViewsInput } from './FieldConfiguration/FieldViewsInput';

export const FieldConfigurationFormSection = props => {
const { sourcePrefix, field, resource } = props;
const translate = useTranslate();
const labelArgs = getFieldLabelTranslationArgs({
source: field.props.source,
resource,
label: field.props.label,
});

return (
<CardContent>
<TextInput
source={`${sourcePrefix}.props.source`}
label="Source"
fullWidth
disabled
/>
<TextInput
source={`${sourcePrefix}.props.label`}
label="Label"
fullWidth
initialValue={translate(...labelArgs)}
/>
<FieldTypeInput
source={`${sourcePrefix}.type`}
label="Type"
fullWidth
/>
<FieldViewsInput
source={`${sourcePrefix}.views`}
label="Views"
fullWidth
/>
</CardContent>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import { Tab } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { getFieldLabelTranslationArgs, useTranslate } from 'ra-core';

export const FieldConfigurationTab = ({ field, resource, ...props }) => {
const classes = useStyles();
const translate = useTranslate();
const labelArgs = getFieldLabelTranslationArgs({
source: field.props.source,
resource,
label: field.props.label,
});

return (
<Tab
{...props}
key={field.props.source}
label={translate(...labelArgs)}
id={`nav-tab-${field.props.source}`}
aria-controls={`nav-tabpanel-${field.props.source}`}
classes={classes}
/>
);
};

const useStyles = makeStyles(theme => ({
root: {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
textTransform: 'none',
minHeight: 0,
fontWeight: 'normal',
},
selected: {
fontWeight: 'bold',
},
}));
Loading

0 comments on commit f983396

Please sign in to comment.