Skip to content

Commit

Permalink
pull views work from PR #22 over
Browse files Browse the repository at this point in the history
  • Loading branch information
devhawk committed Mar 18, 2024
1 parent cf0d19c commit cc8901e
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 7 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 39 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@
"commands": [
{
"command": "dbos-ttdbg.cloud-login",
"title": "Log into DBOS Cloud",
"category": "DBOS"
"title": "Log Into DBOS Cloud",
"category": "DBOS",
"icon": "$(log-in)"
},
{
"command": "dbos-ttdbg.delete-domain-credentials",
"title": "Delete Stored DBOS Cloud Credentials",
"category": "DBOS",
"icon": "$(log-out)"
},
{
"command": "dbos-ttdbg.delete-stored-passwords",
Expand Down Expand Up @@ -64,6 +71,36 @@
"type": "string"
}
}
},
"menus": {
"view/item/context": [
{
"command": "dbos-ttdbg.cloud-login",
"when": "view == dbos-ttdbg.views.resources && viewItem == cloudDomain",
"group": "inline"
},
{
"command": "dbos-ttdbg.delete-domain-credentials",
"when": "view == dbos-ttdbg.views.resources && viewItem == cloudDomain"
}
]
},
"views": {
"dbos-cloud": [
{
"id": "dbos-ttdbg.views.resources",
"name": "Resources"
}
]
},
"viewsContainers": {
"activitybar": [
{
"id": "dbos-cloud",
"title": "DBOS Cloud",
"icon": "resources/dbos-logo.png"
}
]
}
},
"scripts": {
Expand Down
Binary file added resources/dbos-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
132 changes: 132 additions & 0 deletions src/CloudDataProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import * as vscode from 'vscode';
import { DbosCloudApp, DbosCloudDatabase, DbosCloudCredentials, listApps, listDatabases, getCloudOptions, authenticate, isTokenExpired } from './dbosCloudApi';
import { config } from './extension';

interface CloudServiceType {
serviceType: "Applications" | "Databases";
serviceDomain: string;
};

export interface CloudDomain {
domain: string;
};

type CloudProviderNode = CloudDomain | DbosCloudApp | DbosCloudDatabase | CloudServiceType;

function isDomain(node: CloudProviderNode): node is CloudDomain {
return "domain" in node;
}

function isServiceType(node: CloudProviderNode): node is CloudServiceType {
return "serviceType" in node && "serviceDomain" in node;
}

function isCloudDatabase(node: CloudProviderNode): node is DbosCloudDatabase {
return "PostgresInstanceName" in node
&& "HostName" in node
&& "Status" in node
&& "Port" in node
&& "DatabaseUsername" in node
&& "AdminUsername" in node;
}

function isCloudApp(node: CloudProviderNode): node is DbosCloudApp {
return "Name" in node
&& "ID" in node
&& "PostgresInstanceName" in node
&& "ApplicationDatabaseName" in node
&& "Status" in node
&& "Version" in node
&& "AppURL" in node;
}

function domainSecretKey(domain: string) { return `dbos-ttdbg:domain:${domain}`; }

export class CloudDataProvider implements vscode.TreeDataProvider<CloudProviderNode> {
private readonly onDidChangeTreeDataEmitter = new vscode.EventEmitter<CloudProviderNode | CloudProviderNode[] | undefined | null | void>();
readonly onDidChangeTreeData = this.onDidChangeTreeDataEmitter.event;

private readonly domains = new Set<string>();

constructor() {
const { cloudDomain } = getCloudOptions();
this.domains.add(cloudDomain);
}

async #getCredentials(domain: string): Promise<DbosCloudCredentials | undefined> {
const storedCredentials = await config.getStoredCloudCredentials(domain);
if (storedCredentials) {
return storedCredentials;
}
return await config.cloudLogin(domain);
}

async getChildren(element?: CloudProviderNode | undefined): Promise<CloudProviderNode[]> {
if (element === undefined) {
const children = new Array<CloudDomain>();
for (const domain of this.domains) {
children.push({ domain });
}
return children;
}

if (isDomain(element)) {
return [
{ serviceDomain: element.domain, serviceType: "Applications" },
{ serviceDomain: element.domain, serviceType: "Databases" },
];
}

if (isServiceType(element)) {
const credentials = await this.#getCredentials(element.serviceDomain);
if (!credentials) { return []; }
switch (element.serviceType) {
case "Applications":
return await listApps(credentials);
case "Databases":
return await listDatabases(credentials);
default:
throw new Error(`Unknown serviceType: ${element.serviceType}`);
}
}

return [];
}

getTreeItem(element: CloudProviderNode): vscode.TreeItem | Thenable<vscode.TreeItem> {
if (isDomain(element)) {
return {
label: element.domain,
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
contextValue: "cloudDomain",
};
}

if (isServiceType(element)) {
const contextValue = element.serviceType === "Applications" ? "cloudApps" : "cloudDatabases";
return {
label: element.serviceType,
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
contextValue
};
}

if (isCloudApp(element)) {
return {
label: element.Name,
collapsibleState: vscode.TreeItemCollapsibleState.None,
contextValue: "cloudApp",
};
}

if (isCloudDatabase(element)) {
return {
label: element.PostgresInstanceName,
collapsibleState: vscode.TreeItemCollapsibleState.None,
contextValue: "cloudDatabase",
};
}

throw new Error(`Unknown element type: ${JSON.stringify(element)}`);
}
}
17 changes: 17 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { logger, debugProxy, config } from './extension';
import { getDebugConfigFolder, getWorkspaceFolder } from './utils';
import { DbosMethodInfo } from './ProvenanceDatabase';
import { startDebugging, showWorkflowPick, validateCredentials } from './userFlows';
import { CloudDomain } from './CloudDataProvider';

