Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump axios and vscode-tas-client #2

Open
wants to merge 38 commits into
base: Current
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
601c635
Cleanup
NikolaRHristov Oct 29, 2023
9eb04d1
squash!
NikolaRHristov Oct 29, 2023
ef0868c
squash!
NikolaRHristov Oct 29, 2023
26df59f
squash!
NikolaRHristov Oct 29, 2023
d776dd8
squash!
NikolaRHristov Oct 29, 2023
e3cd794
squash!
NikolaRHristov Oct 29, 2023
4cfa077
squash!
NikolaRHristov Oct 29, 2023
43e018b
squash!
NikolaRHristov Oct 30, 2023
cf49144
Merge remote-tracking branch 'upstream/main'
NikolaRHristov Nov 9, 2023
4a277ed
squash!
NikolaRHristov Nov 9, 2023
003c70f
squash!
NikolaRHristov Nov 9, 2023
7b478ba
squash!
NikolaRHristov Nov 11, 2023
1ba4168
Merge remote-tracking branch 'upstream/main'
NikolaRHristov Nov 13, 2023
c2eb702
squash!
NikolaRHristov Nov 14, 2023
3eedf2d
squash!
NikolaRHristov Nov 14, 2023
e3994b8
squash!
NikolaRHristov Nov 15, 2023
66d1de9
Merge remote-tracking branch 'upstream/main'
NikolaRHristov Nov 16, 2023
286a82d
squash!
NikolaRHristov Nov 17, 2023
06c738b
squash!
NikolaRHristov Nov 17, 2023
926ca85
squash!
NikolaRHristov Nov 17, 2023
c4d3917
squash!
NikolaRHristov Nov 18, 2023
bf4e129
squash!
NikolaRHristov Nov 18, 2023
5979865
squash!
NikolaRHristov Nov 18, 2023
9c13062
squash!
NikolaRHristov Nov 20, 2023
dc15765
squash!
NikolaRHristov Nov 20, 2023
173f560
squash!
NikolaRHristov Nov 22, 2023
1d6694b
Merge remote-tracking branch 'upstream/main'
NikolaRHristov Nov 22, 2023
9c2bb37
squash!
NikolaRHristov Nov 22, 2023
9681a9f
squash!
NikolaRHristov Nov 22, 2023
bd1f941
squash!
NikolaRHristov Nov 22, 2023
3f3f2b6
squash!
NikolaRHristov Nov 24, 2023
02dcc31
squash!
NikolaRHristov Nov 27, 2023
b7ffef7
squash!
NikolaRHristov Nov 27, 2023
31d3a6f
squash!
NikolaRHristov Nov 27, 2023
65fd310
squash!
NikolaRHristov Nov 28, 2023
0ff5e30
squash!
NikolaRHristov Nov 28, 2023
efdc9d4
Merge remote-tracking branch 'upstream/main'
NikolaRHristov Nov 28, 2023
d4d9acb
Bump axios and vscode-tas-client
dependabot[bot] Nov 28, 2023
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
204 changes: 204 additions & 0 deletions Source/AzureDBExperiences.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/* ------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { DatabaseAccountGetResults } from "@azure/arm-cosmosdb/src/models";
import { IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
import { nonNullProp } from "./utils/nonNull";

export enum API {
MongoDB = "MongoDB",
Graph = "Graph",
Table = "Table",
Core = "Core",
PostgresSingle = "PostgresSingle",
PostgresFlexible = "PostgresFlexible",
}

export enum DBAccountKind {
MongoDB = "MongoDB",
GlobalDocumentDB = "GlobalDocumentDB",
}

export type CapabilityName = "EnableGremlin" | "EnableTable";

export function getExperienceFromApi(api: API): Experience {
let info = experiencesMap.get(api);
if (!info) {
info = {
api: api,
shortName: api,
longName: api,
kind: DBAccountKind.GlobalDocumentDB,
tag: api,
};
}
return info;
}

export function getExperienceLabel(
databaseAccount: DatabaseAccountGetResults
): string {
const experience: Experience | undefined =
tryGetExperience(databaseAccount);
if (experience) {
return experience.shortName;
}
// Must be some new kind of resource that we aren't aware of. Try to get a decent label
const defaultExperience: string = <API>(
(databaseAccount &&
databaseAccount.tags &&
databaseAccount.tags.defaultExperience)
);
const firstCapability =
databaseAccount.capabilities && databaseAccount.capabilities[0];
const firstCapabilityName = firstCapability?.name?.replace(/^Enable/, "");
return (
defaultExperience ||
firstCapabilityName ||
nonNullProp(databaseAccount, "kind")
);
}

export function tryGetExperience(
resource: DatabaseAccountGetResults
): Experience | undefined {
// defaultExperience in the resource doesn't really mean anything, we can't depend on its value for determining resource type
if (resource.kind === DBAccountKind.MongoDB) {
return MongoExperience;
} else if (
resource.capabilities?.find((cap) => cap.name === "EnableGremlin")
) {
return GremlinExperience;
} else if (
resource.capabilities?.find((cap) => cap.name === "EnableTable")
) {
return TableExperience;
} else if (resource.capabilities?.length === 0) {
return CoreExperience;
}

return undefined;
}

export interface Experience {
/**
* Programmatic name used internally by us for historical reasons. Doesn't actually affect anything in Azure (maybe UI?)
*/
api: API;

