Skip to content

Commit 572c9f8

Browse files
refactor: avoid some unintended refresh, move functions to utils file
1 parent bda7630 commit 572c9f8

5 files changed

Lines changed: 175 additions & 117 deletions

File tree

source/app.tsx

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Box, Text } from 'ink'
2-
import React, { useState, type ReactNode } from 'react'
2+
import React, { useState, type ReactNode, useMemo, useCallback } from 'react'
33
import MainTitle from './import/components/MainTitle.js'
44
import CloneRepo from './import/components/steps/CloneRepo/CloneRepo.js'
5+
import FileCleanup from './import/components/steps/FileCleanup.js'
56
import Install from './import/components/steps/Install/Install.js'
67
import InstallationMode from './import/components/steps/InstallationMode.js'
78
import OptionalPackages from './import/components/steps/OptionalPackages.js'
@@ -13,44 +14,68 @@ const App = () => {
1314
const [projectName, setProjectName] = useState<string>('')
1415
const [currentStep, setCurrentStep] = useState(1)
1516
const [setupType, setSetupType] = useState<InstallationSelectItem | undefined>()
16-
const [customOptions, setCustomOptions] = useState<Array<MultiSelectItem> | undefined>()
17+
const [selectedFeatures, setSelectedFeatures] = useState<Array<MultiSelectItem> | undefined>()
1718

18-
const finishStep = () => setCurrentStep(currentStep + 1)
19-
const onSelectSetupType = (item: InstallationSelectItem) => setSetupType(item)
20-
const onSelectCustomOptions = (selectedItems: Array<MultiSelectItem>) =>
21-
setCustomOptions([...selectedItems])
19+
const finishStep = useCallback(() => setCurrentStep(currentStep + 1), [currentStep])
20+
const onSelectSetupType = useCallback((item: InstallationSelectItem) => setSetupType(item), [])
21+
const onSelectSelectedFeatures = useCallback(
22+
(selectedItems: Array<MultiSelectItem>) => setSelectedFeatures([...selectedItems]),
23+
[],
24+
)
2225

23-
const steps: Array<ReactNode> = [
24-
<ProjectName
25-
onCompletion={finishStep}
26-
onSubmit={setProjectName}
27-
projectName={projectName}
28-
key={1}
29-
/>,
30-
<CloneRepo
31-
onCompletion={finishStep}
32-
projectName={projectName}
33-
key={2}
34-
/>,
35-
<InstallationMode
36-
onCompletion={finishStep}
37-
onSelect={onSelectSetupType}
38-
key={3}
39-
/>,
40-
<OptionalPackages
41-
installation={setupType?.value}
42-
onCompletion={finishStep}
43-
onSubmit={onSelectCustomOptions}
44-
key={4}
45-
/>,
46-
<Install
47-
installation={{ installationType: setupType?.value, customOptions: customOptions }}
48-
onCompletion={finishStep}
49-
projectName={projectName}
50-
key={5}
51-
/>,
52-
<Text key={6}>Done!</Text>,
53-
]
26+
const steps: Array<ReactNode> = useMemo(
27+
() => [
28+
<ProjectName
29+
onCompletion={finishStep}
30+
onSubmit={setProjectName}
31+
projectName={projectName}
32+
key={1}
33+
/>,
34+
<CloneRepo
35+
onCompletion={finishStep}
36+
projectName={projectName}
37+
key={2}
38+
/>,
39+
<InstallationMode
40+
onCompletion={finishStep}
41+
onSelect={onSelectSetupType}
42+
key={3}
43+
/>,
44+
<OptionalPackages
45+
installation={setupType?.value}
46+
onCompletion={finishStep}
47+
onSubmit={onSelectSelectedFeatures}
48+
key={4}
49+
/>,
50+
<Install
51+
installationConfig={{
52+
installationType: setupType?.value,
53+
selectedFeatures: selectedFeatures,
54+
}}
55+
onCompletion={finishStep}
56+
projectName={projectName}
57+
key={5}
58+
/>,
59+
<FileCleanup
60+
installationConfig={{
61+
installationType: setupType?.value,
62+
selectedFeatures: selectedFeatures,
63+
}}
64+
onCompletion={finishStep}
65+
projectName={projectName}
66+
key={6}
67+
/>,
68+
<Text key={7}>Done!</Text>,
69+
],
70+
[
71+
finishStep,
72+
onSelectSelectedFeatures,
73+
setupType?.value,
74+
selectedFeatures,
75+
onSelectSetupType,
76+
projectName,
77+
],
78+
)
5479

5580
return (
5681
<Box
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Box, Text } from 'ink'
2+
import { Script, Spawn } from 'ink-spawn'
3+
import React, { type FC, useMemo } from 'react'
4+
import { homeFolder } from '../../constants/config.js'
5+
import type { InstallationType, MultiSelectItem } from '../../types/types.js'
6+
import { featureSelected, getProjectFolder } from '../../utils/utils.js'
7+
8+
interface Props {
9+
onCompletion: () => void
10+
projectName: string
11+
installationConfig: {
12+
installationType: InstallationType | undefined
13+
selectedFeatures?: Array<MultiSelectItem>
14+
}
15+
}
16+
17+
/**
18+
* Performs file cleanup after the installation process
19+
* @param onCompletion
20+
* @param installation
21+
* @param projectName
22+
*/
23+
const FileCleanup: FC<Props> = ({ onCompletion, installationConfig, projectName }) => {
24+
const { installationType, selectedFeatures } = installationConfig
25+
const projectFolder = useMemo(() => getProjectFolder(projectName), [projectName])
26+
const currentHomeFolder = `${projectFolder}${homeFolder}`
27+
const cleanHomeFile = `${projectFolder}/.install-files/home/index.tsx`
28+
29+
return (
30+
<Box
31+
flexDirection={'column'}
32+
gap={0}
33+
>
34+
{!featureSelected('demo', selectedFeatures) && (
35+
<Script>
36+
<Text color={'whiteBright'}>Removing component demos</Text>
37+
<Spawn
38+
shell
39+
cwd={projectFolder}
40+
// silent
41+
command="rm"
42+
args={['-rf', currentHomeFolder]}
43+
// runningText={'Working...'}
44+
// successText={'Done!'}
45+
// failureText={'Error...'}
46+
/>
47+
<Text color={'whiteBright'}>Creating new home folder</Text>
48+
<Spawn
49+
shell
50+
cwd={projectFolder}
51+
// silent
52+
command="mkdir"
53+
args={['-p', currentHomeFolder]}
54+
// runningText={'Working...'}
55+
// successText={'Done!'}
56+
// failureText={'Error...'}
57+
/>
58+
<Text color={'whiteBright'}>Creating new home page</Text>
59+
<Spawn
60+
shell
61+
cwd={projectFolder}
62+
// silent
63+
command="cp"
64+
args={[cleanHomeFile, currentHomeFolder]}
65+
// runningText={'Working...'}
66+
// successText={'Done!'}
67+
// failureText={'Error...'}
68+
/>
69+
</Script>
70+
)}
71+
</Box>
72+
)
73+
}
74+
75+
export default FileCleanup

source/import/components/steps/Install/CustomInstallation.tsx

Lines changed: 9 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,31 @@
11
import { Box, Text } from 'ink'
22
import { Script, Spawn } from 'ink-spawn'
33
import React, { type FC } from 'react'
4-
import { featurePackages, homeFolder } from '../../../constants/config.js'
54
import type { MultiSelectItem } from '../../../types/types.js'
5+
import { getPackages } from '../../../utils/utils.js'
66
import InstallAllPackages from './InstallAllPackages.js'
77

88
interface Props {
9-
customOptions?: Array<MultiSelectItem>
109
onCompletion: () => void
1110
projectFolder: string
11+
selectedFeatures?: Array<MultiSelectItem>
1212
}
1313

1414
/**
1515
* Performs a custom installation based on the selected features: basically we tell `pnpm` what
1616
* features to remove (everything's included in package.json by default to simplify things)
1717
* @param onCompletion
18-
* @param customOptions
18+
* @param selectedFeatures
1919
* @param projectFolder
2020
*/
21-
const CustomInstallation: FC<Props> = ({ onCompletion, customOptions, projectFolder }) => {
22-
const currentHomeFolder = `${projectFolder}${homeFolder}`
23-
const cleanHomeFile = `${projectFolder}/.install-files/home/index.tsx`
24-
25-
/**
26-
* Selected features won't be removed, unselected features will be.
27-
* @param feature
28-
* @param featuresList
29-
*/
30-
const featureSelected = (feature: string, featuresList: Array<MultiSelectItem> | undefined) => {
31-
return !!featuresList?.find((item: MultiSelectItem) => item.value === feature)
32-
}
33-
34-
/**
35-
* Returns the packages to remove checking first if the feature is selected or not.
36-
* Selected features are kept, unselected features are removed.
37-
* @param feature
38-
*/
39-
const getPackages = (feature: string) => {
40-
const packages = featurePackages[feature]
41-
42-
return featureSelected(feature, customOptions) ? [] : packages?.length ? packages : []
43-
}
44-
21+
const CustomInstallation: FC<Props> = ({ onCompletion, selectedFeatures, projectFolder }) => {
4522
// Collects the packages to remove based on the selected features and makes
4623
// a string out of them so that we can pass it to `pnpm remove` command.
4724
const packagesToRemove = [
48-
...getPackages('subgraph'),
49-
...getPackages('typedoc'),
50-
...getPackages('vocs'),
51-
...getPackages('husky'),
25+
...getPackages('subgraph', selectedFeatures),
26+
...getPackages('typedoc', selectedFeatures),
27+
...getPackages('vocs', selectedFeatures),
28+
...getPackages('husky', selectedFeatures),
5229
]
5330
.join(' ')
5431
.trim()
@@ -68,7 +45,7 @@ const CustomInstallation: FC<Props> = ({ onCompletion, customOptions, projectFol
6845
</Script>
6946
) : (
7047
<Script>
71-
{/* `pnpm remove` will install the necessary packages while uninstalling the unwanted ones... */}
48+
{/* `pnpm remove` will install the necessary packages and then uninstall the unwanted ones... */}
7249
<Text color={'whiteBright'}>Installing packages</Text>
7350
<Spawn
7451
shell
@@ -93,43 +70,6 @@ const CustomInstallation: FC<Props> = ({ onCompletion, customOptions, projectFol
9370
failureText={'Error...'}
9471
onCompletion={onCompletion}
9572
/>
96-
{!featureSelected('demo', customOptions) && (
97-
<Script>
98-
<Text color={'whiteBright'}>Removing component demos</Text>
99-
<Spawn
100-
shell
101-
cwd={projectFolder}
102-
// silent
103-
command="rm"
104-
args={['-rf', currentHomeFolder]}
105-
// runningText={'Working...'}
106-
// successText={'Done!'}
107-
// failureText={'Error...'}
108-
/>
109-
<Text color={'whiteBright'}>Creating new home folder</Text>
110-
<Spawn
111-
shell
112-
cwd={projectFolder}
113-
// silent
114-
command="mkdir"
115-
args={['-p', currentHomeFolder]}
116-
// runningText={'Working...'}
117-
// successText={'Done!'}
118-
// failureText={'Error...'}
119-
/>
120-
<Text color={'whiteBright'}>Creating new home page</Text>
121-
<Spawn
122-
shell
123-
cwd={projectFolder}
124-
// silent
125-
command="cp"
126-
args={[cleanHomeFile, currentHomeFolder]}
127-
// runningText={'Working...'}
128-
// successText={'Done!'}
129-
// failureText={'Error...'}
130-
/>
131-
</Script>
132-
)}
13373
</Script>
13474
)}
13575
</Box>

source/import/components/steps/Install/Install.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
import { join } from 'node:path'
2-
import process from 'node:process'
31
import { Box, Text } from 'ink'
42
import { Script, Spawn } from 'ink-spawn'
53
import React, { type FC, useMemo } from 'react'
64
import type { InstallationType, MultiSelectItem } from '../../../types/types.js'
5+
import { getProjectFolder } from '../../../utils/utils.js'
76
import Divider from '../../Divider.js'
87
import CustomInstallation from './CustomInstallation.js'
98
import FullInstallation from './FullInstallation.js'
109

1110
interface Props {
12-
installation: {
11+
installationConfig: {
1312
installationType: InstallationType | undefined
14-
customOptions?: Array<MultiSelectItem>
13+
selectedFeatures?: Array<MultiSelectItem>
1514
}
1615
projectName: string
1716
onCompletion: () => void
1817
}
1918

20-
const Install: FC<Props> = ({ projectName, onCompletion, installation }) => {
21-
const projectFolder = useMemo(() => join(process.cwd(), projectName), [projectName])
22-
const { installationType, customOptions } = installation
19+
const Install: FC<Props> = ({ projectName, onCompletion, installationConfig }) => {
20+
const { installationType, selectedFeatures } = installationConfig
21+
const projectFolder = useMemo(() => getProjectFolder(projectName), [projectName])
2322

2423
return (
2524
<>
26-
<Divider title={`Executing ${installation.installationType ?? 'full'} installation`} />
25+
<Divider title={`Executing ${installationType ?? 'full'} installation`} />
2726
<Box
2827
flexDirection={'column'}
2928
gap={0}
@@ -59,7 +58,7 @@ const Install: FC<Props> = ({ projectName, onCompletion, installation }) => {
5958
)}
6059
{installationType === 'custom' && (
6160
<CustomInstallation
62-
customOptions={customOptions}
61+
selectedFeatures={selectedFeatures}
6362
onCompletion={onCompletion}
6463
projectFolder={projectFolder}
6564
/>

source/import/utils/utils.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
import { join } from 'node:path'
2+
import process from 'node:process'
3+
import { featurePackages } from '../constants/config.js'
14
import type { MultiSelectItem } from '../types/types.js'
25

6+
export function getProjectFolder(projectName: string) {
7+
return join(process.cwd(), projectName)
8+
}
9+
310
/**
411
* Utility functions for import process
512
* @param name
@@ -29,10 +36,22 @@ export function canShowStep(currentStep: number, stepToShow: number) {
2936
}
3037

3138
/**
32-
* Selected features won't be removed, unselected features will be.
39+
* Returns true a feature is selected in the features list
3340
* @param feature
3441
* @param featuresList
3542
*/
36-
const featureSelected = (feature: string, featuresList: Array<MultiSelectItem> | undefined) => {
43+
export function featureSelected(feature: string, featuresList: Array<MultiSelectItem> | undefined) {
3744
return !!featuresList?.find((item: MultiSelectItem) => item.value === feature)
3845
}
46+
47+
/**
48+
* Returns the packages to remove checking first if the feature is selected or not.
49+
* Selected features are kept, unselected features are removed.
50+
* @param feature
51+
* @param featuresList
52+
*/
53+
export function getPackages(feature: string, featuresList: Array<MultiSelectItem> | undefined) {
54+
const packages = featurePackages[feature]
55+
56+
return featureSelected(feature, featuresList) ? [] : packages?.length ? packages : []
57+
}

0 commit comments

Comments
 (0)