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
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,20 @@
"light": "images/title/light/icon-refresh.svg"
}
},
{
"command": "openshift.componentTypesView.registry.add",
"title": "Add Registry",
"category": "OpenShift",
"icon": {
"dark": "images/title/dark/add-cluster.svg",
"light": "images/title/light/add-cluster.svg"
}
},
{
"command": "openshift.componentTypesView.registry.remove",
"title": "Remove",
"category": "OpenSift"
},
{
"command": "openshift.welcome",
"title": "Welcome",
Expand Down Expand Up @@ -1111,9 +1125,22 @@
{
"command": "openshift.component.revealContextInExplorer",
"when": "false"
},
{
"command": "openshift.componentTypesView.registry.add",
"when": "false"
},
{
"command": "openshift.componentTypesView.registry.remove",
"when": "false"
}
],
"view/title": [
{
"command": "openshift.componentTypesView.registry.add",
"when": "view == openshiftComponentTypesView",
"group": "navigation"
},
{
"command": "openshift.componentTypesView.refresh",
"when": "view == openshiftComponentTypesView",
Expand Down Expand Up @@ -1495,6 +1522,10 @@
"when": "view == openshiftComponentTypesView && viewItem == s2iImageStreamTag || viewItem == devfileStarterProject || viewItem == devfileComponentType",
"group": "0@0"
},
{
"command": "openshift.componentTypesView.registry.remove",
"when": "view == openshiftComponentTypesView && viewItem == devfileRegistry"
},
{
"command": "openshift.component.revealInExplorer",
"when": "view == openshiftComponentsView && viewItem == openshift.component"
Expand Down
95 changes: 92 additions & 3 deletions src/componentTypesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import * as path from 'path';
import { CliExitData } from './cli';
import {
getInstance,
Odo
Odo,
OdoImpl
} from './odo';
import { Command } from './odo/command';
import {
Expand All @@ -44,6 +45,7 @@ import { vsCommand, VsCommandError } from './vscommand';
import { Cluster } from '@kubernetes/client-node/dist/config_types';
import { KubeConfig } from '@kubernetes/client-node';
import { Platform } from './util/platform';
import * as validator from 'validator';

type ExampleProject = SampleProject | StarterProject;
type ComponentType = DevfileComponentType | ImageStreamTag | ExampleProject | Cluster | Registry;
Expand Down Expand Up @@ -104,6 +106,7 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
if (isRegistry(element)) {
return {
label: element.Name,
contextValue: ContextType.DEVFILE_REGISTRY,
tooltip: `Devfile Registry\nName: ${element.Name}\nURL: ${element.URL}`,
collapsibleState: TreeItemCollapsibleState.Collapsed,
}
Expand Down Expand Up @@ -182,6 +185,21 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
return data;
}

addRegistry(newRegistry: Registry): void {
this.registries.push(newRegistry);
this.refresh(false);
this.reveal(newRegistry);

}

removeRegistry(targetRegistry: Registry): void {
this.registries.splice(
this.registries.findIndex((registry) => registry.Name === targetRegistry.Name),
1
);
this.refresh(false);
}

private async getRegistries(): Promise<Registry[]> {
if(!this.registries) {
this.registries = await this.odo.getRegistries();
Expand Down Expand Up @@ -239,8 +257,14 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
return undefined;
}

refresh(): void {
this.registries = undefined;
reveal(item: Registry): void {
this.treeView.reveal(item);
}

refresh(cleanCache = true): void {
if (cleanCache) {
this.registries = undefined;
}
this.onDidChangeTreeDataEmitter.fire();
}

Expand Down Expand Up @@ -289,4 +313,69 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
return 'Cannot find sample project repository url';
}
}

@vsCommand('openshift.componentTypesView.registry.add')
public static async addRegistryCmd(): Promise<void> {
// ask for registry
const regName = await window.showInputBox({
prompt: 'Provide registry name to display in the view',
placeHolder: 'Registry Name',
validateInput: async (value) => {
const trimmedValue = value.trim();
if (trimmedValue.length === 0) {
return 'Registry name cannot be empty'
}
if (!validator.matches(trimmedValue, '^[a-zA-Z0-9]+$')) {
return 'Registry name can have only alphabet characters and numbers';
}
const registries = await ComponentTypesView.instance.getRegistries();
if(registries.find((registry) => registry.Name === value)) {
return `Registry name '${value}' is already used`;
}
}
});

if (!regName) return null;

const regURL = await window.showInputBox({ignoreFocusOut: true,
prompt: 'Provide registry URL to display in the view',
placeHolder: 'Registry URL',
validateInput: async (value) => {
const trimmedValue = value.trim();
if (!validator.isURL(trimmedValue)) {
return 'Entered URL is invalid'
}
const registries = await ComponentTypesView.instance.getRegistries();
if(registries.find((registry) => registry.URL === value)) {
return `Registry with entered URL '${value}' already exists`;
}
}
});

if (!regURL) return null;

const secure = await window.showQuickPick(['Yes', 'No'], {
placeHolder: 'Is it a secure registry?'
});

if (!secure) return null;

let token: string;
if (secure === 'Yes') {
token = await window.showInputBox({placeHolder: 'Token to access the registry'});
if (!token) return null;
}

const newRegistry = await OdoImpl.Instance.addRegistry(regName, regURL, token);
ComponentTypesView.instance.addRegistry(newRegistry);
}

@vsCommand('openshift.componentTypesView.registry.remove')
public static async removeRegistry(registry: Registry): Promise<void> {
const yesNo = await window.showInformationMessage(`Remove registry '${registry.Name}'?`, 'Yes', 'No');
if (yesNo === 'Yes') {
await OdoImpl.Instance.removeRegistry(registry.Name);
ComponentTypesView.instance.removeRegistry(registry);
}
}
}
14 changes: 14 additions & 0 deletions src/odo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ export interface Odo {
loadItems<I>(result: cliInstance.CliExitData, fetch: (data) => I[]): I[];
getRegistries(): Promise<Registry[]>;
readonly subject: Subject<OdoEvent>;
addRegistry(name: string, url: string, token: string): Promise<Registry>;
removeRegistry(name: string): Promise<void>;
}

class OdoModel {
Expand Down Expand Up @@ -1113,6 +1115,18 @@ export class OdoImpl implements Odo {
return this.loadItemsFrom<RegistryList, Registry>(result, (data) => data.registries);
}

public async addRegistry(name: string, url: string, token: string): Promise<Registry> {
await this.execute(Command.addRegistry(name, url, token));
return {
Name: name,
Secure: true,
URL: url
};
}

public async removeRegistry(name: string): Promise<void> {
await this.execute(Command.removeRegistry(name));
}
}

export function getInstance(): Odo {
Expand Down
12 changes: 12 additions & 0 deletions src/odo/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ export class Command {
return new CommandText('odo registry list -o json');
}

static addRegistry(name: string, url: string, token: string): CommandText {
const cTxt = new CommandText('odo registry add', `${name} ${url}`);
if (token) {
cTxt.addOption(new CommandOption('--token', token));
}
return cTxt;
}

static removeRegistry(name: string): CommandText {
return new CommandText('odo registry delete', name, [new CommandOption('-f')]);
}

static listCatalogComponents(): CommandText {
return new CommandText('odo catalog list components');
}
Expand Down