longName: string;
shortName: string;
description?: string;

// These properties are what the portal actually looks at to determine the difference between APIs
kind?: DBAccountKind;
capability?: CapabilityName;

// The defaultExperience tag to place into the resource (has no actual effect in Azure, just imitating the portal)
tag?: string;
}

export function getExperienceQuickPicks(
attached?: boolean
): IAzureQuickPickItem<Experience>[] {
if (attached) {
return experiencesArray.map((exp) =>
getExperienceQuickPickForAttached(exp.api)
);
} else {
return experiencesArray.map((exp) => getExperienceQuickPick(exp.api));
}
}

export function getCosmosExperienceQuickPicks(
attached?: boolean
): IAzureQuickPickItem<Experience>[] {
if (attached) {
return cosmosExperiencesArray.map((exp) =>
getExperienceQuickPickForAttached(exp.api)
);
} else {
return cosmosExperiencesArray.map((exp) =>
getExperienceQuickPick(exp.api)
);
}
}

export function getExperienceQuickPick(
api: API
): IAzureQuickPickItem<Experience> {
const exp = getExperienceFromApi(api);
return { label: exp.longName, description: exp.description, data: exp };
}

export function getExperienceQuickPickForAttached(
api: API
): IAzureQuickPickItem<Experience> {
const exp = getExperienceFromApi(api);
return { label: exp.shortName, description: exp.description, data: exp };
}

// Mongo is distinguished by having kind="MongoDB". All others have kind="GlobalDocumentDB"
// Table and Gremlin are distinguished from SQL by their capabilities
export const CoreExperience: Experience = {
api: API.Core,
longName: "Core",
description: "(SQL)",
shortName: "SQL",
kind: DBAccountKind.GlobalDocumentDB,
tag: "Core (SQL)",
} as const;
export const MongoExperience: Experience = {
api: API.MongoDB,
longName: "Azure Cosmos DB for MongoDB API",
shortName: "MongoDB",
kind: DBAccountKind.MongoDB,
tag: "Azure Cosmos DB for MongoDB API",
} as const;
export const TableExperience: Experience = {
api: API.Table,
longName: "Azure Table",
shortName: "Table",
kind: DBAccountKind.GlobalDocumentDB,
capability: "EnableTable",
tag: "Azure Table",
} as const;
export const GremlinExperience: Experience = {
api: API.Graph,
longName: "Gremlin",
description: "(graph)",
shortName: "Gremlin",
kind: DBAccountKind.GlobalDocumentDB,
capability: "EnableGremlin",
tag: "Gremlin (graph)",
} as const;
const PostgresSingleExperience: Experience = {
api: API.PostgresSingle,
longName: "PostgreSQL Single Server",
shortName: "PostgreSQLSingle",
};
const PostgresFlexibleExperience: Experience = {
api: API.PostgresFlexible,
longName: "PostgreSQL Flexible Server",
shortName: "PostgreSQLFlexible",
};

const cosmosExperiencesArray: Experience[] = [
CoreExperience,
MongoExperience,
TableExperience,
GremlinExperience,
];
const experiencesArray: Experience[] = [
...cosmosExperiencesArray,
PostgresSingleExperience,
PostgresFlexibleExperience,
];
const experiencesMap = new Map<API, Experience>(
experiencesArray.map((info: Experience): [API, Experience] => [
info.api,
info,
])
);
120 changes: 120 additions & 0 deletions Source/DatabasesFileSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import {
AzExtTreeFileSystem,
AzExtTreeItem,
DialogResponses,
IActionContext,
UserCancelledError,
} from "@microsoft/vscode-azext-utils";
import { FileStat, FileType, MessageItem, Uri, workspace } from "vscode";
import { FileChangeType } from "vscode-languageclient";
import { ext } from "./extensionVariables";
import { localize } from "./utils/localize";
import { getWorkspaceSetting, updateGlobalSetting } from "./utils/settingUtils";
import { getNodeEditorLabel } from "./utils/vscodeUtils";

