Skip to content

Commit

Permalink
Merge pull request #6246 from marmelab/ra-no-code-relationships
Browse files Browse the repository at this point in the history
ra-no-code Add support for simple references
  • Loading branch information
fzaninotto authored May 31, 2021
2 parents 53e8627 + a9e28b7 commit dea823f
Show file tree
Hide file tree
Showing 14 changed files with 293 additions and 23 deletions.
13 changes: 12 additions & 1 deletion examples/no-code/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Root } from 'ra-no-code';
import { defaultTheme } from 'react-admin';
import {
unstable_createMuiStrictModeTheme,
createMuiTheme,
} from '@material-ui/core/styles';

// FIXME MUI bug https://github.com/mui-org/material-ui/issues/13394
const theme =
process.env.NODE_ENV !== 'production'
? unstable_createMuiStrictModeTheme(defaultTheme)
: createMuiTheme(defaultTheme);

ReactDOM.render(
<React.StrictMode>
<Root />
<Root theme={theme} />
</React.StrictMode>,
document.getElementById('root')
);
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ import {
createMuiTheme,
makeStyles,
ThemeProvider,
unstable_createMuiStrictModeTheme,
} from '@material-ui/core/styles';
import { defaultTheme } from 'ra-ui-materialui';
import {
defaultTheme as RaDefaultTheme,
RaThemeOptions,
} from 'ra-ui-materialui';
import FolderIcon from '@material-ui/icons/Folder';
import { Application } from './types';
import { NewApplicationForm } from './NewApplicationForm';
Expand All @@ -24,8 +28,19 @@ import {
storeApplicationsInStorage,
} from './applicationStorage';

