Skip to content

Commit 6914a31

Browse files
1 parent f325f34 commit 6914a31

File tree

6 files changed

+97
-22
lines changed

6 files changed

+97
-22
lines changed

packages/databricks-vscode/src/configuration/ConnectionCommands.ts

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import {Cluster, Repo} from "@databricks/databricks-sdk";
1+
import {Cluster, Repo, WorkspaceService} from "@databricks/databricks-sdk";
22
import {homedir} from "node:os";
33
import {resolve} from "node:path";
44
import {
55
Disposable,
66
QuickPickItem,
7+
QuickPickItemKind,
78
ThemeIcon,
89
Uri,
910
window,
@@ -12,6 +13,7 @@ import {
1213
import {ClusterListDataProvider} from "../cluster/ClusterListDataProvider";
1314
import {ClusterModel} from "../cluster/ClusterModel";
1415
import {ConnectionManager} from "./ConnectionManager";
16+
import {UrlUtils} from "../utils";
1517

1618
function formatQuickPickClusterSize(sizeInMB: number): string {
1719
if (sizeInMB > 1024) {
@@ -37,8 +39,8 @@ export function formatQuickPickClusterDetails(cluster: Cluster) {
3739
}
3840

3941
export interface WorkspaceItem extends QuickPickItem {
40-
id: number;
41-
path: string;
42+
id?: number;
43+
path?: string;
4244
}
4345

4446
export interface ClusterItem extends QuickPickItem {
@@ -170,32 +172,59 @@ export class ConnectionCommands implements Disposable {
170172

171173
quickPick.busy = true;
172174
quickPick.canSelectMany = false;
175+
const items: WorkspaceItem[] = [
176+
{
177+
label: "Create New Repo",
178+
detail: `Open databricks in browser and create a new repo under /Repo/${me}`,
179+
alwaysShow: true,
180+
},
181+
{
182+
label: "",
183+
kind: QuickPickItemKind.Separator,
184+
},
185+
];
186+
quickPick.items = items;
187+
173188
quickPick.show();
174189

175190
let repos = await Repo.list(apiClient, {
176191
// eslint-disable-next-line @typescript-eslint/naming-convention
177192
path_prefix: `/Repos/${me}`,
178193
});
179194

180-
quickPick.items = repos!.map((r) => ({
181-
label: r.path.split("/").pop() || "",
182-
detail: r.path,
183-
path: r.path,
184-
id: r.id,
185-
}));
195+
quickPick.items = items.concat(
196+
...repos!.map((r) => ({
197+
label: r.path.split("/").pop() || "",
198+
detail: r.path,
199+
path: r.path,
200+
id: r.id,
201+
}))
202+
);
186203
quickPick.busy = false;
187204

188205
await new Promise<void>((resolve) => {
189206
quickPick.onDidAccept(async () => {
190-
const repoPath = quickPick.selectedItems[0].path;
191-
await this.connectionManager.attachSyncDestination(
192-
Uri.from({
193-
scheme: "dbws",
194-
path: repoPath,
195-
})
196-
);
197-
quickPick.dispose();
198-
resolve();
207+
if (
208+
quickPick.selectedItems[0].label === "Create New Repo"
209+
) {
210+
await UrlUtils.openExternal(
211+
`${
212+
(
213+
await this.connectionManager.apiClient?.host
214+
)?.href ?? ""
215+
}#folder/${this.connectionManager.repoRootId ?? ""}`
216+
);
217+
} else {
218+
const repoPath = quickPick.selectedItems[0].path;
219+
await this.connectionManager.attachSyncDestination(
220+
Uri.from({
221+
scheme: "dbws",
222+
path: repoPath,
223+
})
224+
);
225+
quickPick.dispose();
226+
resolve();
227+
}
199228
});
200229

201230
quickPick.onDidHide(() => {

packages/databricks-vscode/src/configuration/ConnectionManager.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
CredentialProvider,
66
WorkspaceConf,
77
scim,
8+
WorkspaceService,
9+
HttpError,
810
} from "@databricks/databricks-sdk";
911
import {
1012
env,
@@ -19,6 +21,7 @@ import {SyncDestination} from "./SyncDestination";
1921
import {ProjectConfigFile} from "./ProjectConfigFile";
2022
import {selectProfile} from "./selectProfileWizard";
2123
import {ClusterManager} from "../cluster/ClusterManager";
24+
import {workspace} from "@databricks/databricks-sdk";
2225
import {DatabricksWorkspace} from "./DatabricksWorkspace";
2326

2427
const extensionVersion = require("../../package.json").version;
@@ -37,6 +40,7 @@ export class ConnectionManager {
3740
private _syncDestination?: SyncDestination;
3841
private _projectConfigFile?: ProjectConfigFile;
3942
private _clusterManager?: ClusterManager;
43+
private _repoRootDetails?: workspace.ObjectInfo;
4044
private _databricksWorkspace?: DatabricksWorkspace;
4145

4246
private readonly onDidChangeStateEmitter: EventEmitter<ConnectionState> =
@@ -71,6 +75,9 @@ export class ConnectionManager {
7175
return this._syncDestination;
7276
}
7377

78+
get repoRootId() {
79+
return this._repoRootDetails?.object_id;
80+
}
7481
get databricksWorkspace(): DatabricksWorkspace | undefined {
7582
return this._databricksWorkspace;
7683
}
@@ -180,6 +187,18 @@ export class ConnectionManager {
180187
this.updateSyncDestination(undefined);
181188
}
182189

190+
try {
191+
this._repoRootDetails = await new WorkspaceService(
192+
apiClient
193+
).getStatus({
194+
path: `/Repos/${this.databricksWorkspace?.userName}`,
195+
});
196+
} catch (e) {
197+
if (!(e instanceof HttpError && e.code === 404)) {
198+
throw e;
199+
}
200+
}
201+
183202
this.updateState("CONNECTED");
184203
}
185204

@@ -192,6 +211,7 @@ export class ConnectionManager {
192211

193212
this._projectConfigFile = undefined;
194213
this._apiClient = undefined;
214+
this._repoRootDetails = undefined;
195215
this._databricksWorkspace = undefined;
196216
this.updateCluster(undefined);
197217
this.updateSyncDestination(undefined);

packages/databricks-vscode/src/utils/UtilsCommands.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import {Disposable, env, TreeItem, Uri, window} from "vscode";
2+
import {openExternal} from "./urlUtils";
23

34
export class UtilsCommands implements Disposable {
45
private disposables: Disposable[] = [];
56
constructor() {}
67

78
openExternalCommand() {
89
return async (value: TreeItem) => {
9-
const url = `${value.description}`.startsWith("http")
10-
? `${value.description}`
11-
: `https://${value.description}`;
12-
await env.openExternal(Uri.parse(url, true));
10+
await openExternal(`${value.description}`);
1311
};
1412
}
1513

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export * from "./fileUtils";
2+
export * as UrlUtils from "./urlUtils";
3+
export * from "./UtilsCommands";
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import assert from "assert";
2+
import {addHttpsIfNoProtocol} from "./urlUtils";
3+
4+
describe(__filename, () => {
5+
it("should add https if the url does not have it", () => {
6+
assert(
7+
addHttpsIfNoProtocol("www.example.com"),
8+
"https://www.example.com"
9+
);
10+
});
11+
12+
it("should not add https if url has it", () => {
13+
assert(
14+
addHttpsIfNoProtocol("https://www.example.com"),
15+
"https://www.example.com"
16+
);
17+
});
18+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {env, Uri} from "vscode";
2+
3+
export function addHttpsIfNoProtocol(url: string) {
4+
return `${url}`.startsWith("http") ? `${url}` : `https://${url}`;
5+
}
6+
export async function openExternal(url: string) {
7+
await env.openExternal(Uri.parse(addHttpsIfNoProtocol(url), true));
8+
}

0 commit comments

Comments
 (0)