Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
16 changes: 9 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function migrateFromOdo018(): void {
}
}

async function verifyBundledBinaries(): Promise<{odoPath: string, ocPath: string}> {
async function verifyBundledBinaries(): Promise<{ odoPath: string, ocPath: string }> {
return {
odoPath: await ToolsConfig.detect('odo'),
ocPath: await ToolsConfig.detect('oc'),
Expand All @@ -63,8 +63,8 @@ export async function activate(extensionContext: ExtensionContext): Promise<any>
migrateFromOdo018();
Cluster.extensionContext = extensionContext;
TokenStore.extensionContext = extensionContext;
const crcStatusItem = window.createStatusBarItem(StatusBarAlignment.Left);
crcStatusItem.command = 'openshift.explorer.stopCluster';
const crcStatusItem = window.createStatusBarItem(StatusBarAlignment.Left);
crcStatusItem.command = 'openshift.explorer.stopCluster';
const disposable = [
...(await registerCommands(
'./k8s/route',
Expand Down Expand Up @@ -127,10 +127,10 @@ export async function activate(extensionContext: ExtensionContext): Promise<any>
});

function updateStatusBarItem(statusBarItem: StatusBarItem, text: string): void {
if (!workspace.getConfiguration('openshiftConnector').get('crcBinaryLocation')) {
statusBarItem.hide();
return;
}
if (!workspace.getConfiguration('openshiftConnector').get('crcBinaryLocation')) {
statusBarItem.hide();
return;
}
statusBarItem.text = `$(debug-stop) ${text}`;
statusBarItem.show();
}
Expand All @@ -142,6 +142,8 @@ export async function activate(extensionContext: ExtensionContext): Promise<any>
OdoImpl.Instance.loadWorkspaceComponents(event);
});

void ComponentTypesView.instance.getAllComponents();

OdoImpl.Instance.loadWorkspaceComponents(null);

startTelemetry(extensionContext);
Expand Down
11 changes: 0 additions & 11 deletions src/odo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ export interface Odo {
getApplicationChildren(application: OpenShiftObject): Promise<OpenShiftObject[]>;
getComponents(application: OpenShiftObject, condition?: (value: OpenShiftObject) => boolean): Promise<OpenShiftObject[]>;
getCompTypesJson():Promise<DevfileComponentType[]>;
getComponentTypesOfJSON(devFileComponents: DevfileComponentType[]):ComponentTypeAdapter[];
getComponentTypes(): Promise<ComponentTypeAdapter[]>;
getComponentChildren(component: OpenShiftObject): Promise<OpenShiftObject[]>;
getRoutes(component: OpenShiftObject): Promise<OpenShiftObject[]>;
Expand Down Expand Up @@ -645,16 +644,6 @@ export class OdoImpl implements Odo {
return compTypesJson?.items;
}

public getComponentTypesOfJSON(devFileComponents: DevfileComponentType[]): ComponentType[] {
const devfileItems: ComponentTypeAdapter[] = [];

if (devFileComponents) {
devFileComponents.map((item) => devfileItems.push(new ComponentTypeAdapter(item.Name, undefined, item.Description, undefined, item.Registry.Name)));
}

return devfileItems;
}

public async getComponentTypes(): Promise<ComponentType[]> {
// if kc is produced, KUBECONFIG env var is empty or pointing

Expand Down
72 changes: 57 additions & 15 deletions src/registriesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ import {
} from 'vscode';
import { getInstance, Odo, OdoImpl } from './odo';
import {
ComponentTypeDescription,
DevfileComponentType,
Registry,
} from './odo/componentType';
import { StarterProject } from './odo/componentTypeDescription';
import { vsCommand, VsCommandError } from './vscommand';
import validator from 'validator';
import RegistryViewLoader from './webview/devfile-registry/registryViewLoader';
import { Command } from './odo/command';
import { CliExitData } from './cli';
import { Subject } from 'rxjs';

type ComponentType = Registry;

Expand All @@ -45,6 +49,8 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {

readonly odo: Odo = getInstance();
private registries: Registry[];
private readonly compDescriptions: Set<ComponentTypeDescription> = new Set<ComponentTypeDescription>();
public subject: Subject<string> = new Subject<string>();

createTreeView(id: string): TreeView<ComponentType> {
if (!this.treeView) {
Expand Down Expand Up @@ -97,6 +103,45 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
return this.registries;
}

public getCompDescriptions(): Set<ComponentTypeDescription> {
return this.compDescriptions;
}

public getListOfRegistries(): Registry[] {
return this.registries;
}

public getAllComponents(): void {
let isError = false;
this.compDescriptions.clear();
void getInstance().getCompTypesJson().then(async (devFileComponentTypes: DevfileComponentType[]) => {
Comment thread
msivasubramaniaan marked this conversation as resolved.
const components = new Set<string>(devFileComponentTypes.map((devFileComponentType: DevfileComponentType) => devFileComponentType.Name));
await this.getRegistries();
components.forEach((compName: string) => {
getInstance().execute(Command.describeCatalogComponent(compName)).then((componentDesc: CliExitData) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const out: ComponentTypeDescription[] = JSON.parse(componentDesc.stdout);
out.forEach((component) => {
// eslint-disable-next-line max-nested-callbacks
component.Devfile?.starterProjects?.map((starter: StarterProject) => {
starter.typeName = compName;
});
this.compDescriptions.add(component);
});
if (devFileComponentTypes.length === this.compDescriptions.size) {
this.subject.next('refresh');
}
}).catch(() => {
isError = true;
}).finally(() => {
if (isError && !this.subject.closed) {
this.subject.next('refresh');
}
});
});
});
}

// eslint-disable-next-line class-methods-use-this
async getChildren(parent: ComponentType): Promise<ComponentType[]> {
let children: ComponentType[] = [];
Expand Down Expand Up @@ -227,8 +272,8 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
let token: string;
if (secure === 'Yes') {
token = await window.showInputBox({
placeHolder: 'Token to access the registry',
validateInput: (value) => value?.trim().length > 0 ? undefined : 'Token cannot be empty'
placeHolder: 'Token to access the registry',
validateInput: (value) => value?.trim().length > 0 ? undefined : 'Token cannot be empty'
});
if (!token) return null;
}
Expand All @@ -238,17 +283,17 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
*/

if (registryContext) {
const notChangedRegisty = registries.find((registry) => registry.Name === regName && registry.URL === regURL && registry.Secure === (secure === 'Yes'));
if (notChangedRegisty) {
return null;
}
await vscode.commands.executeCommand('openshift.componentTypesView.registry.remove', registryContext, true);
const notChangedRegisty = registries.find((registry) => registry.Name === regName && registry.URL === regURL && registry.Secure === (secure === 'Yes'));
if (notChangedRegisty) {
return null;
}
await vscode.commands.executeCommand('openshift.componentTypesView.registry.remove', registryContext, true);
}

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

RegistryViewLoader.refresh();
ComponentTypesView.instance.getAllComponents();
}

@vsCommand('openshift.componentTypesView.registry.remove')
Expand All @@ -261,7 +306,9 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
if (yesNo === 'Yes') {
await OdoImpl.Instance.removeRegistry(registry.Name);
ComponentTypesView.instance.removeRegistry(registry);
RegistryViewLoader.refresh();
if (!isEdit) {
ComponentTypesView.instance.getAllComponents();
}
}
}

Expand All @@ -274,9 +321,4 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
public static async openRegistryWebSite(registry: Registry): Promise<void> {
await commands.executeCommand('vscode.open', Uri.parse(registry.URL));
}

@vsCommand('openshift.componentTypesView.registry.openInView')
public static async openRegistryInWebview(): Promise<void> {
await RegistryViewLoader.loadView('Devfile Registry');
}
}
15 changes: 8 additions & 7 deletions src/webview/devfile-registry/app/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ export const Home: React.FC<DefaultProps> = ({ }) => {
const [filteredcompDescriptions, setFilteredcompDescriptions] = React.useState([]);
const [registries, setRegistries] = React.useState([]);
const [searchValue, setSearchValue] = React.useState('');
const [error, setError] = React.useState('');
const [error, setError] = React.useState(false);

React.useEffect(() => {
return VSCodeMessage.onMessage((message) => {
if (message.data.action === 'getAllComponents') {
if (message.data.error) {
setError(message.data.error);
} else {
setError('');
setError(false);
message.data.registries.map((registry: Registry) => {
if (registry.URL.toLowerCase().indexOf('https://registry.devfile.io') !== -1) {
registry.state = true;
Expand All @@ -75,10 +75,10 @@ export const Home: React.FC<DefaultProps> = ({ }) => {
setFilteredcompDescriptions(getFilteredCompDesc(message.data.registries, message.data.compDescriptions, searchValue));
}
} else if (message.data.action === 'loadingComponents') {
setError('');
setFilteredcompDescriptions([]);
setCompDescriptions([]);
setSearchValue('');
setError(false);
setFilteredcompDescriptions([]);
setCompDescriptions([]);
setSearchValue('');
}
});
});
Expand Down Expand Up @@ -120,9 +120,10 @@ export const Home: React.FC<DefaultProps> = ({ }) => {
/>
}
<HomeItem compDescriptions={filteredcompDescriptions} />
{error ? <ErrorPage message='Devfiles not downloaded properly' /> : null}
</>
:
error.length > 0 ? <ErrorPage message={error} /> : <LoadScreen />
error ? <ErrorPage message='500: Internal Sever Error' /> : <LoadScreen />
}
</>
);
Expand Down
3 changes: 3 additions & 0 deletions src/webview/devfile-registry/app/loading.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { Theme, createStyles } from '@material-ui/core/styles';

export default (theme: Theme) =>
createStyles({
loadProgress: {
color: '#EE0000'
},
loading: {
display: 'flex',
justifyContent: 'center',
Expand Down
22 changes: 15 additions & 7 deletions src/webview/devfile-registry/app/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,28 @@
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
import React from 'react';
import { makeStyles } from '@material-ui/core';
import { Box, makeStyles, Typography } from '@material-ui/core';
import LinearProgress from '@mui/material/LinearProgress';
import loaderStyle from './loading.style';

const useLoadingStyle = makeStyles(loaderStyle);

export function LoadScreen() {
const loadingStyle = useLoadingStyle();
return (
<Box className={loadingStyle.loading}>
<CircularProgress color='inherit' />
</Box>
<div className={loadingStyle.loading}>
<div style={{ width: '30rem' }}>
<Box sx={{ color: '#EE0000' }}>
<LinearProgress color='inherit' sx={{height: '1rem'}} />
</Box>
<Typography
variant='caption'
component='div'
color='inherit'
style={{ marginTop: '0.5rem', fontSize: '1.25em' }}
>Loading Registry View</Typography>
</div>
</div>
);
}
70 changes: 25 additions & 45 deletions src/webview/devfile-registry/registryViewLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,12 @@ import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import { ExtenisonID } from '../../util/constants';
import { getInstance } from '../../odo';
import { Command } from '../../odo/command';
import { stringify } from 'yaml';
import { ComponentTypesView } from '../../registriesView';
import { StarterProject } from '../../odo/componentTypeDescription';
import { DevfileComponentType } from '../../odo/componentType';
import { ComponentTypesView } from '../../registriesView'
import { vsCommand } from '../../vscommand';
import { ExtCommandTelemetryEvent } from '../../telemetry';

let panel: vscode.WebviewPanel;
let compDescriptions = new Set<any>();

async function devfileRegistryViewerMessageListener(event: any): Promise<any> {
let starterProject = event.selectedProject;
Expand Down Expand Up @@ -110,53 +105,38 @@ export default class RegistryViewLoader {
.replace('<!-- meta http-equiv="Content-Security-Policy" -->', meta);
}

@vsCommand('openshift.componentTypesView.registry.openInView')
public static async openRegistryInWebview(): Promise<void> {
await RegistryViewLoader.loadView('Devfile Registry');
}

@vsCommand('openshift.componentTypesView.registry.closeView')
static async closeRegistryInWebview(): Promise<void> {
panel?.dispose();
}

static refresh(): void {
if(panel) {
panel.webview.postMessage({action: 'loadingComponents' });
getAllComponents('getAllComponents');
}
if (panel) {
panel.webview.postMessage({ action: 'loadingComponents' });
}
}
}

function getAllComponents(eventActionName: string) {
compDescriptions.clear();
getInstance().getCompTypesJson().then(async (devFileComponentTypes: DevfileComponentType[]) => {
const components = new Set<string>();
getInstance().getComponentTypesOfJSON(devFileComponentTypes).map((comp) => {
components.add(comp.name);
});
const registries = await ComponentTypesView.instance.getRegistries();
Array.from(components).map(async (compName: string) => {
getInstance().execute(Command.describeCatalogComponent(compName)).then((componentDesc) => {
const out = JSON.parse(componentDesc.stdout);
out.forEach((component) => {
component.Devfile?.starterProjects?.map((starter: StarterProject) => {
starter.typeName = compName;
});
compDescriptions.add(component);
});
if (devFileComponentTypes.length === compDescriptions.size) {
panel.webview.postMessage(
{
action: eventActionName,
compDescriptions: Array.from(compDescriptions),
registries: registries
}
);
}
}).catch((reason) => {
panel.webview.postMessage(
{
action: eventActionName,
error: '500: Internal Server Error, Please try later'
}
);
});
});
});
const registries = ComponentTypesView.instance.getListOfRegistries();
const componentDescriptions = ComponentTypesView.instance.getCompDescriptions();
panel?.webview.postMessage(
{
action: eventActionName,
compDescriptions: Array.from(componentDescriptions),
registries: registries
}
);
}

ComponentTypesView.instance.subject.subscribe((value: string) => {
if (value === 'refresh') {
RegistryViewLoader.refresh();
getAllComponents('getAllComponents');
}
});