export interface IEditableTreeItem extends AzExtTreeItem {
id: string;
filePath: string;
cTime: number;
mTime: number;
getFileContent(context: IActionContext): Promise<string>;
writeFileContent(context: IActionContext, data: string): Promise<void>;
}

export class DatabasesFileSystem extends AzExtTreeFileSystem<IEditableTreeItem> {
public static scheme: string = "azureDatabases";
public scheme: string = DatabasesFileSystem.scheme;
private _showSaveConfirmation: boolean = true;

public async statImpl(
context: IActionContext,
node: IEditableTreeItem
): Promise<FileStat> {
const size: number = Buffer.byteLength(
await node.getFileContent(context)
);
return {
type: FileType.File,
ctime: node.cTime,
mtime: node.mTime,
size,
};
}

public async readFileImpl(
context: IActionContext,
node: IEditableTreeItem
): Promise<Uint8Array> {
return Buffer.from(await node.getFileContent(context));
}

public async writeFileImpl(
context: IActionContext,
node: IEditableTreeItem,
content: Uint8Array,
_originalUri: Uri
): Promise<void> {
const showSavePromptKey: string = "showSavePrompt";
// NOTE: Using "cosmosDB" instead of "azureDatabases" here for the sake of backwards compatibility. If/when this file system adds support for non-cosmosdb items, we should consider changing this to "azureDatabases"
const prefix: string = "cosmosDB";
const nodeEditorLabel: string = getNodeEditorLabel(node);
if (
this._showSaveConfirmation &&
getWorkspaceSetting<boolean>(showSavePromptKey, undefined, prefix)
) {
const message: string = localize(
"saveConfirmation",
'Saving "{0}" will update the entity "{1}" to the cloud.',
node.filePath,
nodeEditorLabel
);
const result: MessageItem | undefined =
await context.ui.showWarningMessage(
message,
{ stepName: "writeFile" },
DialogResponses.upload,
DialogResponses.alwaysUpload,
DialogResponses.dontUpload
);
if (result === DialogResponses.alwaysUpload) {
await updateGlobalSetting(showSavePromptKey, false, prefix);
} else if (result === DialogResponses.dontUpload) {
throw new UserCancelledError("dontUpload");
}
}

await node.writeFileContent(context, content.toString());
await node.refresh(context);

const updatedMessage: string = localize(
"updatedEntity",
'Updated entity "{0}".',
nodeEditorLabel
);
ext.outputChannel.appendLog(updatedMessage);
}

public getFilePath(node: IEditableTreeItem): string {
return node.filePath;
}

public async updateWithoutPrompt(uri: Uri): Promise<void> {
const textDoc = await workspace.openTextDocument(uri);
this._showSaveConfirmation = false;
try {
await textDoc.save();
} finally {
this._showSaveConfirmation = true;
}
}

public fireChangedEvent(node: IEditableTreeItem): void {
node.mTime = Date.now();
this.fireSoon({ type: FileChangeType.Changed, item: node });
}
}
30 changes: 30 additions & 0 deletions Source/ParsedConnectionString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

export abstract class ParsedConnectionString {
public abstract readonly hostName: string;
public abstract readonly port: string;

/**
* databaseName may be undefined if this is an account-level connection string
*/
public readonly databaseName: string | undefined;
public readonly connectionString: string;

constructor(connectionString: string, databaseName: string | undefined) {
this.connectionString = connectionString;
this.databaseName = databaseName;
}

public get accountId(): string {
return `${this.hostName}:${this.port}`;
}

public get fullId(): string {
return `${this.accountId}${
this.databaseName ? "/" + this.databaseName : ""
}`;
}
}
40 changes: 40 additions & 0 deletions Source/azureAccountUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzExtServiceClientCredentials } from "@microsoft/vscode-azext-utils";
import { getApiExport } from "./getExtensionApi";

const azureAccountExtensionId = "ms-vscode.azure-account";

type AzureSession = {
userId: string;
};

/**
* @returns The user session of the signed-in azure account.
*/
export async function getAzureAdUserSession(): Promise<
AzureSession | undefined
> {
const azureAccountExport = (await getApiExport(
azureAccountExtensionId
)) as { sessions?: AzureSession[] };
return azureAccountExport.sessions?.[0];
}

/**
* Gets a function that can request an access token for a specified scope for the signed-in azure account.
*/
export function getTokenFunction(
credentials: AzExtServiceClientCredentials,
scope: string
): () => Promise<string> {
return async () => {
const getTokenResult = (await credentials.getToken(scope)) as
| { token: string }
| undefined;
return getTokenResult?.token ?? "";
};
}
Loading