Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,16 @@
"command": "openshift.Serverless.invoke",
"title": "Invoke",
"category": "OpenShift"
},
{
"command": "openshift.Serverless.showInTerminal",
"title": "Show in terminal",
"category": "OpenShift"
},
{
"command": "openshift.Serverless.removeSession",
"title": "Remove Serverless Session",
"category": "OpenShift"
}
],
"keybindings": [
Expand Down Expand Up @@ -1349,6 +1359,14 @@
{
"command": "openshift.Serverless.removeGit",
"when": "false"
},
{
"command": "openshift.Serverless.showInTerminal",
"when": "false"
},
{
"command": "openshift.Serverless.removeSession",
"when": "false"
}
],
"view/title": [
Expand Down
77 changes: 44 additions & 33 deletions src/serverlessFunction/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import { CliChannel } from '../cli';
import { Oc } from '../oc/ocWrapper';
import { Odo } from '../odo/odoWrapper';
import { isTektonAware } from '../tekton/tekton';
import { Platform } from '../util/platform';
import { Progress } from '../util/progress';
import { OpenShiftTerminalApi, OpenShiftTerminalManager } from '../webview/openshift-terminal/openShiftTerminal';
import { ServerlessCommand, Utils } from './commands';
import { GitModel, getGitBranchInteractively, getGitRepoInteractively, getGitStateByPath } from './git/git';
import { isKnativeServingAware } from './knative';
import { multiStep } from './multiStepInput';
import { FunctionContent, FunctionObject, InvokeFunction } from './types';
import { FunctionContent, FunctionObject, FunctionSession } from './types';

export class Functions {

Expand Down Expand Up @@ -114,19 +113,36 @@ export class Functions {

private async clustrBuildTerminal(context: FunctionObject, namespace: string, buildImage: string, gitModel: GitModel) {
const isOpenShiftCluster = await Oc.Instance.isOpenShiftCluster();
await OpenShiftTerminalManager.getInstance().createTerminal(
const terminal = await OpenShiftTerminalManager.getInstance().createTerminal(
ServerlessCommand.onClusterBuildFunction(context.folderURI.fsPath, namespace, buildImage, gitModel, isOpenShiftCluster),
`On Cluster Build: ${context.name}`,
context.folderURI.fsPath,
process.env, {
onExit: undefined,
} , true
);
const session = {
sessionName: `On Cluster Build: ${context.name}`,
sessionPath: context.folderURI,
teminal: terminal
};
this.addSession(context, session);
void commands.executeCommand('openshift.Serverless.refresh', context);
}

private addSession(context: FunctionObject, session: FunctionSession) {
if (context.sessions?.length > 0) {
const withoutExistingSameSession = context.sessions.filter((exSession) => exSession.sessionName !== session.sessionName);
context.sessions = withoutExistingSameSession;
context.sessions.push(session);
} else {
context.sessions = [];
context.sessions.push(session);
}
}

public async build(context: FunctionObject, s2iBuild: boolean): Promise<void> {
const existingTerminal: OpenShiftTerminalApi = this.buildTerminalMap.get(`build-${context.folderURI.fsPath}`);

if (existingTerminal) {
void window.showWarningMessage(`Do you want to restart ${context.name} build ?`, 'Yes', 'No').then(async (value: string) => {
if (value === 'Yes') {
Expand All @@ -152,7 +168,7 @@ export class Functions {
const isOpenShiftCluster = await Oc.Instance.isOpenShiftCluster();
const buildImage = await this.getImage(context.folderURI);
const terminalKey = `build-${context.folderURI.fsPath}`;
await this.buildTerminal(context, s2iBuild ? 's2i' : 'pack',buildImage, isOpenShiftCluster, terminalKey);
await this.buildTerminal(context, s2iBuild ? 's2i' : 'pack', buildImage, isOpenShiftCluster, terminalKey);
}

private async buildTerminal(context: FunctionObject, builder: string, buildImage: string, isOpenShiftCluster: boolean, terminalKey: string) {
Expand All @@ -164,9 +180,17 @@ export class Functions {
{
onExit: () => {
this.buildTerminalMap.delete(terminalKey);
}
},

}, true
);
const session: FunctionSession = {
sessionName: `Build: ${context.name}`,
sessionPath: context.folderURI,
teminal: terminal
}
this.addSession(context, session);
void commands.executeCommand('openshift.Serverless.refresh', context);
this.buildTerminalMap.set(terminalKey, terminal);
}

Expand All @@ -186,6 +210,13 @@ export class Functions {
}
}, true
);
const session: FunctionSession = {
sessionName: `${runBuild ? 'Build and ' : ''}Run: ${context.name}`,
sessionPath: context.folderURI,
teminal: terminal
}
this.addSession(context, session);
void commands.executeCommand('openshift.Serverless.refresh', context);
this.runTerminalMap.set(`run-${context.folderURI.fsPath}`, terminal);
}

Expand All @@ -207,14 +238,6 @@ export class Functions {
});
}

public async getTemplates(): Promise<any[]> {
const result = await Odo.Instance.execute(ServerlessCommand.getTemplates(), undefined, false);
if (result.error) {
void window.showErrorMessage(result.error.message);
}
return JSON.parse(result.stdout) as any[];
}

public async deploy(context: FunctionObject) {
const currentNamespace: string = await Odo.Instance.getActiveProject();
const yamlContent = await Utils.getFuncYamlContent(context.folderURI.fsPath);
Expand Down Expand Up @@ -269,16 +292,14 @@ export class Functions {
},
}, true
);
}

public async invoke(functionName: string, invokeFunData: InvokeFunction): Promise<void> {
await OpenShiftTerminalManager.getInstance().createTerminal(
ServerlessCommand.invokeFunction(invokeFunData),
`Invoke: ${functionName}`,
undefined, undefined, {
onExit: undefined
}, true
);
const session = {
sessionName: `Deploy: ${context.name}`,
sessionPath: context.folderURI,
teminal: terminal
};
this.addSession(context, session);
void commands.executeCommand('openshift.Serverless.refresh', context);
}

public async config(title: string, context: FunctionObject, mode: string, isAdd = true) {
Expand Down Expand Up @@ -336,16 +357,6 @@ export class Functions {
});
}

