diff --git a/packages/create-react-admin/src/ProjectState.ts b/packages/create-react-admin/src/ProjectState.ts index 9b12a13a8ae..a1c2d1838ad 100644 --- a/packages/create-react-admin/src/ProjectState.ts +++ b/packages/create-react-admin/src/ProjectState.ts @@ -11,7 +11,7 @@ export type ProjectConfiguration = { | 'finish'; dataProvider: string; authProvider: string; - resources: string[]; + resources?: string[]; messages: string[]; installer: string; }; @@ -21,7 +21,6 @@ export const InitialProjectConfiguration: ProjectConfiguration = { step: 'name', dataProvider: '', authProvider: '', - resources: [], messages: [], installer: '', }; diff --git a/packages/create-react-admin/src/StepAuthProvider.tsx b/packages/create-react-admin/src/StepAuthProvider.tsx index 9141bbe071d..d06e7113144 100644 --- a/packages/create-react-admin/src/StepAuthProvider.tsx +++ b/packages/create-react-admin/src/StepAuthProvider.tsx @@ -4,7 +4,7 @@ import SelectInput from 'ink-select-input'; import { ChoiceType, SelectInputChoice } from './SelectInputChoice'; import { Stack } from './Stack'; -const SupportedAuthProviders: ChoiceType[] = [ +export const SupportedAuthProviders: ChoiceType[] = [ { label: 'Hard coded local username/password', value: 'local-auth-provider', diff --git a/packages/create-react-admin/src/StepDataProvider.tsx b/packages/create-react-admin/src/StepDataProvider.tsx index 0695abff9f8..82124ba4eee 100644 --- a/packages/create-react-admin/src/StepDataProvider.tsx +++ b/packages/create-react-admin/src/StepDataProvider.tsx @@ -4,7 +4,7 @@ import SelectInput from 'ink-select-input'; import { ChoiceType, SelectInputChoice } from './SelectInputChoice'; import { Stack } from './Stack'; -const SupportedDataProviders: ChoiceType[] = [ +export const SupportedDataProviders: ChoiceType[] = [ { label: 'Fakerest', value: 'ra-data-fakerest', diff --git a/packages/create-react-admin/src/StepInstall.tsx b/packages/create-react-admin/src/StepInstall.tsx index 706f71de343..50fa0b40ff8 100644 --- a/packages/create-react-admin/src/StepInstall.tsx +++ b/packages/create-react-admin/src/StepInstall.tsx @@ -15,7 +15,7 @@ const choices: ChoiceType[] = [ }, { label: "Don't install dependencies, I'll do it myself.", - value: '', + value: 'skip', }, ]; diff --git a/packages/create-react-admin/src/app.tsx b/packages/create-react-admin/src/app.tsx index ce422c59e29..69e66e70a13 100644 --- a/packages/create-react-admin/src/app.tsx +++ b/packages/create-react-admin/src/app.tsx @@ -13,7 +13,30 @@ import { StepGenerate } from './StepGenerate'; import { StepRunInstall } from './StepRunInstall'; type Props = { - name: string | undefined; + name?: string; + authProvider?: string; + dataProvider?: string; + resources?: string[]; + install?: string; +}; + +const getNextStep = (state: ProjectConfiguration) => { + if (state.name) { + if (state.dataProvider) { + if (state.authProvider) { + if (state.resources) { + if (state.installer) { + return 'generate'; + } + return 'install'; + } + return 'resources'; + } + return 'auth-provider'; + } + return 'data-provider'; + } + return 'name'; }; const stepReducer = ( @@ -21,48 +44,67 @@ const stepReducer = ( action ): ProjectConfiguration => { switch (state.step) { - case 'name': - return { + case 'name': { + const newState = { ...state, name: action.value, - step: 'data-provider', }; - case 'data-provider': return { + ...newState, + step: getNextStep(newState), + }; + } + case 'data-provider': { + const newState = { ...state, - step: 'auth-provider', dataProvider: action.value, resources: action.value === 'ra-data-fakerest' ? ['posts', 'comments'] : state.resources, }; - case 'auth-provider': return { + ...newState, + step: getNextStep(newState), + }; + } + case 'auth-provider': { + const newState = { ...state, - step: - state.dataProvider === 'ra-data-fakerest' - ? 'install' - : 'resources', authProvider: action.value, }; - case 'resources': return { + ...newState, + step: getNextStep(newState), + }; + } + case 'resources': { + const newState = { ...state, - step: 'install', resources: action.value, }; - case 'install': return { + ...newState, + step: getNextStep(newState), + }; + } + case 'install': + const newState = { ...state, installer: action.value, - step: 'generate', + }; + return { + ...newState, + step: getNextStep(newState), }; case 'generate': return { ...state, messages: action.value.messages, - step: state.installer ? 'run-install' : 'finish', + step: + state.installer && state.installer !== 'skip' + ? 'run-install' + : 'finish', }; case 'run-install': return { @@ -74,12 +116,22 @@ const stepReducer = ( } }; -export default function App({ name = 'my-admin' }: Props) { - const sanitizedName = sanitizeName(name); - const [state, dispatch] = useReducer(stepReducer, { +export default function App(props: Props) { + const sanitizedName = sanitizeName(props.name); + const initialState = { ...InitialProjectConfiguration, + dataProvider: props.dataProvider, + authProvider: props.authProvider, + resources: props.resources?.includes('skip') ? [] : props.resources, + installer: props.install, name: sanitizedName, - step: sanitizedName === name ? 'data-provider' : 'name', + }; + + const initialStep = getNextStep(initialState); + + const [state, dispatch] = useReducer(stepReducer, { + ...initialState, + step: initialStep, }); const handleSubmit = (value: any) => { @@ -145,11 +197,13 @@ export default function App({ name = 'my-admin' }: Props) { ); } -const sanitizeName = (name: string) => { +const sanitizeName = (name?: string) => { return name - .trim() - .toLowerCase() - .replace(/\s+/g, '-') - .replace(/^[._]/, '') - .replace(/[^a-z\d\-~]+/g, '-'); + ? name + .trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/^[._]/, '') + .replace(/[^a-z\d\-~]+/g, '-') + : undefined; }; diff --git a/packages/create-react-admin/src/cli.tsx b/packages/create-react-admin/src/cli.tsx index 20b9d395454..9910fa5a800 100644 --- a/packages/create-react-admin/src/cli.tsx +++ b/packages/create-react-admin/src/cli.tsx @@ -3,19 +3,66 @@ import React from 'react'; import { render } from 'ink'; import meow from 'meow'; import App from './app.js'; +import { SupportedDataProviders } from './StepDataProvider.js'; +import { SupportedAuthProviders } from './StepAuthProvider.js'; const cli = meow( ` Usage $ create-admin-app + Options + --data-provider Set the data provider to use ("ra-data-fakerest", "ra-data-simple-rest", "ra-data-json-server" or "none") + --auth-provider Set the auth provider to use ("local-auth-provider" or "none") + --resource Add a resource that will be initialized with guessers (can be used multiple times). Set to "skip" to bypass the interactive resource step. + --install Set the package manager to use for installing dependencies ("yarn", "npm" or "skip" to bypass the interactive install step) + Examples $ create-admin-app my-admin -` + $ create-admin-app my-admin --data-provider ra-data-json-server --auth-provider local-auth-provider --resource posts --resource comments --install npm +`, + { + flags: { + help: { + type: 'boolean', + alias: 'h', + }, + dataProvider: { + type: 'string', + choices: SupportedDataProviders.map(choice => choice.value), + }, + authProvider: { + type: 'string', + choices: SupportedAuthProviders.map(choice => choice.value), + }, + resource: { + type: 'string', + isMultiple: true, + }, + install: { + type: 'string', + choices: ['yarn', 'npm', 'skip'], + }, + }, + } ); if (cli.flags.h) { cli.showHelp(); } else { - render( 0 ? cli.input[0] : 'my-admin'} />); + render( + 0 ? cli.input[0] : undefined} + dataProvider={cli.flags.dataProvider} + authProvider={cli.flags.authProvider} + resources={ + cli.flags.resource.includes('skip') + ? [] + : cli.flags.resource.length > 0 + ? cli.flags.resource + : undefined + } + install={cli.flags.install} + /> + ); }