Skip to content

Commit

Permalink
Adds custom scaffolding options to the form (#184)
Browse files Browse the repository at this point in the history
## 🎯 Aim

Is to extend the scaffolding form with custom steps

## ✅ What was done

- [X] Extended form UI to show custom scaffolding steps
- [X] Supports installing custom steps after new project is created

## 🔗 Related issue

Closes: #124
  • Loading branch information
Adam-it committed Mar 2, 2024
1 parent 73630ec commit 1fb57ad
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 9 deletions.
5 changes: 4 additions & 1 deletion src/constants/ProjectFileContent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* eslint-disable no-unused-vars */
// eslint-disable-next-line no-shadow
export enum ProjectFileContent {
init = 'init',
init = 'init-project',
initScenario = 'init-scenario',
installReusablePropertyPaneControls = 'install-spfx-property-controls',
installReusableReactControls = 'install-spfx-controls-react',
installPnPJs = 'install-pnpjs',
}
4 changes: 4 additions & 0 deletions src/constants/SpfxScaffoldCommandInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ import { SpfxAddComponentCommandInput } from './SpfxAddComponentCommandInput';
export interface SpfxScaffoldCommandInput extends SpfxAddComponentCommandInput {
folderPath: string;
solutionName: string;
shouldRunInit: boolean;
shouldInstallReusablePropertyPaneControls: boolean;
shouldInstallReusableReactControls: boolean;
shouldInstallPnPJs: boolean;
}
21 changes: 17 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,35 @@ export async function activate(context: ExtensionContext) {
if (files.length > 0) {
const fileContents = readFileSync(files[0].fsPath, 'utf8');

if (fileContents && (fileContents === ProjectFileContent.init || fileContents === ProjectFileContent.initScenario)) {
if (fileContents) {
unlinkSync(files[0].fsPath);

const terminal = window.createTerminal({
name: 'Installing dependencies',
iconPath: new ThemeIcon('cloud-download')
});

if (terminal) {
if (fileContents.indexOf(ProjectFileContent.init) > -1 || fileContents.indexOf(ProjectFileContent.initScenario) > -1) {
terminal.sendText('npm i');
terminal.show(true);
}

if (fileContents === ProjectFileContent.initScenario) {
if (fileContents.indexOf(ProjectFileContent.initScenario) > -1) {
commands.executeCommand('codetour.startTour');
}

if (fileContents.indexOf(ProjectFileContent.installReusablePropertyPaneControls) > -1) {
terminal.sendText('npm install @pnp/spfx-property-controls --save --save-exact');
}

if (fileContents.indexOf(ProjectFileContent.installReusableReactControls) > -1) {
terminal.sendText('npm install @pnp/spfx-controls-react --save --save-exact');
}

if (fileContents.indexOf(ProjectFileContent.installPnPJs) > -1) {
terminal.sendText('npm install @pnp/sp @pnp/graph --save');
}

terminal.show(true);
}
}
});
Expand Down
20 changes: 18 additions & 2 deletions src/services/Scaffolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,21 @@ export class Scaffolder {
if (isNewProject) {
const newSolutionInput = input as SpfxScaffoldCommandInput;
const newFolderPath = join(newSolutionInput.folderPath, newSolutionInput.solutionName!);
Scaffolder.createProjectFileAndOpen(newFolderPath, 'init');

let content = newSolutionInput.shouldRunInit ? ProjectFileContent.init : '';
if (newSolutionInput.shouldInstallReusablePropertyPaneControls) {
content += ` ${ProjectFileContent.installReusablePropertyPaneControls}`;
}

if (newSolutionInput.shouldInstallReusableReactControls) {
content += ` ${ProjectFileContent.installReusableReactControls}`;
}

if (newSolutionInput.shouldInstallPnPJs) {
content += ` ${ProjectFileContent.installPnPJs}`;
}

Scaffolder.createProjectFileAndOpen(newFolderPath, content);
} else {
PnPWebview.close();
}
Expand Down Expand Up @@ -256,7 +270,9 @@ export class Scaffolder {
}

private static async createProjectFileAndOpen(folderPath: string, content: any) {
writeFileSync(join(folderPath, PROJECT_FILE), content, { encoding: 'utf8' });
if (content) {
writeFileSync(join(folderPath, PROJECT_FILE), content, { encoding: 'utf8' });
}

if (getPlatform() === 'windows') {
await commands.executeCommand('vscode.openFolder', Uri.file(parseWinPath(folderPath)));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { VSCodeButton, VSCodeDropdown, VSCodeOption, VSCodeProgressRing, VSCodeTextField } from '@vscode/webview-ui-toolkit/react';
import { VSCodeButton, VSCodeCheckbox, VSCodeDropdown, VSCodeOption, VSCodeProgressRing, VSCodeTextField } from '@vscode/webview-ui-toolkit/react';
import * as React from 'react';
import { useEffect, useState } from 'react';
import { AdaptiveCardTypesNode16, AdaptiveCardTypesNode18, ComponentType, ComponentTypes, ExtensionType, ExtensionTypes, FrameworkType, FrameworkTypes, SpfxAddComponentCommandInput, SpfxScaffoldCommandInput, WebviewCommand } from '../../../../../constants';
Expand All @@ -24,6 +24,10 @@ export const ScaffoldSpfxProjectView: React.FunctionComponent<IScaffoldSpfxProje
const [aceType, setAceType] = useState<string>(AdaptiveCardTypesNode18[0].value);
const [isFormValid, setIsFormValid] = useState<boolean>(false);
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const [shouldRunInit, setShouldRunInit] = useState<boolean>(true);
const [shouldInstallReusablePropertyPaneControls, setShouldInstallReusablePropertyPaneControls] = useState<boolean>(false);
const [shouldInstallReusableReactControls, setShouldInstallReusableReactControls] = useState<boolean>(false);
const [shouldInstallPnPJs, setShouldInstallPnPJs] = useState<boolean>(false);
const location: any = useLocation();
const componentTypeName = ComponentTypes.find((component) => component.value === componentType)?.name;

Expand Down Expand Up @@ -139,7 +143,11 @@ export const ScaffoldSpfxProjectView: React.FunctionComponent<IScaffoldSpfxProje
componentName,
frameworkType,
extensionType,
aceType
aceType,
shouldRunInit,
shouldInstallReusablePropertyPaneControls,
shouldInstallReusableReactControls,
shouldInstallPnPJs
} as SpfxScaffoldCommandInput);
}
};
Expand Down Expand Up @@ -276,6 +284,58 @@ export const ScaffoldSpfxProjectView: React.FunctionComponent<IScaffoldSpfxProje
}
</div>
</div>
{
isNewProject &&
<div className={'spfx__form__step'}>
<div className={'border-b pb-2 mb-6'}>
<label className={'text-xl border mt-4 rounded-full px-3 py-1 bg-vscode absolute'}>3</label>
<div className={'pl-10'}>
<p className={'text-lg'}>Additional steps</p>
</div>
</div>
<div className={'spfx__form__step__content ml-10'}>
<div className={'mb-2'}>
<label className={'block mb-1'}>
Run <code>npm install</code> after the project is created?
</label>
<VSCodeCheckbox checked={shouldRunInit} onChange={() => setShouldRunInit(!shouldRunInit)} />
</div>
<div className={'mb-3'}>
<VSCodeButton onClick={() => setShouldInstallReusablePropertyPaneControls(!shouldInstallReusablePropertyPaneControls)} appearance={shouldInstallReusablePropertyPaneControls ? '' : 'secondary'} className={'float-left'}>
Yes
</VSCodeButton>
<VSCodeButton onClick={() => setShouldInstallReusablePropertyPaneControls(!shouldInstallReusablePropertyPaneControls)} appearance={!shouldInstallReusablePropertyPaneControls ? '' : 'secondary'} className={'float-left'}>
No
</VSCodeButton>
<label className={'ml-2 pt-1 inline-block'}>
Install reusable property pane controls
</label>
</div>
<div className={'mb-3'}>
<VSCodeButton onClick={() => setShouldInstallReusableReactControls(!shouldInstallReusableReactControls)} appearance={shouldInstallReusableReactControls ? '' : 'secondary'} className={'float-left'}>
Yes
</VSCodeButton>
<VSCodeButton onClick={() => setShouldInstallReusableReactControls(!shouldInstallReusableReactControls)} appearance={!shouldInstallReusableReactControls ? '' : 'secondary'} className={'float-left'}>
No
</VSCodeButton>
<label className={'ml-2 pt-1 inline-block'}>
Install reusable React controls
</label>
</div>
<div className={'mb-3'}>
<VSCodeButton onClick={() => setShouldInstallPnPJs(!shouldInstallPnPJs)} appearance={shouldInstallPnPJs ? '' : 'secondary'} className={'float-left'}>
Yes
</VSCodeButton>
<VSCodeButton onClick={() => setShouldInstallPnPJs(!shouldInstallPnPJs)} appearance={!shouldInstallPnPJs ? '' : 'secondary'} className={'float-left'}>
No
</VSCodeButton>
<label className={'ml-2 pt-1 inline-block'}>
Install PnPjs (@pnp/sp, @pnp/graph)
</label>
</div>
</div>
</div>
}
</div>
<div className={'spfx__action mb-3 pb-3 border-b pl-10'}>
{!isFormValid ?
Expand Down

0 comments on commit 1fb57ad

Please sign in to comment.