Skip to content

Commit 5023a41

Browse files
authored
Show all dabs resources in the explorer panel (#1525)
## Changes "Unknown" resources are shown with the "created/deleted" icons and external links (if they have been deployed already). <img width="610" alt="Screenshot 2025-01-17 at 11 51 54" src="https://github.com/user-attachments/assets/aa8f030b-8afa-422a-92c7-df38e308199f" /> <img width="633" alt="Screenshot 2025-01-17 at 11 45 11" src="https://github.com/user-attachments/assets/e974a660-c495-47d8-a0ba-71aba282f4e9" /> ## Tests <!-- How is this tested? -->
1 parent 6b5762e commit 5023a41

File tree

4 files changed

+147
-21
lines changed

4 files changed

+147
-21
lines changed

packages/databricks-vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@
11251125
"useYarn": false
11261126
},
11271127
"cli": {
1128-
"version": "0.236.0"
1128+
"version": "0.238.0"
11291129
},
11301130
"scripts": {
11311131
"vscode:prepublish": "rm -rf out && yarn run package:compile && yarn run package:wrappers:write && yarn run package:jupyter-init-script:write && yarn run package:copy-webview-toolkit && yarn run generate-telemetry",

packages/databricks-vscode/src/ui/bundle-resource-explorer/ResourceTypeHeaderTreeNode.ts

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import {JobTreeNode} from "./JobTreeNode";
66
import {
77
BundleResourceExplorerTreeItem,
88
BundleResourceExplorerTreeNode,
9+
KNOWN_RESOURCE_TYPES,
910
} from "./types";
10-
import {ExtensionContext, TreeItemCollapsibleState} from "vscode";
11+
import {ExtensionContext, ThemeIcon, TreeItemCollapsibleState} from "vscode";
1112
import {PipelineTreeNode} from "./PipelineTreeNode";
1213
import {BundlePipelinesManager} from "../../bundle/BundlePipelinesManager";
14+
import {UnknownResourceTreeNode} from "./UnknownResourceTreeNode";
15+
import {capitalize} from "lodash";
1316

1417
function humaniseResourceType(type: BundleResourceExplorerTreeNode["type"]) {
1518
switch (type) {
@@ -18,13 +21,15 @@ function humaniseResourceType(type: BundleResourceExplorerTreeNode["type"]) {
1821
case "jobs":
1922
return "Workflows";
2023
default:
21-
return type;
24+
return capitalize(type).replace(/_/g, " ");
2225
}
2326
}
27+
2428
export class ResourceTypeHeaderTreeNode
2529
implements BundleResourceExplorerTreeNode
2630
{
2731
readonly type = "resource_type_header";
32+
2833
constructor(
2934
private readonly context: ExtensionContext,
3035
private readonly resourceType: BundleResourceExplorerTreeNode["type"],
@@ -34,7 +39,11 @@ export class ResourceTypeHeaderTreeNode
3439
this.children.forEach((child) => (child.parent = this));
3540
}
3641

37-
private getIconPath(resourceType: string) {
42+
private getIconPath(resourceType: BundleResourceExplorerTreeNode["type"]) {
43+
if (!KNOWN_RESOURCE_TYPES.includes(resourceType)) {
44+
return new ThemeIcon("folder");
45+
}
46+
3847
return {
3948
dark: this.context.asAbsolutePath(
4049
path.join(
@@ -77,26 +86,47 @@ export class ResourceTypeHeaderTreeNode
7786
) {
7887
const roots: BundleResourceExplorerTreeNode[] = [];
7988

80-
const jobs = JobTreeNode.getRoots(
81-
context,
82-
bundleRunStatusManager,
83-
connectionManager,
84-
bundleRemoteState
85-
);
86-
if (jobs.length > 0) {
87-
roots.push(new ResourceTypeHeaderTreeNode(context, "jobs", jobs));
89+
for (const resourceType of KNOWN_RESOURCE_TYPES) {
90+
let resources: BundleResourceExplorerTreeNode[] = [];
91+
switch (resourceType) {
92+
case "jobs":
93+
resources = JobTreeNode.getRoots(
94+
context,
95+
bundleRunStatusManager,
96+
connectionManager,
97+
bundleRemoteState
98+
);
99+
break;
100+
case "pipelines":
101+
resources = PipelineTreeNode.getRoots(
102+
connectionManager,
103+
bundleRunStatusManager,
104+
pipelinesManager,
105+
bundleRemoteState
106+
);
107+
break;
108+
}
109+
if (resources.length > 0) {
110+
roots.push(
111+
new ResourceTypeHeaderTreeNode(
112+
context,
113+
resourceType,
114+
resources
115+
)
116+
);
117+
}
88118
}
89119

90-
const pipelines = PipelineTreeNode.getRoots(
91-
connectionManager,
92-
bundleRunStatusManager,
93-
pipelinesManager,
94-
bundleRemoteState
120+
const unknownResourceGroups = UnknownResourceTreeNode.getRootGroups(
121+
bundleRemoteState,
122+
KNOWN_RESOURCE_TYPES
95123
);
96-
if (pipelines.length > 0) {
97-
roots.push(
98-
new ResourceTypeHeaderTreeNode(context, "pipelines", pipelines)
99-
);
124+
for (const [type, resources] of unknownResourceGroups) {
125+
if (resources.length > 0) {
126+
roots.push(
127+
new ResourceTypeHeaderTreeNode(context, type, resources)
128+
);
129+
}
100130
}
101131

102132
return roots;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {ThemeIcon} from "vscode";
2+
import {BundleRemoteState} from "../../bundle/models/BundleRemoteStateModel";
3+
import {
4+
BundleResourceExplorerResourceKey,
5+
BundleResourceExplorerTreeItem,
6+
BundleResourceExplorerTreeNode,
7+
} from "./types";
8+
import {ContextUtils} from "./utils";
9+
import {DecorationUtils} from "../utils";
10+
11+
type UnknownResourcesMap = Map<
12+
BundleResourceExplorerResourceKey,
13+
BundleResourceExplorerTreeNode[]
14+
>;
15+
16+
export class UnknownResourceTreeNode implements BundleResourceExplorerTreeNode {
17+
readonly type = "unknown_resource";
18+
19+
constructor(
20+
public readonly resourceType: BundleResourceExplorerResourceKey,
21+
public readonly resourceKey: string,
22+
public readonly data: any,
23+
public parent?: BundleResourceExplorerTreeNode
24+
) {}
25+
26+
get url(): string | undefined {
27+
return this.data.url;
28+
}
29+
30+
getTreeItem(): BundleResourceExplorerTreeItem {
31+
const name =
32+
this.data.name ??
33+
this.data.display_name ??
34+
this.data.table_name ??
35+
this.data.cluster_name ??
36+
this.data.key ??
37+
this.resourceKey;
38+
39+
return {
40+
label: name,
41+
iconPath: new ThemeIcon("file"),
42+
contextValue: ContextUtils.getContextString({
43+
nodeType: "unknown_resource",
44+
resourceType: this.resourceType,
45+
hasUrl: this.url !== undefined,
46+
modifiedStatus: this.data.modified_status,
47+
}),
48+
resourceUri: DecorationUtils.getModifiedStatusDecoration(
49+
name,
50+
this.data.modified_status
51+
),
52+
};
53+
}
54+
55+
getChildren(): BundleResourceExplorerTreeNode[] {
56+
return [];
57+
}
58+
59+
static getRootGroups(
60+
bundleRemoteState: BundleRemoteState,
61+
knownResourceTypes: readonly string[]
62+
): UnknownResourcesMap {
63+
const allResources = bundleRemoteState.resources || {};
64+
const allTypes = Object.keys(
65+
allResources
66+
) as BundleResourceExplorerResourceKey[];
67+
const unknownTypes = allTypes.filter(
68+
(type) =>
69+
!knownResourceTypes.includes(type) &&
70+
Object.keys(allResources[type] || {}).length > 0
71+
) as BundleResourceExplorerResourceKey[];
72+
73+
return unknownTypes.reduce((result, type) => {
74+
const resources = allResources[type];
75+
if (resources) {
76+
result.set(
77+
type,
78+
Object.keys(resources).map((key) => {
79+
return new UnknownResourceTreeNode(
80+
type,
81+
key,
82+
resources[key]
83+
);
84+
})
85+
);
86+
}
87+
return result;
88+
}, new Map() as UnknownResourcesMap);
89+
}
90+
}

packages/databricks-vscode/src/ui/bundle-resource-explorer/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface BundleResourceExplorerTreeNode {
2020
| "pipeline_datasets"
2121
| "pipeline_dataset"
2222
| "resource_type_header"
23+
| "unknown_resource"
2324
| "task"
2425
| "job_run_status"
2526
| "task_header";
@@ -29,3 +30,8 @@ export interface BundleResourceExplorerTreeNode {
2930
| BundleResourceExplorerTreeNode[]
3031
| Promise<BundleResourceExplorerTreeNode[]>;
3132
}
33+
34+
export const KNOWN_RESOURCE_TYPES: BundleResourceExplorerTreeNode["type"][] = [
35+
"jobs",
36+
"pipelines",
37+
];

0 commit comments

Comments
 (0)