Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stepper for create #79

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"@dslab/ra-jsonschema-input": "^2.1.1",
"@dslab/ra-language-italian": "^1.0.0",
"@dslab/ra-root-selector": "^1.0.1",
"@dslab/ra-stepper": "^1.1.1",
"@dslab/ra-stepper": "^1.1.4",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@melloware/react-logviewer": "^5.0.6",
Expand Down Expand Up @@ -80,7 +80,7 @@
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"@vitejs/plugin-react": "^4.2.1",
"conventional-changelog-cli": "^5.0.0",
"conventional-changelog-cli": "^5.0.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-react": "^7.32.2",
Expand Down
21 changes: 12 additions & 9 deletions src/components/SpecInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Card, CardContent } from '@mui/material';
import deepEqual from 'deep-is';
import { useEffect, useState } from 'react';
import {
InputProps,
useRecordContext,
useResourceContext,
useTranslate,
Expand All @@ -10,46 +11,48 @@ import { useWatch } from 'react-hook-form';
import { useSchemaProvider } from '../provider/schemaProvider';
import { JsonSchemaInput } from './JsonSchema';

export const SpecInput = (props: {
export const SpecInput = (props: InputProps & {
source: string;
onDirty?: (state: boolean) => void;
getUiSchema: (kind: string) => any;
schema?: any;
kind?: string;
kindSource?: string;
}) => {
const {
source,
onDirty,
getUiSchema,
schema: schemaProp,
kind: kindProp,
kindSource = 'kind',
} = props;
const translate = useTranslate();
const resource = useResourceContext();
const record = useRecordContext();
const value = useWatch({ name: source });
const eq = deepEqual(record[source], value);
const kindValue = useWatch({ name: kindSource });

const schemaProvider = useSchemaProvider();
const [schema, setSchema] = useState<any>();
const kind = kindProp || record?.kind || null;
const kind = kindProp || kindValue || (record ? record[kindSource] : null);

useEffect(() => {
if (!kind) {
return;
}
if (schemaProp) {
setSchema(schemaProp);
} else if (schemaProvider && record) {
} else if (schemaProvider) {
schemaProvider.get(resource, kind).then(s => setSchema(s.schema));
}
}, [record, schemaProvider, schemaProp]);
}, [kind, schemaProvider, schemaProp]);

useEffect(() => {
if (onDirty) {
onDirty(!eq);
if (onDirty && record) {
onDirty(!deepEqual(record[source], value));
}
}, [eq]);
}, [record, value]);

if (!kind || !schema) {
return (
Expand All @@ -70,7 +73,7 @@ export const SpecInput = (props: {
<JsonSchemaInput
source={source}
schema={{ ...schema, title: 'Spec' }}
uiSchema={getUiSchema(record.kind)}
uiSchema={getUiSchema(kind)}
/>
);
};
13 changes: 0 additions & 13 deletions src/components/StepForm.tsx

This file was deleted.

22 changes: 22 additions & 0 deletions src/components/StepperToolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useStepper, StepperForm } from "@dslab/ra-stepper";
import { Box } from "@mui/material";
import { Toolbar, SaveButton } from "react-admin";

export const StepperToolbar = () => {
const { steps, currentStep } = useStepper();

return (
<Toolbar sx={{ justifyContent: 'space-between' }}>
<Box>
<StepperForm.PreviousButton
variant={'text'}
color="secondary"
/>
</Box>
<Box>
<StepperForm.NextButton />
{steps && currentStep === steps.length - 1 && <SaveButton />}
</Box>
</Toolbar>
);
};
78 changes: 55 additions & 23 deletions src/resources/artifacts/create.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import { useRootSelector } from '@dslab/ra-root-selector';
import { Box, Container, Stack } from '@mui/material';
import { Box, Container } from '@mui/material';
import { useEffect, useRef } from 'react';
import {
CreateBase,
CreateView,
FormDataConsumer,
ListButton,
SimpleForm,
TextInput,
TopToolbar,
required,
regex,
useInput,
useResourceContext,
useGetResourceLabel,
useTranslate,
} from 'react-admin';
import {
ALPHANUMERIC_REGEX,
isAlphaNumeric,
randomId,
} from '../../common/helper';
import { isAlphaNumeric, randomId } from '../../common/helper';
import { FlatCard } from '../../components/FlatCard';
import { FormLabel } from '../../components/FormLabel';
import { CreatePageTitle } from '../../components/PageTitle';
import { ArtifactIcon } from './icon';
import { getArtifactSpecUiSchema } from './types';
Expand All @@ -33,6 +28,10 @@ import {
import { KindSelector } from '../../components/KindSelector';
import { useGetSchemas } from '../../controllers/schemaController';
import { SpecInput } from '../../components/SpecInput';
import { StepperForm } from '@dslab/ra-stepper';
import { StepperToolbar } from '../../components/StepperToolbar';
import { toYaml } from '@dslab/ra-export-record-button';
import { AceEditorField } from '@dslab/ra-ace-editor';

const CreateToolbar = () => {
return (
Expand All @@ -44,6 +43,8 @@ const CreateToolbar = () => {

export const ArtifactCreate = () => {
const { root } = useRootSelector();
const getResourceLabel = useGetResourceLabel();
const translate = useTranslate();
const id = useRef(randomId());
const uploader = useUploadController({
id: id.current,
Expand All @@ -70,7 +71,7 @@ export const ArtifactCreate = () => {
<CreateBase
transform={transform}
redirect="list"
record={{ id: id.current }}
record={{ id: id.current, spec: {path: null} }}
>
<>
<CreatePageTitle
Expand All @@ -79,9 +80,48 @@ export const ArtifactCreate = () => {

<CreateView component={Box} actions={<CreateToolbar />}>
<FlatCard sx={{ paddingBottom: '12px' }}>
<SimpleForm>
<ArtifactCreateForm uploader={uploader} />
</SimpleForm>
<StepperForm toolbar={<StepperToolbar />}>
<StepperForm.Step
label={getResourceLabel('base', 1)}
>
<TextInput
source="name"
validate={[
required(),
isAlphaNumeric(),
]}
/>
<MetadataInput />
</StepperForm.Step>
<StepperForm.Step
label={getResourceLabel('spec', 1)}
>
<SpecCreateStep uploader={uploader} />
</StepperForm.Step>
<StepperForm.Step
label={translate('Recap')}
optional
>
<FormDataConsumer>
{({ formData }) => {
//read-only view
const r = {
spec: btoa(
toYaml(formData?.spec)
),
};
return (
<AceEditorField
mode="yaml"
source="spec"
record={r}
parse={atob}
/>
);
}}
</FormDataConsumer>
</StepperForm.Step>
</StepperForm>
</FlatCard>
</CreateView>
</>
Expand All @@ -90,7 +130,7 @@ export const ArtifactCreate = () => {
);
};

const ArtifactCreateForm = (props: { uploader?: UploadController }) => {
const SpecCreateStep = (props: { uploader?: UploadController }) => {
const { uploader } = props;
const resource = useResourceContext();

Expand Down Expand Up @@ -142,15 +182,7 @@ const ArtifactCreateForm = (props: { uploader?: UploadController }) => {

return (
<>
<FormLabel label="fields.base" />
<Stack direction={'row'} spacing={3} pt={4}>
<TextInput
source="name"
validate={[required(), isAlphaNumeric()]}
/>
<KindSelector kinds={kinds} />
</Stack>
<MetadataInput />
<KindSelector kinds={kinds} />
<FormDataConsumer<{ kind: string }>>
{({ formData }) => (
<>
Expand Down
71 changes: 54 additions & 17 deletions src/resources/dataitems/create.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { useRootSelector } from '@dslab/ra-root-selector';
import { Box, Container, Stack } from '@mui/material';
import { Box, Container } from '@mui/material';
import {
CreateBase,
CreateView,
FormDataConsumer,
ListButton,
SimpleForm,
TextInput,
TopToolbar,
required,
useGetResourceLabel,
useInput,
useResourceContext,
useTranslate,
} from 'react-admin';
import { isAlphaNumeric, randomId } from '../../common/helper';
import { FlatCard } from '../../components/FlatCard';
import { FormLabel } from '../../components/FormLabel';
import { CreatePageTitle } from '../../components/PageTitle';
import { DataItemIcon } from './icon';
import { getDataItemSpecUiSchema } from './types';
Expand All @@ -28,6 +28,10 @@ import {
import { FileInput } from '../../components/FileInput';
import { KindSelector } from '../../components/KindSelector';
import { SpecInput } from '../../components/SpecInput';
import { StepperForm } from '@dslab/ra-stepper';
import { StepperToolbar } from '../../components/StepperToolbar';
import { toYaml } from '@dslab/ra-export-record-button';
import { AceEditorField } from '@dslab/ra-ace-editor';

const CreateToolbar = () => {
return (
Expand All @@ -39,6 +43,8 @@ const CreateToolbar = () => {

export const DataItemCreate = () => {
const { root } = useRootSelector();
const getResourceLabel = useGetResourceLabel();
const translate = useTranslate();
const id = useRef(randomId());
const uploader = useUploadController({
id: id.current,
Expand All @@ -65,7 +71,7 @@ export const DataItemCreate = () => {
<CreateBase
transform={transform}
redirect="list"
record={{ id: id.current }}
record={{ id: id.current, spec: { path: null } }}
>
<>
<CreatePageTitle
Expand All @@ -74,9 +80,48 @@ export const DataItemCreate = () => {

<CreateView component={Box} actions={<CreateToolbar />}>
<FlatCard sx={{ paddingBottom: '12px' }}>
<SimpleForm>
<DataItemCreateForm uploader={uploader} />
</SimpleForm>
<StepperForm toolbar={<StepperToolbar />}>
<StepperForm.Step
label={getResourceLabel('base', 1)}
>
<TextInput
source="name"
validate={[
required(),
isAlphaNumeric(),
]}
/>
<MetadataInput />
</StepperForm.Step>
<StepperForm.Step
label={getResourceLabel('spec', 1)}
>
<SpecCreateStep uploader={uploader} />
</StepperForm.Step>
<StepperForm.Step
label={translate('Recap')}
optional
>
<FormDataConsumer>
{({ formData }) => {
//read-only view
const r = {
spec: btoa(
toYaml(formData?.spec)
),
};
return (
<AceEditorField
mode="yaml"
source="spec"
record={r}
parse={atob}
/>
);
}}
</FormDataConsumer>
</StepperForm.Step>
</StepperForm>
</FlatCard>
</CreateView>
</>
Expand All @@ -85,7 +130,7 @@ export const DataItemCreate = () => {
);
};

const DataItemCreateForm = (props: { uploader?: UploadController }) => {
const SpecCreateStep = (props: { uploader?: UploadController }) => {
const { uploader } = props;
const resource = useResourceContext();

Expand Down Expand Up @@ -137,15 +182,7 @@ const DataItemCreateForm = (props: { uploader?: UploadController }) => {

return (
<>
<FormLabel label="fields.base" />
<Stack direction={'row'} spacing={3} pt={4}>
<TextInput
source="name"
validate={[required(), isAlphaNumeric()]}
/>
<KindSelector kinds={kinds} />
</Stack>
<MetadataInput />
<KindSelector kinds={kinds} />
<FormDataConsumer<{ kind: string }>>
{({ formData }) => (
<>
Expand Down
Loading