export const ApplicationsDashboard = ({ onApplicationSelected }) => (
<ThemeProvider theme={createMuiTheme(defaultTheme)}>
const defaultTheme =
process.env.NODE_ENV !== 'production'
? unstable_createMuiStrictModeTheme(RaDefaultTheme)
: createMuiTheme(RaDefaultTheme);

export const ApplicationsDashboard = ({
onApplicationSelected,
theme = defaultTheme,
}: {
onApplicationSelected: any;
theme: RaThemeOptions;
}) => (
<ThemeProvider theme={createMuiTheme(theme)}>
<Applications onApplicationSelected={onApplicationSelected} />
</ThemeProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import { FormDataConsumer, InferredElementDescription } from 'ra-core';
import { SelectInput } from 'ra-ui-materialui';
import get from 'lodash/get';
import { useResourcesConfiguration } from './useResourcesConfiguration';

export const ConfigurationInputsFromFieldDefinition = ({
definition,
sourcePrefix,
}: {
definition: InferredElementDescription;
sourcePrefix?: string;
}) => {
const [resources] = useResourcesConfiguration();

switch (definition.type) {
case 'reference':
return (
<>
<SelectInput
source={`${sourcePrefix}.props.reference`}
label="Referenced resource"
fullWidth
choices={Object.keys(resources).map(name => ({
id: name,
name: resources[name].label || resources[name].name,
}))}
/>
<SelectInput
source={`${sourcePrefix}.options.selectionType`}
label="How to select the reference"
fullWidth
choices={ReferenceSelectionChoice}
/>
<FormDataConsumer>
{({ formData, ...rest }) => {
const resourceName = get(
formData,
`${sourcePrefix}.props.reference`
);
if (!resourceName) return null;

const resource = resources[resourceName];
return (
<SelectInput
source={`${sourcePrefix}.options.referenceField`}
label="Displayed field"
choices={resource.fields.map(field => ({
id: field.props.source,
name:
field.props.label ||
field.props.source,
}))}
{...rest}
/>
);
}}
</FormDataConsumer>
</>
);
default:
return null;
}
};

const ReferenceSelectionChoice = [
{ id: 'select', name: 'Simple list' },
{ id: 'autocomplete', name: 'Searchable list' },
{ id: 'radio', name: 'Radio buttons' },
];
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TextInput } from 'ra-ui-materialui';
import { CardContent } from '@material-ui/core';
import { FieldTypeInput } from './FieldConfiguration/FieldTypeInput';
import { FieldViewsInput } from './FieldConfiguration/FieldViewsInput';
import { ConfigurationInputsFromFieldDefinition } from './ConfigurationInputsFromFieldDefinition';

export const FieldConfigurationFormSection = props => {
const { sourcePrefix, field, resource } = props;
Expand Down Expand Up @@ -38,6 +39,10 @@ export const FieldConfigurationFormSection = props => {
label="Views"
fullWidth
/>
<ConfigurationInputsFromFieldDefinition
definition={field}
sourcePrefix={sourcePrefix}
/>
</CardContent>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,25 @@ export type ResourceConfiguration = {
fields?: FieldConfiguration[];
};

export interface FieldConfiguration extends InferredElementDescription {
export interface ReferenceFieldConfiguration extends BaseFieldConfiguration {
type: 'reference';
options: {
selectionType: 'select' | 'autocomplete' | 'radio';
referenceField: 'string';
};
}

export interface BaseFieldConfiguration extends InferredElementDescription {
views: FieldView[];
options?: {
[key: string]: any;
};
}

export type FieldConfiguration =
| BaseFieldConfiguration
| ReferenceFieldConfiguration;

export type FieldView = 'list' | 'create' | 'edit' | 'show';

export type ResourceConfigurationMap =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@ export const getFieldDefinitionsFromRecords = (
): FieldConfiguration[] => {
const values = getValuesFromRecords(records);

return Object.keys(values).map(key => ({
...inferTypeFromValues(key, values[key]),
views: ['list', 'create', 'edit', 'show'],
}));
return Object.keys(values).map(key => {
const inferedDefinition = inferTypeFromValues(key, values[key]);

return {
...inferedDefinition,
options:
inferedDefinition.type === 'reference'
? {
referenceField: 'id',
selectionType: 'select',
}
: undefined,
views: ['list', 'create', 'edit', 'show'],
};
});
};
6 changes: 4 additions & 2 deletions packages/ra-no-code/src/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { RaThemeOptions } from 'ra-ui-materialui';
import * as React from 'react';
import { useMemo, useState } from 'react';
import { Admin } from './Admin';
import { ApplicationContext } from './ApplicationContext';
import { ApplicationsDashboard } from './ApplicationsDashboard';

export const Root = () => {
export const Root = ({ theme }: { theme: RaThemeOptions }) => {
const [application, setApplication] = useState();

const handleExitApplication = () => {
Expand All @@ -26,14 +27,15 @@ export const Root = () => {
if (context.application) {
return (
<ApplicationContext.Provider value={context}>
<Admin />
<Admin theme={theme} />
</ApplicationContext.Provider>
);
}

return (
<ApplicationsDashboard
onApplicationSelected={handleApplicationSelected}
theme={theme}
/>
);
};
10 changes: 8 additions & 2 deletions packages/ra-no-code/src/builders/Create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
SimpleFormProps,
} from 'ra-ui-materialui';
import { getInputFromFieldDefinition } from './getInputFromFieldDefinition';
import { useResourceConfiguration } from '../ResourceConfiguration';
import {
useResourceConfiguration,
useResourcesConfiguration,
} from '../ResourceConfiguration';

export const Create = (props: CreateProps) => (
<RaCreate {...props}>
Expand All @@ -17,13 +20,16 @@ export const Create = (props: CreateProps) => (

export const CreateForm = (props: Omit<SimpleFormProps, 'children'>) => {
const resource = useResourceContext(props);
const [resources] = useResourcesConfiguration();
const [resourceConfiguration] = useResourceConfiguration(resource);

return (
<SimpleForm {...props}>
{resourceConfiguration.fields
.filter(definition => definition.views.includes('create'))
.map(definition => getInputFromFieldDefinition(definition))}
.map(definition =>
getInputFromFieldDefinition(definition, resources)
)}
</SimpleForm>
);
};
10 changes: 8 additions & 2 deletions packages/ra-no-code/src/builders/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
SimpleForm,
SimpleFormProps,
} from 'ra-ui-materialui';
import { useResourceConfiguration } from '../ResourceConfiguration';
import {
useResourceConfiguration,
useResourcesConfiguration,
} from '../ResourceConfiguration';
import { getInputFromFieldDefinition } from './getInputFromFieldDefinition';

export const Edit = (props: EditProps) => (
Expand All @@ -17,13 +20,16 @@ export const Edit = (props: EditProps) => (

export const EditForm = (props: Omit<SimpleFormProps, 'children'>) => {
const resource = useResourceContext(props);
const [resources] = useResourcesConfiguration();
const [resourceConfiguration] = useResourceConfiguration(resource);

return (
<SimpleForm {...props}>
{resourceConfiguration.fields
.filter(definition => definition.views.includes('edit'))
.map(definition => getInputFromFieldDefinition(definition))}
.map(definition =>
getInputFromFieldDefinition(definition, resources)
)}
</SimpleForm>
);
};
10 changes: 8 additions & 2 deletions packages/ra-no-code/src/builders/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
ListProps,
} from 'ra-ui-materialui';

import { useResourceConfiguration } from '../ResourceConfiguration';
import {
useResourceConfiguration,
useResourcesConfiguration,
} from '../ResourceConfiguration';
import { getFieldFromFieldDefinition } from './getFieldFromFieldDefinition';

export const List = (props: ListProps) => (
Expand All @@ -18,13 +21,16 @@ export const List = (props: ListProps) => (

export const Datagrid = (props: Omit<DatagridProps, 'children'>) => {
const resource = useResourceContext(props);
const [resources] = useResourcesConfiguration();
const [resourceConfiguration] = useResourceConfiguration(resource);

return (
<RaDatagrid rowClick="edit" {...props}>
{resourceConfiguration.fields
.filter(definition => definition.views.includes('list'))
.map(definition => getFieldFromFieldDefinition(definition))}
.map(definition =>
getFieldFromFieldDefinition(definition, resources)
)}
</RaDatagrid>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from 'react';
import {
AutocompleteInput,
RadioButtonGroupInput,
SelectInput,
} from 'ra-ui-materialui';
import { ReferenceFieldConfiguration } from '../ResourceConfiguration';

export const ReferenceInputChildFromDefinition = ({
definition,
...props
}: ReferenceInputChildFromDefinitionProps) => {
if (definition.options.selectionType === 'select') {
return (
<SelectInput
optionText={definition.options.referenceField}
{...props}
/>
);
}

if (definition.options.selectionType === 'autocomplete') {
return (
<AutocompleteInput
optionText={definition.options.referenceField}
{...props}
/>
);
}

if (definition.options.selectionType === 'radio') {
return (
<RadioButtonGroupInput
optionText={definition.options.referenceField}
{...props}
/>
);
}
};

interface ReferenceInputChildFromDefinitionProps {
definition: ReferenceFieldConfiguration;
}
10 changes: 8 additions & 2 deletions packages/ra-no-code/src/builders/Show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
SimpleShowLayout,
SimpleShowLayoutProps,
} from 'ra-ui-materialui';
import { useResourceConfiguration } from '../ResourceConfiguration';
import {
useResourceConfiguration,
useResourcesConfiguration,
} from '../ResourceConfiguration';
import { getFieldFromFieldDefinition } from './getFieldFromFieldDefinition';

export const Show = (props: ShowProps) => (
Expand All @@ -17,13 +20,16 @@ export const Show = (props: ShowProps) => (

export const ShowForm = (props: Omit<SimpleShowLayoutProps, 'children'>) => {
const resource = useResourceContext(props);
const [resources] = useResourcesConfiguration();
const [resourceConfiguration] = useResourceConfiguration(resource);

return (
<SimpleShowLayout {...props}>
{resourceConfiguration.fields
.filter(definition => definition.views.includes('show'))
.map(definition => getFieldFromFieldDefinition(definition))}
.map(definition =>
getFieldFromFieldDefinition(definition, resources)
)}
</SimpleShowLayout>
);
};
Loading

0 comments on commit dea823f

Please sign in to comment.