export const cloudLoginCommandName = "dbos-ttdbg.cloud-login";
export async function cloudLogin(host?: string) {
Expand All @@ -22,6 +23,22 @@ export function shutdownDebugProxy() {
}
}

export const deleteDomainCredentialsCommandName = "dbos-ttdbg.delete-domain-credentials";
export async function deleteDomainCredentials(cloudDomain?: CloudDomain) {
if (!cloudDomain) {
logger.warn("deleteDomainCredentials: no domain provided");
return;
}

try {
logger.info("deleteDomainCredentials", { domain: cloudDomain.domain });
await config.deleteStoredCloudCredentials(cloudDomain.domain);
} catch (e) {
logger.error("shutdownDebugProxy", e);
}
}


export const deleteStoredPasswordsCommandName = "dbos-ttdbg.delete-stored-passwords";
export async function deleteStoredPasswords() {
try {
Expand Down
12 changes: 8 additions & 4 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ export class Configuration {
return credentials;
}

async deleteStoredCloudCredentials(host?: string) {
const { cloudDomain } = getCloudOptions(host);
const secretKey = domainSecretKey(cloudDomain);
await this.secrets.delete(secretKey);
logger.debug("Deleted DBOS Cloud credentials", { cloudDomain });
}

async getCloudConfig(folder: vscode.WorkspaceFolder, credentials: DbosCloudCredentials): Promise<CloudConfig> {
const cloudConfig = await vscode.window.withProgress(
{ location: vscode.ProgressLocation.Window },
Expand Down Expand Up @@ -183,10 +190,7 @@ export class Configuration {
}

async deletePasswords() {
const { cloudDomain } = getCloudOptions();
const secretKey = domainSecretKey(cloudDomain);
await this.secrets.delete(secretKey);
logger.debug("Deleted DBOS Cloud credentials", { cloudDomain });
await this.deleteStoredCloudCredentials();

const set = await this.#getDatabaseKeySet();
for (const key of set) {
Expand Down
9 changes: 8 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as vscode from 'vscode';
import { S3CloudStorage } from './CloudStorage';
import { TTDbgCodeLensProvider } from './codeLensProvider';
import { deleteStoredPasswords, deleteStoredPasswordsCommandName, shutdownDebugProxyCommandName, shutdownDebugProxy, cloudLoginCommandName, cloudLogin, startDebuggingCodeLensCommandName, startDebuggingFromCodeLens, startDebuggingFromUri, startDebuggingUriCommandName, getProxyUrl, getProxyUrlCommandName, pickWorkflowIdCommandName, pickWorkflowId } from './commands';
import { deleteStoredPasswords, deleteStoredPasswordsCommandName, shutdownDebugProxyCommandName, shutdownDebugProxy, cloudLoginCommandName, cloudLogin, startDebuggingCodeLensCommandName, startDebuggingFromCodeLens, startDebuggingFromUri, startDebuggingUriCommandName, getProxyUrl, getProxyUrlCommandName, pickWorkflowIdCommandName, pickWorkflowId, deleteDomainCredentials, deleteDomainCredentialsCommandName } from './commands';
import { Configuration } from './configuration';
import { DebugProxy, } from './DebugProxy';
import { LogOutputChannelTransport, Logger, createLogger } from './logger';
import { ProvenanceDatabase } from './ProvenanceDatabase';
import { TTDbgUriHandler } from './uriHandler';
import { CloudDataProvider } from './CloudDataProvider';

export let logger: Logger;
export let config: Configuration;
Expand All @@ -32,6 +33,7 @@ export async function activate(context: vscode.ExtensionContext) {

context.subscriptions.push(
vscode.commands.registerCommand(cloudLoginCommandName, cloudLogin),
vscode.commands.registerCommand(deleteDomainCredentialsCommandName, deleteDomainCredentials),
vscode.commands.registerCommand(deleteStoredPasswordsCommandName, deleteStoredPasswords),
vscode.commands.registerCommand(shutdownDebugProxyCommandName, shutdownDebugProxy),
vscode.commands.registerCommand(startDebuggingCodeLensCommandName, startDebuggingFromCodeLens),
Expand All @@ -40,9 +42,14 @@ export async function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand(getProxyUrlCommandName, getProxyUrl),
vscode.commands.registerCommand(pickWorkflowIdCommandName, pickWorkflowId),

vscode.window.registerTreeDataProvider(
"dbos-ttdbg.views.resources",
new CloudDataProvider()),

vscode.languages.registerCodeLensProvider(
{ scheme: 'file', language: 'typescript' },
new TTDbgCodeLensProvider()),

vscode.window.registerUriHandler(new TTDbgUriHandler())
);

Expand Down

0 comments on commit cc8901e

Please sign in to comment.