From 4f43a57c2db0ea528fe3cf06d2166e55bade7b52 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Fri, 25 Aug 2023 03:23:18 +0530 Subject: [PATCH 01/11] manage repo initial commit Signed-off-by: msivasubramaniaan --- .eslintignore | 1 + build/esbuild.mjs | 1 + package.json | 11 ++ src/serverlessFunction/commands.ts | 31 ++- src/serverlessFunction/mangeRepository.ts | 63 +++++++ src/serverlessFunction/view.ts | 6 + .../manage-repository/app/addRepository.tsx | 175 +++++++++++++++++ src/webview/manage-repository/app/home.scss | 177 ++++++++++++++++++ src/webview/manage-repository/app/home.tsx | 82 ++++++++ src/webview/manage-repository/app/index.html | 52 +++++ src/webview/manage-repository/app/index.tsx | 12 ++ .../app/showRepositories.tsx | 176 +++++++++++++++++ .../manage-repository/app/tsconfig.json | 29 +++ .../manage-repository/app/vsCodeMessage.ts | 37 ++++ .../manageRepositoryLoader.ts | 170 +++++++++++++++++ tsconfig.json | 1 + 16 files changed, 1023 insertions(+), 1 deletion(-) create mode 100644 src/serverlessFunction/mangeRepository.ts create mode 100644 src/webview/manage-repository/app/addRepository.tsx create mode 100644 src/webview/manage-repository/app/home.scss create mode 100644 src/webview/manage-repository/app/home.tsx create mode 100644 src/webview/manage-repository/app/index.html create mode 100644 src/webview/manage-repository/app/index.tsx create mode 100644 src/webview/manage-repository/app/showRepositories.tsx create mode 100644 src/webview/manage-repository/app/tsconfig.json create mode 100644 src/webview/manage-repository/app/vsCodeMessage.ts create mode 100644 src/webview/manage-repository/manageRepositoryLoader.ts diff --git a/.eslintignore b/.eslintignore index c74715385..45188406f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,6 +18,7 @@ src/webview/welcome src/webview/helm-chart src/webview/feedback src/webview/serverless-function +src/webview/manage-repository # vendored from https://github.com/IonicaBizau/git-url-parse, see https://github.com/IonicaBizau/git-url-parse/pull/159 src/util/gitParse.ts test/sandbox-registration diff --git a/build/esbuild.mjs b/build/esbuild.mjs index 6de044eb7..494dbfdc4 100644 --- a/build/esbuild.mjs +++ b/build/esbuild.mjs @@ -19,6 +19,7 @@ const webviews = [ 'welcome', 'feedback', 'serverless-function', + 'manage-repository', 'add-service-binding', ]; diff --git a/package.json b/package.json index c99774731..841169036 100644 --- a/package.json +++ b/package.json @@ -778,6 +778,12 @@ "category": "OpenShift", "icon": "$(plus)" }, + { + "command": "openshift.Serverless.manageRepository", + "title": "Manage Repositories", + "category": "OpenShift", + "icon": "$(gist)" + }, { "command": "openshift.Serverless.refresh", "title": "Refresh Serverless Function View", @@ -1280,6 +1286,11 @@ "when": "view == openshiftServerlessFunctionsView", "group": "navigation@1" }, + { + "command": "openshift.Serverless.manageRepository", + "when": "view == openshiftServerlessFunctionsView", + "group": "navigation@2" + }, { "command": "openshift.component.openCreateComponent", "when": "view == openshiftComponentsView", diff --git a/src/serverlessFunction/commands.ts b/src/serverlessFunction/commands.ts index a7656c35f..228827f1c 100644 --- a/src/serverlessFunction/commands.ts +++ b/src/serverlessFunction/commands.ts @@ -60,7 +60,7 @@ export class ServerlessCommand { new CommandOption('-i', image), new CommandOption('-v') ]); - if (namespace){ + if (namespace) { commandText.addOption(new CommandOption('-n', namespace)) } if (clusterVersion) { @@ -96,4 +96,33 @@ export class ServerlessCommand { } return commandText; } + + static addRepo(name: string, gitURL: string): CommandText { + const commandText = new CommandText('func', 'repository'); + commandText.addOption(new CommandOption('add')); + commandText.addOption(new CommandOption(name)); + commandText.addOption(new CommandOption(gitURL)); + return commandText; + } + + static deleteRepo(name: string): CommandText { + const commandText = new CommandText('func', 'repository'); + commandText.addOption(new CommandOption('remove')); + commandText.addOption(new CommandOption(name)); + return commandText; + } + + static list(): CommandText { + const commandText = new CommandText('func', 'repository'); + commandText.addOption(new CommandOption('list')); + return commandText; + } + + static renameRepo(oldName: string, newName: string): CommandText { + const commandText = new CommandText('func', 'repository'); + commandText.addOption(new CommandOption('rename')); + commandText.addOption(new CommandOption(oldName)); + commandText.addOption(new CommandOption(newName)); + return commandText; + } } diff --git a/src/serverlessFunction/mangeRepository.ts b/src/serverlessFunction/mangeRepository.ts new file mode 100644 index 000000000..69f6f549d --- /dev/null +++ b/src/serverlessFunction/mangeRepository.ts @@ -0,0 +1,63 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { OdoImpl } from '../odo'; +import { Progress } from '../util/progress'; +import { ServerlessCommand } from './commands'; + +export class ManageRepository { + + private static instance: ManageRepository; + + static getInstance(): ManageRepository { + if (!ManageRepository.instance) { + ManageRepository.instance = new ManageRepository(); + } + return ManageRepository.instance; + } + + public async deleteRepo(name: string): Promise { + const result = await OdoImpl.Instance.execute(ServerlessCommand.deleteRepo(name)); + if (result.error) { + void vscode.window.showErrorMessage(result.error.message); + return false; + } + return true; + } + + public async renameRepo(oldName: string, newName: string): Promise { + const result = await OdoImpl.Instance.execute(ServerlessCommand.renameRepo(oldName, newName)); + if (result.error) { + void vscode.window.showErrorMessage(result.error.message); + return false; + } + return true; + } + + public addRepo(name: string, url: string): Promise { + return new Promise((resolve, _reject) => { + void Progress.execFunctionWithProgress(`Adding repository ${name}`, async () => { + const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url)); + if (result.error) { + void vscode.window.showErrorMessage(result.error.message); + resolve(false); + } else if (result.stdout.length === 0) { + void vscode.window.showInformationMessage(`Repository ${name} added successfully`); + resolve(true); + } + }); + }); + } + + public async list(): Promise { + const result = await OdoImpl.Instance.execute(ServerlessCommand.list()); + if (result.error) { + void vscode.window.showErrorMessage(result.error.message); + return []; + } + return result.stdout.split('\n'); + } +} diff --git a/src/serverlessFunction/view.ts b/src/serverlessFunction/view.ts index 49cab79c1..58cfd04ef 100644 --- a/src/serverlessFunction/view.ts +++ b/src/serverlessFunction/view.ts @@ -29,6 +29,7 @@ import { FunctionContextType, FunctionObject, FunctionStatus } from './types'; import ServerlessFunctionViewLoader from '../webview/serverless-function/serverlessFunctionLoader'; import { BuildAndDeploy } from './build-run-deploy'; import { vsCommand } from '../vscommand'; +import ManageRepositoryViewLoader from '../webview/manage-repository/manageRepositoryLoader'; const kubeConfigFolder: string = path.join(Platform.getUserHomePath(), '.kube'); @@ -203,6 +204,11 @@ export class ServerlessFunctionView implements TreeDataProvider, D await ServerlessFunctionViewLoader.loadView('Serverless Function - Create'); } + @vsCommand('openshift.Serverless.manageRepository') + static async openManageRepository(): Promise { + await ManageRepositoryViewLoader.loadView('Manage Repository'); + } + @vsCommand('openshift.Serverless.refresh') static refresh(target?: ExplorerItem) { ServerlessFunctionView.getInstance().refresh(target); diff --git a/src/webview/manage-repository/app/addRepository.tsx b/src/webview/manage-repository/app/addRepository.tsx new file mode 100644 index 000000000..00f422d87 --- /dev/null +++ b/src/webview/manage-repository/app/addRepository.tsx @@ -0,0 +1,175 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ + +import * as React from 'react'; +import { Button, Stack, TextField } from '@mui/material'; +import { DefaultProps } from '../../common/propertyTypes'; +import './home.scss'; +import { VSCodeMessage } from './vsCodeMessage'; + +export class AddRepository extends React.Component { + + constructor(props: DefaultProps | Readonly) { + super(props); + this.state = { + input: { + name: '', + error: false, + helpText: '' + }, + repo: { + url: '', + error: false, + helpText: '' + } + } + } + + componentDidMount(): void { + VSCodeMessage.onMessage((message) => { + if (message.data.action === 'validateGitURL') { + this.setState({ + repo: { + url: message.data.url, + error: message.data.error, + helpText: message.data.helpText + } + }) + } else if (message.data.action === 'validateName') { + this.setState({ + input: { + name: message.data.name, + error: message.data.error, + helpText: message.data.helpText + } + }) + } else if (message.data.action === 'addRepo' && message.data.status) { + this.setState({ + input: { + name: '', + error: false, + helpText: '' + }, + repo: { + url: '', + error: false, + helpText: '' + } + }) + } + }); + } + + handleButtonDisable(): boolean { + return this.state.input.name?.length === 0 || this.state.input.error + || this.state.repo.url?.length === 0 || this.state.repo.error + } + + validateGitURL = (value: string): void => { + VSCodeMessage.postMessage({ + action: `validateGitURL`, + url: value + }) + } + + validateName = (value: string): void => { + VSCodeMessage.postMessage({ + action: `validateName`, + name: value + }) + } + + addRepo = (): void => { + VSCodeMessage.postMessage({ + action: `addRepo`, + name: this.state.input.name, + url: this.state.repo.url + }) + } + + + render(): React.ReactNode { + const { input, repo } = this.state; + return ( + <> + + + this.validateName(e.target.value)} + id='git-name' + placeholder='Provide name for the repository' + sx={{ + input: { + color: 'var(--vscode-settings-textInputForeground)', + height: '7px !important', + } + }} + helperText={input.helpText} /> + + + + this.validateGitURL(e.target.value)} + id='git-url' + placeholder='Provide git URL' + sx={{ + input: { + color: 'var(--vscode-settings-textInputForeground)', + height: '7px !important', + } + }} + helperText={repo.helpText} /> + + + + + + ) + } +} diff --git a/src/webview/manage-repository/app/home.scss b/src/webview/manage-repository/app/home.scss new file mode 100644 index 000000000..b74a07568 --- /dev/null +++ b/src/webview/manage-repository/app/home.scss @@ -0,0 +1,177 @@ +body { + &.vscode-light { + background-color: var(--color-background--darken-05); + } +} + +button { + padding: 0; +} + +.margin { + margin: 3rem; +} + +.mainContainer, +.formContainer, +.form { + display: flex; + flex-direction: column; + font-family: var(--vscode-font-family) !important; +} + +.title { + width: 100%; + margin-bottom: 1rem; +} + +.subTitle { + margin-bottom: 2rem; + width: auto; + word-spacing: 2px; + text-align: left; + color: var(--vscode-foreground); +} + +.buttonStyle { + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + color: var(--vscode-button-foreground); + width: 3rem; + height: 2.5rem !important; + &:hover { + background-color: '#BE0000' !important; + } + + text-transform: none; +} + +.MuiButton-root.Mui-disabled { + -webkit-text-fill-color: white !important; +} + +.labelStyle { + text-align: center; + text-transform: none; + height: 2.5rem !important; + background-color: var(--vscode-button-background) !important; + border: 1px solid var(--vscode-settings-textInputForeground); +} + +.strategyContainer { + display: flex; + flex-direction: row; + border-top: 3px solid; + max-width: 55rem; + margin-top: 2rem; + padding-top: 0.5rem; + padding-left: 1rem; + min-height: 2rem; +} + +.cardContainer { + display: flex; + flex-direction: column; + margin-top: 1rem; +} + +.strategySuccess { + border-color: green; + background-color: darkseagreen !important; +} + +.strategyWarning { + border-color: orange; + background-color: burlywood !important; +} + +.MuiTypography-root { + font-family: var(--vscode-font-family) !important; +} + +.MuiFormHelperText-root { + color: var(--vscode-foreground) !important; + font-family: var(--vscode-font-family) !important; + margin-left: 0px !important; +} + +.Mui-error { + color: #EE0000 !important; +} + +.MuiSelect-select, +.MuiAutocomplete-inputRoot { + color: var(--vscode-dropdown-foreground) !important; +} + +.MuiMenu-paper { + background-color: var(--vscode-dropdown-background) !important; + color: var(--vscode-dropdown-foreground) !important; +} + +.MuiInputLabel-root, +.MuiFormLabel-root { + background-color: transparent; + color: var(--vscode-settings-textInputForeground) !important; +} + +.MuiAutocomplete-inputRoot { + padding: 0 !important; + padding-left: 5px !important; + height: 2.5rem !important; +} + +.MuiMenuItem-root { + background-color: var(--vscode-dropdown-background) !important; + color: var(--vscode-dropdown-foreground) !important; +} + +.MuiMenuItem-root:hover { + background-color: var(--vscode-button-hoverBackground) !important; +} + +.MuiFormControl-root { + border: none; + &:hover { + border: none; + } +} + +.MuiOutlinedInput-notchedOutline { + border-color: var(--vscode-settings-textInputForeground) !important; +} + +.MuiFormControl-fullWidth { + max-width: 100% !important; +} + +.MuiSvgIcon-root, +.MuiStepLabel-label { + color: var(--vscode-settings-textInputForeground) !important; +} + +.MuiCircularProgress-svg { + color: #EE0000 !important; +} + +.MuiOutlinedInput-root.Mui-disabled { + border: 0px solid var(--vscode-tab-unfocusedActiveBorder) !important; +} + +.Mui-disabled { + -webkit-text-fill-color: var(--vscode-settings-textInputForeground) !important; +} + +.Mui-active { + color: var(--vscode-button-hoverBackground) !important; +} + +.MuiAutocomplete-noOptions { + background-color: var(--vscode-settings-textInputBackground); + color: var(--vscode-settings-textInputForeground) !important; +} + +li:hover { + background-color: var(--vscode-button-hoverBackground) !important; +} diff --git a/src/webview/manage-repository/app/home.tsx b/src/webview/manage-repository/app/home.tsx new file mode 100644 index 000000000..eab9fb767 --- /dev/null +++ b/src/webview/manage-repository/app/home.tsx @@ -0,0 +1,82 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Box, Button, Container, FormControlLabel, Radio, RadioGroup, Stack, Typography } from '@mui/material'; +import { DefaultProps } from '../../common/propertyTypes'; +import './home.scss'; +import { AddRepository } from './addRepository'; +import { ShowRepositories } from './showRepositories'; +import { VSCodeMessage } from './vsCodeMessage'; + +export class ManageRepository extends React.Component { + + constructor(props: DefaultProps | Readonly) { + super(props); + this.state = { + value: 'add' + }; + } + + handleOptionChange = (event: React.ChangeEvent): void => { + + this.setState({ + value: event.target.value + }); + + if (event.target.value === 'show') { + VSCodeMessage.postMessage({ + action: `getRepositoryList` + }); + } + } + + render(): React.ReactNode { + const { value } = this.state; + return ( +
+
+ Manage Repositories +
+
+ Manage template repositories installed on disk at either the default location (~/.config/func/repositories) or the location specified by the --repository flag. Once added, a template from the repository can be used when creating a new function. +
+ + + + + + this.handleOptionChange(e)} + > + } label='Add' /> + } label='Show' /> + + + { + value === 'add' ? : + } + + + +
+ ) + } +} diff --git a/src/webview/manage-repository/app/index.html b/src/webview/manage-repository/app/index.html new file mode 100644 index 000000000..cb9b0ca63 --- /dev/null +++ b/src/webview/manage-repository/app/index.html @@ -0,0 +1,52 @@ + + + + + + + Serverless Function + + + + +
+ + + + diff --git a/src/webview/manage-repository/app/index.tsx b/src/webview/manage-repository/app/index.tsx new file mode 100644 index 000000000..769c62ea9 --- /dev/null +++ b/src/webview/manage-repository/app/index.tsx @@ -0,0 +1,12 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ +import * as ReactDOM from 'react-dom'; +import * as React from 'react'; +import { ManageRepository } from './home'; + +ReactDOM.render( + , + document.getElementById('root'), +); diff --git a/src/webview/manage-repository/app/showRepositories.tsx b/src/webview/manage-repository/app/showRepositories.tsx new file mode 100644 index 000000000..5b3ffce0f --- /dev/null +++ b/src/webview/manage-repository/app/showRepositories.tsx @@ -0,0 +1,176 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ + +import * as React from 'react'; +import { Edit, Delete } from '@mui/icons-material'; +import { VSCodeMessage } from './vsCodeMessage'; +import { DefaultProps } from '../../common/propertyTypes'; +import { Box, Typography, Stack, Button, Grid, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, TextField } from '@mui/material'; + +export class ShowRepositories extends React.Component { + constructor(props: DefaultProps | Readonly) { + super(props); + this.state = { + repositories: [], + openDialog: false, + newRepoInput: { + name: '', + error: false, + helpText: '' + } + } + } + + componentDidMount(): void { + VSCodeMessage.onMessage((message) => { + if (message.data.action === 'getRepositoryList') { + this.setState({ + repositories: message.data.repositories + }); + } else if (message.data.action === 'validateNewName') { + this.setState({ + newRepoInput: { + name: message.data.name, + error: message.data.error, + helpText: message.data.helpText + } + }) + } + }); + } + + handleDelete = (repo: string): void => { + VSCodeMessage.postMessage({ + action: `deleteRepo`, + name: repo + }); + } + + handleEdit = (): void => { + this.setState({ + openDialog: !this.state.openDialog + }) + } + + dialogClose = (): void => { + this.setState({ + openDialog: false + }) + } + + validateName = (value: string): void => { + VSCodeMessage.postMessage({ + action: `validateNewName`, + name: value + }) + } + + handleDisable = (): boolean => { + return this.state.newRepoInput.name.length === 0 || this.state.newRepoInput.error + } + + rename(oldName: string, newName: string): void { + VSCodeMessage.postMessage({ + action: `renameRepo`, + oldName: oldName, + newName: newName + }) + } + + render(): React.ReactNode { + const { newRepoInput, openDialog, repositories } = this.state; + return ( + + { + repositories.map((repoName: string, index: number) => ( + + + + + + {repoName} + + + + + + + this.dialogClose()}> + Subscribe + + + To subscribe to this website, please enter your email address here. We + will send updates occasionally. + + this.validateName(e.target.value)} + /> + + + + + + + + + + )) + } + + ) + } +} diff --git a/src/webview/manage-repository/app/tsconfig.json b/src/webview/manage-repository/app/tsconfig.json new file mode 100644 index 000000000..9d75542c3 --- /dev/null +++ b/src/webview/manage-repository/app/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "node", + "target": "es6", + "outDir": "configViewer", + "lib": [ + "es6", + "dom" + ], + "jsx": "react", + "sourceMap": true, + "noUnusedLocals": true, + // "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "experimentalDecorators": true, + "typeRoots": [ + "../../../../node_modules/@types", + "../../@types" + ], + "baseUrl": ".", + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "exclude": [ + "node_modules" + ] +} diff --git a/src/webview/manage-repository/app/vsCodeMessage.ts b/src/webview/manage-repository/app/vsCodeMessage.ts new file mode 100644 index 000000000..aac1a4b7a --- /dev/null +++ b/src/webview/manage-repository/app/vsCodeMessage.ts @@ -0,0 +1,37 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ + +declare const acquireVsCodeApi: Function; + +interface VSCodeApi { + getState: () => any; + setState: (newState: any) => any; + postMessage: (message: any) => void; +} + +class VSCodeWrapper { + private readonly vscodeApi: VSCodeApi = acquireVsCodeApi(); + + /** + * Send message to the extension framework. + * @param message + */ + public postMessage(message: any): void { + this.vscodeApi.postMessage(message); + } + + /** + * Add listener for messages from extension framework. + * @param callback called when the extension sends a message + * @returns function to clean up the message eventListener. + */ + public onMessage(callback: (message: any) => void): () => void { + window.addEventListener('message', callback); + return () => window.removeEventListener('message', callback); + } +} + +// Singleton to prevent multiple fetches of VsCodeAPI. +export const VSCodeMessage: VSCodeWrapper = new VSCodeWrapper(); diff --git a/src/webview/manage-repository/manageRepositoryLoader.ts b/src/webview/manage-repository/manageRepositoryLoader.ts new file mode 100644 index 000000000..fc78cbdc4 --- /dev/null +++ b/src/webview/manage-repository/manageRepositoryLoader.ts @@ -0,0 +1,170 @@ +/*----------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + *-----------------------------------------------------------------------------------------------*/ +import { ChildProcess } from 'child_process'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { ManageRepository } from '../../serverlessFunction/mangeRepository'; +import { ExtensionID } from '../../util/constants'; +import { gitUrlParse } from '../../util/gitParse'; +import { loadWebviewHtml } from '../common-ext/utils'; +import { validateName } from '../common/utils'; + +export default class ManageRepositoryViewLoader { + + static panel: vscode.WebviewPanel; + + public static processMap: Map = new Map(); + + private static get extensionPath(): string { + return vscode.extensions.getExtension(ExtensionID).extensionPath; + } + + /** + * Returns a webview panel with the "Add Service Binding" UI, + * or if there is an existing view for the given contextPath, focuses that view and returns null. + * + * @param contextPath the path to the component that's being binded to a service + * @param availableServices the list of all bindable services on the cluster + * @param listenerFactory the listener function to receive and process messages from the webview + * @return the webview as a promise + */ + static async loadView( + title: string + ): Promise { + if (ManageRepositoryViewLoader.panel) { + ManageRepositoryViewLoader.panel.reveal(); + return; + } + const localResourceRoot = vscode.Uri.file( + path.join(ManageRepositoryViewLoader.extensionPath, 'out', 'manageRepositoryViewer'), + ); + + let panel = vscode.window.createWebviewPanel('manageRepositoryView', title, vscode.ViewColumn.One, { + enableScripts: true, + localResourceRoots: [localResourceRoot], + retainContextWhenHidden: true, + }); + + const messageHandlerDisposable = panel.webview.onDidReceiveMessage( + ManageRepositoryViewLoader.messageHandler, + ); + + panel.onDidDispose(() => { + messageHandlerDisposable.dispose(); + ManageRepositoryViewLoader.panel = undefined; + }); + + panel.iconPath = vscode.Uri.file( + path.join(ManageRepositoryViewLoader.extensionPath, 'images/context/cluster-node.png'), + ); + + panel.webview.html = await loadWebviewHtml('manageRepositoryViewer', panel); + ManageRepositoryViewLoader.panel = panel; + + return panel; + } + + static async messageHandler(event: any) { + const action = event.action; + switch (action) { + case 'validateGitURL': + validateGitURL(event); + break; + case 'validateName': + case 'validateNewName': + const flag = validateName(event.name); + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: action, + name: event.name, + error: !flag ? false : true, + helpText: !flag ? '' : flag + }); + break; + case 'addRepo': + const addRepoStatus = await ManageRepository.getInstance().addRepo(event.name, event.url); + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: action, + status: addRepoStatus + }); + break; + case 'getRepositoryList': + const repositories = await ManageRepository.getInstance().list(); + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: action, + repositories: repositories + }); + break; + case 'deleteRepo': + const status = await ManageRepository.getInstance().deleteRepo(event.name); + if (status) { + const repositories = await ManageRepository.getInstance().list(); + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: 'getRepositoryList', + repositories: repositories + }); + } + break; + case 'renameRepo': + const renameRepoStatus = await ManageRepository.getInstance().renameRepo(event.oldName, event.newName); + if (renameRepoStatus) { + const repositories = await ManageRepository.getInstance().list(); + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: 'getRepositoryList', + repositories: repositories + }); + } + break; + } + } +} + +function validateGitURL(event: any) { + if (typeof event.url === 'string' && (event.url as string).trim().length === 0) { + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: event.action, + error: true, + helpText: 'Please enter a Git URL.', + }); + } else { + try { + const parse = gitUrlParse(event.url); + const isGitRepo = isGitURL(parse.host); + if (!isGitRepo) { + throw 'Invalid Git URL'; + } + if (parse.organization !== '' && parse.name !== '') { + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: event.action, + url: event.url, + error: false, + helpText: 'The git repo URL is valid.', + }); + } else { + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: event.action, + error: true, + helpText: 'URL is missing organization or repo name.', + }); + } + } catch (e) { + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: event.action, + error: true, + helpText: 'Invalid Git URL.', + }); + } + } +} + +function isGitURL(host: string): boolean { + return [ + 'github.com', + 'bitbucket.org', + 'gitlab.com', + 'git.sr.ht', + 'codeberg.org', + 'gitea.com', + ].includes(host); +} diff --git a/tsconfig.json b/tsconfig.json index bc97936fb..85c595bad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -38,6 +38,7 @@ "src/webview/helm-chart/app", "src/webview/feedback/app", "src/webview/serverless-function/app", + "src/webview/manage-repository/app", "src/webview/common" ] } From 150b434a47d3f1b787ab1d8a22602daf38ee889b Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Fri, 25 Aug 2023 20:57:30 +0530 Subject: [PATCH 02/11] add,edit and delete functionalites were added Signed-off-by: msivasubramaniaan --- src/serverlessFunction/mangeRepository.ts | 8 +- src/webview/common/utils.ts | 2 +- .../manage-repository/app/addRepository.tsx | 13 -- src/webview/manage-repository/app/home.scss | 8 + src/webview/manage-repository/app/home.tsx | 13 ++ .../app/showRepositories.tsx | 156 +++++++++++++----- .../manageRepositoryLoader.ts | 22 ++- 7 files changed, 157 insertions(+), 65 deletions(-) diff --git a/src/serverlessFunction/mangeRepository.ts b/src/serverlessFunction/mangeRepository.ts index 69f6f549d..2f8dcb726 100644 --- a/src/serverlessFunction/mangeRepository.ts +++ b/src/serverlessFunction/mangeRepository.ts @@ -20,7 +20,7 @@ export class ManageRepository { } public async deleteRepo(name: string): Promise { - const result = await OdoImpl.Instance.execute(ServerlessCommand.deleteRepo(name)); + const result = await OdoImpl.Instance.execute(ServerlessCommand.deleteRepo(name), '', false); if (result.error) { void vscode.window.showErrorMessage(result.error.message); return false; @@ -29,7 +29,7 @@ export class ManageRepository { } public async renameRepo(oldName: string, newName: string): Promise { - const result = await OdoImpl.Instance.execute(ServerlessCommand.renameRepo(oldName, newName)); + const result = await OdoImpl.Instance.execute(ServerlessCommand.renameRepo(oldName, newName), '', false); if (result.error) { void vscode.window.showErrorMessage(result.error.message); return false; @@ -40,7 +40,7 @@ export class ManageRepository { public addRepo(name: string, url: string): Promise { return new Promise((resolve, _reject) => { void Progress.execFunctionWithProgress(`Adding repository ${name}`, async () => { - const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url)); + const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url), '', false); if (result.error) { void vscode.window.showErrorMessage(result.error.message); resolve(false); @@ -53,7 +53,7 @@ export class ManageRepository { } public async list(): Promise { - const result = await OdoImpl.Instance.execute(ServerlessCommand.list()); + const result = await OdoImpl.Instance.execute(ServerlessCommand.list(), '', false); if (result.error) { void vscode.window.showErrorMessage(result.error.message); return []; diff --git a/src/webview/common/utils.ts b/src/webview/common/utils.ts index c784e8477..a8fe031e4 100644 --- a/src/webview/common/utils.ts +++ b/src/webview/common/utils.ts @@ -9,7 +9,7 @@ export function validateName(value: string): string | null { let validationMessage = OpenShiftItem.emptyName('Required', value.trim()); if (!validationMessage) validationMessage = OpenShiftItem.validateMatches( - `Please use lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character`, + `Only lower case alphabets and numeric characters or '-', start and ends with only alphabets`, value, ); if (!validationMessage) diff --git a/src/webview/manage-repository/app/addRepository.tsx b/src/webview/manage-repository/app/addRepository.tsx index 00f422d87..d2e5b5098 100644 --- a/src/webview/manage-repository/app/addRepository.tsx +++ b/src/webview/manage-repository/app/addRepository.tsx @@ -56,19 +56,6 @@ export class AddRepository extends React.Component { + if (message.data.action === 'addRepo' && message.data.status) { + this.setState({ + value: 'show' + }); + VSCodeMessage.postMessage({ + action: `getRepositoryList` + }); + } + }); + } + handleOptionChange = (event: React.ChangeEvent): void => { this.setState({ diff --git a/src/webview/manage-repository/app/showRepositories.tsx b/src/webview/manage-repository/app/showRepositories.tsx index 5b3ffce0f..ac883d8c5 100644 --- a/src/webview/manage-repository/app/showRepositories.tsx +++ b/src/webview/manage-repository/app/showRepositories.tsx @@ -4,14 +4,16 @@ *-----------------------------------------------------------------------------------------------*/ import * as React from 'react'; -import { Edit, Delete } from '@mui/icons-material'; +import { Cancel, Delete, Done, Edit } from '@mui/icons-material'; import { VSCodeMessage } from './vsCodeMessage'; import { DefaultProps } from '../../common/propertyTypes'; -import { Box, Typography, Stack, Button, Grid, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, TextField } from '@mui/material'; +import { Box, Typography, Stack, Button, Grid, Dialog, DialogActions, DialogContent, TextField } from '@mui/material'; export class ShowRepositories extends React.Component { + handleDialog = (repoName: string, isEdit = true): void => { + this.setState({ + openedRepo: repoName, + newRepoInput: { + name: repoName, + error: false, + helpText: '' + }, + openDeleteDialog: isEdit ? false : !this.state.openDeleteDialog, + openEditDialog: isEdit ? !this.state.openEditDialog : false + }); + } + + delete = (repo: string): void => { + this.CloseDialog(); VSCodeMessage.postMessage({ action: `deleteRepo`, name: repo }); } - handleEdit = (): void => { + CloseDialog = (): void => { this.setState({ - openDialog: !this.state.openDialog - }) + openEditDialog: false, + openDeleteDialog: false, + openedRepo: '', + newRepoInput: { + name: '', + error: false, + helpText: '' + } + }); } - dialogClose = (): void => { + setRepoName = (value: string): boolean => { this.setState({ - openDialog: false - }) + openEditDialog: true, + newRepoInput: { + name: value, + error: false, + helpText: '' + } + }); + return this.state.openEditDialog; } validateName = (value: string): void => { VSCodeMessage.postMessage({ action: `validateNewName`, name: value - }) + }); } handleDisable = (): boolean => { @@ -80,15 +111,16 @@ export class ShowRepositories extends React.Component { @@ -127,7 +159,7 @@ export class ShowRepositories extends React.Component this.handleEdit()} + onClick={() => this.handleDialog(repoName)} > Edit @@ -136,40 +168,82 @@ export class ShowRepositories extends React.Component this.handleDelete(repoName)}> + onClick={() => this.handleDialog(repoName, false)}> Delete - this.dialogClose()}> - Subscribe - - - To subscribe to this website, please enter your email address here. We - will send updates occasionally. - - this.validateName(e.target.value)} - /> - - - - - - )) } + { + openedRepo.length > 0 && + this.CloseDialog()}> + + + {`Are you sure want to delete the repository '${openedRepo}' ?`} + + + + + + + + } + { + openedRepo.length > 0 && + this.CloseDialog()}> + + + + this.validateName(e.target.value)} + id='repo-new-name' + sx={{ + input: { + color: 'var(--vscode-settings-textInputForeground)', + height: '7px !important', + } + }} + helperText={newRepoInput.helpText} /> + + + + + + + + } ) } diff --git a/src/webview/manage-repository/manageRepositoryLoader.ts b/src/webview/manage-repository/manageRepositoryLoader.ts index fc78cbdc4..9592367b9 100644 --- a/src/webview/manage-repository/manageRepositoryLoader.ts +++ b/src/webview/manage-repository/manageRepositoryLoader.ts @@ -75,12 +75,22 @@ export default class ManageRepositoryViewLoader { case 'validateName': case 'validateNewName': const flag = validateName(event.name); - ManageRepositoryViewLoader.panel?.webview.postMessage({ - action: action, - name: event.name, - error: !flag ? false : true, - helpText: !flag ? '' : flag - }); + const repoList = await ManageRepository.getInstance().list(); + if (repoList.includes(event.name)) { + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: action, + name: event.name, + error: true, + helpText: `Repository ${event.name} already exists` + }); + } else { + ManageRepositoryViewLoader.panel?.webview.postMessage({ + action: action, + name: event.name, + error: !flag ? false : true, + helpText: !flag ? '' : flag + }); + } break; case 'addRepo': const addRepoStatus = await ManageRepository.getInstance().addRepo(event.name, event.url); From 5c6de2eb2e822fa09d6ed2ef82eb810976d000f6 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Sat, 26 Aug 2023 12:35:45 +0530 Subject: [PATCH 03/11] added telemetery Signed-off-by: msivasubramaniaan --- src/serverlessFunction/mangeRepository.ts | 33 ++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/serverlessFunction/mangeRepository.ts b/src/serverlessFunction/mangeRepository.ts index 2f8dcb726..6401832a1 100644 --- a/src/serverlessFunction/mangeRepository.ts +++ b/src/serverlessFunction/mangeRepository.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode'; import { OdoImpl } from '../odo'; +import sendTelemetry from '../telemetry'; import { Progress } from '../util/progress'; import { ServerlessCommand } from './commands'; @@ -20,8 +21,14 @@ export class ManageRepository { } public async deleteRepo(name: string): Promise { + await sendTelemetry('openshift.managerepo.delete', { + name + }); const result = await OdoImpl.Instance.execute(ServerlessCommand.deleteRepo(name), '', false); if (result.error) { + await sendTelemetry('openshift.managerepo.delete.error', { + error: result.error.message + }); void vscode.window.showErrorMessage(result.error.message); return false; } @@ -29,22 +36,39 @@ export class ManageRepository { } public async renameRepo(oldName: string, newName: string): Promise { + await sendTelemetry('openshift.managerepo.rename', { + oldName, + newName + }); const result = await OdoImpl.Instance.execute(ServerlessCommand.renameRepo(oldName, newName), '', false); if (result.error) { + await sendTelemetry('openshift.managerepo.rename.error', { + error: result.error.message + }); void vscode.window.showErrorMessage(result.error.message); return false; } return true; } - public addRepo(name: string, url: string): Promise { + public async addRepo(name: string, url: string): Promise { + await sendTelemetry('openshift.managerepo.add', { + name, url + }); return new Promise((resolve, _reject) => { void Progress.execFunctionWithProgress(`Adding repository ${name}`, async () => { const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url), '', false); if (result.error) { + await sendTelemetry('openshift.managerepo.add.error', { + error: result.error.message + }); void vscode.window.showErrorMessage(result.error.message); resolve(false); } else if (result.stdout.length === 0) { + await sendTelemetry('openshift.managerepo.add.success', { + name, + message: 'Repo added successfully' + }); void vscode.window.showInformationMessage(`Repository ${name} added successfully`); resolve(true); } @@ -53,8 +77,15 @@ export class ManageRepository { } public async list(): Promise { + await sendTelemetry('openshift.managerepo.list'); const result = await OdoImpl.Instance.execute(ServerlessCommand.list(), '', false); if (result.error) { + await sendTelemetry('openshift.managerepo.list.error', { + error: result.error.message + }); + await sendTelemetry('openshift.managerepo.list.success', { + repos: result.stdout.split('\n') + }); void vscode.window.showErrorMessage(result.error.message); return []; } From 5d14acd6680a91e4445ba252351ea17551434bd5 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Sat, 26 Aug 2023 23:05:33 +0530 Subject: [PATCH 04/11] added telemetery Signed-off-by: msivasubramaniaan --- .editorconfig | 2 +- src/serverlessFunction/mangeRepository.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index 24e7dd207..f45bad7fd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,7 +11,7 @@ indent_style = space indent_size = 4 # We recommend you to keep these unchanged -end_of_line = lf +end_of_line = crlf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true diff --git a/src/serverlessFunction/mangeRepository.ts b/src/serverlessFunction/mangeRepository.ts index 6401832a1..9834a83e5 100644 --- a/src/serverlessFunction/mangeRepository.ts +++ b/src/serverlessFunction/mangeRepository.ts @@ -48,6 +48,9 @@ export class ManageRepository { void vscode.window.showErrorMessage(result.error.message); return false; } + await sendTelemetry('openshift.managerepo.rename.success', { + message: `Repo ${newName} renamed successfully` + }); return true; } @@ -83,12 +86,12 @@ export class ManageRepository { await sendTelemetry('openshift.managerepo.list.error', { error: result.error.message }); - await sendTelemetry('openshift.managerepo.list.success', { - repos: result.stdout.split('\n') - }); void vscode.window.showErrorMessage(result.error.message); return []; } + await sendTelemetry('openshift.managerepo.list.success', { + repos: result.stdout.split('\n') + }); return result.stdout.split('\n'); } } From d3acb596cef99ae21dd6bc20aa3209e03def1541 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Sun, 27 Aug 2023 00:38:58 +0530 Subject: [PATCH 05/11] refactor the method Signed-off-by: msivasubramaniaan --- .editorconfig | 2 +- src/serverlessFunction/commands.ts | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.editorconfig b/.editorconfig index f45bad7fd..24e7dd207 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,7 +11,7 @@ indent_style = space indent_size = 4 # We recommend you to keep these unchanged -end_of_line = crlf +end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true diff --git a/src/serverlessFunction/commands.ts b/src/serverlessFunction/commands.ts index 4740a3eec..b39b579ad 100644 --- a/src/serverlessFunction/commands.ts +++ b/src/serverlessFunction/commands.ts @@ -117,19 +117,12 @@ export class ServerlessCommand { } static config(functionPath: string, mode: string, isAdd: boolean): CommandText { + const option = isAdd ? mode === 'git' ? 'set' : 'add' : 'remove'; const commandText = new CommandText('func', 'config', [ new CommandOption(mode), + new CommandOption(option), new CommandOption('-p', functionPath) ]); - if (isAdd) { - if (mode === 'git') { - commandText.addOption(new CommandOption('set')); - } else { - commandText.addOption(new CommandOption('add')); - } - } else { - commandText.addOption(new CommandOption('remove')); - } return commandText; } From 189247fb8870ea3b00628e2e9af2740ac1889366 Mon Sep 17 00:00:00 2001 From: Muthurajan Sivasubramanian <93245779+msivasubramaniaan@users.noreply.github.com> Date: Sun, 27 Aug 2023 12:34:06 +0530 Subject: [PATCH 06/11] Update src/webview/manage-repository/app/addRepository.tsx Co-authored-by: Mohit Suman --- src/webview/manage-repository/app/addRepository.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webview/manage-repository/app/addRepository.tsx b/src/webview/manage-repository/app/addRepository.tsx index d2e5b5098..96f5d353b 100644 --- a/src/webview/manage-repository/app/addRepository.tsx +++ b/src/webview/manage-repository/app/addRepository.tsx @@ -109,7 +109,7 @@ export class AddRepository extends React.Component this.validateName(e.target.value)} id='git-name' - placeholder='Provide name for the repository' + placeholder='Provide repository name' sx={{ input: { color: 'var(--vscode-settings-textInputForeground)', From 0f1f948e9fcfa11a3882a353374b884966670865 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Mon, 28 Aug 2023 21:57:22 +0530 Subject: [PATCH 07/11] changed the entire layout Signed-off-by: msivasubramaniaan --- .../manage-repository/app/addRepository.tsx | 9 +- src/webview/manage-repository/app/home.scss | 21 ++ src/webview/manage-repository/app/home.tsx | 74 +----- .../app/showRepositories.tsx | 246 +++++++++++++----- 4 files changed, 203 insertions(+), 147 deletions(-) diff --git a/src/webview/manage-repository/app/addRepository.tsx b/src/webview/manage-repository/app/addRepository.tsx index 96f5d353b..1bc2a7ba0 100644 --- a/src/webview/manage-repository/app/addRepository.tsx +++ b/src/webview/manage-repository/app/addRepository.tsx @@ -91,10 +91,10 @@ export class AddRepository extends React.Component + - this.handleOptionChange(e)} - > - } label='Add' /> - } label='Show' /> - - - { - value === 'add' ? : - } - - - - + ) } } diff --git a/src/webview/manage-repository/app/showRepositories.tsx b/src/webview/manage-repository/app/showRepositories.tsx index ac883d8c5..c98cb499f 100644 --- a/src/webview/manage-repository/app/showRepositories.tsx +++ b/src/webview/manage-repository/app/showRepositories.tsx @@ -4,13 +4,15 @@ *-----------------------------------------------------------------------------------------------*/ import * as React from 'react'; -import { Cancel, Delete, Done, Edit } from '@mui/icons-material'; +import { Add, Cancel, Delete, Done, Edit } from '@mui/icons-material'; import { VSCodeMessage } from './vsCodeMessage'; import { DefaultProps } from '../../common/propertyTypes'; -import { Box, Typography, Stack, Button, Grid, Dialog, DialogActions, DialogContent, TextField } from '@mui/material'; +import { Typography, Stack, Button, Dialog, DialogActions, DialogContent, TextField, TableCell, TableRow, Table, TableContainer, TableHead, styled, tableCellClasses, TableBody, Box, TablePagination, IconButton, Container, CircularProgress, Tooltip } from '@mui/material'; +import { AddRepository } from './addRepository'; export class ShowRepositories extends React.Component { constructor(props: DefaultProps | Readonly) { super(props); this.state = { repositories: [], + openAddDialog: false, openEditDialog: false, openDeleteDialog: false, openedRepo: '', @@ -31,7 +36,9 @@ export class ShowRepositories extends React.Component { - this.setState({ - openedRepo: repoName, - newRepoInput: { - name: repoName, - error: false, - helpText: '' - }, - openDeleteDialog: isEdit ? false : !this.state.openDeleteDialog, - openEditDialog: isEdit ? !this.state.openEditDialog : false - }); + if (!repoName) { + this.setState({ + openAddDialog: !this.state.openAddDialog + }) + } else { + this.setState({ + openedRepo: repoName, + newRepoInput: { + name: repoName, + error: false, + helpText: '' + }, + openDeleteDialog: isEdit ? false : !this.state.openDeleteDialog, + openEditDialog: isEdit ? !this.state.openEditDialog : false + }); + } } delete = (repo: string): void => { @@ -76,6 +96,7 @@ export class ShowRepositories extends React.Component { this.setState({ + openAddDialog: false, openEditDialog: false, openDeleteDialog: false, openedRepo: '', @@ -119,64 +140,142 @@ export class ShowRepositories extends React.Component ({ + [`&.${tableCellClasses.head}`]: { + backgroundColor: 'var(--vscode-button-background)', + color: 'var(--vscode-settings-textInputForeground)', + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14, + }, + })); + + StyledTableRow = styled(TableRow)(({ }) => ({ + '&:nth-of-type(odd)': { + backgroundColor: 'var(--vscode-button-secondaryBackground)' + }, + + '&:nth-of-type(even)': { + backgroundColor: 'var(--vscode-button-secondaryHoverBackground)' + } + })); + + handleChangeRowsPerPage = (event: React.ChangeEvent) => { + this.setState({ + page: 0, + rowsPerPage: parseInt(event.target.value, 10) + }); + }; + + handleChangePage = (_event: unknown, newPage: number) => { + this.setState({ + page: newPage + }); + }; + render(): React.ReactNode { - const { newRepoInput, openedRepo, openDeleteDialog, openEditDialog, repositories } = this.state; + const { newRepoInput, openedRepo, openAddDialog, openDeleteDialog, openEditDialog, page, repositories, rowsPerPage } = this.state; return ( - - { - repositories.map((repoName: string, index: number) => ( - - - - - - {repoName} - - - - - - - - - - )) - } +
+
+ Manage Repositories +
+
+ Manage template repositories installed on disk at either the default location (~/.config/func/repositories) or the location specified by the --repository flag. Once added, a template from the repository can be used when creating a new function. +
+ + + <> + { + repositories.length > 0 ? + <> + + + + + + Repository Name + Actions + + + + {repositories.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((repo) => ( + + +
+ <> + { + repo.length > 24 ? + {repo} + : {repo} + } + +
+
+ + + + this.handleDialog(repo)} + > + + + + + this.handleDialog(repo, false)} + > + + + + + +
+ ))} +
+
+
+ { + repositories.length > 10 && + + } + +
+ + + + + + + : + + } + +
+
{ openedRepo.length > 0 && this.CloseDialog()}> @@ -244,7 +343,12 @@ export class ShowRepositories extends React.Component } - + this.CloseDialog()}> + + + + +
) } } From 0fccdf0a8818d9d0cc58cdc36014b4d58e4bb798 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Tue, 29 Aug 2023 22:44:34 +0530 Subject: [PATCH 08/11] addressed review comments Signed-off-by: msivasubramaniaan --- .eslintignore | 2 +- build/esbuild.mjs | 2 +- package.json | 2 +- ...mangeRepository.ts => manageRepository.ts} | 6 +- src/serverlessFunction/view.ts | 2 +- src/webview/common-ext/utils.ts | 69 ++++++++++++++- src/webview/common/propertyTypes.ts | 8 +- src/webview/common/utils.ts | 18 ---- .../create-component/createComponentLoader.ts | 68 ++------------- src/webview/serverless-function/app/home.scss | 33 ++++++- .../serverlessFunctionLoader.ts | 3 +- .../app/addRepository.tsx | 29 +++++-- .../app/home.scss | 7 +- .../app/home.tsx | 1 - .../app/index.html | 0 .../app/index.tsx | 0 .../app/showRepositories.tsx | 17 ++-- .../app/tsconfig.json | 0 .../app/vsCodeMessage.ts | 0 .../manageRepositoryLoader.ts | 87 +++++-------------- tsconfig.json | 2 +- 21 files changed, 178 insertions(+), 178 deletions(-) rename src/serverlessFunction/{mangeRepository.ts => manageRepository.ts} (93%) delete mode 100644 src/webview/common/utils.ts rename src/webview/{manage-repository => serverless-manage-repository}/app/addRepository.tsx (90%) rename src/webview/{manage-repository => serverless-manage-repository}/app/home.scss (94%) rename src/webview/{manage-repository => serverless-manage-repository}/app/home.tsx (98%) rename src/webview/{manage-repository => serverless-manage-repository}/app/index.html (100%) rename src/webview/{manage-repository => serverless-manage-repository}/app/index.tsx (100%) rename src/webview/{manage-repository => serverless-manage-repository}/app/showRepositories.tsx (98%) rename src/webview/{manage-repository => serverless-manage-repository}/app/tsconfig.json (100%) rename src/webview/{manage-repository => serverless-manage-repository}/app/vsCodeMessage.ts (100%) rename src/webview/{manage-repository => serverless-manage-repository}/manageRepositoryLoader.ts (67%) diff --git a/.eslintignore b/.eslintignore index 45188406f..8d9be89c6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,7 +18,7 @@ src/webview/welcome src/webview/helm-chart src/webview/feedback src/webview/serverless-function -src/webview/manage-repository +src/webview/serverless-manage-repository # vendored from https://github.com/IonicaBizau/git-url-parse, see https://github.com/IonicaBizau/git-url-parse/pull/159 src/util/gitParse.ts test/sandbox-registration diff --git a/build/esbuild.mjs b/build/esbuild.mjs index 494dbfdc4..993617e1f 100644 --- a/build/esbuild.mjs +++ b/build/esbuild.mjs @@ -19,7 +19,7 @@ const webviews = [ 'welcome', 'feedback', 'serverless-function', - 'manage-repository', + 'serverless-manage-repository', 'add-service-binding', ]; diff --git a/package.json b/package.json index 3a80692c4..df87d2070 100644 --- a/package.json +++ b/package.json @@ -786,7 +786,7 @@ }, { "command": "openshift.Serverless.manageRepository", - "title": "Manage Repositories", + "title": "Manage Knative Function Template Repositories", "category": "OpenShift", "icon": "$(gist)" }, diff --git a/src/serverlessFunction/mangeRepository.ts b/src/serverlessFunction/manageRepository.ts similarity index 93% rename from src/serverlessFunction/mangeRepository.ts rename to src/serverlessFunction/manageRepository.ts index 9834a83e5..b1f8bbcba 100644 --- a/src/serverlessFunction/mangeRepository.ts +++ b/src/serverlessFunction/manageRepository.ts @@ -67,7 +67,7 @@ export class ManageRepository { }); void vscode.window.showErrorMessage(result.error.message); resolve(false); - } else if (result.stdout.length === 0) { + } else if (result.stdout.length === 0 && result.stderr.length === 0) { await sendTelemetry('openshift.managerepo.add.success', { name, message: 'Repo added successfully' @@ -75,6 +75,10 @@ export class ManageRepository { void vscode.window.showInformationMessage(`Repository ${name} added successfully`); resolve(true); } + await sendTelemetry('openshift.managerepo.add.error', { + error: result.stderr + }); + resolve(false); }); }); } diff --git a/src/serverlessFunction/view.ts b/src/serverlessFunction/view.ts index 1e625399c..05fa68758 100644 --- a/src/serverlessFunction/view.ts +++ b/src/serverlessFunction/view.ts @@ -29,7 +29,7 @@ import { FunctionContextType, FunctionObject, FunctionStatus } from './types'; import ServerlessFunctionViewLoader from '../webview/serverless-function/serverlessFunctionLoader'; import { Functions } from './functions'; import { vsCommand } from '../vscommand'; -import ManageRepositoryViewLoader from '../webview/manage-repository/manageRepositoryLoader'; +import ManageRepositoryViewLoader from '../webview/serverless-manage-repository/manageRepositoryLoader'; const kubeConfigFolder: string = path.join(Platform.getUserHomePath(), '.kube'); diff --git a/src/webview/common-ext/utils.ts b/src/webview/common-ext/utils.ts index 32ca226f9..df8bc5f26 100644 --- a/src/webview/common-ext/utils.ts +++ b/src/webview/common-ext/utils.ts @@ -6,7 +6,15 @@ import * as fs from 'fs/promises'; import * as path from 'path'; import { Uri, WebviewPanel, extensions } from 'vscode'; +import OpenShiftItem from '../../openshift/openshiftItem'; import { ExtensionID } from '../../util/constants'; +import { gitUrlParse } from '../../util/gitParse'; +import { validateGitURLProps } from '../common/propertyTypes'; + +export type Message = { + action: string; + data: any; +}; export async function loadWebviewHtml(webviewName: string, webviewPanel: WebviewPanel, additionalInjections?: Map): Promise { @@ -28,7 +36,7 @@ export async function loadWebviewHtml(webviewName: string, webviewPanel: Webview style-src 'self' vscode-resource: 'unsafe-inline';">`; const htmlWithDefaultInjections = `${htmlString}` .replace('%PLATFORM%', process.platform) - .replace('%SCRIPT%',`${reactJavascriptUri}`) + .replace('%SCRIPT%', `${reactJavascriptUri}`) .replace('%BASE_URL%', `${reactJavascriptUri}`) .replace('%STYLE%', `${reactStylesheetUri}`) .replace('', meta); @@ -41,3 +49,62 @@ export async function loadWebviewHtml(webviewName: string, webviewPanel: Webview } return htmlWithAdditionalInjections; } + +function isGitURL(host: string): boolean { + return [ + 'github.com', + 'bitbucket.org', + 'gitlab.com', + 'git.sr.ht', + 'codeberg.org', + 'gitea.com', + ].includes(host); +} + +export function validateGitURL(event: Message): validateGitURLProps { + if (typeof event.data === 'string' && (event.data).trim().length === 0) { + return { + url: event.data, + error: true, + helpText: 'Please enter a Git URL.' + } as validateGitURLProps + } + try { + const parse = gitUrlParse(event.data); + const isGitRepo = isGitURL(parse.host); + if (!isGitRepo) { + throw 'Invalid Git URL'; + } + if (parse.organization !== '' && parse.name !== '') { + return { + url: event.data, + error: false, + helpText: 'The git repo URL is valid.' + } as validateGitURLProps + } + return { + url: event.data, + error: true, + helpText: 'URL is missing organization or repo name.' + } as validateGitURLProps + + } catch (e) { + return { + url: event.data, + error: true, + helpText: 'Invalid Git URL.' + } as validateGitURLProps + } +} + +export function validateName(value: string): string | null { + let validationMessage = OpenShiftItem.emptyName('Required', value.trim()); + if (!validationMessage) { + validationMessage = OpenShiftItem.validateMatches( + 'Only lower case alphabets and numeric characters or \'-\', start and ends with only alphabets', + value, + ); + } + if (!validationMessage) { validationMessage = OpenShiftItem.lengthName('Should be between 2-63 characters', value, 0); } + return validationMessage; +} diff --git a/src/webview/common/propertyTypes.ts b/src/webview/common/propertyTypes.ts index f64705780..8fd9d4f36 100644 --- a/src/webview/common/propertyTypes.ts +++ b/src/webview/common/propertyTypes.ts @@ -2,8 +2,6 @@ * Copyright (c) Red Hat, Inc. All rights reserved. * Licensed under the MIT License. See LICENSE file in the project root for license information. *-----------------------------------------------------------------------------------------------*/ - -import { ChangeEvent } from 'react'; import { ComponentTypeDescription, Registry } from '../../odo/componentType'; import { StarterProject } from '../../odo/componentTypeDescription'; import { ChartResponse } from '../helm-chart/helmChartType'; @@ -84,3 +82,9 @@ export interface RunFunctionPageProps extends DefaultProps { skip: (stepCount: number) => void; onRunSubmit: (folderPath: Uri, build: boolean) => void; } + +export interface validateGitURLProps { + url: string; + error: boolean; + helpText: string; +} diff --git a/src/webview/common/utils.ts b/src/webview/common/utils.ts deleted file mode 100644 index a8fe031e4..000000000 --- a/src/webview/common/utils.ts +++ /dev/null @@ -1,18 +0,0 @@ -/*----------------------------------------------------------------------------------------------- - * Copyright (c) Red Hat, Inc. All rights reserved. - * Licensed under the MIT License. See LICENSE file in the project root for license information. - *-----------------------------------------------------------------------------------------------*/ - -import OpenShiftItem from '../../openshift/openshiftItem'; - -export function validateName(value: string): string | null { - let validationMessage = OpenShiftItem.emptyName('Required', value.trim()); - if (!validationMessage) - validationMessage = OpenShiftItem.validateMatches( - `Only lower case alphabets and numeric characters or '-', start and ends with only alphabets`, - value, - ); - if (!validationMessage) - validationMessage = OpenShiftItem.lengthName('Should be between 2-63 characters', value, 0); - return validationMessage; -} diff --git a/src/webview/create-component/createComponentLoader.ts b/src/webview/create-component/createComponentLoader.ts index e8add06af..2a5268343 100644 --- a/src/webview/create-component/createComponentLoader.ts +++ b/src/webview/create-component/createComponentLoader.ts @@ -18,14 +18,13 @@ import { ComponentTypesView } from '../../registriesView'; import sendTelemetry from '../../telemetry'; import { ExtensionID } from '../../util/constants'; import { DevfileConverter } from '../../util/devfileConverter'; -import { gitUrlParse } from '../../util/gitParse'; import { selectWorkspaceFolder } from '../../util/workspace'; import { getDevfileRegistries, isValidProjectFolder, validateComponentName } from '../common-ext/createComponentHelpers'; -import { loadWebviewHtml } from '../common-ext/utils'; +import { loadWebviewHtml, validateGitURL } from '../common-ext/utils'; import { Devfile, DevfileRegistry, TemplateProjectIdentifier } from '../common/devfile'; interface CloneProcess { @@ -326,7 +325,14 @@ export default class CreateComponentLoader { * The panel requested to validate the git repository URL. */ case 'validateGitURL': { - validateGitURL(message); + const response = validateGitURL(message); + CreateComponentLoader.panel?.webview.postMessage({ + action: message.action, + data: { + isValid: !response.error, + helpText: response.helpText + } + }); break; } /** @@ -457,62 +463,6 @@ async function isDevfileExists(uri: vscode.Uri): Promise { } } -function validateGitURL(event: any) { - if (typeof event.data === 'string' && (event.data as string).trim().length === 0) { - CreateComponentLoader.panel?.webview.postMessage({ - action: event.action, - data: { - isValid: false, - helpText: 'Please enter a Git URL.', - }, - }); - } else { - try { - const parse = gitUrlParse(event.data); - const isGitRepo = isGitURL(parse.host); - if (!isGitRepo) { - throw 'Invalid Git URL'; - } - if (parse.organization !== '' && parse.name !== '') { - CreateComponentLoader.panel?.webview.postMessage({ - action: event.action, - data: { - isValid: true, - helpText: 'The git repo URL is valid.', - }, - }); - } else { - CreateComponentLoader.panel?.webview.postMessage({ - action: event.action, - data: { - isValid: false, - helpText: 'URL is missing organization or repo name.', - }, - }); - } - } catch (e) { - CreateComponentLoader.panel?.webview.postMessage({ - action: event.action, - data: { - isValid: false, - helpText: 'Invalid Git URL.', - }, - }); - } - } -} - -function isGitURL(host: string): boolean { - return [ - 'github.com', - 'bitbucket.org', - 'gitlab.com', - 'git.sr.ht', - 'codeberg.org', - 'gitea.com', - ].includes(host); -} - function clone(url: string, location: string, branch?: string): Promise { const gitExtension = vscode.extensions.getExtension('vscode.git').exports; const git = gitExtension.getAPI(1).git.path; diff --git a/src/webview/serverless-function/app/home.scss b/src/webview/serverless-function/app/home.scss index 0757f87db..ce665feda 100644 --- a/src/webview/serverless-function/app/home.scss +++ b/src/webview/serverless-function/app/home.scss @@ -30,7 +30,6 @@ button { width: auto; word-spacing: 2px; text-align: left; - color: var(--vscode-foreground); } .buttonStyle { @@ -88,7 +87,6 @@ button { .MuiTypography-root { font-family: var(--vscode-font-family) !important; - color: var(--vscode-settings-textInputForeground) !important; } .MuiFormHelperText-root { @@ -149,6 +147,18 @@ button { .MuiSvgIcon-root, .MuiStepLabel-label { + color: var(--vscode-button-foreground) !important; +} + +.successicon { + color: #198754 !important; +} + +.erroricon { + color: #ff3333 !important; +} + +.disabledicon { color: var(--vscode-settings-textInputForeground) !important; } @@ -161,7 +171,7 @@ button { } .Mui-disabled { - -webkit-text-fill-color: var(--vscode-titleBar-inactiveForeground) !important; + -webkit-text-fill-color: var(--vscode-button-foreground) !important; } .Mui-active { @@ -176,3 +186,20 @@ button { li:hover { background-color: var(--vscode-button-hoverBackground) !important; } + +.MuiDialog-paper { + border: 1px groove var(--vscode-activityBar-activeBorder) !important; + border-radius: 1rem !important; + margin: auto !important; + background-color: #101418 !important; + color: var(--vscode-settings-textInputForeground) !important +} + +.MuiTableCell-body { + color: var(--vscode-button-foreground) !important +} + +.MuiTablePagination-toolbar { + background-color: var(--vscode-button-secondaryHoverBackground) !important; + color: var(--vscode-settings-textInputForeground) !important +} diff --git a/src/webview/serverless-function/serverlessFunctionLoader.ts b/src/webview/serverless-function/serverlessFunctionLoader.ts index 9457f78f9..af388433f 100644 --- a/src/webview/serverless-function/serverlessFunctionLoader.ts +++ b/src/webview/serverless-function/serverlessFunctionLoader.ts @@ -11,8 +11,7 @@ import { serverlessInstance } from '../../serverlessFunction/functionImpl'; import { ExtensionID } from '../../util/constants'; import { Progress } from '../../util/progress'; import { selectWorkspaceFolder, selectWorkspaceFolders } from '../../util/workspace'; -import { loadWebviewHtml } from '../common-ext/utils'; -import { validateName } from '../common/utils'; +import { loadWebviewHtml, validateName } from '../common-ext/utils'; import { InvokeFunction } from '../../serverlessFunction/types'; export interface ServiceBindingFormResponse { diff --git a/src/webview/manage-repository/app/addRepository.tsx b/src/webview/serverless-manage-repository/app/addRepository.tsx similarity index 90% rename from src/webview/manage-repository/app/addRepository.tsx rename to src/webview/serverless-manage-repository/app/addRepository.tsx index 1bc2a7ba0..79cdfbf21 100644 --- a/src/webview/manage-repository/app/addRepository.tsx +++ b/src/webview/serverless-manage-repository/app/addRepository.tsx @@ -5,6 +5,7 @@ import * as React from 'react'; import { Button, Stack, TextField } from '@mui/material'; +import LoadingButton from '@mui/lab/LoadingButton'; import { DefaultProps } from '../../common/propertyTypes'; import './home.scss'; import { VSCodeMessage } from './vsCodeMessage'; @@ -19,7 +20,8 @@ export class AddRepository extends React.Component { constructor(props: DefaultProps | Readonly) { @@ -34,7 +36,8 @@ export class AddRepository extends React.Component { VSCodeMessage.postMessage({ action: `validateGitURL`, - url: value + data: value }) } validateName = (value: string): void => { VSCodeMessage.postMessage({ action: `validateName`, - name: value + data: value }) } addRepo = (): void => { + this.setState({ + loading: true + }); VSCodeMessage.postMessage({ action: `addRepo`, - name: this.state.input.name, - url: this.state.repo.url + data: { + name: this.state.input.name, + url: this.state.repo.url + } }) } render(): React.ReactNode { - const { input, repo } = this.state; + const { input, repo, loading } = this.state; return ( @@ -144,7 +152,10 @@ export class AddRepository extends React.Component - + ) diff --git a/src/webview/manage-repository/app/home.scss b/src/webview/serverless-manage-repository/app/home.scss similarity index 94% rename from src/webview/manage-repository/app/home.scss rename to src/webview/serverless-manage-repository/app/home.scss index 40fe336d3..ce665feda 100644 --- a/src/webview/manage-repository/app/home.scss +++ b/src/webview/serverless-manage-repository/app/home.scss @@ -30,7 +30,6 @@ button { width: auto; word-spacing: 2px; text-align: left; - color: var(--vscode-foreground); } .buttonStyle { @@ -148,7 +147,7 @@ button { .MuiSvgIcon-root, .MuiStepLabel-label { - color: var(--vscode-settings-textInputForeground) !important; + color: var(--vscode-button-foreground) !important; } .successicon { @@ -172,7 +171,7 @@ button { } .Mui-disabled { - -webkit-text-fill-color: var(--vscode-settings-textInputForeground) !important; + -webkit-text-fill-color: var(--vscode-button-foreground) !important; } .Mui-active { @@ -197,7 +196,7 @@ li:hover { } .MuiTableCell-body { - color: var(--vscode-settings-textInputForeground) !important + color: var(--vscode-button-foreground) !important } .MuiTablePagination-toolbar { diff --git a/src/webview/manage-repository/app/home.tsx b/src/webview/serverless-manage-repository/app/home.tsx similarity index 98% rename from src/webview/manage-repository/app/home.tsx rename to src/webview/serverless-manage-repository/app/home.tsx index a4a417c3a..a38b17ee4 100644 --- a/src/webview/manage-repository/app/home.tsx +++ b/src/webview/serverless-manage-repository/app/home.tsx @@ -9,7 +9,6 @@ import { ShowRepositories } from './showRepositories'; import { VSCodeMessage } from './vsCodeMessage'; export class ManageRepository extends React.Component { constructor(props: DefaultProps | Readonly) { diff --git a/src/webview/manage-repository/app/index.html b/src/webview/serverless-manage-repository/app/index.html similarity index 100% rename from src/webview/manage-repository/app/index.html rename to src/webview/serverless-manage-repository/app/index.html diff --git a/src/webview/manage-repository/app/index.tsx b/src/webview/serverless-manage-repository/app/index.tsx similarity index 100% rename from src/webview/manage-repository/app/index.tsx rename to src/webview/serverless-manage-repository/app/index.tsx diff --git a/src/webview/manage-repository/app/showRepositories.tsx b/src/webview/serverless-manage-repository/app/showRepositories.tsx similarity index 98% rename from src/webview/manage-repository/app/showRepositories.tsx rename to src/webview/serverless-manage-repository/app/showRepositories.tsx index c98cb499f..a4e1c9dee 100644 --- a/src/webview/manage-repository/app/showRepositories.tsx +++ b/src/webview/serverless-manage-repository/app/showRepositories.tsx @@ -90,7 +90,9 @@ export class ShowRepositories extends React.Component { VSCodeMessage.postMessage({ action: `validateNewName`, - name: value + data: value }); } @@ -135,15 +137,17 @@ export class ShowRepositories extends React.Component ({ [`&.${tableCellClasses.head}`]: { backgroundColor: 'var(--vscode-button-background)', - color: 'var(--vscode-settings-textInputForeground)', + color: 'var(--vscode-button-foreground)' }, [`&.${tableCellClasses.body}`]: { fontSize: 14, @@ -185,8 +189,7 @@ export class ShowRepositories extends React.Component Date: Tue, 29 Aug 2023 23:02:09 +0530 Subject: [PATCH 09/11] removed loading button Signed-off-by: msivasubramaniaan --- .../app/addRepository.tsx | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/webview/serverless-manage-repository/app/addRepository.tsx b/src/webview/serverless-manage-repository/app/addRepository.tsx index 79cdfbf21..c67129dc1 100644 --- a/src/webview/serverless-manage-repository/app/addRepository.tsx +++ b/src/webview/serverless-manage-repository/app/addRepository.tsx @@ -5,7 +5,6 @@ import * as React from 'react'; import { Button, Stack, TextField } from '@mui/material'; -import LoadingButton from '@mui/lab/LoadingButton'; import { DefaultProps } from '../../common/propertyTypes'; import './home.scss'; import { VSCodeMessage } from './vsCodeMessage'; @@ -20,8 +19,7 @@ export class AddRepository extends React.Component { constructor(props: DefaultProps | Readonly) { @@ -36,8 +34,7 @@ export class AddRepository extends React.Component { - this.setState({ - loading: true - }); VSCodeMessage.postMessage({ action: `addRepo`, data: { @@ -97,7 +91,7 @@ export class AddRepository extends React.Component @@ -152,10 +146,7 @@ export class AddRepository extends React.Component - this.addRepo()}> Add - + ) From 44eef52d3ae4f8549b0bd67e097b92a7abaae754 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Wed, 30 Aug 2023 17:30:46 +0530 Subject: [PATCH 10/11] addressed review comments Signed-off-by: msivasubramaniaan --- src/serverlessFunction/manageRepository.ts | 39 ++++++++----------- .../app/showRepositories.tsx | 2 +- .../manageRepositoryLoader.ts | 6 ++- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/serverlessFunction/manageRepository.ts b/src/serverlessFunction/manageRepository.ts index b1f8bbcba..6312fc481 100644 --- a/src/serverlessFunction/manageRepository.ts +++ b/src/serverlessFunction/manageRepository.ts @@ -6,7 +6,6 @@ import * as vscode from 'vscode'; import { OdoImpl } from '../odo'; import sendTelemetry from '../telemetry'; -import { Progress } from '../util/progress'; import { ServerlessCommand } from './commands'; export class ManageRepository { @@ -58,29 +57,25 @@ export class ManageRepository { await sendTelemetry('openshift.managerepo.add', { name, url }); - return new Promise((resolve, _reject) => { - void Progress.execFunctionWithProgress(`Adding repository ${name}`, async () => { - const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url), '', false); - if (result.error) { - await sendTelemetry('openshift.managerepo.add.error', { - error: result.error.message - }); - void vscode.window.showErrorMessage(result.error.message); - resolve(false); - } else if (result.stdout.length === 0 && result.stderr.length === 0) { - await sendTelemetry('openshift.managerepo.add.success', { - name, - message: 'Repo added successfully' - }); - void vscode.window.showInformationMessage(`Repository ${name} added successfully`); - resolve(true); - } - await sendTelemetry('openshift.managerepo.add.error', { - error: result.stderr - }); - resolve(false); + const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url), '', false); + if (result.error) { + await sendTelemetry('openshift.managerepo.add.error', { + error: result.error.message + }); + void vscode.window.showErrorMessage(result.error.message); + return false; + } else if (result.stdout.length === 0 && result.stderr.length === 0) { + await sendTelemetry('openshift.managerepo.add.success', { + name, + message: 'Repo added successfully' }); + void vscode.window.showInformationMessage(`Repository ${name} added successfully`); + return true; + } + await sendTelemetry('openshift.managerepo.add.error', { + error: result.stderr }); + return false; } public async list(): Promise { diff --git a/src/webview/serverless-manage-repository/app/showRepositories.tsx b/src/webview/serverless-manage-repository/app/showRepositories.tsx index a4e1c9dee..50ea4a8ed 100644 --- a/src/webview/serverless-manage-repository/app/showRepositories.tsx +++ b/src/webview/serverless-manage-repository/app/showRepositories.tsx @@ -189,7 +189,7 @@ export class ShowRepositories extends React.Component { + addRepoStatus = await ManageRepository.getInstance().addRepo(message.data.name, message.data.url); + }); ManageRepositoryViewLoader.panel?.webview.postMessage({ action: action, status: addRepoStatus From 2443ebb385bcbfa1e3dc43fa0cd2811c4e1816ec Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Wed, 30 Aug 2023 17:50:52 +0530 Subject: [PATCH 11/11] desc changed Signed-off-by: msivasubramaniaan --- .../serverless-manage-repository/app/showRepositories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webview/serverless-manage-repository/app/showRepositories.tsx b/src/webview/serverless-manage-repository/app/showRepositories.tsx index 50ea4a8ed..908bee332 100644 --- a/src/webview/serverless-manage-repository/app/showRepositories.tsx +++ b/src/webview/serverless-manage-repository/app/showRepositories.tsx @@ -185,7 +185,7 @@ export class ShowRepositories extends React.ComponentManage Repositories
- Manage template repositories installed on disk at either the default location (~/.config/func/repositories) or the location specified by the --repository flag. Once added, a template from the repository can be used when creating a new function. + Manage template repositories installed on disk at the default location (~/.config/func/repositories) Once added, a template from the repository can be used when creating a new function.