Skip to content

Commit

Permalink
Add user custom init script feature
Browse files Browse the repository at this point in the history
  • Loading branch information
9Ninety committed Jun 16, 2020
1 parent b35066b commit 7e2cf89
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 11 deletions.
13 changes: 12 additions & 1 deletion images/remote-workspace/initialize/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ const v = require('villa');

/** @type {import('../../../bld/shared').WorkspaceMetadata} */
// @ts-ignore
const {projects} = require('/root/workspace/metadata.json');
const {projects, customInitScript} = require('/root/workspace/metadata.json');

main(async () => {
// prepare projects

console.info('Checking project hosts...');

// #region SSH initialize
let hostSet = new Set(
projects
.map(project => (project.git.url.match(/@(.+?):/) || [])[1])
Expand Down Expand Up @@ -59,7 +60,16 @@ main(async () => {
...process.env,
GIT_SSH_COMMAND: 'ssh -i /root/.ssh/initialize-identity',
};
// #endregion

if (customInitScript) {
let scriptPath = `/root/workspace/custom-init-script.sh`;
console.info('Running user custom init script...');
FSE.writeFileSync(scriptPath, customInitScript);
await spawn('bash', [scriptPath], {cwd: '/root/workspace/'});
}

// #region Per project initialize
for (let {
name,
git: {url, branch = 'master', newBranch = branch},
Expand Down Expand Up @@ -142,6 +152,7 @@ main(async () => {
}).catch(console.error);
}
}
// #endregion
});

/**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"ts-node": "^8.4.1",
"tslib": "^1.10.0",
"tslint": "^5.20.0",
"typescript": "^3.7.2",
"typescript": "^3.7.5",
"typescript-tslint-plugin": "^0.5.4"
}
}
2 changes: 2 additions & 0 deletions src/client/@components/workspace-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface WorkspaceFormProps {
workspace: WorkspaceMetadata | undefined;
defaultWorkspaceName?: string;
defaultParams?: Dict<string>;
customInitScript?: string;
onSubmitSuccess(data: CreateWorkspaceOptions): void;
}

Expand Down Expand Up @@ -236,6 +237,7 @@ export class WorkspaceForm extends Component<WorkspaceFormProps> {
owner: localStorage.email,
projects: this.selectedProjectTemplates.map(({params, ...rest}) => rest),
services: this.selectedServiceTemplates.map(({params, ...rest}) => rest),
customInitScript: this.props.customInitScript,
};

options = _.cloneDeepWith(options, value => {
Expand Down
1 change: 1 addition & 0 deletions src/client/@utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './localStorage';
14 changes: 14 additions & 0 deletions src/client/@utils/localStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Save customize init script, set to empty or null to delete
*/
export function saveCustomInitScript(content: string): void {
if (content === null || content === '') {
localStorage.removeItem('customInitScript');
} else {
localStorage.setItem('customInitScript', content);
}
}

export function loadCustomInitScript(): string {
return localStorage.getItem('customInitScript') || '';
}
74 changes: 69 additions & 5 deletions src/client/@views/home-view.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {Checkbox, PageHeader} from 'antd';
import {Button, Checkbox, Modal, PageHeader, message} from 'antd';
import {CheckboxChangeEvent} from 'antd/lib/checkbox';
import TextArea from 'antd/lib/input/TextArea';
import {RouteComponentProps} from 'boring-router-react';
import {observable} from 'mobx';
import {computed, observable} from 'mobx';
import {observer} from 'mobx-react';
import React, {Component, ReactNode, createRef} from 'react';
import React, {ChangeEvent, Component, ReactNode, createRef} from 'react';

import {RawTemplatesConfig, WorkspaceMetadata} from '../../../bld/shared';
import {VersionInfo, WorkspaceForm, WorkspaceList} from '../@components';
import {WorkspaceRoute} from '../@routes';
import {loadCustomInitScript, saveCustomInitScript} from '../@utils';

export interface HomeViewProps
extends RouteComponentProps<WorkspaceRoute['home']> {
Expand All @@ -30,6 +32,12 @@ export class HomeView extends Component<HomeViewProps> {
@observable
private formKey = 0;

@observable
private toShowCustomizeModal = false;

@observable
private customInitScriptContent = loadCustomInitScript();

render(): ReactNode {
let editingWorkspace = this.editingWorkspace;

Expand Down Expand Up @@ -60,8 +68,18 @@ export class HomeView extends Component<HomeViewProps> {
<PageHeader
title={editingWorkspace ? 'Edit Workspace' : 'Create Workspace'}
extra={
editingWorkspace && (
<a onClick={this.onCancelEditButtonClick}>cancel</a>
editingWorkspace ? (
<Button size="small" onClick={this.onCancelEditButtonClick}>
Cancel
</Button>
) : (
<Button
size="small"
icon="setting"
onClick={this.onShowCustomizeModal}
>
Customize
</Button>
)
}
/>
Expand All @@ -71,12 +89,36 @@ export class HomeView extends Component<HomeViewProps> {
templates={this.templates}
workspace={editingWorkspace}
onSubmitSuccess={this.onWorkspaceFormSubmitSuccess}
customInitScript={this.customInitScriptContent}
/>
</div>
{this.customizeModalRendering}
</div>
);
}

@computed
get customizeModalRendering(): ReactNode {
return (
<Modal
title="Customize create steps"
visible={this.toShowCustomizeModal}
onOk={this.onSaveCustomizeSettings}
onCancel={this.onCloseCustomizeSettings}
>
<p>
Your personal customize script will be saved in browser storage.
<br /> <strong>Supported syntx: bash</strong>
</p>
<TextArea
rows={20}
value={this.customInitScriptContent}
onChange={this.onCustomInitScriptInputChange}
></TextArea>
</Modal>
);
}

componentDidMount(): void {
this.loadTemplates().catch(console.error);
}
Expand All @@ -103,6 +145,28 @@ export class HomeView extends Component<HomeViewProps> {
this.toShowAllWorkspaces = target.checked;
};

private onShowCustomizeModal = (): void => {
this.customInitScriptContent = loadCustomInitScript();
this.toShowCustomizeModal = true;
};

private onSaveCustomizeSettings = (): void => {
this.toShowCustomizeModal = false;
saveCustomInitScript(this.customInitScriptContent);

message.success('Saved');
};

private onCloseCustomizeSettings = (): void => {
this.toShowCustomizeModal = false;
};

private onCustomInitScriptInputChange = (
e: ChangeEvent<HTMLTextAreaElement>,
): void => {
this.customInitScriptContent = e.target.value;
};

private async loadTemplates(): Promise<void> {
let response = await fetch('/api/templates');
let {data} = (await response.json()) as {
Expand Down
4 changes: 4 additions & 0 deletions src/shared/types/raw-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export interface RawWorkspace {
* editing.
*/
params?: Dict<string>;
/**
* A script that allow user to customize their workspace at create or edit.
*/
customInitScript?: string;
}

export interface RawWorkspaceProjectGit {
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6803,10 +6803,10 @@ typescript-tslint-plugin@^0.5.4:
mock-require "^3.0.2"
vscode-languageserver "^5.1.0"

typescript@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb"
integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==
typescript@^3.7.5:
version "3.7.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==

ua-parser-js@^0.7.18:
version "0.7.20"
Expand Down

0 comments on commit 7e2cf89

Please sign in to comment.