diff --git a/package-lock.json b/package-lock.json index 20206129..bbe44a51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@kubernetes/client-node": "^0.18.1", "@types/ws": "^8.5.4", - "@vscode/extension-telemetry": "^0.4.7", + "@vscode/extension-telemetry": "^0.6.0", "bufferutil": "^4.0.7", "change-case": "^4.1.2", "extract-zip": "^2.0.1", @@ -62,7 +62,7 @@ }, "engines": { "npm": ">=7.0.0", - "vscode": "^1.63.0" + "vscode": "^1.82.0" } }, "node_modules/@discoveryjs/json-ext": { @@ -560,6 +560,48 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, + "node_modules/@microsoft/1ds-core-js": { + "version": "3.2.13", + "resolved": "https://registry.npmjs.org/@microsoft/1ds-core-js/-/1ds-core-js-3.2.13.tgz", + "integrity": "sha512-CluYTRWcEk0ObG5EWFNWhs87e2qchJUn0p2D21ZUa3PWojPZfPSBs4//WIE0MYV8Qg1Hdif2ZTwlM7TbYUjfAg==", + "dependencies": { + "@microsoft/applicationinsights-core-js": "2.8.15", + "@microsoft/applicationinsights-shims": "^2.0.2", + "@microsoft/dynamicproto-js": "^1.1.7" + } + }, + "node_modules/@microsoft/1ds-post-js": { + "version": "3.2.13", + "resolved": "https://registry.npmjs.org/@microsoft/1ds-post-js/-/1ds-post-js-3.2.13.tgz", + "integrity": "sha512-HgS574fdD19Bo2vPguyznL4eDw7Pcm1cVNpvbvBLWiW3x4e1FCQ3VMXChWnAxCae8Hb0XqlA2sz332ZobBavTA==", + "dependencies": { + "@microsoft/1ds-core-js": "3.2.13", + "@microsoft/applicationinsights-shims": "^2.0.2", + "@microsoft/dynamicproto-js": "^1.1.7" + } + }, + "node_modules/@microsoft/applicationinsights-core-js": { + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.15.tgz", + "integrity": "sha512-yYAs9MyjGr2YijQdUSN9mVgT1ijI1FPMgcffpaPmYbHAVbQmF7bXudrBWHxmLzJlwl5rfep+Zgjli2e67lwUqQ==", + "dependencies": { + "@microsoft/applicationinsights-shims": "2.0.2", + "@microsoft/dynamicproto-js": "^1.1.9" + }, + "peerDependencies": { + "tslib": "*" + } + }, + "node_modules/@microsoft/applicationinsights-shims": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.2.tgz", + "integrity": "sha512-PoHEgsnmcqruLNHZ/amACqdJ6YYQpED0KSRe6J7gIJTtpZC1FfFU9b1fmDKDKtFoUSrPzEh1qzO3kmRZP0betg==" + }, + "node_modules/@microsoft/dynamicproto-js": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.9.tgz", + "integrity": "sha512-n1VPsljTSkthsAFYdiWfC+DKzK2WwcRp83Y1YAqdX552BstvsDjft9YXppjUzp11BPsapDoO1LDgrDB0XVsfNQ==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -949,9 +991,13 @@ "dev": true }, "node_modules/@vscode/extension-telemetry": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.4.7.tgz", - "integrity": "sha512-tXjChgxFN6EAfa6LIy/PE3fIbIvj0BnELUmGAG+8tUpsLY3g2iACcVM/UJJXtsU6db29tMqCLITUX2Dd3N06GA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz", + "integrity": "sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w==", + "dependencies": { + "@microsoft/1ds-core-js": "^3.2.3", + "@microsoft/1ds-post-js": "^3.2.3" + }, "engines": { "vscode": "^1.60.0" } @@ -1177,6 +1223,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -2803,9 +2858,9 @@ } }, "node_modules/is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dependencies": { "has": "^1.0.3" }, @@ -4039,12 +4094,16 @@ "dev": true }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4485,6 +4544,17 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tapable": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", @@ -4690,8 +4760,7 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -5090,15 +5159,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/acorn-import-assertions": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz", - "integrity": "sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5535,6 +5595,45 @@ } } }, + "@microsoft/1ds-core-js": { + "version": "3.2.13", + "resolved": "https://registry.npmjs.org/@microsoft/1ds-core-js/-/1ds-core-js-3.2.13.tgz", + "integrity": "sha512-CluYTRWcEk0ObG5EWFNWhs87e2qchJUn0p2D21ZUa3PWojPZfPSBs4//WIE0MYV8Qg1Hdif2ZTwlM7TbYUjfAg==", + "requires": { + "@microsoft/applicationinsights-core-js": "2.8.15", + "@microsoft/applicationinsights-shims": "^2.0.2", + "@microsoft/dynamicproto-js": "^1.1.7" + } + }, + "@microsoft/1ds-post-js": { + "version": "3.2.13", + "resolved": "https://registry.npmjs.org/@microsoft/1ds-post-js/-/1ds-post-js-3.2.13.tgz", + "integrity": "sha512-HgS574fdD19Bo2vPguyznL4eDw7Pcm1cVNpvbvBLWiW3x4e1FCQ3VMXChWnAxCae8Hb0XqlA2sz332ZobBavTA==", + "requires": { + "@microsoft/1ds-core-js": "3.2.13", + "@microsoft/applicationinsights-shims": "^2.0.2", + "@microsoft/dynamicproto-js": "^1.1.7" + } + }, + "@microsoft/applicationinsights-core-js": { + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.15.tgz", + "integrity": "sha512-yYAs9MyjGr2YijQdUSN9mVgT1ijI1FPMgcffpaPmYbHAVbQmF7bXudrBWHxmLzJlwl5rfep+Zgjli2e67lwUqQ==", + "requires": { + "@microsoft/applicationinsights-shims": "2.0.2", + "@microsoft/dynamicproto-js": "^1.1.9" + } + }, + "@microsoft/applicationinsights-shims": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.2.tgz", + "integrity": "sha512-PoHEgsnmcqruLNHZ/amACqdJ6YYQpED0KSRe6J7gIJTtpZC1FfFU9b1fmDKDKtFoUSrPzEh1qzO3kmRZP0betg==" + }, + "@microsoft/dynamicproto-js": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.9.tgz", + "integrity": "sha512-n1VPsljTSkthsAFYdiWfC+DKzK2WwcRp83Y1YAqdX552BstvsDjft9YXppjUzp11BPsapDoO1LDgrDB0XVsfNQ==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5823,9 +5922,13 @@ "dev": true }, "@vscode/extension-telemetry": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.4.7.tgz", - "integrity": "sha512-tXjChgxFN6EAfa6LIy/PE3fIbIvj0BnELUmGAG+8tUpsLY3g2iACcVM/UJJXtsU6db29tMqCLITUX2Dd3N06GA==" + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz", + "integrity": "sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w==", + "requires": { + "@microsoft/1ds-core-js": "^3.2.3", + "@microsoft/1ds-post-js": "^3.2.3" + } }, "@vscode/test-electron": { "version": "2.1.3", @@ -6026,6 +6129,13 @@ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "requires": {} + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -7286,9 +7396,9 @@ } }, "is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "requires": { "has": "^1.0.3" } @@ -8237,12 +8347,13 @@ "dev": true }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -8561,6 +8672,11 @@ "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "tapable": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", @@ -8709,8 +8825,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { "version": "3.21.0", @@ -8929,15 +9044,6 @@ "terser-webpack-plugin": "^5.1.3", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" - }, - "dependencies": { - "acorn-import-assertions": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz", - "integrity": "sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==", - "dev": true, - "requires": {} - } } }, "webpack-cli": { diff --git a/package.json b/package.json index 7a2f6111..02f0c3be 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "publisher": "weaveworks", "icon": "resources/icons/gitops-logo.png", "engines": { - "vscode": "^1.63.0", + "vscode": "^1.82.0", "npm": ">=7.0.0" }, "categories": [ @@ -644,7 +644,7 @@ "dependencies": { "@kubernetes/client-node": "^0.18.1", "@types/ws": "^8.5.4", - "@vscode/extension-telemetry": "^0.4.7", + "@vscode/extension-telemetry": "^0.6.0", "bufferutil": "^4.0.7", "change-case": "^4.1.2", "extract-zip": "^2.0.1", diff --git a/src/cli/kubernetes/apiResources.ts b/src/cli/kubernetes/apiResources.ts index 5f844fd6..059dff31 100644 --- a/src/cli/kubernetes/apiResources.ts +++ b/src/cli/kubernetes/apiResources.ts @@ -1,4 +1,4 @@ -import { redrawhResourcesTreeViews, refreshResourcesTreeViews } from 'commands/refreshTreeViews'; +import { redrawResourcesTreeViews, refreshResourcesTreeViews } from 'commands/refreshTreeViews'; import { currentContextData } from 'data/contextData'; import { setVSCodeContext, telemetry } from 'extension'; import { ContextId } from 'types/extensionIds'; @@ -52,7 +52,7 @@ export async function loadAvailableResourceKinds() { context.apiResources = undefined; context.apiState = ApiState.Loading; // will set their content to Loading API... - redrawhResourcesTreeViews(); + redrawResourcesTreeViews(); const kindsShellResult = await invokeKubectlCommand('api-resources --verbs=list -o wide'); if (kindsShellResult?.code !== 0) { @@ -62,7 +62,7 @@ export async function loadAvailableResourceKinds() { setVSCodeContext(ContextId.ClusterUnreachable, true); clusterDataProvider.updateCurrentContextChildNodes(); refreshResourcesTreeViews(); - redrawhResourcesTreeViews(); + redrawResourcesTreeViews(); return; } diff --git a/src/commands/kubectlApply.ts b/src/commands/kubectlApply.ts index 6300b1b8..7eb4d631 100644 --- a/src/commands/kubectlApply.ts +++ b/src/commands/kubectlApply.ts @@ -1,12 +1,14 @@ import * as shell from 'cli/shell/exec'; -import { Uri } from 'vscode'; +import { Uri, window } from 'vscode'; export async function kubectlApplyPath(uri?: Uri) { + uri ??= window.activeTextEditor?.document.uri; if(uri) { return await shell.execWithOutput(`kubectl apply -f ${uri.fsPath}`); } } export async function kubectlDeletePath(uri?: Uri) { + uri ??= window.activeTextEditor?.document.uri; if(uri) { return await shell.execWithOutput(`kubectl delete -f ${uri.fsPath}`); } diff --git a/src/commands/refreshTreeViews.ts b/src/commands/refreshTreeViews.ts index 6fd2b562..4c6fdbe3 100644 --- a/src/commands/refreshTreeViews.ts +++ b/src/commands/refreshTreeViews.ts @@ -30,7 +30,7 @@ export function refreshResourcesTreeViews() { reloadTemplatesTreeView(); } -export function redrawhResourcesTreeViews() { +export function redrawResourcesTreeViews() { sourceDataProvider.redraw(); workloadDataProvider.redraw(); templateDateProvider.redraw(); diff --git a/src/data/telemetry.ts b/src/data/telemetry.ts index 2e31d9bc..909db5fd 100644 --- a/src/data/telemetry.ts +++ b/src/data/telemetry.ts @@ -40,6 +40,7 @@ export class Telemetry { this.context = context; const key = '9a491deb-120a-4a6e-8893-f528d4f6bd9c'; this.reporter = new TelemetryReporter(extensionId, extensionVersion, key); + context.subscriptions.push(this.reporter); } /** diff --git a/src/ui/treeviews/dataProviders/asyncDataProvider.ts b/src/ui/treeviews/dataProviders/asyncDataProvider.ts index aae63317..4afbbd71 100644 --- a/src/ui/treeviews/dataProviders/asyncDataProvider.ts +++ b/src/ui/treeviews/dataProviders/asyncDataProvider.ts @@ -2,6 +2,7 @@ import { ApiState } from 'cli/kubernetes/apiResources'; import { KubeConfigState, kubeConfigState } from 'cli/kubernetes/kubernetesConfig'; import { ContextData, ViewData, currentContextData } from 'data/contextData'; import { InfoNode, infoNodes } from 'utils/makeTreeviewInfoNode'; +import { NamespaceNode } from '../nodes/namespaceNode'; import { TreeNode } from '../nodes/treeNode'; import { clusterDataProvider } from '../treeViews'; import { SimpleDataProvider } from './simpleDataProvider'; @@ -72,8 +73,12 @@ export class AsyncDataProvider extends SimpleDataProvider{ viewData.nodes = await this.loadRootNodes(); viewData.loadCollapsibleStates(); viewData.loading = false; - console.log(`finish loading ${context.contextName} ${this.constructor.name}`); + this.nodes.forEach(node => { + if(node instanceof NamespaceNode) { + node.updateLabel(); + } + }); this.redraw(); } diff --git a/src/ui/treeviews/dataProviders/sourceDataProvider.ts b/src/ui/treeviews/dataProviders/sourceDataProvider.ts index 54e8600c..78743c5e 100644 --- a/src/ui/treeviews/dataProviders/sourceDataProvider.ts +++ b/src/ui/treeviews/dataProviders/sourceDataProvider.ts @@ -50,6 +50,7 @@ export class SourceDataProvider extends KubernetesObjectDataProvider { for (const helmRepository of sortByMetadataName(helmRepositories)) { sourceNodes.push(new HelmRepositoryNode(helmRepository)); + const x = new HelmRepositoryNode(helmRepository); } // add buckets to the tree diff --git a/src/ui/treeviews/dataProviders/workloadDataProvider.ts b/src/ui/treeviews/dataProviders/workloadDataProvider.ts index b6c6bbba..bd7bc7f0 100644 --- a/src/ui/treeviews/dataProviders/workloadDataProvider.ts +++ b/src/ui/treeviews/dataProviders/workloadDataProvider.ts @@ -62,7 +62,7 @@ export class WorkloadDataProvider extends KubernetesObjectDataProvider { * @param workloadNode target workload node */ async updateWorkloadChildren(workloadNode: WorkloadNode) { - workloadNode.children = [new TreeNode('Loading...')]; + workloadNode.children = infoNodes(InfoNode.Loading); if (workloadNode instanceof KustomizationNode) { this.updateKustomizationChildren(workloadNode); diff --git a/src/ui/treeviews/nodes/namespaceNode.ts b/src/ui/treeviews/nodes/namespaceNode.ts index 3513b81d..60560837 100644 --- a/src/ui/treeviews/nodes/namespaceNode.ts +++ b/src/ui/treeviews/nodes/namespaceNode.ts @@ -29,19 +29,25 @@ export class NamespaceNode extends TreeNode { updateLabel(withIcons = true) { const totalLength = this.children.length; let readyLength = 0; + let loadingLength = 0; for(const child of this.children) { if(child instanceof SourceNode || child instanceof WorkloadNode) { - if(!child.isReconcileFailed) { + if(child.resourceIsReady) { readyLength++; + } else if(child.resourceIsProgressing) { + loadingLength++; } } else { readyLength++; } } + const validLength = readyLength + loadingLength; if(withIcons) { if(readyLength === totalLength) { this.setIcon(TreeNodeIcon.Success); + } else if(validLength === totalLength) { + this.setIcon(TreeNodeIcon.Progressing); } else { this.setIcon(TreeNodeIcon.Warning); } @@ -50,7 +56,7 @@ export class NamespaceNode extends TreeNode { } if(this.collapsibleState === TreeItemCollapsibleState.Collapsed) { - const lengthLabel = totalLength === readyLength ? `${totalLength}` : `${readyLength}/${totalLength}`; + const lengthLabel = totalLength === validLength ? `${totalLength}` : `${validLength}/${totalLength}`; this.label = `${this.resource.metadata?.name} (${lengthLabel})`; } else { this.label = `${this.resource.metadata?.name}`; diff --git a/src/ui/treeviews/nodes/source/bucketNode.ts b/src/ui/treeviews/nodes/source/bucketNode.ts index 351ec3e9..3754c156 100644 --- a/src/ui/treeviews/nodes/source/bucketNode.ts +++ b/src/ui/treeviews/nodes/source/bucketNode.ts @@ -6,21 +6,10 @@ import { SourceNode } from './sourceNode'; * Defines Bucket tree view item for display in GitOps Sources tree view. */ export class BucketNode extends SourceNode { - /** * Bucket kubernetes resource object */ - resource: Bucket; - - /** - * Creates new bucket tree view item for display. - * @param bucket Bucket kubernetes object info. - */ - constructor(bucket: Bucket) { - super(`${Kind.Bucket}: ${bucket.metadata?.name}`, bucket); - - this.resource = bucket; - } + resource!: Bucket; get contexts() { return [Kind.Bucket]; diff --git a/src/ui/treeviews/nodes/source/gitRepositoryNode.ts b/src/ui/treeviews/nodes/source/gitRepositoryNode.ts index 11eaf9c1..a3535c6e 100644 --- a/src/ui/treeviews/nodes/source/gitRepositoryNode.ts +++ b/src/ui/treeviews/nodes/source/gitRepositoryNode.ts @@ -7,21 +7,8 @@ import { SourceNode } from './sourceNode'; * Defines GitRepository tree view item for display in GitOps Sources tree view. */ export class GitRepositoryNode extends SourceNode { + resource!: GitRepository; - /** - * Git repository kubernetes resource object - */ - resource: GitRepository; - - /** - * Creates new git repository tree view item for display. - * @param gitRepository Git repository kubernetes object info. - */ - constructor(gitRepository: GitRepository) { - super(`${Kind.GitRepository}: ${gitRepository.metadata?.name}`, gitRepository); - - this.resource = gitRepository; - } get contexts() { const contextsArr: string[] = [Kind.GitRepository]; diff --git a/src/ui/treeviews/nodes/source/helmRepositoryNode.ts b/src/ui/treeviews/nodes/source/helmRepositoryNode.ts index aab22ed6..9358dd7d 100644 --- a/src/ui/treeviews/nodes/source/helmRepositoryNode.ts +++ b/src/ui/treeviews/nodes/source/helmRepositoryNode.ts @@ -7,21 +7,8 @@ import { SourceNode } from './sourceNode'; * Defines HelmRepository tree view item for display in GitOps Sources tree view. */ export class HelmRepositoryNode extends SourceNode { + resource!: HelmRepository; - /** - * Helm repository kubernetes resource object - */ - resource: HelmRepository; - - /** - * Creates new helm repository tree view item for display. - * @param helmRepository Helm repository kubernetes object info. - */ - constructor(helmRepository: HelmRepository) { - super(`${Kind.HelmRepository}: ${helmRepository.metadata?.name}`, helmRepository); - - this.resource = helmRepository; - } get contexts() { const contextsArr: string[] = [Kind.HelmRepository]; diff --git a/src/ui/treeviews/nodes/source/ociRepositoryNode.ts b/src/ui/treeviews/nodes/source/ociRepositoryNode.ts index 7787fa53..09cc9fdb 100644 --- a/src/ui/treeviews/nodes/source/ociRepositoryNode.ts +++ b/src/ui/treeviews/nodes/source/ociRepositoryNode.ts @@ -7,20 +7,14 @@ import { SourceNode } from './sourceNode'; * Defines OCIRepository tree view item for display in GitOps Sources tree view. */ export class OCIRepositoryNode extends SourceNode { - - /** - * OCI repository kubernetes resource object - */ - resource: OCIRepository; + resource!: OCIRepository; /** * Creates new oci repository tree view item for display. * @param ociRepository OCI repository kubernetes object info. */ constructor(ociRepository: OCIRepository) { - super(`${Kind.OCIRepository}: ${ociRepository.metadata?.name}`, ociRepository); - - this.resource = ociRepository; + super(ociRepository); } get contexts() { diff --git a/src/ui/treeviews/nodes/source/sourceNode.ts b/src/ui/treeviews/nodes/source/sourceNode.ts index 365d28d0..d7a2ae04 100644 --- a/src/ui/treeviews/nodes/source/sourceNode.ts +++ b/src/ui/treeviews/nodes/source/sourceNode.ts @@ -1,94 +1,15 @@ -import { MarkdownString } from 'vscode'; -import { Bucket } from 'types/flux/bucket'; -import { GitRepository } from 'types/flux/gitRepository'; -import { HelmRepository } from 'types/flux/helmRepository'; import { FluxSourceObject } from 'types/flux/object'; -import { OCIRepository } from 'types/flux/ociRepository'; -import { Condition } from 'types/kubernetes/kubernetesTypes'; -import { createMarkdownError, createMarkdownHr, createMarkdownTable } from 'utils/markdownUtils'; import { shortenRevision } from 'utils/stringUtils'; -import { TreeNode, TreeNodeIcon } from '../treeNode'; - +import { ToolkitNode } from './toolkitNode'; /** * Base class for all the Source tree view items. */ -export class SourceNode extends TreeNode { - - resource: FluxSourceObject; - - /** - * Whether or not the source failed to reconcile. - */ - isReconcileFailed = false; - - constructor(label: string, source: FluxSourceObject) { - super(label); - - this.resource = source; - - // update reconciliation status - this.updateStatus(); - } - - get tooltip() { - return this.getMarkdownHover(this.resource); - } +export class SourceNode extends ToolkitNode { + resource!: FluxSourceObject; - // @ts-ignore - get description() { - const isSuspendIcon = this.resource.spec?.suspend ? '⏸ ' : ''; - let revisionOrError = ''; - - if (this.isReconcileFailed) { - revisionOrError = `${this.findReadyOrFirstCondition(this.resource.status.conditions)?.reason || ''}`; - } else { - revisionOrError = shortenRevision(this.resource.status.artifact?.revision); - } - - return `${isSuspendIcon}${revisionOrError}`; + get revision() { + return shortenRevision(this.resource.status.artifact?.revision); } - /** - * Creates markdwon string for Source tree view item tooltip. - * @param source GitRepository, HelmRepository or Bucket kubernetes object. - * @returns Markdown string to use for Source tree view item tooltip. - */ - getMarkdownHover(source: GitRepository | OCIRepository | HelmRepository | Bucket): MarkdownString { - const markdown: MarkdownString = createMarkdownTable(source); - - // show status in hover when source fetching failed - if (this.isReconcileFailed) { - const readyCondition = this.findReadyOrFirstCondition(source.status.conditions); - createMarkdownHr(markdown); - createMarkdownError('Status message', readyCondition?.message, markdown); - createMarkdownError('Status reason', readyCondition?.reason, markdown); - } - - return markdown; - } - - /** - * Find condition with the "Ready" type or - * return first one if "Ready" not found. - * - * @param conditions "status.conditions" of the source - */ - findReadyOrFirstCondition(conditions?: Condition[]): Condition | undefined { - return conditions?.find(condition => condition.type === 'Ready') || conditions?.[0]; - } - - /** - * Update source status with showing error icon when fetch failed. - * @param source target source - */ - updateStatus(): void { - if (this.findReadyOrFirstCondition(this.resource.status.conditions)?.status === 'True') { - this.setIcon(TreeNodeIcon.Success); - this.isReconcileFailed = false; - } else { - this.setIcon(TreeNodeIcon.Error); - this.isReconcileFailed = true; - } - } } diff --git a/src/ui/treeviews/nodes/source/toolkitNode.ts b/src/ui/treeviews/nodes/source/toolkitNode.ts new file mode 100644 index 00000000..2e2491f7 --- /dev/null +++ b/src/ui/treeviews/nodes/source/toolkitNode.ts @@ -0,0 +1,92 @@ +import { FluxObject } from 'types/flux/object'; +import { Condition } from 'types/kubernetes/kubernetesTypes'; +import { createMarkdownError, createMarkdownHr, createMarkdownTable } from 'utils/markdownUtils'; +import { TreeNode, TreeNodeIcon } from '../treeNode'; + +export enum ReconcileState { + Ready, + Failed, + Progressing, +} + +export class ToolkitNode extends TreeNode { + resource: FluxObject; + reconcileState: ReconcileState = ReconcileState.Progressing; + + constructor(resource: FluxObject) { + super(`${resource.kind}: ${resource.metadata?.name || 'unknown'}`); + + this.resource = resource; + this.updateStatus(); + } + + /** + * Update status with showing error icon when fetch failed. + * @param source target source + */ + updateStatus() { + const condition = this.readyOrFirstCondition; + if (condition?.status === 'True') { + this.reconcileState = ReconcileState.Ready; + this.setIcon(TreeNodeIcon.Success); + } else if (condition?.reason === 'Progressing') { + this.reconcileState = ReconcileState.Progressing; + this.setIcon(TreeNodeIcon.Progressing); + } else { + this.reconcileState = ReconcileState.Failed; + this.setIcon(TreeNodeIcon.Error); + } + } + + /** + * Find condition with the "Ready" type or + * return first one if "Ready" not found. + */ + get readyOrFirstCondition(): Condition | undefined { + const conditions = this.resource.status.conditions; + + if (Array.isArray(conditions)) { + return conditions.find(condition => condition.type === 'Ready') || conditions[0]; + } else { + return conditions; + } + } + + get tooltip() { + const markdown = createMarkdownTable(this.resource); + // show status in hoverwhat failed + if (!this.resourceIsReady) { + createMarkdownHr(markdown); + createMarkdownError('Status message', this.readyOrFirstCondition?.message, markdown); + createMarkdownError('Status reason', this.readyOrFirstCondition?.reason, markdown); + } + + return markdown; + } + + get resourceIsReady(): boolean { + return this.reconcileState === ReconcileState.Ready; + } + + get resourceIsProgressing(): boolean { + return this.reconcileState === ReconcileState.Progressing; + } + + // @ts-ignore + get description() { + const isSuspendIcon = this.resource.spec?.suspend ? '⏸ ' : ''; + let revisionOrError = ''; + + if (!this.resourceIsReady) { + revisionOrError = `${this.readyOrFirstCondition?.reason || ''}`; + } else { + revisionOrError = this.revision; + } + + return `${isSuspendIcon}${revisionOrError}`; + } + + get revision(): string { + return 'unknown'; + } +} diff --git a/src/ui/treeviews/nodes/treeNode.ts b/src/ui/treeviews/nodes/treeNode.ts index 9f5fbbfd..9dcac84c 100644 --- a/src/ui/treeviews/nodes/treeNode.ts +++ b/src/ui/treeviews/nodes/treeNode.ts @@ -12,6 +12,8 @@ export const enum TreeNodeIcon { Warning = 'warning', Success = 'success', Disconnected = 'disconnected', + Progressing = 'progressing', + Loading = 'loading', Unknown = 'unknown', } @@ -77,6 +79,10 @@ export class TreeNode extends TreeItem { this.iconPath = new ThemeIcon('warning', new ThemeColor('editorWarning.foreground')); } else if (icon === TreeNodeIcon.Disconnected) { this.iconPath = new ThemeIcon('sync-ignored', new ThemeColor('editorError.foreground')); + } else if (icon === TreeNodeIcon.Progressing) { + this.iconPath = new ThemeIcon('sync~spin', new ThemeColor('terminal.ansiGreen')); + } else if (icon === TreeNodeIcon.Loading) { + this.iconPath = new ThemeIcon('loading~spin', new ThemeColor('foreground')); } else if (icon === TreeNodeIcon.Success) { this.iconPath = new ThemeIcon('pass', new ThemeColor('terminal.ansiGreen')); } else if (icon === TreeNodeIcon.Unknown) { diff --git a/src/ui/treeviews/nodes/workload/helmReleaseNode.ts b/src/ui/treeviews/nodes/workload/helmReleaseNode.ts index 2d283bfc..38165c67 100644 --- a/src/ui/treeviews/nodes/workload/helmReleaseNode.ts +++ b/src/ui/treeviews/nodes/workload/helmReleaseNode.ts @@ -7,20 +7,14 @@ import { WorkloadNode } from './workloadNode'; * Defines Helm release tree view item for display in GitOps Workloads tree view. */ export class HelmReleaseNode extends WorkloadNode { - - /** - * Helm release kubernetes resource object - */ - resource: HelmRelease; + resource!: HelmRelease; /** * Creates new helm release tree view item for display. * @param helmRelease Helm release kubernetes object info. */ constructor(helmRelease: HelmRelease) { - super(helmRelease.metadata?.name || '', helmRelease); - - this.resource = helmRelease; + super(helmRelease); this.makeCollapsible(); } diff --git a/src/ui/treeviews/nodes/workload/kustomizationNode.ts b/src/ui/treeviews/nodes/workload/kustomizationNode.ts index 45af035f..586355dc 100644 --- a/src/ui/treeviews/nodes/workload/kustomizationNode.ts +++ b/src/ui/treeviews/nodes/workload/kustomizationNode.ts @@ -1,5 +1,5 @@ -import { Kind } from 'types/kubernetes/kubernetesTypes'; import { Kustomization } from 'types/flux/kustomization'; +import { Kind } from 'types/kubernetes/kubernetesTypes'; import { NodeContext } from 'types/nodeContext'; import { WorkloadNode } from './workloadNode'; @@ -7,19 +7,14 @@ import { WorkloadNode } from './workloadNode'; * Defines Kustomization tree view item for display in GitOps Workload tree view. */ export class KustomizationNode extends WorkloadNode { - /** - * Kustomize kubernetes resource object - */ - resource: Kustomization; + resource!: Kustomization; /** * Creates new app kustomization tree view item for display. * @param kustomization Kustomize kubernetes object info. */ constructor(kustomization: Kustomization) { - super(kustomization.metadata?.name || '', kustomization); - - this.resource = kustomization; + super(kustomization); this.makeCollapsible(); } diff --git a/src/ui/treeviews/nodes/workload/workloadNode.ts b/src/ui/treeviews/nodes/workload/workloadNode.ts index d0dfb1d7..02853c22 100644 --- a/src/ui/treeviews/nodes/workload/workloadNode.ts +++ b/src/ui/treeviews/nodes/workload/workloadNode.ts @@ -1,97 +1,14 @@ -import { MarkdownString } from 'vscode'; - -import { HelmRelease } from 'types/flux/helmRelease'; -import { Kustomization } from 'types/flux/kustomization'; import { FluxWorkloadObject } from 'types/flux/object'; -import { Condition } from 'types/kubernetes/kubernetesTypes'; -import { createMarkdownError, createMarkdownHr, createMarkdownTable } from 'utils/markdownUtils'; import { shortenRevision } from 'utils/stringUtils'; -import { TreeNode, TreeNodeIcon } from '../treeNode'; +import { ToolkitNode } from '../source/toolkitNode'; /** * Base class for all Workload tree view items. */ -export class WorkloadNode extends TreeNode { - - /** - * Whether or not the application failed to reconcile. - */ - isReconcileFailed = false; - - resource: FluxWorkloadObject; - - constructor(label: string, resource: FluxWorkloadObject) { - super(`${resource.kind}: ${label}`); - - this.resource = resource; - - this.updateStatus(); - } - - /** - * Find condition with the "Ready" type or - * return first one if "Ready" not found. - * - * @param conditions "status.conditions" of the workload - */ - findReadyOrFirstCondition(conditions?: Condition | Condition[]): Condition | undefined { - if (Array.isArray(conditions)) { - return conditions.find(condition => condition.type === 'Ready') || conditions[0]; - } else { - return conditions; - } - } - - /** - * Update workload status with showing error icon when reconcile has failed. - * @param workload target resource - */ - updateStatus(): void { - const condition = this.findReadyOrFirstCondition(this.resource.status.conditions); - - if (condition?.status === 'True') { - this.isReconcileFailed = false; - this.setIcon(TreeNodeIcon.Success); - } else { - this.isReconcileFailed = true; - this.setIcon(TreeNodeIcon.Error); - } - } - - get tooltip() { - const md = this.getMarkdownHover(this.resource); - return md; - } - - // @ts-ignore - get description() { - const isSuspendIcon = this.resource.spec?.suspend ? '⏸ ' : ''; - let revisionOrError = ''; - - if (this.isReconcileFailed) { - revisionOrError = `${this.findReadyOrFirstCondition(this.resource.status.conditions)?.reason || ''}`; - } else { - revisionOrError = shortenRevision(this.resource.status.lastAppliedRevision); - } - return `${isSuspendIcon}${revisionOrError}`; - } - - /** - * Creates markdwon string for Source tree view item tooltip. - * @param workload Kustomize or HelmRelease kubernetes object. - * @returns Markdown string to use for Source tree view item tooltip. - */ - getMarkdownHover(workload: Kustomization | HelmRelease): MarkdownString { - const markdown: MarkdownString = createMarkdownTable(workload); - - // show status in hover when source fetching failed - if (this.isReconcileFailed) { - const readyCondition = this.findReadyOrFirstCondition(workload.status.conditions); - createMarkdownHr(markdown); - createMarkdownError('Status message', readyCondition?.message, markdown); - createMarkdownError('Status reason', readyCondition?.reason, markdown); - } +export class WorkloadNode extends ToolkitNode { + resource!: FluxWorkloadObject; - return markdown; + get revision() { + return shortenRevision(this.resource.status.lastAppliedRevision); } } diff --git a/src/ui/treeviews/treeViews.ts b/src/ui/treeviews/treeViews.ts index 7374cb12..2f4c3951 100644 --- a/src/ui/treeviews/treeViews.ts +++ b/src/ui/treeviews/treeViews.ts @@ -87,7 +87,8 @@ function listenCollapsableState() { workloadTreeView.onDidCollapseElement(e => { if (e.element instanceof NamespaceNode) { e.element.collapsibleState = TreeItemCollapsibleState.Collapsed; - e.element.updateLabel(); + const showIcons = workloadDataProvider.nodes.includes(e.element); + e.element.updateLabel(showIcons); workloadDataProvider.redraw(e.element); } }); @@ -95,7 +96,8 @@ function listenCollapsableState() { workloadTreeView.onDidExpandElement(e => { if (e.element instanceof NamespaceNode) { e.element.collapsibleState = TreeItemCollapsibleState.Expanded; - e.element.updateLabel(); + const showIcons = workloadDataProvider.nodes.includes(e.element); + e.element.updateLabel(showIcons); workloadDataProvider.redraw(e.element); } }); diff --git a/src/utils/makeTreeviewInfoNode.ts b/src/utils/makeTreeviewInfoNode.ts index 1e71a9b7..f2028821 100644 --- a/src/utils/makeTreeviewInfoNode.ts +++ b/src/utils/makeTreeviewInfoNode.ts @@ -25,9 +25,13 @@ export function infoNode(type: InfoNode) { case InfoNode.NoResources: return new TreeNode('No Resources'); case InfoNode.Loading: - return new TreeNode('Loading...'); + node = new TreeNode('Loading...'); + node.setIcon(TreeNodeIcon.Loading); + return node; case InfoNode.LoadingApi: - return new TreeNode('Loading API...'); + node = new TreeNode('Loading API...'); + node.setIcon(TreeNodeIcon.Loading); + return node; case InfoNode.ClusterUnreachable: const name = kubeConfig.currentContext; node = new TreeNode(`Cluster ${name} unreachable`);