public getDefaultImages(name: string): string[] {
const imageList: string[] = [];
const defaultUsername = Platform.getEnv();
const defaultQuayImage = `quay.io/${Platform.getOS() === 'win32' ? defaultUsername.USERNAME : defaultUsername.USER}/${name}:latest`;
const defaultDockerImage = `docker.io/${Platform.getOS() === 'win32' ? defaultUsername.USERNAME : defaultUsername.USER}/${name}:latest`;
imageList.push(defaultQuayImage);
imageList.push(defaultDockerImage);
return imageList;
}

public async getImage(folderURI: Uri): Promise<string> {
const yamlContent = await Utils.getFuncYamlContent(folderURI.fsPath);
if (yamlContent?.image && Functions.imageRegex.test(yamlContent.image)) {
Expand Down
9 changes: 9 additions & 0 deletions src/serverlessFunction/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*-----------------------------------------------------------------------------------------------*/

import { Uri } from 'vscode';
import { OpenShiftTerminalApi } from '../webview/openshift-terminal/openShiftTerminal';

export interface FunctionView {
refresh(context?: FunctionObject);
Expand Down Expand Up @@ -33,6 +34,14 @@ export interface FunctionObject {
hasImage?: boolean;
hadBuilt?: boolean;
isRunning?: boolean;
sessions?: FunctionSession[];
}

export interface FunctionSession {
sessionName: string;
sessionPath: Uri;
teminal?: OpenShiftTerminalApi;
isDone?: boolean;
}

export interface GitModel {
Expand Down
72 changes: 60 additions & 12 deletions src/serverlessFunction/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
TreeItemCollapsibleState,
TreeView,
Uri,
commands,
window,
workspace
} from 'vscode';
Expand All @@ -24,9 +25,9 @@ import ServerlessFunctionViewLoader from '../webview/serverless-function/serverl
import ManageRepositoryViewLoader from '../webview/serverless-manage-repository/manageRepositoryLoader';
import { ServerlessFunctionModel } from './functionModel';
import { Functions } from './functions';
import { FunctionContextType, FunctionObject, FunctionStatus } from './types';
import { FunctionContextType, FunctionObject, FunctionSession, FunctionStatus } from './types';

type ExplorerItem = KubernetesObject | FunctionObject | Context | TreeItem;
type ExplorerItem = KubernetesObject | FunctionObject | FunctionSession | Context | TreeItem;

export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, Disposable {
private static instance: ServerlessFunctionView;
Expand All @@ -41,6 +42,8 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D

private serverlessFunction: ServerlessFunctionModel;

private serverlessFunctionTreeNodes: Map<string, FunctionObject> = new Map();

private constructor() {
this.serverlessFunction = new ServerlessFunctionModel(this);
this.treeView = window.createTreeView<ExplorerItem>('openshiftServerlessFunctionsView', {
Expand All @@ -56,7 +59,6 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
}

getTreeItem(element: ExplorerItem): TreeItem | Thenable<TreeItem> {

if ('kind' in element) {
if (element.kind === 'project') {
return {
Expand All @@ -69,18 +71,27 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
const functionObj: FunctionObject = element;
const explorerItem: ExplorerItem = {
label: functionObj?.name,
collapsibleState: TreeItemCollapsibleState.None
collapsibleState: element.sessions?.length > 0 ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None
}
if (functionObj.context !== FunctionStatus.NONE) {
explorerItem.iconPath = new ThemeIcon('symbol-function'),
explorerItem.iconPath = new ThemeIcon('symbol-function'),
explorerItem.description = this.getDescription(functionObj.context),
explorerItem.tooltip = this.getTooltip(functionObj),
explorerItem.contextValue = this.getContext(functionObj),
explorerItem.command = this.getCommand(functionObj);
}
return explorerItem;
} else if ('sessionName' in element) {
const functionSession: FunctionSession = element;
const explorerItem: ExplorerItem = {
label: element.sessionName.substring(0, element.sessionName.indexOf(':')).trim(),
collapsibleState: TreeItemCollapsibleState.None,
iconPath: new ThemeIcon('symbol-value'),
}
explorerItem.contextValue = 'FunctionSession';
explorerItem.command = this.getSessionCommand(functionSession)
return explorerItem;
}

}

getContext(functionObj: FunctionObject): string {
Expand All @@ -104,6 +115,10 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
return { command: 'openshift.Serverless.openFunction', title: 'Open Function', arguments: [functionObj] };
}

getSessionCommand(functionSession: FunctionSession): Command {
return { command: 'openshift.Serverless.showInTerminal', title: 'Show in terminal', arguments: [functionSession] };
}

getTooltip(functionObj: FunctionObject): string {
let text = '';
if (functionObj.name) {
Expand All @@ -128,13 +143,15 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
let result: ExplorerItem[] = [];
if (!element) {
result = [...await this.serverlessFunction.getLocalFunctions()]
if (result.length === 0) {
const functionNode: FunctionObject = {
name: 'No Available Functions',
context: FunctionStatus.NONE
}
result = [functionNode]
if (result.length === 0) {
const functionNode: FunctionObject = {
name: 'No Available Functions',
context: FunctionStatus.NONE
}
result = [functionNode]
}
} else if ('sessions' in element && element.sessions.length > 0) {
result = [...this.processSessions(element)];
}
return result;
}
Expand Down Expand Up @@ -226,6 +243,15 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
);
}

@vsCommand('openshift.Serverless.showInTerminal')
static async openTerminal(context: FunctionSession) {
if (!context || context.isDone) {
return null;
}
await commands.executeCommand('openShiftTerminalView.focus');
context.teminal.focusTerminal();
}

@vsCommand('openshift.Serverless.addEnv')
static async addEnv(context: FunctionObject) {
await Functions.getInstance().config(`Add environment variables '${context.name}'`, context, 'envs');
Expand Down Expand Up @@ -265,4 +291,26 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
static async removeGit(context: FunctionObject) {
await Functions.getInstance().config(`Remove Git '${context.name}'`, context, 'git', false);
}

@vsCommand('openshift.Serverless.removeSession')
static removeSesson(uuid: string ,cwdPath: string, sessionName: string) {
if (ServerlessFunctionView.getInstance().serverlessFunctionTreeNodes.has(cwdPath)) {
const element = ServerlessFunctionView.getInstance().serverlessFunctionTreeNodes.get(cwdPath);
const index = element.sessions.findIndex((session) => session.sessionName === sessionName && session.teminal.id === uuid);
if(index !== -1) {
element.sessions.splice(index, 1);
ServerlessFunctionView.getInstance().refresh(element);
}
}
}

processSessions(element: FunctionObject): FunctionSession[] {
const functionSessions: FunctionSession[] = [];
this.serverlessFunctionTreeNodes.set(element.folderURI.fsPath, element);
const treeNode = this.serverlessFunctionTreeNodes.get(element.folderURI.fsPath);
treeNode.sessions.forEach((session: FunctionSession) => {
functionSessions.push(session);
});
return functionSessions;
}
}
Loading