From 73cb86583aebcbb9136d6d6c99c8484929aeeed6 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Tue, 18 Aug 2020 15:25:49 +0300 Subject: [PATCH] Refactor views management Signed-off-by: Lauri Nevala --- .gitignore | 2 +- integration/helpers/utils.ts | 8 +- integration/specs/app_spec.ts | 15 +- locales/en/messages.po | 370 +++++++++--------- locales/fi/messages.po | 364 +++++++++-------- locales/ru/messages.po | 366 ++++++++--------- package.json | 39 +- src/common/base-store.ts | 4 - src/common/cluster-ipc.ts | 15 +- src/common/cluster-store.ts | 20 +- src/common/cluster-store_test.ts | 333 ++++++++++++++++ src/common/ipc.ts | 115 +++--- src/common/kube-helpers.ts | 5 +- src/common/tracker.ts | 3 +- src/common/user-store.ts | 10 +- src/common/user-store_test.ts | 102 +++++ src/common/utils/defineGlobal.ts | 12 + src/common/vars.ts | 19 +- src/common/workspace-store.ts | 15 +- src/common/workspace-store_test.ts | 128 ++++++ src/main/cluster-manager.ts | 31 +- src/main/cluster.ts | 14 +- src/main/index.ts | 14 +- src/main/menu.ts | 168 +++++--- src/main/router.ts | 8 +- src/main/routes/metrics-route.ts | 6 +- src/main/routes/port-forward-route.ts | 21 +- src/main/window-manager.ts | 39 +- src/renderer/api/kube-api-parse.ts | 5 +- src/renderer/api/kube-api-parse_test.ts | 13 + src/renderer/browser-check.tsx | 20 - .../components/+add-cluster/add-cluster.scss | 9 + .../components/+add-cluster/add-cluster.tsx | 48 +-- .../cluster-settings.route.ts | 10 +- .../+cluster-settings/cluster-settings.scss | 127 +++--- .../+cluster-settings/cluster-settings.tsx | 47 ++- .../components/cluster-home-dir-setting.tsx | 101 ++--- .../components/cluster-icon-setting.tsx | 64 +-- .../components/cluster-name-setting.tsx | 93 ++--- .../components/cluster-prometheus-setting.tsx | 114 ++++-- .../components/cluster-proxy-setting.tsx | 118 ++---- .../components/cluster-workspace-setting.tsx | 50 +-- .../components/install-feature.tsx | 93 +++++ .../components/install-metrics.tsx | 109 ------ .../components/install-user-mode.tsx | 108 ----- .../components/remove-cluster-button.tsx | 58 +-- .../+cluster-settings/components/statuses.ts | 24 -- .../components/+cluster-settings/features.tsx | 36 +- .../components/+cluster-settings/general.tsx | 2 - .../components/+cluster-settings/removal.tsx | 12 +- .../components/+cluster-settings/status.tsx | 39 +- .../resource-quota-details.tsx | 48 ++- .../+network-services/service-details.tsx | 10 +- .../service-port-component.scss | 22 ++ .../service-port-component.tsx | 48 +++ .../+network-services/service-ports.scss | 24 -- .../+network-services/service-ports.tsx | 54 --- .../components/+preferences/preferences.scss | 56 ++- .../components/+preferences/preferences.tsx | 162 ++++---- .../components/+whats-new/whats-new.tsx | 3 +- .../+workloads-deployments/deployments.tsx | 2 +- .../+workloads-pods/pod-container-port.scss | 23 ++ .../+workloads-pods/pod-container-port.tsx | 54 +++ .../+workloads-pods/pod-details-container.tsx | 12 +- .../+workloads-pods/pod-logs-dialog.tsx | 2 +- src/renderer/components/app-init/app-init.tsx | 1 - src/renderer/components/app.scss | 6 +- src/renderer/components/app.tsx | 12 +- .../components/cluster-icon/cluster-icon.scss | 7 +- .../components/cluster-icon/cluster-icon.tsx | 4 +- .../cluster-manager/cluster-manager.scss | 21 +- .../cluster-manager/cluster-manager.tsx | 65 ++- .../cluster-manager/cluster-status.route.ts | 8 - .../cluster-manager/cluster-status.scss | 3 + .../cluster-manager/cluster-status.tsx | 107 ++--- .../cluster-manager/cluster-view.route.ts | 46 +++ .../cluster-manager/cluster-view.scss | 5 + .../cluster-manager/cluster-view.tsx | 21 + .../cluster-manager/clusters-menu.tsx | 30 +- .../components/cluster-manager/lens-views.ts | 43 ++ .../components/file-picker/file-picker.scss | 19 +- .../components/file-picker/file-picker.tsx | 6 +- src/renderer/components/input/input.scss | 2 +- src/renderer/components/input/input.tsx | 1 + .../components/input/input.validators.ts | 7 +- .../components/input/input.validators_test.ts | 48 +++ .../components/layout/main-layout.tsx | 3 +- .../components/layout/wizard-layout.scss | 27 ++ .../components/layout/wizard-layout.tsx | 24 +- src/renderer/components/select/select.scss | 6 +- src/renderer/lens-app.tsx | 4 + src/renderer/navigation.ts | 16 +- src/renderer/utils/convertCpu.ts | 13 +- src/renderer/utils/convertMemory.ts | 10 +- src/renderer/utils/index.ts | 1 + src/renderer/utils/metricUnitsToNumber.ts | 10 + .../utils/metricUnitsToNumber_test.ts | 15 + types/mocks.d.ts | 3 + webpack.dll.ts | 4 +- webpack.main.ts | 5 +- webpack.renderer.ts | 7 +- yarn.lock | 184 +++------ 102 files changed, 2845 insertions(+), 2015 deletions(-) create mode 100644 src/common/cluster-store_test.ts create mode 100644 src/common/user-store_test.ts create mode 100755 src/common/utils/defineGlobal.ts create mode 100644 src/common/workspace-store_test.ts delete mode 100644 src/renderer/browser-check.tsx create mode 100644 src/renderer/components/+cluster-settings/components/install-feature.tsx delete mode 100644 src/renderer/components/+cluster-settings/components/install-metrics.tsx delete mode 100644 src/renderer/components/+cluster-settings/components/install-user-mode.tsx delete mode 100644 src/renderer/components/+cluster-settings/components/statuses.ts create mode 100644 src/renderer/components/+network-services/service-port-component.scss create mode 100644 src/renderer/components/+network-services/service-port-component.tsx delete mode 100644 src/renderer/components/+network-services/service-ports.scss delete mode 100644 src/renderer/components/+network-services/service-ports.tsx create mode 100644 src/renderer/components/+workloads-pods/pod-container-port.scss create mode 100644 src/renderer/components/+workloads-pods/pod-container-port.tsx delete mode 100644 src/renderer/components/cluster-manager/cluster-status.route.ts create mode 100644 src/renderer/components/cluster-manager/cluster-view.route.ts create mode 100644 src/renderer/components/cluster-manager/cluster-view.scss create mode 100644 src/renderer/components/cluster-manager/cluster-view.tsx create mode 100644 src/renderer/components/cluster-manager/lens-views.ts create mode 100644 src/renderer/components/input/input.validators_test.ts create mode 100644 src/renderer/utils/metricUnitsToNumber.ts create mode 100644 src/renderer/utils/metricUnitsToNumber_test.ts diff --git a/.gitignore b/.gitignore index 2381ff83b1..53701a44d2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ node_modules/ yarn-error.log coverage/ tmp/ -static/build/client/ +static/build/** binaries/client/ binaries/server/ locales/**/**.js diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index 3e3fc60add..72d6e3d732 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -3,13 +3,13 @@ import { Application } from "spectron"; let appPath = "" switch(process.platform) { case "win32": - appPath = "./dist/win-unpacked/LensDev.exe" + appPath = "./dist/win-unpacked/Lens.exe" break case "linux": appPath = "./dist/linux-unpacked/kontena-lens" break case "darwin": - appPath = "./dist/mac/LensDev.app/Contents/MacOS/LensDev" + appPath = "./dist/mac/Lens.app/Contents/MacOS/Lens" break } @@ -20,6 +20,10 @@ export function setup(): Application { path: appPath, startTimeout: 30000, waitTimeout: 30000, + chromeDriverArgs: ['remote-debugging-port=9222'], + env: { + CICD: "true" + } }) } diff --git a/integration/specs/app_spec.ts b/integration/specs/app_spec.ts index 79f867b53a..f3cb922740 100644 --- a/integration/specs/app_spec.ts +++ b/integration/specs/app_spec.ts @@ -1,7 +1,6 @@ import { Application } from "spectron" import * as util from "../helpers/utils" import { spawnSync } from "child_process" -import { stat } from "fs" jest.setTimeout(20000) @@ -11,19 +10,21 @@ describe("app start", () => { let app: Application const clickWhatsNew = async (app: Application) => { await app.client.waitUntilTextExists("h1", "What's new") - await app.client.click("button.btn-primary") + await app.client.click("button.primary") await app.client.waitUntilTextExists("h1", "Welcome") } const addMinikubeCluster = async (app: Application) => { - await app.client.click("a#add-cluster") - await app.client.waitUntilTextExists("legend", "Choose config:") - await app.client.selectByVisibleText("select#kubecontext-select", "minikube (new)") - await app.client.click("button.btn-primary") + await app.client.click("div.add-cluster") + await app.client.waitUntilTextExists("p", "Choose config") + await app.client.click("div#kubecontext-select") + await app.client.waitUntilTextExists("div", "minikube") + await app.client.click("div.minikube") + await app.client.click("button.primary") } const waitForMinikubeDashboard = async (app: Application) => { - await app.client.waitUntilTextExists("pre.auth-output", "Authentication proxy started") + await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started") let windowCount = await app.client.getWindowCount() // wait for webview to appear on window count while (windowCount == 1) { diff --git a/locales/en/messages.po b/locales/en/messages.po index cfa796b938..30d81b3b08 100644 --- a/locales/en/messages.po +++ b/locales/en/messages.po @@ -34,24 +34,28 @@ msgid "(empty) (Allowing the specific traffic to all pods in this namespace)" msgstr "(empty) (Allowing the specific traffic to all pods in this namespace)" #: src/renderer/components/+add-cluster/add-cluster.tsx:105 -msgid "(new)" -msgstr "(new)" +#~ msgid "(new)" +#~ msgstr "(new)" -#: src/renderer/components/item-object-list/item-list-layout.tsx:226 +#: src/renderer/components/item-object-list/item-list-layout.tsx:224 msgid "<0>Filtered: {itemsCount} / {allItemsCount}" msgstr "<0>Filtered: {itemsCount} / {allItemsCount}" #: src/renderer/browser-check.tsx:11 -msgid "<0>Your browser does not support all Lens features. Please consider using another browser." -msgstr "<0>Your browser does not support all Lens features. Please consider using another browser." +#~ msgid "<0>Your browser does not support all Lens features. Please consider using another browser." +#~ msgstr "<0>Your browser does not support all Lens features. Please consider using another browser." #: src/renderer/components/dock/create-resource.tsx:56 msgid "<0>{0} successfully created" msgstr "<0>{0} successfully created" #: src/renderer/components/+add-cluster/add-cluster.tsx:176 -msgid "A HTTP proxy server URL (format: http://
:)" -msgstr "A HTTP proxy server URL (format: http://
:)" +#~ msgid "A HTTP proxy server URL (format: http://
:)" +#~ msgstr "A HTTP proxy server URL (format: http://
:)" + +#: src/renderer/components/input/input.validators.ts:40 +msgid "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." +msgstr "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." #: src/renderer/components/+workspaces/workspaces.tsx:84 msgid "A single workspaces contains a list of clusters and their full configuration." @@ -61,7 +65,7 @@ msgstr "A single workspaces contains a list of clusters and their full configura msgid "API Group" msgstr "API Group" -#: src/renderer/components/layout/sidebar.tsx:94 +#: src/renderer/components/layout/sidebar.tsx:88 msgid "Access Control" msgstr "Access Control" @@ -79,8 +83,8 @@ msgstr "Account Name" msgid "Active" msgstr "Active" -#: src/renderer/components/+add-cluster/add-cluster.tsx:168 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:99 +#: src/renderer/components/+add-cluster/add-cluster.tsx:170 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:116 msgid "Add Cluster" msgstr "Add Cluster" @@ -101,8 +105,12 @@ msgid "Add bindings to {name}" msgstr "Add bindings to {name}" #: src/renderer/components/+add-cluster/add-cluster.tsx:187 -msgid "Add cluster" -msgstr "Add cluster" +#~ msgid "Add cluster" +#~ msgstr "Add cluster" + +#: src/renderer/components/+add-cluster/add-cluster.tsx:191 +msgid "Add cluster(s)" +msgstr "Add cluster(s)" #: src/renderer/components/+workspaces/clusters-menu.tsx:58 #~ msgid "Add clusters" @@ -116,11 +124,11 @@ msgstr "Add field" #~ msgid "Added repos" #~ msgstr "Added repos" -#: src/renderer/components/+preferences/preferences.tsx:147 +#: src/renderer/components/+preferences/preferences.tsx:144 msgid "Added repos:" msgstr "Added repos:" -#: src/renderer/components/+preferences/preferences.tsx:106 +#: src/renderer/components/+preferences/preferences.tsx:103 msgid "Adding helm branch <0>{0} has failed: {1}" msgstr "Adding helm branch <0>{0} has failed: {1}" @@ -134,7 +142,7 @@ msgstr "Additional Printer Columns" #: src/renderer/components/+network-endpoints/endpoint-subset-list.tsx:29 #: src/renderer/components/+network-endpoints/endpoint-subset-list.tsx:60 -#: src/renderer/components/+nodes/node-details.tsx:84 +#: src/renderer/components/+nodes/node-details.tsx:83 msgid "Addresses" msgstr "Addresses" @@ -156,7 +164,7 @@ msgstr "Affinities" #: src/renderer/components/+network-ingresses/ingresses.tsx:35 #: src/renderer/components/+network-policies/network-policies.tsx:34 #: src/renderer/components/+network-services/services.tsx:51 -#: src/renderer/components/+nodes/nodes.tsx:119 +#: src/renderer/components/+nodes/nodes.tsx:126 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:38 #: src/renderer/components/+storage-classes/storage-classes.tsx:38 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:51 @@ -168,7 +176,7 @@ msgstr "Affinities" #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:50 #: src/renderer/components/+workloads-deployments/deployments.tsx:63 #: src/renderer/components/+workloads-jobs/jobs.tsx:41 -#: src/renderer/components/+workloads-pods/pods.tsx:80 +#: src/renderer/components/+workloads-pods/pods.tsx:81 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:53 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:44 msgid "Age" @@ -194,7 +202,7 @@ msgstr "All logs" msgid "All namespaces" msgstr "All namespaces" -#: src/renderer/components/+nodes/node-details.tsx:78 +#: src/renderer/components/+nodes/node-details.tsx:77 msgid "Allocatable" msgstr "Allocatable" @@ -202,11 +210,11 @@ msgstr "Allocatable" msgid "Allow Privilege Escalation" msgstr "Allow Privilege Escalation" -#: src/renderer/components/+preferences/preferences.tsx:175 +#: src/renderer/components/+preferences/preferences.tsx:172 msgid "Allow telemetry & usage tracking" msgstr "Allow telemetry & usage tracking" -#: src/renderer/components/+preferences/preferences.tsx:167 +#: src/renderer/components/+preferences/preferences.tsx:164 msgid "Allow untrusted Certificate Authorities" msgstr "Allow untrusted Certificate Authorities" @@ -238,7 +246,7 @@ msgstr "Allowed Runtime Class Names" msgid "Allowed Unsafe Sysctls" msgstr "Allowed Unsafe Sysctls" -#: src/renderer/components/+nodes/node-details.tsx:103 +#: src/renderer/components/+nodes/node-details.tsx:102 #: src/renderer/components/kube-object/kube-object-meta.tsx:36 msgid "Annotations" msgstr "Annotations" @@ -260,7 +268,7 @@ msgstr "App crash at <0>{pageUrl}" msgid "Applying.." msgstr "Applying.." -#: src/renderer/components/layout/sidebar.tsx:93 +#: src/renderer/components/layout/sidebar.tsx:87 msgid "Apps" msgstr "Apps" @@ -272,11 +280,11 @@ msgstr "Are you sure you want remove workspace <0>{0}?" msgid "Are you sure you want to drain <0>{nodeName}?" msgstr "Are you sure you want to drain <0>{nodeName}?" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:86 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:84 msgid "Arguments" msgstr "Arguments" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:86 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:106 msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button." msgstr "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button." @@ -310,7 +318,7 @@ msgstr "Bindings" #~ msgid "Build version" #~ msgstr "Build version" -#: src/renderer/components/+workloads-pods/container-charts.tsx:74 +#: src/renderer/components/+workloads-pods/container-charts.tsx:75 #: src/renderer/components/+workloads-pods/pod-charts.tsx:100 msgid "Bytes consumed on this filesystem" msgstr "Bytes consumed on this filesystem" @@ -346,12 +354,12 @@ msgstr "CA Bundle" #: src/renderer/components/+cluster/cluster-metric-switchers.tsx:24 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:140 -#: src/renderer/components/+nodes/node-details.tsx:63 -#: src/renderer/components/+nodes/node-details.tsx:74 -#: src/renderer/components/+nodes/node-details.tsx:79 -#: src/renderer/components/+nodes/nodes.tsx:113 +#: src/renderer/components/+nodes/node-details.tsx:62 +#: src/renderer/components/+nodes/node-details.tsx:73 +#: src/renderer/components/+nodes/node-details.tsx:78 +#: src/renderer/components/+nodes/nodes.tsx:120 #: src/renderer/components/+workloads-pods/pod-charts.tsx:11 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:25 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:26 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:53 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:95 #: src/renderer/components/resource-metrics/resource-metrics-text.tsx:13 @@ -363,21 +371,21 @@ msgid "CPU capacity" msgstr "CPU capacity" #: src/renderer/components/+nodes/node-charts.tsx:26 -#: src/renderer/components/+workloads-pods/container-charts.tsx:26 +#: src/renderer/components/+workloads-pods/container-charts.tsx:27 msgid "CPU cores usage" msgstr "CPU cores usage" -#: src/renderer/components/+workloads-pods/container-charts.tsx:40 +#: src/renderer/components/+workloads-pods/container-charts.tsx:41 #: src/renderer/components/+workloads-pods/pod-charts.tsx:49 msgid "CPU limits" msgstr "CPU limits" #: src/renderer/components/+nodes/node-charts.tsx:33 -#: src/renderer/components/+workloads-pods/container-charts.tsx:33 +#: src/renderer/components/+workloads-pods/container-charts.tsx:34 msgid "CPU requests" msgstr "CPU requests" -#: src/renderer/components/+nodes/nodes.tsx:55 +#: src/renderer/components/+nodes/nodes.tsx:57 msgid "CPU:" msgstr "CPU:" @@ -394,14 +402,14 @@ msgstr "Cancel" #: src/renderer/components/+nodes/node-charts.tsx:39 #: src/renderer/components/+nodes/node-charts.tsx:63 #: src/renderer/components/+nodes/node-charts.tsx:97 -#: src/renderer/components/+nodes/node-details.tsx:73 +#: src/renderer/components/+nodes/node-details.tsx:72 #: src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx:31 #: src/renderer/components/+storage-volumes/volume-details.tsx:29 #: src/renderer/components/+storage-volumes/volumes.tsx:42 msgid "Capacity" msgstr "Capacity" -#: src/renderer/components/+preferences/preferences.tsx:166 +#: src/renderer/components/+preferences/preferences.tsx:163 msgid "Certificate Trust" msgstr "Certificate Trust" @@ -455,7 +463,7 @@ msgid "Cloud API Token Secret" msgstr "Cloud API Token Secret" #: src/renderer/components/+namespaces/namespace-select.tsx:43 -#: src/renderer/components/layout/sidebar.tsx:85 +#: src/renderer/components/layout/sidebar.tsx:79 msgid "Cluster" msgstr "Cluster" @@ -468,11 +476,11 @@ msgstr "Cluster IP" msgid "Cluster Issuers" msgstr "Cluster Issuers" -#: src/renderer/components/+preferences/preferences.tsx:137 +#: src/renderer/components/+preferences/preferences.tsx:134 msgid "Color Theme" msgstr "Color Theme" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:81 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:79 msgid "Command" msgstr "Command" @@ -481,7 +489,7 @@ msgstr "Command" msgid "Common Name" msgstr "Common Name" -#: src/renderer/components/layout/sidebar.tsx:80 +#: src/renderer/components/layout/sidebar.tsx:76 msgid "Compact view" msgstr "Compact view" @@ -499,8 +507,8 @@ msgid "Condition" msgstr "Condition" #: src/renderer/components/+custom-resources/crd-details.tsx:52 -#: src/renderer/components/+nodes/node-details.tsx:108 -#: src/renderer/components/+nodes/nodes.tsx:120 +#: src/renderer/components/+nodes/node-details.tsx:107 +#: src/renderer/components/+nodes/nodes.tsx:127 #: src/renderer/components/+workloads-deployments/deployment-details.tsx:79 #: src/renderer/components/+workloads-deployments/deployments.tsx:64 #: src/renderer/components/+workloads-jobs/job-details.tsx:77 @@ -525,7 +533,7 @@ msgstr "ConfigMap <0>{0} successfully updated." msgid "ConfigMaps" msgstr "ConfigMaps" -#: src/renderer/components/layout/sidebar.tsx:88 +#: src/renderer/components/layout/sidebar.tsx:82 msgid "Configuration" msgstr "Configuration" @@ -557,13 +565,13 @@ msgstr "Container memory requests" msgid "Container memory usage" msgstr "Container memory usage" -#: src/renderer/components/+nodes/node-details.tsx:96 +#: src/renderer/components/+nodes/node-details.tsx:95 msgid "Container runtime" msgstr "Container runtime" #: src/renderer/components/+workloads-pods/pod-details.tsx:122 #: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:186 -#: src/renderer/components/+workloads-pods/pods.tsx:76 +#: src/renderer/components/+workloads-pods/pods.tsx:77 msgid "Containers" msgstr "Containers" @@ -571,7 +579,7 @@ msgstr "Containers" msgid "Context" msgstr "Context" -#: src/renderer/components/+workloads-pods/pods.tsx:78 +#: src/renderer/components/+workloads-pods/pods.tsx:79 #: src/renderer/components/kube-object/kube-object-meta.tsx:39 msgid "Controlled By" msgstr "Controlled By" @@ -671,7 +679,7 @@ msgid "Cron Jobs" msgstr "Cron Jobs" #: src/renderer/components/+workloads/workloads.tsx:77 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:69 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:67 msgid "CronJobs" msgstr "CronJobs" @@ -692,11 +700,11 @@ msgstr "Currently applied filters:" #~ msgstr "Custom" #: src/renderer/components/+custom-resources/crd-list.tsx:55 -#: src/renderer/components/layout/sidebar.tsx:95 +#: src/renderer/components/layout/sidebar.tsx:89 msgid "Custom Resources" msgstr "Custom Resources" -#: src/renderer/components/+add-cluster/add-cluster.tsx:111 +#: src/renderer/components/+add-cluster/add-cluster.tsx:115 msgid "Custom.." msgstr "Custom.." @@ -713,13 +721,13 @@ msgid "Daemon Sets" msgstr "Daemon Sets" #: src/renderer/components/+workloads/workloads.tsx:53 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:59 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:57 msgid "DaemonSets" msgstr "DaemonSets" #: src/renderer/theme.store.ts:32 -msgid "Dark" -msgstr "Dark" +#~ msgid "Dark" +#~ msgstr "Dark" #: src/renderer/components/+config-maps/config-map-details.tsx:69 #: src/renderer/components/+config-secrets/secret-details.tsx:78 @@ -753,7 +761,7 @@ msgstr "Deploy Revisions" #: src/renderer/components/+workloads/workloads.tsx:45 #: src/renderer/components/+workloads-deployments/deployments.tsx:57 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:49 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:47 msgid "Deployments" msgstr "Deployments" @@ -766,21 +774,21 @@ msgstr "Description" msgid "Desired number of replicas" msgstr "Desired number of replicas" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:52 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:64 msgid "Disconnect" msgstr "Disconnect" -#: src/renderer/components/+nodes/node-details.tsx:65 -#: src/renderer/components/+nodes/nodes.tsx:115 +#: src/renderer/components/+nodes/node-details.tsx:64 +#: src/renderer/components/+nodes/nodes.tsx:122 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:44 msgid "Disk" msgstr "Disk" -#: src/renderer/components/+nodes/nodes.tsx:71 +#: src/renderer/components/+nodes/nodes.tsx:79 msgid "Disk:" msgstr "Disk:" -#: src/renderer/components/+preferences/preferences.tsx:171 +#: src/renderer/components/+preferences/preferences.tsx:168 msgid "Does not affect cluster communications!" msgstr "Does not affect cluster communications!" @@ -788,7 +796,7 @@ msgstr "Does not affect cluster communications!" msgid "Domains" msgstr "Domains" -#: src/renderer/components/+preferences/preferences.tsx:140 +#: src/renderer/components/+preferences/preferences.tsx:137 msgid "Download Mirror" msgstr "Download Mirror" @@ -796,7 +804,7 @@ msgstr "Download Mirror" msgid "Download file" msgstr "Download file" -#: src/renderer/components/+preferences/preferences.tsx:141 +#: src/renderer/components/+preferences/preferences.tsx:138 msgid "Download mirror for kubectl" msgstr "Download mirror for kubectl" @@ -841,7 +849,7 @@ msgstr "Effect" msgid "Egress" msgstr "Egress" -#: src/renderer/components/+network-services/service-details.tsx:66 +#: src/renderer/components/+network-services/service-details.tsx:68 msgid "Endpoint" msgstr "Endpoint" @@ -867,7 +875,7 @@ msgstr "Error stack" #: src/renderer/components/+events/events.tsx:56 #: src/renderer/components/+events/kube-event-details.tsx:34 #: src/renderer/components/+events/kube-event-details.tsx:39 -#: src/renderer/components/layout/sidebar.tsx:92 +#: src/renderer/components/layout/sidebar.tsx:86 msgid "Events" msgstr "Events" @@ -905,7 +913,7 @@ msgid "Field Path" msgstr "Field Path" #: src/renderer/components/+workloads-pods/pod-charts.tsx:14 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:27 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:28 msgid "Filesystem" msgstr "Filesystem" @@ -945,7 +953,7 @@ msgstr "From <0>{from} to <1>{to}" msgid "Fs Group" msgstr "Fs Group" -#: src/renderer/components/+landing-page/landing-page.tsx:21 +#: src/renderer/components/+landing-page/landing-page.tsx:23 msgid "Get started by associating one or more clusters to Lens." msgstr "Get started by associating one or more clusters to Lens." @@ -967,15 +975,15 @@ msgstr "Groups" msgid "HPA" msgstr "HPA" -#: src/renderer/components/+preferences/preferences.tsx:160 +#: src/renderer/components/+preferences/preferences.tsx:157 msgid "HTTP Proxy" msgstr "HTTP Proxy" #: src/renderer/components/+add-cluster/add-cluster.tsx:178 -msgid "HTTP Proxy server. Used for communicating with Kubernetes API." -msgstr "HTTP Proxy server. Used for communicating with Kubernetes API." +#~ msgid "HTTP Proxy server. Used for communicating with Kubernetes API." +#~ msgstr "HTTP Proxy server. Used for communicating with Kubernetes API." -#: src/renderer/components/+preferences/preferences.tsx:143 +#: src/renderer/components/+preferences/preferences.tsx:140 msgid "Helm" msgstr "Helm" @@ -995,7 +1003,7 @@ msgstr "Helm Install: {repo}/{name}" msgid "Helm Upgrade: {0}" msgstr "Helm Upgrade: {0}" -#: src/renderer/components/+preferences/preferences.tsx:50 +#: src/renderer/components/+preferences/preferences.tsx:47 msgid "Helm branch <0>{0} already in use" msgstr "Helm branch <0>{0} already in use" @@ -1051,11 +1059,11 @@ msgstr "Http01" msgid "IP addresses" msgstr "IP addresses" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:44 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:45 msgid "Image" msgstr "Image" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:48 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:49 msgid "ImagePullPolicy" msgstr "ImagePullPolicy" @@ -1097,7 +1105,7 @@ msgstr "Installation complete!" msgid "Installing..." msgstr "Installing..." -#: src/renderer/components/input/input.validators.ts:43 +#: src/renderer/components/input/input.validators.ts:44 msgid "Invalid account ID" msgstr "Invalid account ID" @@ -1133,11 +1141,11 @@ msgstr "JSON Path" #: src/renderer/components/+workloads/workloads.tsx:69 #: src/renderer/components/+workloads-cronjobs/cronjob-details.tsx:62 #: src/renderer/components/+workloads-jobs/jobs.tsx:36 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:64 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:62 msgid "Jobs" msgstr "Jobs" -#: src/renderer/components/+nodes/node-details.tsx:93 +#: src/renderer/components/+nodes/node-details.tsx:92 msgid "Kernel version" msgstr "Kernel version" @@ -1177,14 +1185,14 @@ msgstr "Kubeconfig" msgid "Kubeconfig File" msgstr "Kubeconfig File" -#: src/renderer/components/+nodes/node-details.tsx:99 +#: src/renderer/components/+nodes/node-details.tsx:98 msgid "Kubelet version" msgstr "Kubelet version" #: src/renderer/components/+config-secrets/secrets.tsx:43 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuers.tsx:65 #: src/renderer/components/+namespaces/namespaces.tsx:32 -#: src/renderer/components/+nodes/node-details.tsx:102 +#: src/renderer/components/+nodes/node-details.tsx:101 #: src/renderer/components/kube-object/kube-object-meta.tsx:35 msgid "Labels" msgstr "Labels" @@ -1209,7 +1217,7 @@ msgstr "Last seen" msgid "Last transition time: {lastTransitionTime}" msgstr "Last transition time: {lastTransitionTime}" -#: src/renderer/components/+preferences/preferences.tsx:129 +#: src/renderer/components/+preferences/preferences.tsx:126 msgid "Lens Global Settings" msgstr "Lens Global Settings" @@ -1218,8 +1226,8 @@ msgid "Level" msgstr "Level" #: src/renderer/theme.store.ts:33 -msgid "Light" -msgstr "Light" +#~ msgid "Light" +#~ msgstr "Light" #: src/renderer/components/+events/events.tsx:59 msgid "Limited to {0}" @@ -1227,8 +1235,8 @@ msgstr "Limited to {0}" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:72 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:115 -#: src/renderer/components/+workloads-pods/container-charts.tsx:39 -#: src/renderer/components/+workloads-pods/container-charts.tsx:63 +#: src/renderer/components/+workloads-pods/container-charts.tsx:40 +#: src/renderer/components/+workloads-pods/container-charts.tsx:64 #: src/renderer/components/+workloads-pods/pod-charts.tsx:48 #: src/renderer/components/+workloads-pods/pod-charts.tsx:72 msgid "Limits" @@ -1242,11 +1250,11 @@ msgstr "Lines" msgid "Link" msgstr "Link" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:73 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:71 msgid "Liveness" msgstr "Liveness" -#: src/renderer/components/+network-services/service-details.tsx:63 +#: src/renderer/components/+network-services/service-details.tsx:65 msgid "Load Balancer IP" msgstr "Load Balancer IP" @@ -1294,12 +1302,12 @@ msgstr "Medium" #: src/renderer/components/+cluster/cluster-metric-switchers.tsx:25 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:144 -#: src/renderer/components/+nodes/node-details.tsx:64 -#: src/renderer/components/+nodes/node-details.tsx:75 -#: src/renderer/components/+nodes/node-details.tsx:80 -#: src/renderer/components/+nodes/nodes.tsx:114 +#: src/renderer/components/+nodes/node-details.tsx:63 +#: src/renderer/components/+nodes/node-details.tsx:74 +#: src/renderer/components/+nodes/node-details.tsx:79 +#: src/renderer/components/+nodes/nodes.tsx:121 #: src/renderer/components/+workloads-pods/pod-charts.tsx:12 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:26 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:27 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:63 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:96 #: src/renderer/components/resource-metrics/resource-metrics-text.tsx:18 @@ -1310,21 +1318,21 @@ msgstr "Memory" msgid "Memory capacity" msgstr "Memory capacity" -#: src/renderer/components/+workloads-pods/container-charts.tsx:64 +#: src/renderer/components/+workloads-pods/container-charts.tsx:65 msgid "Memory limits" msgstr "Memory limits" #: src/renderer/components/+nodes/node-charts.tsx:57 -#: src/renderer/components/+workloads-pods/container-charts.tsx:57 +#: src/renderer/components/+workloads-pods/container-charts.tsx:58 msgid "Memory requests" msgstr "Memory requests" #: src/renderer/components/+nodes/node-charts.tsx:50 -#: src/renderer/components/+workloads-pods/container-charts.tsx:50 +#: src/renderer/components/+workloads-pods/container-charts.tsx:51 msgid "Memory usage" msgstr "Memory usage" -#: src/renderer/components/+nodes/nodes.tsx:63 +#: src/renderer/components/+nodes/nodes.tsx:68 msgid "Memory:" msgstr "Memory:" @@ -1368,13 +1376,13 @@ msgstr "Mount Options" msgid "Mountable secrets" msgstr "Mountable secrets" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:63 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:61 msgid "Mounts" msgstr "Mounts" #: src/renderer/components/+workspaces/workspaces.tsx:36 -msgid "My Workspace" -msgstr "My Workspace" +#~ msgid "My Workspace" +#~ msgstr "My Workspace" #: src/renderer/components/+apps-helm-charts/helm-charts.tsx:64 #: src/renderer/components/+apps-releases/releases.tsx:87 @@ -1397,7 +1405,7 @@ msgstr "My Workspace" #: src/renderer/components/+network-policies/network-policies.tsx:31 #: src/renderer/components/+network-services/service-details-endpoint.tsx:26 #: src/renderer/components/+network-services/services.tsx:44 -#: src/renderer/components/+nodes/nodes.tsx:112 +#: src/renderer/components/+nodes/nodes.tsx:119 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:35 #: src/renderer/components/+storage-classes/storage-classes.tsx:34 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:46 @@ -1415,7 +1423,7 @@ msgstr "My Workspace" #: src/renderer/components/+workloads-jobs/jobs.tsx:37 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:92 #: src/renderer/components/+workloads-pods/pod-details.tsx:144 -#: src/renderer/components/+workloads-pods/pods.tsx:73 +#: src/renderer/components/+workloads-pods/pods.tsx:74 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:50 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:40 #: src/renderer/components/+workspaces/workspaces.tsx:117 @@ -1462,7 +1470,7 @@ msgstr "Names" #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:46 #: src/renderer/components/+workloads-deployments/deployments.tsx:59 #: src/renderer/components/+workloads-jobs/jobs.tsx:38 -#: src/renderer/components/+workloads-pods/pods.tsx:75 +#: src/renderer/components/+workloads-pods/pods.tsx:76 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:41 #: src/renderer/components/dock/edit-resource.tsx:91 #: src/renderer/components/dock/install-chart.tsx:122 @@ -1477,7 +1485,7 @@ msgid "Namespace: {0}" msgstr "Namespace: {0}" #: src/renderer/components/+namespaces/namespaces.tsx:30 -#: src/renderer/components/layout/sidebar.tsx:91 +#: src/renderer/components/layout/sidebar.tsx:85 msgid "Namespaces" msgstr "Namespaces" @@ -1485,13 +1493,13 @@ msgstr "Namespaces" msgid "Namespaces: {0}" msgstr "Namespaces: {0}" -#: src/renderer/components/+preferences/preferences.tsx:170 +#: src/renderer/components/+preferences/preferences.tsx:167 msgid "Needed with some corporate proxies that do certificate re-writing." msgstr "Needed with some corporate proxies that do certificate re-writing." #: src/renderer/components/+network-ingresses/ingress-details.tsx:66 #: src/renderer/components/+workloads-pods/pod-charts.tsx:13 -#: src/renderer/components/layout/sidebar.tsx:89 +#: src/renderer/components/layout/sidebar.tsx:83 msgid "Network" msgstr "Network" @@ -1524,6 +1532,7 @@ msgstr "New tab" msgid "Next" msgstr "Next" +#: src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx:29 #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:44 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:71 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:42 @@ -1549,7 +1558,7 @@ msgstr "No filters available." msgid "No issues found" msgstr "No issues found" -#: src/renderer/components/item-object-list/item-list-layout.tsx:198 +#: src/renderer/components/item-object-list/item-list-layout.tsx:196 msgid "No items found." msgstr "No items found." @@ -1588,8 +1597,8 @@ msgstr "Node filesystem usage in bytes" msgid "Node shell" msgstr "Node shell" -#: src/renderer/components/+nodes/nodes.tsx:111 -#: src/renderer/components/layout/sidebar.tsx:86 +#: src/renderer/components/+nodes/nodes.tsx:118 +#: src/renderer/components/layout/sidebar.tsx:80 msgid "Nodes" msgstr "Nodes" @@ -1613,11 +1622,11 @@ msgstr "Notes" msgid "Number of running Pods" msgstr "Number of running Pods" -#: src/renderer/components/+nodes/node-details.tsx:87 +#: src/renderer/components/+nodes/node-details.tsx:86 msgid "OS" msgstr "OS" -#: src/renderer/components/+nodes/node-details.tsx:90 +#: src/renderer/components/+nodes/node-details.tsx:89 msgid "OS Image" msgstr "OS Image" @@ -1629,7 +1638,7 @@ msgstr "Object" msgid "Ok" msgstr "Ok" -#: src/renderer/components/+whats-new/whats-new.tsx:36 +#: src/renderer/components/+whats-new/whats-new.tsx:35 msgid "Ok, got it!" msgstr "Ok, got it!" @@ -1637,11 +1646,12 @@ msgstr "Ok, got it!" msgid "Open" msgstr "Open" -#: src/renderer/components/+network-services/service-ports.tsx:49 +#: src/renderer/components/+network-services/service-port-component.tsx:49 +#: src/renderer/components/+workloads-pods/pod-container-port.tsx:51 msgid "Open in a browser" msgstr "Open in a browser" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:63 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:60 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:78 #: src/renderer/components/+workloads-pods/pod-details-tolerations.tsx:17 msgid "Operator" @@ -1652,7 +1662,7 @@ msgid "Organization" msgstr "Organization" #: src/renderer/components/+workloads/workloads.tsx:29 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:37 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:35 msgid "Overview" msgstr "Overview" @@ -1678,17 +1688,17 @@ msgstr "Path" msgid "Path Prefix" msgstr "Path Prefix" -#: src/renderer/components/+storage/storage.tsx:26 +#: src/renderer/components/+storage/storage.tsx:25 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:45 msgid "Persistent Volume Claims" msgstr "Persistent Volume Claims" -#: src/renderer/components/+storage/storage.tsx:33 +#: src/renderer/components/+storage/storage.tsx:32 #: src/renderer/components/+storage-volumes/volumes.tsx:39 msgid "Persistent Volumes" msgstr "Persistent Volumes" -#: src/renderer/components/+add-cluster/add-cluster.tsx:52 +#: src/renderer/components/+add-cluster/add-cluster.tsx:62 msgid "Please select kubeconfig" msgstr "Please select kubeconfig" @@ -1701,7 +1711,7 @@ msgid "Pod IP" msgstr "Pod IP" #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:34 -#: src/renderer/components/+user-management/user-management.tsx:44 +#: src/renderer/components/+user-management/user-management.tsx:43 msgid "Pod Security Policies" msgstr "Pod Security Policies" @@ -1721,17 +1731,17 @@ msgid "Pod shell" msgstr "Pod shell" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:148 -#: src/renderer/components/+nodes/node-details.tsx:66 -#: src/renderer/components/+nodes/node-details.tsx:76 -#: src/renderer/components/+nodes/node-details.tsx:81 +#: src/renderer/components/+nodes/node-details.tsx:65 +#: src/renderer/components/+nodes/node-details.tsx:75 +#: src/renderer/components/+nodes/node-details.tsx:80 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:60 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:50 #: src/renderer/components/+workloads/workloads.tsx:37 #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:47 #: src/renderer/components/+workloads-deployments/deployments.tsx:60 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:44 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:42 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:89 -#: src/renderer/components/+workloads-pods/pods.tsx:72 +#: src/renderer/components/+workloads-pods/pods.tsx:73 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:52 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:42 msgid "Pods" @@ -1751,11 +1761,11 @@ msgstr "Port" #: src/renderer/components/+network-policies/network-policy-details.tsx:109 #: src/renderer/components/+network-services/service-details.tsx:59 #: src/renderer/components/+network-services/services.tsx:48 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:52 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:53 msgid "Ports" msgstr "Ports" -#: src/renderer/components/+preferences/preferences.tsx:124 +#: src/renderer/components/+preferences/preferences.tsx:121 msgid "Preferences" msgstr "Preferences" @@ -1777,15 +1787,15 @@ msgstr "Privileged" msgid "Provisioner" msgstr "Provisioner" -#: src/renderer/components/+preferences/preferences.tsx:163 +#: src/renderer/components/+preferences/preferences.tsx:160 msgid "Proxy is used only for non-cluster communication." msgstr "Proxy is used only for non-cluster communication." -#: src/renderer/components/+add-cluster/add-cluster.tsx:172 +#: src/renderer/components/+add-cluster/add-cluster.tsx:175 msgid "Proxy settings" msgstr "Proxy settings" -#: src/renderer/components/+workloads-pods/pods.tsx:79 +#: src/renderer/components/+workloads-pods/pods.tsx:80 msgid "QoS" msgstr "QoS" @@ -1793,7 +1803,7 @@ msgstr "QoS" msgid "QoS Class" msgstr "QoS Class" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:55 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:52 msgid "Quotas" msgstr "Quotas" @@ -1809,7 +1819,7 @@ msgstr "Read-only" msgid "Read-only Root Filesystem" msgstr "Read-only Root Filesystem" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:77 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:75 msgid "Readiness" msgstr "Readiness" @@ -1861,11 +1871,11 @@ msgstr "Release: {0}" msgid "Releases" msgstr "Releases" -#: src/renderer/components/+preferences/preferences.tsx:154 +#: src/renderer/components/+preferences/preferences.tsx:151 #: src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx:60 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:60 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:64 -#: src/renderer/components/item-object-list/item-list-layout.tsx:181 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:74 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:80 +#: src/renderer/components/item-object-list/item-list-layout.tsx:179 #: src/renderer/components/menu/menu-actions.tsx:49 #: src/renderer/components/menu/menu-actions.tsx:85 msgid "Remove" @@ -1895,7 +1905,7 @@ msgstr "Remove selected bindings for <0>{0}?" msgid "Remove selected bindings from ${name}" msgstr "Remove selected bindings from ${name}" -#: src/renderer/components/item-object-list/item-list-layout.tsx:277 +#: src/renderer/components/item-object-list/item-list-layout.tsx:275 msgid "Remove selected items ({0})" msgstr "Remove selected items ({0})" @@ -1903,7 +1913,7 @@ msgstr "Remove selected items ({0})" msgid "Remove {resourceKind} <0>{resourceName}?" msgstr "Remove {resourceKind} <0>{resourceName}?" -#: src/renderer/components/+preferences/preferences.tsx:117 +#: src/renderer/components/+preferences/preferences.tsx:114 msgid "Removing helm branch <0>{0} has failed: {1}" msgstr "Removing helm branch <0>{0} has failed: {1}" @@ -1927,7 +1937,7 @@ msgstr "Replicas" msgid "Repo/Name" msgstr "Repo/Name" -#: src/renderer/components/+preferences/preferences.tsx:144 +#: src/renderer/components/+preferences/preferences.tsx:141 msgid "Repositories" msgstr "Repositories" @@ -1947,8 +1957,8 @@ msgstr "Request duration in seconds" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:114 #: src/renderer/components/+nodes/node-charts.tsx:32 #: src/renderer/components/+nodes/node-charts.tsx:56 -#: src/renderer/components/+workloads-pods/container-charts.tsx:32 -#: src/renderer/components/+workloads-pods/container-charts.tsx:56 +#: src/renderer/components/+workloads-pods/container-charts.tsx:33 +#: src/renderer/components/+workloads-pods/container-charts.tsx:57 #: src/renderer/components/+workloads-pods/pod-charts.tsx:41 #: src/renderer/components/+workloads-pods/pod-charts.tsx:65 msgid "Requests" @@ -1966,7 +1976,7 @@ msgstr "Required field" msgid "Reset" msgstr "Reset" -#: src/renderer/components/item-object-list/item-list-layout.tsx:201 +#: src/renderer/components/item-object-list/item-list-layout.tsx:199 msgid "Reset filters?" msgstr "Reset filters?" @@ -2018,7 +2028,7 @@ msgstr "Response duration in seconds" msgid "Restart session" msgstr "Restart session" -#: src/renderer/components/+workloads-pods/pods.tsx:77 +#: src/renderer/components/+workloads-pods/pods.tsx:78 msgid "Restarts" msgstr "Restarts" @@ -2036,7 +2046,7 @@ msgstr "Right click cluster icon to open cluster settings." msgid "Role" msgstr "Role" -#: src/renderer/components/+user-management/user-management.tsx:32 +#: src/renderer/components/+user-management/user-management.tsx:31 #: src/renderer/components/+user-management-roles-bindings/role-bindings.tsx:34 msgid "Role Bindings" msgstr "Role Bindings" @@ -2049,8 +2059,8 @@ msgstr "Role ID" msgid "Role name" msgstr "Role name" -#: src/renderer/components/+nodes/nodes.tsx:117 -#: src/renderer/components/+user-management/user-management.tsx:37 +#: src/renderer/components/+nodes/nodes.tsx:124 +#: src/renderer/components/+user-management/user-management.tsx:36 #: src/renderer/components/+user-management-roles/roles.tsx:32 msgid "Roles" msgstr "Roles" @@ -2117,11 +2127,11 @@ msgstr "Schedule" msgid "Scope" msgstr "Scope" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:60 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:57 msgid "Scope Selector" msgstr "Scope Selector" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:64 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:61 msgid "Scope name" msgstr "Scope name" @@ -2169,7 +2179,7 @@ msgstr "Secrets" msgid "Select a quota.." msgstr "Select a quota.." -#: src/renderer/components/+add-cluster/add-cluster.tsx:169 +#: src/renderer/components/+add-cluster/add-cluster.tsx:172 msgid "Select kubeconfig" msgstr "Select kubeconfig" @@ -2206,7 +2216,7 @@ msgstr "Server" msgid "Service" msgstr "Service" -#: src/renderer/components/+user-management/user-management.tsx:27 +#: src/renderer/components/+user-management/user-management.tsx:26 #: src/renderer/components/+user-management-service-accounts/service-accounts.tsx:35 msgid "Service Accounts" msgstr "Service Accounts" @@ -2220,7 +2230,7 @@ msgstr "Services" msgid "Session Affinity" msgstr "Session Affinity" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:43 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:40 msgid "Set" msgstr "Set" @@ -2228,7 +2238,7 @@ msgstr "Set" msgid "Set quota" msgstr "Set quota" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:47 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:53 msgid "Settings" msgstr "Settings" @@ -2280,7 +2290,7 @@ msgid "Stateful Sets" msgstr "Stateful Sets" #: src/renderer/components/+workloads/workloads.tsx:61 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:54 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:52 msgid "StatefulSets" msgstr "StatefulSets" @@ -2300,10 +2310,10 @@ msgstr "StatefulSets" #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:52 #: src/renderer/components/+storage-volumes/volume-details.tsx:46 #: src/renderer/components/+storage-volumes/volumes.tsx:45 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:38 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:39 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:97 #: src/renderer/components/+workloads-pods/pod-details.tsx:82 -#: src/renderer/components/+workloads-pods/pods.tsx:81 +#: src/renderer/components/+workloads-pods/pods.tsx:82 msgid "Status" msgstr "Status" @@ -2312,7 +2322,7 @@ msgid "Status URI" msgstr "Status URI" #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:57 -#: src/renderer/components/layout/sidebar.tsx:90 +#: src/renderer/components/layout/sidebar.tsx:84 msgid "Storage" msgstr "Storage" @@ -2325,7 +2335,7 @@ msgstr "Storage Class" msgid "Storage Class Name" msgstr "Storage Class Name" -#: src/renderer/components/+storage/storage.tsx:41 +#: src/renderer/components/+storage/storage.tsx:40 #: src/renderer/components/+storage-classes/storage-classes.tsx:33 msgid "Storage Classes" msgstr "Storage Classes" @@ -2373,20 +2383,20 @@ msgstr "Suspend" msgid "TLS" msgstr "TLS" -#: src/renderer/components/+nodes/node-details.tsx:104 -#: src/renderer/components/+nodes/nodes.tsx:116 +#: src/renderer/components/+nodes/node-details.tsx:103 +#: src/renderer/components/+nodes/nodes.tsx:123 msgid "Taints" msgstr "Taints" -#: src/renderer/components/+preferences/preferences.tsx:174 +#: src/renderer/components/+preferences/preferences.tsx:171 msgid "Telemetry & Usage Tracking" msgstr "Telemetry & Usage Tracking" -#: src/renderer/components/+preferences/preferences.tsx:177 +#: src/renderer/components/+preferences/preferences.tsx:174 msgid "Telemetry & usage data is collected to continuously improve the Lens experience." msgstr "Telemetry & usage data is collected to continuously improve the Lens experience." -#: src/renderer/components/dock/terminal.store.ts:29 +#: src/renderer/components/dock/terminal.store.ts:28 msgid "Terminal" msgstr "Terminal" @@ -2407,14 +2417,14 @@ msgid "This field is required" msgstr "This field is required" #: src/renderer/components/input/input.validators.ts:39 -msgid "This field must contain only lowercase latin characters, numbers and dash." -msgstr "This field must contain only lowercase latin characters, numbers and dash." +msgid "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." +msgstr "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." -#: src/renderer/components/cluster-manager/clusters-menu.tsx:84 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:104 msgid "This is the quick launch menu." msgstr "This is the quick launch menu." -#: src/renderer/components/+preferences/preferences.tsx:169 +#: src/renderer/components/+preferences/preferences.tsx:166 msgid "This will make Lens to trust ANY certificate authority without any validations." msgstr "This will make Lens to trust ANY certificate authority without any validations." @@ -2457,7 +2467,7 @@ msgstr "Transmit" msgid "Type" msgstr "Type" -#: src/renderer/components/+preferences/preferences.tsx:161 +#: src/renderer/components/+preferences/preferences.tsx:158 msgid "Type HTTP proxy url (example: http://proxy.acme.org:8080)" msgstr "Type HTTP proxy url (example: http://proxy.acme.org:8080)" @@ -2499,14 +2509,15 @@ msgstr "Upgrade version" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:70 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:113 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:134 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:40 #: src/renderer/components/+nodes/node-charts.tsx:25 #: src/renderer/components/+nodes/node-charts.tsx:49 #: src/renderer/components/+nodes/node-charts.tsx:73 #: src/renderer/components/+nodes/node-charts.tsx:90 #: src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx:24 -#: src/renderer/components/+workloads-pods/container-charts.tsx:25 -#: src/renderer/components/+workloads-pods/container-charts.tsx:49 -#: src/renderer/components/+workloads-pods/container-charts.tsx:73 +#: src/renderer/components/+workloads-pods/container-charts.tsx:26 +#: src/renderer/components/+workloads-pods/container-charts.tsx:50 +#: src/renderer/components/+workloads-pods/container-charts.tsx:74 #: src/renderer/components/+workloads-pods/pod-charts.tsx:34 #: src/renderer/components/+workloads-pods/pod-charts.tsx:58 #: src/renderer/components/+workloads-pods/pod-charts.tsx:99 @@ -2518,8 +2529,8 @@ msgid "Use same name for RoleBinding" msgstr "Use same name for RoleBinding" #: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:43 -msgid "Used" -msgstr "Used" +#~ msgid "Used" +#~ msgstr "Used" #: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:155 msgid "User" @@ -2537,7 +2548,7 @@ msgstr "Value" #: src/renderer/components/+apps-releases/release-details.tsx:111 #: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:132 -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:65 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:62 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:79 msgid "Values" msgstr "Values" @@ -2552,7 +2563,7 @@ msgstr "Verbs" #: src/renderer/components/+apps-releases/releases.tsx:91 #: src/renderer/components/+custom-resources/crd-details.tsx:35 #: src/renderer/components/+custom-resources/crd-list.tsx:75 -#: src/renderer/components/+nodes/nodes.tsx:118 +#: src/renderer/components/+nodes/nodes.tsx:125 #: src/renderer/components/dock/install-chart.tsx:120 #: src/renderer/components/dock/upgrade-chart.tsx:99 msgid "Version" @@ -2588,7 +2599,7 @@ msgstr "Waiting services to be running" msgid "Warnings: {0}" msgstr "Warnings: {0}" -#: src/renderer/components/+landing-page/landing-page.tsx:18 +#: src/renderer/components/+landing-page/landing-page.tsx:20 msgid "Welcome!" msgstr "Welcome!" @@ -2600,7 +2611,7 @@ msgstr "What is a Workspace?" msgid "Worker" msgstr "Worker" -#: src/renderer/components/layout/sidebar.tsx:87 +#: src/renderer/components/layout/sidebar.tsx:81 msgid "Workloads" msgstr "Workloads" @@ -2621,6 +2632,7 @@ msgstr "Wrong email format" msgid "Wrong url format" msgstr "Wrong url format" +#: src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx:28 #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:44 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:71 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:42 @@ -2646,19 +2658,19 @@ msgstr "Zone" msgid "ago" msgstr "ago" -#: src/renderer/components/item-object-list/item-list-layout.tsx:180 +#: src/renderer/components/item-object-list/item-list-layout.tsx:178 msgid "and <0>{tailCount} more" msgstr "and <0>{tailCount} more" -#: src/renderer/components/+preferences/preferences.tsx:129 +#: src/renderer/components/+preferences/preferences.tsx:126 msgid "applicable to all clusters" msgstr "applicable to all clusters" -#: src/renderer/components/+nodes/nodes.tsx:55 +#: src/renderer/components/+nodes/nodes.tsx:57 msgid "cores:" msgstr "cores:" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:41 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:42 msgid "exit code" msgstr "exit code" @@ -2675,11 +2687,15 @@ msgstr "listKind" msgid "never" msgstr "never" +#: src/renderer/components/cluster-manager/clusters-menu.tsx:119 +msgid "new" +msgstr "new" + #: src/renderer/components/+custom-resources/crd-details.tsx:64 msgid "plural" msgstr "plural" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:40 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:41 msgid "ready" msgstr "ready" @@ -2727,7 +2743,7 @@ msgstr "{0} unavailable" msgid "{accountName} kubeconfig" msgstr "{accountName} kubeconfig" -#: src/renderer/components/item-object-list/item-list-layout.tsx:230 +#: src/renderer/components/item-object-list/item-list-layout.tsx:228 msgid "{allItemsCount, plural, one {# item} other {# items}}" msgstr "{allItemsCount, plural, one {# item} other {# items}}" @@ -2743,7 +2759,7 @@ msgstr "{podName} Logs" msgid "{resourceType} <0>{resourceName} updated." msgstr "{resourceType} <0>{resourceName} updated." -#: src/renderer/components/item-object-list/item-list-layout.tsx:181 +#: src/renderer/components/item-object-list/item-list-layout.tsx:179 msgid "{selectedCount, plural, one {<0>Remove item <1>{selectedNames}?} other {<2>Remove <3>{selectedCount} items <4>{selectedNames} {tail}?}}" msgstr "{selectedCount, plural, one {<0>Remove item <1>{selectedNames}?} other {<2>Remove <3>{selectedCount} items <4>{selectedNames} {tail}?}}" diff --git a/locales/fi/messages.po b/locales/fi/messages.po index 0aa7bb5ca8..36a8a390a5 100644 --- a/locales/fi/messages.po +++ b/locales/fi/messages.po @@ -34,23 +34,27 @@ msgid "(empty) (Allowing the specific traffic to all pods in this namespace)" msgstr "" #: src/renderer/components/+add-cluster/add-cluster.tsx:105 -msgid "(new)" -msgstr "" +#~ msgid "(new)" +#~ msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:226 +#: src/renderer/components/item-object-list/item-list-layout.tsx:224 msgid "<0>Filtered: {itemsCount} / {allItemsCount}" msgstr "" #: src/renderer/browser-check.tsx:11 -msgid "<0>Your browser does not support all Lens features. Please consider using another browser." -msgstr "" +#~ msgid "<0>Your browser does not support all Lens features. Please consider using another browser." +#~ msgstr "" #: src/renderer/components/dock/create-resource.tsx:56 msgid "<0>{0} successfully created" msgstr "" #: src/renderer/components/+add-cluster/add-cluster.tsx:176 -msgid "A HTTP proxy server URL (format: http://
:)" +#~ msgid "A HTTP proxy server URL (format: http://
:)" +#~ msgstr "" + +#: src/renderer/components/input/input.validators.ts:40 +msgid "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." msgstr "" #: src/renderer/components/+workspaces/workspaces.tsx:84 @@ -61,7 +65,7 @@ msgstr "" msgid "API Group" msgstr "" -#: src/renderer/components/layout/sidebar.tsx:94 +#: src/renderer/components/layout/sidebar.tsx:88 msgid "Access Control" msgstr "" @@ -79,8 +83,8 @@ msgstr "" msgid "Active" msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:168 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:99 +#: src/renderer/components/+add-cluster/add-cluster.tsx:170 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:116 msgid "Add Cluster" msgstr "" @@ -101,7 +105,11 @@ msgid "Add bindings to {name}" msgstr "" #: src/renderer/components/+add-cluster/add-cluster.tsx:187 -msgid "Add cluster" +#~ msgid "Add cluster" +#~ msgstr "" + +#: src/renderer/components/+add-cluster/add-cluster.tsx:191 +msgid "Add cluster(s)" msgstr "" #: src/renderer/components/+workspaces/clusters-menu.tsx:58 @@ -116,11 +124,11 @@ msgstr "" #~ msgid "Added repos" #~ msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:147 +#: src/renderer/components/+preferences/preferences.tsx:144 msgid "Added repos:" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:106 +#: src/renderer/components/+preferences/preferences.tsx:103 msgid "Adding helm branch <0>{0} has failed: {1}" msgstr "" @@ -134,7 +142,7 @@ msgstr "" #: src/renderer/components/+network-endpoints/endpoint-subset-list.tsx:29 #: src/renderer/components/+network-endpoints/endpoint-subset-list.tsx:60 -#: src/renderer/components/+nodes/node-details.tsx:84 +#: src/renderer/components/+nodes/node-details.tsx:83 msgid "Addresses" msgstr "" @@ -156,7 +164,7 @@ msgstr "" #: src/renderer/components/+network-ingresses/ingresses.tsx:35 #: src/renderer/components/+network-policies/network-policies.tsx:34 #: src/renderer/components/+network-services/services.tsx:51 -#: src/renderer/components/+nodes/nodes.tsx:119 +#: src/renderer/components/+nodes/nodes.tsx:126 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:38 #: src/renderer/components/+storage-classes/storage-classes.tsx:38 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:51 @@ -168,7 +176,7 @@ msgstr "" #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:50 #: src/renderer/components/+workloads-deployments/deployments.tsx:63 #: src/renderer/components/+workloads-jobs/jobs.tsx:41 -#: src/renderer/components/+workloads-pods/pods.tsx:80 +#: src/renderer/components/+workloads-pods/pods.tsx:81 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:53 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:44 msgid "Age" @@ -194,7 +202,7 @@ msgstr "" msgid "All namespaces" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:78 +#: src/renderer/components/+nodes/node-details.tsx:77 msgid "Allocatable" msgstr "" @@ -202,11 +210,11 @@ msgstr "" msgid "Allow Privilege Escalation" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:175 +#: src/renderer/components/+preferences/preferences.tsx:172 msgid "Allow telemetry & usage tracking" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:167 +#: src/renderer/components/+preferences/preferences.tsx:164 msgid "Allow untrusted Certificate Authorities" msgstr "" @@ -238,7 +246,7 @@ msgstr "" msgid "Allowed Unsafe Sysctls" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:103 +#: src/renderer/components/+nodes/node-details.tsx:102 #: src/renderer/components/kube-object/kube-object-meta.tsx:36 msgid "Annotations" msgstr "" @@ -260,7 +268,7 @@ msgstr "" msgid "Applying.." msgstr "" -#: src/renderer/components/layout/sidebar.tsx:93 +#: src/renderer/components/layout/sidebar.tsx:87 msgid "Apps" msgstr "" @@ -272,11 +280,11 @@ msgstr "" msgid "Are you sure you want to drain <0>{nodeName}?" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:86 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:84 msgid "Arguments" msgstr "" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:86 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:106 msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button." msgstr "" @@ -310,7 +318,7 @@ msgstr "" #~ msgid "Build version" #~ msgstr "" -#: src/renderer/components/+workloads-pods/container-charts.tsx:74 +#: src/renderer/components/+workloads-pods/container-charts.tsx:75 #: src/renderer/components/+workloads-pods/pod-charts.tsx:100 msgid "Bytes consumed on this filesystem" msgstr "" @@ -346,12 +354,12 @@ msgstr "" #: src/renderer/components/+cluster/cluster-metric-switchers.tsx:24 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:140 -#: src/renderer/components/+nodes/node-details.tsx:63 -#: src/renderer/components/+nodes/node-details.tsx:74 -#: src/renderer/components/+nodes/node-details.tsx:79 -#: src/renderer/components/+nodes/nodes.tsx:113 +#: src/renderer/components/+nodes/node-details.tsx:62 +#: src/renderer/components/+nodes/node-details.tsx:73 +#: src/renderer/components/+nodes/node-details.tsx:78 +#: src/renderer/components/+nodes/nodes.tsx:120 #: src/renderer/components/+workloads-pods/pod-charts.tsx:11 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:25 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:26 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:53 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:95 #: src/renderer/components/resource-metrics/resource-metrics-text.tsx:13 @@ -363,21 +371,21 @@ msgid "CPU capacity" msgstr "" #: src/renderer/components/+nodes/node-charts.tsx:26 -#: src/renderer/components/+workloads-pods/container-charts.tsx:26 +#: src/renderer/components/+workloads-pods/container-charts.tsx:27 msgid "CPU cores usage" msgstr "" -#: src/renderer/components/+workloads-pods/container-charts.tsx:40 +#: src/renderer/components/+workloads-pods/container-charts.tsx:41 #: src/renderer/components/+workloads-pods/pod-charts.tsx:49 msgid "CPU limits" msgstr "" #: src/renderer/components/+nodes/node-charts.tsx:33 -#: src/renderer/components/+workloads-pods/container-charts.tsx:33 +#: src/renderer/components/+workloads-pods/container-charts.tsx:34 msgid "CPU requests" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:55 +#: src/renderer/components/+nodes/nodes.tsx:57 msgid "CPU:" msgstr "" @@ -394,14 +402,14 @@ msgstr "" #: src/renderer/components/+nodes/node-charts.tsx:39 #: src/renderer/components/+nodes/node-charts.tsx:63 #: src/renderer/components/+nodes/node-charts.tsx:97 -#: src/renderer/components/+nodes/node-details.tsx:73 +#: src/renderer/components/+nodes/node-details.tsx:72 #: src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx:31 #: src/renderer/components/+storage-volumes/volume-details.tsx:29 #: src/renderer/components/+storage-volumes/volumes.tsx:42 msgid "Capacity" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:166 +#: src/renderer/components/+preferences/preferences.tsx:163 msgid "Certificate Trust" msgstr "" @@ -451,7 +459,7 @@ msgid "Cloud API Token Secret" msgstr "" #: src/renderer/components/+namespaces/namespace-select.tsx:43 -#: src/renderer/components/layout/sidebar.tsx:85 +#: src/renderer/components/layout/sidebar.tsx:79 msgid "Cluster" msgstr "" @@ -464,11 +472,11 @@ msgstr "" msgid "Cluster Issuers" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:137 +#: src/renderer/components/+preferences/preferences.tsx:134 msgid "Color Theme" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:81 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:79 msgid "Command" msgstr "" @@ -477,7 +485,7 @@ msgstr "" msgid "Common Name" msgstr "" -#: src/renderer/components/layout/sidebar.tsx:80 +#: src/renderer/components/layout/sidebar.tsx:76 msgid "Compact view" msgstr "" @@ -495,8 +503,8 @@ msgid "Condition" msgstr "" #: src/renderer/components/+custom-resources/crd-details.tsx:52 -#: src/renderer/components/+nodes/node-details.tsx:108 -#: src/renderer/components/+nodes/nodes.tsx:120 +#: src/renderer/components/+nodes/node-details.tsx:107 +#: src/renderer/components/+nodes/nodes.tsx:127 #: src/renderer/components/+workloads-deployments/deployment-details.tsx:79 #: src/renderer/components/+workloads-deployments/deployments.tsx:64 #: src/renderer/components/+workloads-jobs/job-details.tsx:77 @@ -521,7 +529,7 @@ msgstr "" msgid "ConfigMaps" msgstr "" -#: src/renderer/components/layout/sidebar.tsx:88 +#: src/renderer/components/layout/sidebar.tsx:82 msgid "Configuration" msgstr "" @@ -553,13 +561,13 @@ msgstr "" msgid "Container memory usage" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:96 +#: src/renderer/components/+nodes/node-details.tsx:95 msgid "Container runtime" msgstr "" #: src/renderer/components/+workloads-pods/pod-details.tsx:122 #: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:186 -#: src/renderer/components/+workloads-pods/pods.tsx:76 +#: src/renderer/components/+workloads-pods/pods.tsx:77 msgid "Containers" msgstr "" @@ -567,7 +575,7 @@ msgstr "" msgid "Context" msgstr "" -#: src/renderer/components/+workloads-pods/pods.tsx:78 +#: src/renderer/components/+workloads-pods/pods.tsx:79 #: src/renderer/components/kube-object/kube-object-meta.tsx:39 msgid "Controlled By" msgstr "" @@ -667,7 +675,7 @@ msgid "Cron Jobs" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:77 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:69 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:67 msgid "CronJobs" msgstr "" @@ -688,11 +696,11 @@ msgstr "" #~ msgstr "" #: src/renderer/components/+custom-resources/crd-list.tsx:55 -#: src/renderer/components/layout/sidebar.tsx:95 +#: src/renderer/components/layout/sidebar.tsx:89 msgid "Custom Resources" msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:111 +#: src/renderer/components/+add-cluster/add-cluster.tsx:115 msgid "Custom.." msgstr "" @@ -709,13 +717,13 @@ msgid "Daemon Sets" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:53 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:59 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:57 msgid "DaemonSets" msgstr "" #: src/renderer/theme.store.ts:32 -msgid "Dark" -msgstr "" +#~ msgid "Dark" +#~ msgstr "" #: src/renderer/components/+config-maps/config-map-details.tsx:69 #: src/renderer/components/+config-secrets/secret-details.tsx:78 @@ -749,7 +757,7 @@ msgstr "" #: src/renderer/components/+workloads/workloads.tsx:45 #: src/renderer/components/+workloads-deployments/deployments.tsx:57 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:49 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:47 msgid "Deployments" msgstr "" @@ -762,21 +770,21 @@ msgstr "" msgid "Desired number of replicas" msgstr "" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:52 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:64 msgid "Disconnect" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:65 -#: src/renderer/components/+nodes/nodes.tsx:115 +#: src/renderer/components/+nodes/node-details.tsx:64 +#: src/renderer/components/+nodes/nodes.tsx:122 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:44 msgid "Disk" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:71 +#: src/renderer/components/+nodes/nodes.tsx:79 msgid "Disk:" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:171 +#: src/renderer/components/+preferences/preferences.tsx:168 msgid "Does not affect cluster communications!" msgstr "" @@ -784,7 +792,7 @@ msgstr "" msgid "Domains" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:140 +#: src/renderer/components/+preferences/preferences.tsx:137 msgid "Download Mirror" msgstr "" @@ -792,7 +800,7 @@ msgstr "" msgid "Download file" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:141 +#: src/renderer/components/+preferences/preferences.tsx:138 msgid "Download mirror for kubectl" msgstr "" @@ -837,7 +845,7 @@ msgstr "" msgid "Egress" msgstr "" -#: src/renderer/components/+network-services/service-details.tsx:66 +#: src/renderer/components/+network-services/service-details.tsx:68 msgid "Endpoint" msgstr "" @@ -863,7 +871,7 @@ msgstr "" #: src/renderer/components/+events/events.tsx:56 #: src/renderer/components/+events/kube-event-details.tsx:34 #: src/renderer/components/+events/kube-event-details.tsx:39 -#: src/renderer/components/layout/sidebar.tsx:92 +#: src/renderer/components/layout/sidebar.tsx:86 msgid "Events" msgstr "" @@ -896,7 +904,7 @@ msgid "Field Path" msgstr "" #: src/renderer/components/+workloads-pods/pod-charts.tsx:14 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:27 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:28 msgid "Filesystem" msgstr "" @@ -936,7 +944,7 @@ msgstr "" msgid "Fs Group" msgstr "" -#: src/renderer/components/+landing-page/landing-page.tsx:21 +#: src/renderer/components/+landing-page/landing-page.tsx:23 msgid "Get started by associating one or more clusters to Lens." msgstr "" @@ -958,15 +966,15 @@ msgstr "" msgid "HPA" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:160 +#: src/renderer/components/+preferences/preferences.tsx:157 msgid "HTTP Proxy" msgstr "" #: src/renderer/components/+add-cluster/add-cluster.tsx:178 -msgid "HTTP Proxy server. Used for communicating with Kubernetes API." -msgstr "" +#~ msgid "HTTP Proxy server. Used for communicating with Kubernetes API." +#~ msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:143 +#: src/renderer/components/+preferences/preferences.tsx:140 msgid "Helm" msgstr "" @@ -986,7 +994,7 @@ msgstr "" msgid "Helm Upgrade: {0}" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:50 +#: src/renderer/components/+preferences/preferences.tsx:47 msgid "Helm branch <0>{0} already in use" msgstr "" @@ -1042,11 +1050,11 @@ msgstr "" msgid "IP addresses" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:44 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:45 msgid "Image" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:48 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:49 msgid "ImagePullPolicy" msgstr "" @@ -1088,7 +1096,7 @@ msgstr "" msgid "Installing..." msgstr "" -#: src/renderer/components/input/input.validators.ts:43 +#: src/renderer/components/input/input.validators.ts:44 msgid "Invalid account ID" msgstr "" @@ -1124,11 +1132,11 @@ msgstr "" #: src/renderer/components/+workloads/workloads.tsx:69 #: src/renderer/components/+workloads-cronjobs/cronjob-details.tsx:62 #: src/renderer/components/+workloads-jobs/jobs.tsx:36 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:64 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:62 msgid "Jobs" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:93 +#: src/renderer/components/+nodes/node-details.tsx:92 msgid "Kernel version" msgstr "" @@ -1168,14 +1176,14 @@ msgstr "" msgid "Kubeconfig File" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:99 +#: src/renderer/components/+nodes/node-details.tsx:98 msgid "Kubelet version" msgstr "" #: src/renderer/components/+config-secrets/secrets.tsx:43 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuers.tsx:65 #: src/renderer/components/+namespaces/namespaces.tsx:32 -#: src/renderer/components/+nodes/node-details.tsx:102 +#: src/renderer/components/+nodes/node-details.tsx:101 #: src/renderer/components/kube-object/kube-object-meta.tsx:35 msgid "Labels" msgstr "" @@ -1200,7 +1208,7 @@ msgstr "" msgid "Last transition time: {lastTransitionTime}" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:129 +#: src/renderer/components/+preferences/preferences.tsx:126 msgid "Lens Global Settings" msgstr "" @@ -1209,8 +1217,8 @@ msgid "Level" msgstr "" #: src/renderer/theme.store.ts:33 -msgid "Light" -msgstr "" +#~ msgid "Light" +#~ msgstr "" #: src/renderer/components/+events/events.tsx:59 msgid "Limited to {0}" @@ -1218,8 +1226,8 @@ msgstr "" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:72 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:115 -#: src/renderer/components/+workloads-pods/container-charts.tsx:39 -#: src/renderer/components/+workloads-pods/container-charts.tsx:63 +#: src/renderer/components/+workloads-pods/container-charts.tsx:40 +#: src/renderer/components/+workloads-pods/container-charts.tsx:64 #: src/renderer/components/+workloads-pods/pod-charts.tsx:48 #: src/renderer/components/+workloads-pods/pod-charts.tsx:72 msgid "Limits" @@ -1233,11 +1241,11 @@ msgstr "" msgid "Link" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:73 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:71 msgid "Liveness" msgstr "" -#: src/renderer/components/+network-services/service-details.tsx:63 +#: src/renderer/components/+network-services/service-details.tsx:65 msgid "Load Balancer IP" msgstr "" @@ -1285,12 +1293,12 @@ msgstr "" #: src/renderer/components/+cluster/cluster-metric-switchers.tsx:25 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:144 -#: src/renderer/components/+nodes/node-details.tsx:64 -#: src/renderer/components/+nodes/node-details.tsx:75 -#: src/renderer/components/+nodes/node-details.tsx:80 -#: src/renderer/components/+nodes/nodes.tsx:114 +#: src/renderer/components/+nodes/node-details.tsx:63 +#: src/renderer/components/+nodes/node-details.tsx:74 +#: src/renderer/components/+nodes/node-details.tsx:79 +#: src/renderer/components/+nodes/nodes.tsx:121 #: src/renderer/components/+workloads-pods/pod-charts.tsx:12 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:26 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:27 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:63 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:96 #: src/renderer/components/resource-metrics/resource-metrics-text.tsx:18 @@ -1301,21 +1309,21 @@ msgstr "" msgid "Memory capacity" msgstr "" -#: src/renderer/components/+workloads-pods/container-charts.tsx:64 +#: src/renderer/components/+workloads-pods/container-charts.tsx:65 msgid "Memory limits" msgstr "" #: src/renderer/components/+nodes/node-charts.tsx:57 -#: src/renderer/components/+workloads-pods/container-charts.tsx:57 +#: src/renderer/components/+workloads-pods/container-charts.tsx:58 msgid "Memory requests" msgstr "" #: src/renderer/components/+nodes/node-charts.tsx:50 -#: src/renderer/components/+workloads-pods/container-charts.tsx:50 +#: src/renderer/components/+workloads-pods/container-charts.tsx:51 msgid "Memory usage" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:63 +#: src/renderer/components/+nodes/nodes.tsx:68 msgid "Memory:" msgstr "" @@ -1359,13 +1367,13 @@ msgstr "" msgid "Mountable secrets" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:63 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:61 msgid "Mounts" msgstr "" #: src/renderer/components/+workspaces/workspaces.tsx:36 -msgid "My Workspace" -msgstr "" +#~ msgid "My Workspace" +#~ msgstr "" #: src/renderer/components/+apps-helm-charts/helm-charts.tsx:64 #: src/renderer/components/+apps-releases/releases.tsx:87 @@ -1388,7 +1396,7 @@ msgstr "" #: src/renderer/components/+network-policies/network-policies.tsx:31 #: src/renderer/components/+network-services/service-details-endpoint.tsx:26 #: src/renderer/components/+network-services/services.tsx:44 -#: src/renderer/components/+nodes/nodes.tsx:112 +#: src/renderer/components/+nodes/nodes.tsx:119 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:35 #: src/renderer/components/+storage-classes/storage-classes.tsx:34 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:46 @@ -1406,7 +1414,7 @@ msgstr "" #: src/renderer/components/+workloads-jobs/jobs.tsx:37 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:92 #: src/renderer/components/+workloads-pods/pod-details.tsx:144 -#: src/renderer/components/+workloads-pods/pods.tsx:73 +#: src/renderer/components/+workloads-pods/pods.tsx:74 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:50 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:40 #: src/renderer/components/+workspaces/workspaces.tsx:117 @@ -1453,7 +1461,7 @@ msgstr "" #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:46 #: src/renderer/components/+workloads-deployments/deployments.tsx:59 #: src/renderer/components/+workloads-jobs/jobs.tsx:38 -#: src/renderer/components/+workloads-pods/pods.tsx:75 +#: src/renderer/components/+workloads-pods/pods.tsx:76 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:41 #: src/renderer/components/dock/edit-resource.tsx:91 #: src/renderer/components/dock/install-chart.tsx:122 @@ -1468,7 +1476,7 @@ msgid "Namespace: {0}" msgstr "" #: src/renderer/components/+namespaces/namespaces.tsx:30 -#: src/renderer/components/layout/sidebar.tsx:91 +#: src/renderer/components/layout/sidebar.tsx:85 msgid "Namespaces" msgstr "" @@ -1476,13 +1484,13 @@ msgstr "" msgid "Namespaces: {0}" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:170 +#: src/renderer/components/+preferences/preferences.tsx:167 msgid "Needed with some corporate proxies that do certificate re-writing." msgstr "" #: src/renderer/components/+network-ingresses/ingress-details.tsx:66 #: src/renderer/components/+workloads-pods/pod-charts.tsx:13 -#: src/renderer/components/layout/sidebar.tsx:89 +#: src/renderer/components/layout/sidebar.tsx:83 msgid "Network" msgstr "" @@ -1507,6 +1515,7 @@ msgstr "" msgid "Next" msgstr "" +#: src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx:29 #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:44 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:71 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:42 @@ -1532,7 +1541,7 @@ msgstr "" msgid "No issues found" msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:198 +#: src/renderer/components/item-object-list/item-list-layout.tsx:196 msgid "No items found." msgstr "" @@ -1571,8 +1580,8 @@ msgstr "" msgid "Node shell" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:111 -#: src/renderer/components/layout/sidebar.tsx:86 +#: src/renderer/components/+nodes/nodes.tsx:118 +#: src/renderer/components/layout/sidebar.tsx:80 msgid "Nodes" msgstr "" @@ -1596,11 +1605,11 @@ msgstr "" msgid "Number of running Pods" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:87 +#: src/renderer/components/+nodes/node-details.tsx:86 msgid "OS" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:90 +#: src/renderer/components/+nodes/node-details.tsx:89 msgid "OS Image" msgstr "" @@ -1612,7 +1621,7 @@ msgstr "" msgid "Ok" msgstr "" -#: src/renderer/components/+whats-new/whats-new.tsx:36 +#: src/renderer/components/+whats-new/whats-new.tsx:35 msgid "Ok, got it!" msgstr "" @@ -1620,11 +1629,12 @@ msgstr "" msgid "Open" msgstr "" -#: src/renderer/components/+network-services/service-ports.tsx:49 +#: src/renderer/components/+network-services/service-port-component.tsx:49 +#: src/renderer/components/+workloads-pods/pod-container-port.tsx:51 msgid "Open in a browser" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:63 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:60 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:78 #: src/renderer/components/+workloads-pods/pod-details-tolerations.tsx:17 msgid "Operator" @@ -1635,7 +1645,7 @@ msgid "Organization" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:29 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:37 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:35 msgid "Overview" msgstr "" @@ -1661,17 +1671,17 @@ msgstr "" msgid "Path Prefix" msgstr "" -#: src/renderer/components/+storage/storage.tsx:26 +#: src/renderer/components/+storage/storage.tsx:25 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:45 msgid "Persistent Volume Claims" msgstr "" -#: src/renderer/components/+storage/storage.tsx:33 +#: src/renderer/components/+storage/storage.tsx:32 #: src/renderer/components/+storage-volumes/volumes.tsx:39 msgid "Persistent Volumes" msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:52 +#: src/renderer/components/+add-cluster/add-cluster.tsx:62 msgid "Please select kubeconfig" msgstr "" @@ -1684,7 +1694,7 @@ msgid "Pod IP" msgstr "" #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:34 -#: src/renderer/components/+user-management/user-management.tsx:44 +#: src/renderer/components/+user-management/user-management.tsx:43 msgid "Pod Security Policies" msgstr "" @@ -1704,17 +1714,17 @@ msgid "Pod shell" msgstr "" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:148 -#: src/renderer/components/+nodes/node-details.tsx:66 -#: src/renderer/components/+nodes/node-details.tsx:76 -#: src/renderer/components/+nodes/node-details.tsx:81 +#: src/renderer/components/+nodes/node-details.tsx:65 +#: src/renderer/components/+nodes/node-details.tsx:75 +#: src/renderer/components/+nodes/node-details.tsx:80 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:60 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:50 #: src/renderer/components/+workloads/workloads.tsx:37 #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:47 #: src/renderer/components/+workloads-deployments/deployments.tsx:60 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:44 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:42 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:89 -#: src/renderer/components/+workloads-pods/pods.tsx:72 +#: src/renderer/components/+workloads-pods/pods.tsx:73 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:52 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:42 msgid "Pods" @@ -1734,11 +1744,11 @@ msgstr "" #: src/renderer/components/+network-policies/network-policy-details.tsx:109 #: src/renderer/components/+network-services/service-details.tsx:59 #: src/renderer/components/+network-services/services.tsx:48 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:52 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:53 msgid "Ports" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:124 +#: src/renderer/components/+preferences/preferences.tsx:121 msgid "Preferences" msgstr "" @@ -1760,15 +1770,15 @@ msgstr "" msgid "Provisioner" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:163 +#: src/renderer/components/+preferences/preferences.tsx:160 msgid "Proxy is used only for non-cluster communication." msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:172 +#: src/renderer/components/+add-cluster/add-cluster.tsx:175 msgid "Proxy settings" msgstr "" -#: src/renderer/components/+workloads-pods/pods.tsx:79 +#: src/renderer/components/+workloads-pods/pods.tsx:80 msgid "QoS" msgstr "" @@ -1776,7 +1786,7 @@ msgstr "" msgid "QoS Class" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:55 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:52 msgid "Quotas" msgstr "" @@ -1792,7 +1802,7 @@ msgstr "" msgid "Read-only Root Filesystem" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:77 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:75 msgid "Readiness" msgstr "" @@ -1844,11 +1854,11 @@ msgstr "" msgid "Releases" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:154 +#: src/renderer/components/+preferences/preferences.tsx:151 #: src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx:60 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:60 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:64 -#: src/renderer/components/item-object-list/item-list-layout.tsx:181 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:74 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:80 +#: src/renderer/components/item-object-list/item-list-layout.tsx:179 #: src/renderer/components/menu/menu-actions.tsx:49 #: src/renderer/components/menu/menu-actions.tsx:85 msgid "Remove" @@ -1878,7 +1888,7 @@ msgstr "" msgid "Remove selected bindings from ${name}" msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:277 +#: src/renderer/components/item-object-list/item-list-layout.tsx:275 msgid "Remove selected items ({0})" msgstr "" @@ -1886,7 +1896,7 @@ msgstr "" msgid "Remove {resourceKind} <0>{resourceName}?" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:117 +#: src/renderer/components/+preferences/preferences.tsx:114 msgid "Removing helm branch <0>{0} has failed: {1}" msgstr "" @@ -1910,7 +1920,7 @@ msgstr "" msgid "Repo/Name" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:144 +#: src/renderer/components/+preferences/preferences.tsx:141 msgid "Repositories" msgstr "" @@ -1930,8 +1940,8 @@ msgstr "" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:114 #: src/renderer/components/+nodes/node-charts.tsx:32 #: src/renderer/components/+nodes/node-charts.tsx:56 -#: src/renderer/components/+workloads-pods/container-charts.tsx:32 -#: src/renderer/components/+workloads-pods/container-charts.tsx:56 +#: src/renderer/components/+workloads-pods/container-charts.tsx:33 +#: src/renderer/components/+workloads-pods/container-charts.tsx:57 #: src/renderer/components/+workloads-pods/pod-charts.tsx:41 #: src/renderer/components/+workloads-pods/pod-charts.tsx:65 msgid "Requests" @@ -1949,7 +1959,7 @@ msgstr "" msgid "Reset" msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:201 +#: src/renderer/components/item-object-list/item-list-layout.tsx:199 msgid "Reset filters?" msgstr "" @@ -2001,7 +2011,7 @@ msgstr "" msgid "Restart session" msgstr "" -#: src/renderer/components/+workloads-pods/pods.tsx:77 +#: src/renderer/components/+workloads-pods/pods.tsx:78 msgid "Restarts" msgstr "" @@ -2019,7 +2029,7 @@ msgstr "" msgid "Role" msgstr "" -#: src/renderer/components/+user-management/user-management.tsx:32 +#: src/renderer/components/+user-management/user-management.tsx:31 #: src/renderer/components/+user-management-roles-bindings/role-bindings.tsx:34 msgid "Role Bindings" msgstr "" @@ -2032,8 +2042,8 @@ msgstr "" msgid "Role name" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:117 -#: src/renderer/components/+user-management/user-management.tsx:37 +#: src/renderer/components/+nodes/nodes.tsx:124 +#: src/renderer/components/+user-management/user-management.tsx:36 #: src/renderer/components/+user-management-roles/roles.tsx:32 msgid "Roles" msgstr "" @@ -2100,11 +2110,11 @@ msgstr "" msgid "Scope" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:60 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:57 msgid "Scope Selector" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:64 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:61 msgid "Scope name" msgstr "" @@ -2152,7 +2162,7 @@ msgstr "" msgid "Select a quota.." msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:169 +#: src/renderer/components/+add-cluster/add-cluster.tsx:172 msgid "Select kubeconfig" msgstr "" @@ -2189,7 +2199,7 @@ msgstr "" msgid "Service" msgstr "" -#: src/renderer/components/+user-management/user-management.tsx:27 +#: src/renderer/components/+user-management/user-management.tsx:26 #: src/renderer/components/+user-management-service-accounts/service-accounts.tsx:35 msgid "Service Accounts" msgstr "" @@ -2203,7 +2213,7 @@ msgstr "" msgid "Session Affinity" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:43 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:40 msgid "Set" msgstr "" @@ -2211,7 +2221,7 @@ msgstr "" msgid "Set quota" msgstr "" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:47 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:53 msgid "Settings" msgstr "" @@ -2263,7 +2273,7 @@ msgid "Stateful Sets" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:61 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:54 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:52 msgid "StatefulSets" msgstr "" @@ -2283,10 +2293,10 @@ msgstr "" #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:52 #: src/renderer/components/+storage-volumes/volume-details.tsx:46 #: src/renderer/components/+storage-volumes/volumes.tsx:45 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:38 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:39 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:97 #: src/renderer/components/+workloads-pods/pod-details.tsx:82 -#: src/renderer/components/+workloads-pods/pods.tsx:81 +#: src/renderer/components/+workloads-pods/pods.tsx:82 msgid "Status" msgstr "" @@ -2295,7 +2305,7 @@ msgid "Status URI" msgstr "" #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:57 -#: src/renderer/components/layout/sidebar.tsx:90 +#: src/renderer/components/layout/sidebar.tsx:84 msgid "Storage" msgstr "" @@ -2308,7 +2318,7 @@ msgstr "" msgid "Storage Class Name" msgstr "" -#: src/renderer/components/+storage/storage.tsx:41 +#: src/renderer/components/+storage/storage.tsx:40 #: src/renderer/components/+storage-classes/storage-classes.tsx:33 msgid "Storage Classes" msgstr "" @@ -2356,20 +2366,20 @@ msgstr "" msgid "TLS" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:104 -#: src/renderer/components/+nodes/nodes.tsx:116 +#: src/renderer/components/+nodes/node-details.tsx:103 +#: src/renderer/components/+nodes/nodes.tsx:123 msgid "Taints" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:174 +#: src/renderer/components/+preferences/preferences.tsx:171 msgid "Telemetry & Usage Tracking" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:177 +#: src/renderer/components/+preferences/preferences.tsx:174 msgid "Telemetry & usage data is collected to continuously improve the Lens experience." msgstr "" -#: src/renderer/components/dock/terminal.store.ts:29 +#: src/renderer/components/dock/terminal.store.ts:28 msgid "Terminal" msgstr "" @@ -2390,14 +2400,14 @@ msgid "This field is required" msgstr "" #: src/renderer/components/input/input.validators.ts:39 -msgid "This field must contain only lowercase latin characters, numbers and dash." +msgid "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." msgstr "" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:84 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:104 msgid "This is the quick launch menu." msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:169 +#: src/renderer/components/+preferences/preferences.tsx:166 msgid "This will make Lens to trust ANY certificate authority without any validations." msgstr "" @@ -2440,7 +2450,7 @@ msgstr "" msgid "Type" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:161 +#: src/renderer/components/+preferences/preferences.tsx:158 msgid "Type HTTP proxy url (example: http://proxy.acme.org:8080)" msgstr "" @@ -2482,14 +2492,15 @@ msgstr "" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:70 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:113 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:134 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:40 #: src/renderer/components/+nodes/node-charts.tsx:25 #: src/renderer/components/+nodes/node-charts.tsx:49 #: src/renderer/components/+nodes/node-charts.tsx:73 #: src/renderer/components/+nodes/node-charts.tsx:90 #: src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx:24 -#: src/renderer/components/+workloads-pods/container-charts.tsx:25 -#: src/renderer/components/+workloads-pods/container-charts.tsx:49 -#: src/renderer/components/+workloads-pods/container-charts.tsx:73 +#: src/renderer/components/+workloads-pods/container-charts.tsx:26 +#: src/renderer/components/+workloads-pods/container-charts.tsx:50 +#: src/renderer/components/+workloads-pods/container-charts.tsx:74 #: src/renderer/components/+workloads-pods/pod-charts.tsx:34 #: src/renderer/components/+workloads-pods/pod-charts.tsx:58 #: src/renderer/components/+workloads-pods/pod-charts.tsx:99 @@ -2501,8 +2512,8 @@ msgid "Use same name for RoleBinding" msgstr "" #: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:43 -msgid "Used" -msgstr "" +#~ msgid "Used" +#~ msgstr "" #: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:155 msgid "User" @@ -2520,7 +2531,7 @@ msgstr "" #: src/renderer/components/+apps-releases/release-details.tsx:111 #: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:132 -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:65 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:62 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:79 msgid "Values" msgstr "" @@ -2535,7 +2546,7 @@ msgstr "" #: src/renderer/components/+apps-releases/releases.tsx:91 #: src/renderer/components/+custom-resources/crd-details.tsx:35 #: src/renderer/components/+custom-resources/crd-list.tsx:75 -#: src/renderer/components/+nodes/nodes.tsx:118 +#: src/renderer/components/+nodes/nodes.tsx:125 #: src/renderer/components/dock/install-chart.tsx:120 #: src/renderer/components/dock/upgrade-chart.tsx:99 msgid "Version" @@ -2571,7 +2582,7 @@ msgstr "" msgid "Warnings: {0}" msgstr "" -#: src/renderer/components/+landing-page/landing-page.tsx:18 +#: src/renderer/components/+landing-page/landing-page.tsx:20 msgid "Welcome!" msgstr "" @@ -2583,7 +2594,7 @@ msgstr "" msgid "Worker" msgstr "" -#: src/renderer/components/layout/sidebar.tsx:87 +#: src/renderer/components/layout/sidebar.tsx:81 msgid "Workloads" msgstr "" @@ -2604,6 +2615,7 @@ msgstr "" msgid "Wrong url format" msgstr "" +#: src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx:28 #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:44 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:71 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:42 @@ -2629,19 +2641,19 @@ msgstr "" msgid "ago" msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:180 +#: src/renderer/components/item-object-list/item-list-layout.tsx:178 msgid "and <0>{tailCount} more" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:129 +#: src/renderer/components/+preferences/preferences.tsx:126 msgid "applicable to all clusters" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:55 +#: src/renderer/components/+nodes/nodes.tsx:57 msgid "cores:" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:41 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:42 msgid "exit code" msgstr "" @@ -2658,11 +2670,15 @@ msgstr "" msgid "never" msgstr "" +#: src/renderer/components/cluster-manager/clusters-menu.tsx:119 +msgid "new" +msgstr "" + #: src/renderer/components/+custom-resources/crd-details.tsx:64 msgid "plural" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:40 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:41 msgid "ready" msgstr "" @@ -2710,7 +2726,7 @@ msgstr "" msgid "{accountName} kubeconfig" msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:230 +#: src/renderer/components/item-object-list/item-list-layout.tsx:228 msgid "{allItemsCount, plural, one {# item} other {# items}}" msgstr "" @@ -2726,7 +2742,7 @@ msgstr "" msgid "{resourceType} <0>{resourceName} updated." msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:181 +#: src/renderer/components/item-object-list/item-list-layout.tsx:179 msgid "{selectedCount, plural, one {<0>Remove item <1>{selectedNames}?} other {<2>Remove <3>{selectedCount} items <4>{selectedNames} {tail}?}}" msgstr "" diff --git a/locales/ru/messages.po b/locales/ru/messages.po index c32d565891..704970ed74 100644 --- a/locales/ru/messages.po +++ b/locales/ru/messages.po @@ -35,24 +35,28 @@ msgid "(empty) (Allowing the specific traffic to all pods in this namespace)" msgstr "(Пусто) (Допускается трафик ко всем подам в данной области имен)" #: src/renderer/components/+add-cluster/add-cluster.tsx:105 -msgid "(new)" -msgstr "" +#~ msgid "(new)" +#~ msgstr "" -#: src/renderer/components/item-object-list/item-list-layout.tsx:226 +#: src/renderer/components/item-object-list/item-list-layout.tsx:224 msgid "<0>Filtered: {itemsCount} / {allItemsCount}" msgstr "<0>Отфильтровано: {itemsCount} / {allItemsCount}" #: src/renderer/browser-check.tsx:11 -msgid "<0>Your browser does not support all Lens features. Please consider using another browser." -msgstr "<0>Ваш браузер не поддерживает все возможности Lens. Пожалуйста рассмотрите использование другого современного браузера." +#~ msgid "<0>Your browser does not support all Lens features. Please consider using another browser." +#~ msgstr "<0>Ваш браузер не поддерживает все возможности Lens. Пожалуйста рассмотрите использование другого современного браузера." #: src/renderer/components/dock/create-resource.tsx:56 msgid "<0>{0} successfully created" msgstr "" #: src/renderer/components/+add-cluster/add-cluster.tsx:176 -msgid "A HTTP proxy server URL (format: http://
:)" -msgstr "" +#~ msgid "A HTTP proxy server URL (format: http://
:)" +#~ msgstr "" + +#: src/renderer/components/input/input.validators.ts:40 +msgid "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." +msgstr "Это поле может содержать только латинские буквы в нижнем регистре, номера и дефис." #: src/renderer/components/+workspaces/workspaces.tsx:84 msgid "A single workspaces contains a list of clusters and their full configuration." @@ -62,7 +66,7 @@ msgstr "" msgid "API Group" msgstr "" -#: src/renderer/components/layout/sidebar.tsx:94 +#: src/renderer/components/layout/sidebar.tsx:88 msgid "Access Control" msgstr "Контроль доступа" @@ -80,8 +84,8 @@ msgstr "Название аккаунта" msgid "Active" msgstr "Активный" -#: src/renderer/components/+add-cluster/add-cluster.tsx:168 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:99 +#: src/renderer/components/+add-cluster/add-cluster.tsx:170 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:116 msgid "Add Cluster" msgstr "" @@ -102,7 +106,11 @@ msgid "Add bindings to {name}" msgstr "Добавить привязки к {name}" #: src/renderer/components/+add-cluster/add-cluster.tsx:187 -msgid "Add cluster" +#~ msgid "Add cluster" +#~ msgstr "" + +#: src/renderer/components/+add-cluster/add-cluster.tsx:191 +msgid "Add cluster(s)" msgstr "" #: src/renderer/components/+workspaces/clusters-menu.tsx:58 @@ -117,11 +125,11 @@ msgstr "Добавить поле" #~ msgid "Added repos" #~ msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:147 +#: src/renderer/components/+preferences/preferences.tsx:144 msgid "Added repos:" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:106 +#: src/renderer/components/+preferences/preferences.tsx:103 msgid "Adding helm branch <0>{0} has failed: {1}" msgstr "" @@ -135,7 +143,7 @@ msgstr "" #: src/renderer/components/+network-endpoints/endpoint-subset-list.tsx:29 #: src/renderer/components/+network-endpoints/endpoint-subset-list.tsx:60 -#: src/renderer/components/+nodes/node-details.tsx:84 +#: src/renderer/components/+nodes/node-details.tsx:83 msgid "Addresses" msgstr "Адреса" @@ -157,7 +165,7 @@ msgstr "Аффинитеты" #: src/renderer/components/+network-ingresses/ingresses.tsx:35 #: src/renderer/components/+network-policies/network-policies.tsx:34 #: src/renderer/components/+network-services/services.tsx:51 -#: src/renderer/components/+nodes/nodes.tsx:119 +#: src/renderer/components/+nodes/nodes.tsx:126 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:38 #: src/renderer/components/+storage-classes/storage-classes.tsx:38 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:51 @@ -169,7 +177,7 @@ msgstr "Аффинитеты" #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:50 #: src/renderer/components/+workloads-deployments/deployments.tsx:63 #: src/renderer/components/+workloads-jobs/jobs.tsx:41 -#: src/renderer/components/+workloads-pods/pods.tsx:80 +#: src/renderer/components/+workloads-pods/pods.tsx:81 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:53 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:44 msgid "Age" @@ -195,7 +203,7 @@ msgstr "Все логи" msgid "All namespaces" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:78 +#: src/renderer/components/+nodes/node-details.tsx:77 msgid "Allocatable" msgstr "" @@ -203,11 +211,11 @@ msgstr "" msgid "Allow Privilege Escalation" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:175 +#: src/renderer/components/+preferences/preferences.tsx:172 msgid "Allow telemetry & usage tracking" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:167 +#: src/renderer/components/+preferences/preferences.tsx:164 msgid "Allow untrusted Certificate Authorities" msgstr "" @@ -239,7 +247,7 @@ msgstr "" msgid "Allowed Unsafe Sysctls" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:103 +#: src/renderer/components/+nodes/node-details.tsx:102 #: src/renderer/components/kube-object/kube-object-meta.tsx:36 msgid "Annotations" msgstr "Аннотации" @@ -261,7 +269,7 @@ msgstr "Сбой работы приложения на <0>{pageUrl}" msgid "Applying.." msgstr "Применение.." -#: src/renderer/components/layout/sidebar.tsx:93 +#: src/renderer/components/layout/sidebar.tsx:87 msgid "Apps" msgstr "Приложения" @@ -273,11 +281,11 @@ msgstr "" msgid "Are you sure you want to drain <0>{nodeName}?" msgstr "Выполнить команду drain для ноды <0>{nodeName}?" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:86 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:84 msgid "Arguments" msgstr "Аргументы" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:86 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:106 msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button." msgstr "" @@ -311,7 +319,7 @@ msgstr "Привязки" #~ msgid "Build version" #~ msgstr "Версия билда" -#: src/renderer/components/+workloads-pods/container-charts.tsx:74 +#: src/renderer/components/+workloads-pods/container-charts.tsx:75 #: src/renderer/components/+workloads-pods/pod-charts.tsx:100 msgid "Bytes consumed on this filesystem" msgstr "Байты, потребляемые в файловой системе" @@ -347,12 +355,12 @@ msgstr "CA Bundle" #: src/renderer/components/+cluster/cluster-metric-switchers.tsx:24 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:140 -#: src/renderer/components/+nodes/node-details.tsx:63 -#: src/renderer/components/+nodes/node-details.tsx:74 -#: src/renderer/components/+nodes/node-details.tsx:79 -#: src/renderer/components/+nodes/nodes.tsx:113 +#: src/renderer/components/+nodes/node-details.tsx:62 +#: src/renderer/components/+nodes/node-details.tsx:73 +#: src/renderer/components/+nodes/node-details.tsx:78 +#: src/renderer/components/+nodes/nodes.tsx:120 #: src/renderer/components/+workloads-pods/pod-charts.tsx:11 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:25 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:26 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:53 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:95 #: src/renderer/components/resource-metrics/resource-metrics-text.tsx:13 @@ -364,21 +372,21 @@ msgid "CPU capacity" msgstr "Мощность процессора" #: src/renderer/components/+nodes/node-charts.tsx:26 -#: src/renderer/components/+workloads-pods/container-charts.tsx:26 +#: src/renderer/components/+workloads-pods/container-charts.tsx:27 msgid "CPU cores usage" msgstr "Использование ядер процессора" -#: src/renderer/components/+workloads-pods/container-charts.tsx:40 +#: src/renderer/components/+workloads-pods/container-charts.tsx:41 #: src/renderer/components/+workloads-pods/pod-charts.tsx:49 msgid "CPU limits" msgstr "Лимиты процессора" #: src/renderer/components/+nodes/node-charts.tsx:33 -#: src/renderer/components/+workloads-pods/container-charts.tsx:33 +#: src/renderer/components/+workloads-pods/container-charts.tsx:34 msgid "CPU requests" msgstr "Запросы к процессору" -#: src/renderer/components/+nodes/nodes.tsx:55 +#: src/renderer/components/+nodes/nodes.tsx:57 msgid "CPU:" msgstr "CPU:" @@ -395,14 +403,14 @@ msgstr "Отмена" #: src/renderer/components/+nodes/node-charts.tsx:39 #: src/renderer/components/+nodes/node-charts.tsx:63 #: src/renderer/components/+nodes/node-charts.tsx:97 -#: src/renderer/components/+nodes/node-details.tsx:73 +#: src/renderer/components/+nodes/node-details.tsx:72 #: src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx:31 #: src/renderer/components/+storage-volumes/volume-details.tsx:29 #: src/renderer/components/+storage-volumes/volumes.tsx:42 msgid "Capacity" msgstr "Емкость" -#: src/renderer/components/+preferences/preferences.tsx:166 +#: src/renderer/components/+preferences/preferences.tsx:163 msgid "Certificate Trust" msgstr "" @@ -456,7 +464,7 @@ msgid "Cloud API Token Secret" msgstr "Cloud API Token Secret" #: src/renderer/components/+namespaces/namespace-select.tsx:43 -#: src/renderer/components/layout/sidebar.tsx:85 +#: src/renderer/components/layout/sidebar.tsx:79 msgid "Cluster" msgstr "Кластер" @@ -469,11 +477,11 @@ msgstr "IP-адрес кластера" msgid "Cluster Issuers" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:137 +#: src/renderer/components/+preferences/preferences.tsx:134 msgid "Color Theme" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:81 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:79 msgid "Command" msgstr "Команда" @@ -482,7 +490,7 @@ msgstr "Команда" msgid "Common Name" msgstr "Общее имя" -#: src/renderer/components/layout/sidebar.tsx:80 +#: src/renderer/components/layout/sidebar.tsx:76 msgid "Compact view" msgstr "Компактный вид" @@ -500,8 +508,8 @@ msgid "Condition" msgstr "Состояние" #: src/renderer/components/+custom-resources/crd-details.tsx:52 -#: src/renderer/components/+nodes/node-details.tsx:108 -#: src/renderer/components/+nodes/nodes.tsx:120 +#: src/renderer/components/+nodes/node-details.tsx:107 +#: src/renderer/components/+nodes/nodes.tsx:127 #: src/renderer/components/+workloads-deployments/deployment-details.tsx:79 #: src/renderer/components/+workloads-deployments/deployments.tsx:64 #: src/renderer/components/+workloads-jobs/job-details.tsx:77 @@ -526,7 +534,7 @@ msgstr "ConfigMap <0>{0} успешно обновлена." msgid "ConfigMaps" msgstr "ConfigMaps" -#: src/renderer/components/layout/sidebar.tsx:88 +#: src/renderer/components/layout/sidebar.tsx:82 msgid "Configuration" msgstr "Конфигурация" @@ -558,13 +566,13 @@ msgstr "Запросы памяти от контейнеров" msgid "Container memory usage" msgstr "Использование памяти" -#: src/renderer/components/+nodes/node-details.tsx:96 +#: src/renderer/components/+nodes/node-details.tsx:95 msgid "Container runtime" msgstr "Среда контейнеров" #: src/renderer/components/+workloads-pods/pod-details.tsx:122 #: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:186 -#: src/renderer/components/+workloads-pods/pods.tsx:76 +#: src/renderer/components/+workloads-pods/pods.tsx:77 msgid "Containers" msgstr "Контейнеры" @@ -572,7 +580,7 @@ msgstr "Контейнеры" msgid "Context" msgstr "Контекст" -#: src/renderer/components/+workloads-pods/pods.tsx:78 +#: src/renderer/components/+workloads-pods/pods.tsx:79 #: src/renderer/components/kube-object/kube-object-meta.tsx:39 msgid "Controlled By" msgstr "Управляемый" @@ -672,7 +680,7 @@ msgid "Cron Jobs" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:77 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:69 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:67 msgid "CronJobs" msgstr "CronJobs" @@ -693,11 +701,11 @@ msgstr "Текущие фильтры:" #~ msgstr "" #: src/renderer/components/+custom-resources/crd-list.tsx:55 -#: src/renderer/components/layout/sidebar.tsx:95 +#: src/renderer/components/layout/sidebar.tsx:89 msgid "Custom Resources" msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:111 +#: src/renderer/components/+add-cluster/add-cluster.tsx:115 msgid "Custom.." msgstr "" @@ -714,13 +722,13 @@ msgid "Daemon Sets" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:53 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:59 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:57 msgid "DaemonSets" msgstr "DaemonSets" #: src/renderer/theme.store.ts:32 -msgid "Dark" -msgstr "" +#~ msgid "Dark" +#~ msgstr "" #: src/renderer/components/+config-maps/config-map-details.tsx:69 #: src/renderer/components/+config-secrets/secret-details.tsx:78 @@ -754,7 +762,7 @@ msgstr "" #: src/renderer/components/+workloads/workloads.tsx:45 #: src/renderer/components/+workloads-deployments/deployments.tsx:57 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:49 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:47 msgid "Deployments" msgstr "Deployments" @@ -767,21 +775,21 @@ msgstr "Описание" msgid "Desired number of replicas" msgstr "Нужный уровень реплик" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:52 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:64 msgid "Disconnect" msgstr "" -#: src/renderer/components/+nodes/node-details.tsx:65 -#: src/renderer/components/+nodes/nodes.tsx:115 +#: src/renderer/components/+nodes/node-details.tsx:64 +#: src/renderer/components/+nodes/nodes.tsx:122 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:44 msgid "Disk" msgstr "Диск" -#: src/renderer/components/+nodes/nodes.tsx:71 +#: src/renderer/components/+nodes/nodes.tsx:79 msgid "Disk:" msgstr "Диск:" -#: src/renderer/components/+preferences/preferences.tsx:171 +#: src/renderer/components/+preferences/preferences.tsx:168 msgid "Does not affect cluster communications!" msgstr "" @@ -789,7 +797,7 @@ msgstr "" msgid "Domains" msgstr "Домены" -#: src/renderer/components/+preferences/preferences.tsx:140 +#: src/renderer/components/+preferences/preferences.tsx:137 msgid "Download Mirror" msgstr "" @@ -797,7 +805,7 @@ msgstr "" msgid "Download file" msgstr "Скачать файл" -#: src/renderer/components/+preferences/preferences.tsx:141 +#: src/renderer/components/+preferences/preferences.tsx:138 msgid "Download mirror for kubectl" msgstr "" @@ -842,7 +850,7 @@ msgstr "Эффект" msgid "Egress" msgstr "Egress" -#: src/renderer/components/+network-services/service-details.tsx:66 +#: src/renderer/components/+network-services/service-details.tsx:68 msgid "Endpoint" msgstr "" @@ -868,7 +876,7 @@ msgstr "Стэк ошибки" #: src/renderer/components/+events/events.tsx:56 #: src/renderer/components/+events/kube-event-details.tsx:34 #: src/renderer/components/+events/kube-event-details.tsx:39 -#: src/renderer/components/layout/sidebar.tsx:92 +#: src/renderer/components/layout/sidebar.tsx:86 msgid "Events" msgstr "События" @@ -906,7 +914,7 @@ msgid "Field Path" msgstr "" #: src/renderer/components/+workloads-pods/pod-charts.tsx:14 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:27 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:28 msgid "Filesystem" msgstr "Файловая система" @@ -946,7 +954,7 @@ msgstr "От <0>{from} до <1>{to}" msgid "Fs Group" msgstr "" -#: src/renderer/components/+landing-page/landing-page.tsx:21 +#: src/renderer/components/+landing-page/landing-page.tsx:23 msgid "Get started by associating one or more clusters to Lens." msgstr "" @@ -968,15 +976,15 @@ msgstr "Группы" msgid "HPA" msgstr "HPA" -#: src/renderer/components/+preferences/preferences.tsx:160 +#: src/renderer/components/+preferences/preferences.tsx:157 msgid "HTTP Proxy" msgstr "" #: src/renderer/components/+add-cluster/add-cluster.tsx:178 -msgid "HTTP Proxy server. Used for communicating with Kubernetes API." -msgstr "" +#~ msgid "HTTP Proxy server. Used for communicating with Kubernetes API." +#~ msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:143 +#: src/renderer/components/+preferences/preferences.tsx:140 msgid "Helm" msgstr "" @@ -996,7 +1004,7 @@ msgstr "Helm установка: {repo}/{name}" msgid "Helm Upgrade: {0}" msgstr "Helm обновление: {0}" -#: src/renderer/components/+preferences/preferences.tsx:50 +#: src/renderer/components/+preferences/preferences.tsx:47 msgid "Helm branch <0>{0} already in use" msgstr "" @@ -1052,11 +1060,11 @@ msgstr "Http01" msgid "IP addresses" msgstr "IP-адреса" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:44 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:45 msgid "Image" msgstr "Изображение" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:48 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:49 msgid "ImagePullPolicy" msgstr "ImagePullPolicy" @@ -1098,7 +1106,7 @@ msgstr "Установка завершена!" msgid "Installing..." msgstr "Установка.." -#: src/renderer/components/input/input.validators.ts:43 +#: src/renderer/components/input/input.validators.ts:44 msgid "Invalid account ID" msgstr "Неверный ID аккаунта" @@ -1134,11 +1142,11 @@ msgstr "" #: src/renderer/components/+workloads/workloads.tsx:69 #: src/renderer/components/+workloads-cronjobs/cronjob-details.tsx:62 #: src/renderer/components/+workloads-jobs/jobs.tsx:36 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:64 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:62 msgid "Jobs" msgstr "Jobs" -#: src/renderer/components/+nodes/node-details.tsx:93 +#: src/renderer/components/+nodes/node-details.tsx:92 msgid "Kernel version" msgstr "Версия Kernel" @@ -1178,14 +1186,14 @@ msgstr "Файл конфигурации" msgid "Kubeconfig File" msgstr "Файл конфигурации" -#: src/renderer/components/+nodes/node-details.tsx:99 +#: src/renderer/components/+nodes/node-details.tsx:98 msgid "Kubelet version" msgstr "Версия Kubelet" #: src/renderer/components/+config-secrets/secrets.tsx:43 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuers.tsx:65 #: src/renderer/components/+namespaces/namespaces.tsx:32 -#: src/renderer/components/+nodes/node-details.tsx:102 +#: src/renderer/components/+nodes/node-details.tsx:101 #: src/renderer/components/kube-object/kube-object-meta.tsx:35 msgid "Labels" msgstr "Метки" @@ -1210,7 +1218,7 @@ msgstr "Увиденно в последний раз" msgid "Last transition time: {lastTransitionTime}" msgstr "Последнее изменение: {lastTransitionTime}" -#: src/renderer/components/+preferences/preferences.tsx:129 +#: src/renderer/components/+preferences/preferences.tsx:126 msgid "Lens Global Settings" msgstr "" @@ -1219,8 +1227,8 @@ msgid "Level" msgstr "" #: src/renderer/theme.store.ts:33 -msgid "Light" -msgstr "" +#~ msgid "Light" +#~ msgstr "" #: src/renderer/components/+events/events.tsx:59 msgid "Limited to {0}" @@ -1228,8 +1236,8 @@ msgstr "" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:72 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:115 -#: src/renderer/components/+workloads-pods/container-charts.tsx:39 -#: src/renderer/components/+workloads-pods/container-charts.tsx:63 +#: src/renderer/components/+workloads-pods/container-charts.tsx:40 +#: src/renderer/components/+workloads-pods/container-charts.tsx:64 #: src/renderer/components/+workloads-pods/pod-charts.tsx:48 #: src/renderer/components/+workloads-pods/pod-charts.tsx:72 msgid "Limits" @@ -1243,11 +1251,11 @@ msgstr "Строки" msgid "Link" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:73 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:71 msgid "Liveness" msgstr "Живучесть" -#: src/renderer/components/+network-services/service-details.tsx:63 +#: src/renderer/components/+network-services/service-details.tsx:65 msgid "Load Balancer IP" msgstr "IP балансировщика нагрузки" @@ -1295,12 +1303,12 @@ msgstr "" #: src/renderer/components/+cluster/cluster-metric-switchers.tsx:25 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:144 -#: src/renderer/components/+nodes/node-details.tsx:64 -#: src/renderer/components/+nodes/node-details.tsx:75 -#: src/renderer/components/+nodes/node-details.tsx:80 -#: src/renderer/components/+nodes/nodes.tsx:114 +#: src/renderer/components/+nodes/node-details.tsx:63 +#: src/renderer/components/+nodes/node-details.tsx:74 +#: src/renderer/components/+nodes/node-details.tsx:79 +#: src/renderer/components/+nodes/nodes.tsx:121 #: src/renderer/components/+workloads-pods/pod-charts.tsx:12 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:26 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:27 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:63 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:96 #: src/renderer/components/resource-metrics/resource-metrics-text.tsx:18 @@ -1311,21 +1319,21 @@ msgstr "Память" msgid "Memory capacity" msgstr "Объем памяти" -#: src/renderer/components/+workloads-pods/container-charts.tsx:64 +#: src/renderer/components/+workloads-pods/container-charts.tsx:65 msgid "Memory limits" msgstr "Лимиты памяти" #: src/renderer/components/+nodes/node-charts.tsx:57 -#: src/renderer/components/+workloads-pods/container-charts.tsx:57 +#: src/renderer/components/+workloads-pods/container-charts.tsx:58 msgid "Memory requests" msgstr "Запросы к памяти" #: src/renderer/components/+nodes/node-charts.tsx:50 -#: src/renderer/components/+workloads-pods/container-charts.tsx:50 +#: src/renderer/components/+workloads-pods/container-charts.tsx:51 msgid "Memory usage" msgstr "Использование памяти" -#: src/renderer/components/+nodes/nodes.tsx:63 +#: src/renderer/components/+nodes/nodes.tsx:68 msgid "Memory:" msgstr "Память:" @@ -1369,13 +1377,13 @@ msgstr "Опции монтирования" msgid "Mountable secrets" msgstr "Монтируемые секреты" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:63 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:61 msgid "Mounts" msgstr "Установки" #: src/renderer/components/+workspaces/workspaces.tsx:36 -msgid "My Workspace" -msgstr "" +#~ msgid "My Workspace" +#~ msgstr "" #: src/renderer/components/+apps-helm-charts/helm-charts.tsx:64 #: src/renderer/components/+apps-releases/releases.tsx:87 @@ -1398,7 +1406,7 @@ msgstr "" #: src/renderer/components/+network-policies/network-policies.tsx:31 #: src/renderer/components/+network-services/service-details-endpoint.tsx:26 #: src/renderer/components/+network-services/services.tsx:44 -#: src/renderer/components/+nodes/nodes.tsx:112 +#: src/renderer/components/+nodes/nodes.tsx:119 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:35 #: src/renderer/components/+storage-classes/storage-classes.tsx:34 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:46 @@ -1416,7 +1424,7 @@ msgstr "" #: src/renderer/components/+workloads-jobs/jobs.tsx:37 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:92 #: src/renderer/components/+workloads-pods/pod-details.tsx:144 -#: src/renderer/components/+workloads-pods/pods.tsx:73 +#: src/renderer/components/+workloads-pods/pods.tsx:74 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:50 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:40 #: src/renderer/components/+workspaces/workspaces.tsx:117 @@ -1463,7 +1471,7 @@ msgstr "" #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:46 #: src/renderer/components/+workloads-deployments/deployments.tsx:59 #: src/renderer/components/+workloads-jobs/jobs.tsx:38 -#: src/renderer/components/+workloads-pods/pods.tsx:75 +#: src/renderer/components/+workloads-pods/pods.tsx:76 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:41 #: src/renderer/components/dock/edit-resource.tsx:91 #: src/renderer/components/dock/install-chart.tsx:122 @@ -1478,7 +1486,7 @@ msgid "Namespace: {0}" msgstr "Namespace: {0}" #: src/renderer/components/+namespaces/namespaces.tsx:30 -#: src/renderer/components/layout/sidebar.tsx:91 +#: src/renderer/components/layout/sidebar.tsx:85 msgid "Namespaces" msgstr "Namespaces" @@ -1486,13 +1494,13 @@ msgstr "Namespaces" msgid "Namespaces: {0}" msgstr "Namespaces: {0}" -#: src/renderer/components/+preferences/preferences.tsx:170 +#: src/renderer/components/+preferences/preferences.tsx:167 msgid "Needed with some corporate proxies that do certificate re-writing." msgstr "" #: src/renderer/components/+network-ingresses/ingress-details.tsx:66 #: src/renderer/components/+workloads-pods/pod-charts.tsx:13 -#: src/renderer/components/layout/sidebar.tsx:89 +#: src/renderer/components/layout/sidebar.tsx:83 msgid "Network" msgstr "Сеть" @@ -1525,6 +1533,7 @@ msgstr "Новая вкладка" msgid "Next" msgstr "Далее" +#: src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx:29 #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:44 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:71 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:42 @@ -1550,7 +1559,7 @@ msgstr "Нет доступных фильтров." msgid "No issues found" msgstr "Проблемы не обнаружены" -#: src/renderer/components/item-object-list/item-list-layout.tsx:198 +#: src/renderer/components/item-object-list/item-list-layout.tsx:196 msgid "No items found." msgstr "Ничего не найдено." @@ -1589,8 +1598,8 @@ msgstr "Использование файловой системы ноды в msgid "Node shell" msgstr "Командная строка ноды" -#: src/renderer/components/+nodes/nodes.tsx:111 -#: src/renderer/components/layout/sidebar.tsx:86 +#: src/renderer/components/+nodes/nodes.tsx:118 +#: src/renderer/components/layout/sidebar.tsx:80 msgid "Nodes" msgstr "Ноды" @@ -1614,11 +1623,11 @@ msgstr "Заметки" msgid "Number of running Pods" msgstr "Кол-во работающих подов" -#: src/renderer/components/+nodes/node-details.tsx:87 +#: src/renderer/components/+nodes/node-details.tsx:86 msgid "OS" msgstr "ОС" -#: src/renderer/components/+nodes/node-details.tsx:90 +#: src/renderer/components/+nodes/node-details.tsx:89 msgid "OS Image" msgstr "Образ ОС" @@ -1630,7 +1639,7 @@ msgstr "Объект" msgid "Ok" msgstr "Ок" -#: src/renderer/components/+whats-new/whats-new.tsx:36 +#: src/renderer/components/+whats-new/whats-new.tsx:35 msgid "Ok, got it!" msgstr "" @@ -1638,11 +1647,12 @@ msgstr "" msgid "Open" msgstr "Открыть" -#: src/renderer/components/+network-services/service-ports.tsx:49 +#: src/renderer/components/+network-services/service-port-component.tsx:49 +#: src/renderer/components/+workloads-pods/pod-container-port.tsx:51 msgid "Open in a browser" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:63 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:60 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:78 #: src/renderer/components/+workloads-pods/pod-details-tolerations.tsx:17 msgid "Operator" @@ -1653,7 +1663,7 @@ msgid "Organization" msgstr "Организация" #: src/renderer/components/+workloads/workloads.tsx:29 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:37 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:35 msgid "Overview" msgstr "Обзор" @@ -1679,17 +1689,17 @@ msgstr "Путь" msgid "Path Prefix" msgstr "" -#: src/renderer/components/+storage/storage.tsx:26 +#: src/renderer/components/+storage/storage.tsx:25 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:45 msgid "Persistent Volume Claims" msgstr "Persistent Volume Claims" -#: src/renderer/components/+storage/storage.tsx:33 +#: src/renderer/components/+storage/storage.tsx:32 #: src/renderer/components/+storage-volumes/volumes.tsx:39 msgid "Persistent Volumes" msgstr "Persistent Volumes" -#: src/renderer/components/+add-cluster/add-cluster.tsx:52 +#: src/renderer/components/+add-cluster/add-cluster.tsx:62 msgid "Please select kubeconfig" msgstr "" @@ -1702,7 +1712,7 @@ msgid "Pod IP" msgstr "IP пода" #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:34 -#: src/renderer/components/+user-management/user-management.tsx:44 +#: src/renderer/components/+user-management/user-management.tsx:43 msgid "Pod Security Policies" msgstr "" @@ -1722,17 +1732,17 @@ msgid "Pod shell" msgstr "Командная строка пода" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:148 -#: src/renderer/components/+nodes/node-details.tsx:66 -#: src/renderer/components/+nodes/node-details.tsx:76 -#: src/renderer/components/+nodes/node-details.tsx:81 +#: src/renderer/components/+nodes/node-details.tsx:65 +#: src/renderer/components/+nodes/node-details.tsx:75 +#: src/renderer/components/+nodes/node-details.tsx:80 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:60 #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:50 #: src/renderer/components/+workloads/workloads.tsx:37 #: src/renderer/components/+workloads-daemonsets/daemonsets.tsx:47 #: src/renderer/components/+workloads-deployments/deployments.tsx:60 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:44 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:42 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:89 -#: src/renderer/components/+workloads-pods/pods.tsx:72 +#: src/renderer/components/+workloads-pods/pods.tsx:73 #: src/renderer/components/+workloads-replicasets/replicasets.tsx:52 #: src/renderer/components/+workloads-statefulsets/statefulsets.tsx:42 msgid "Pods" @@ -1752,11 +1762,11 @@ msgstr "" #: src/renderer/components/+network-policies/network-policy-details.tsx:109 #: src/renderer/components/+network-services/service-details.tsx:59 #: src/renderer/components/+network-services/services.tsx:48 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:52 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:53 msgid "Ports" msgstr "Порты" -#: src/renderer/components/+preferences/preferences.tsx:124 +#: src/renderer/components/+preferences/preferences.tsx:121 msgid "Preferences" msgstr "" @@ -1778,15 +1788,15 @@ msgstr "" msgid "Provisioner" msgstr "Комиссия" -#: src/renderer/components/+preferences/preferences.tsx:163 +#: src/renderer/components/+preferences/preferences.tsx:160 msgid "Proxy is used only for non-cluster communication." msgstr "" -#: src/renderer/components/+add-cluster/add-cluster.tsx:172 +#: src/renderer/components/+add-cluster/add-cluster.tsx:175 msgid "Proxy settings" msgstr "" -#: src/renderer/components/+workloads-pods/pods.tsx:79 +#: src/renderer/components/+workloads-pods/pods.tsx:80 msgid "QoS" msgstr "QoS" @@ -1794,7 +1804,7 @@ msgstr "QoS" msgid "QoS Class" msgstr "QoS класс" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:55 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:52 msgid "Quotas" msgstr "Квоты" @@ -1810,7 +1820,7 @@ msgstr "" msgid "Read-only Root Filesystem" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:77 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:75 msgid "Readiness" msgstr "Готовность" @@ -1862,11 +1872,11 @@ msgstr "Установка: {0}" msgid "Releases" msgstr "Релизы" -#: src/renderer/components/+preferences/preferences.tsx:154 +#: src/renderer/components/+preferences/preferences.tsx:151 #: src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx:60 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:60 -#: src/renderer/components/cluster-manager/clusters-menu.tsx:64 -#: src/renderer/components/item-object-list/item-list-layout.tsx:181 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:74 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:80 +#: src/renderer/components/item-object-list/item-list-layout.tsx:179 #: src/renderer/components/menu/menu-actions.tsx:49 #: src/renderer/components/menu/menu-actions.tsx:85 msgid "Remove" @@ -1896,7 +1906,7 @@ msgstr "Удалить выбранные связки <0>{0}?" msgid "Remove selected bindings from ${name}" msgstr "Удалить выбранные связки из ${name}" -#: src/renderer/components/item-object-list/item-list-layout.tsx:277 +#: src/renderer/components/item-object-list/item-list-layout.tsx:275 msgid "Remove selected items ({0})" msgstr "Удалить выбранные элементы ({0})" @@ -1904,7 +1914,7 @@ msgstr "Удалить выбранные элементы ({0})" msgid "Remove {resourceKind} <0>{resourceName}?" msgstr "Удалить {resourceKind} <0>{resourceName}?" -#: src/renderer/components/+preferences/preferences.tsx:117 +#: src/renderer/components/+preferences/preferences.tsx:114 msgid "Removing helm branch <0>{0} has failed: {1}" msgstr "" @@ -1928,7 +1938,7 @@ msgstr "Реплики" msgid "Repo/Name" msgstr "Репозиторий/Имя" -#: src/renderer/components/+preferences/preferences.tsx:144 +#: src/renderer/components/+preferences/preferences.tsx:141 msgid "Repositories" msgstr "" @@ -1948,8 +1958,8 @@ msgstr "Продолжительность запроса в секундах" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:114 #: src/renderer/components/+nodes/node-charts.tsx:32 #: src/renderer/components/+nodes/node-charts.tsx:56 -#: src/renderer/components/+workloads-pods/container-charts.tsx:32 -#: src/renderer/components/+workloads-pods/container-charts.tsx:56 +#: src/renderer/components/+workloads-pods/container-charts.tsx:33 +#: src/renderer/components/+workloads-pods/container-charts.tsx:57 #: src/renderer/components/+workloads-pods/pod-charts.tsx:41 #: src/renderer/components/+workloads-pods/pod-charts.tsx:65 msgid "Requests" @@ -1967,7 +1977,7 @@ msgstr "Обязательное поле" msgid "Reset" msgstr "Сбросить" -#: src/renderer/components/item-object-list/item-list-layout.tsx:201 +#: src/renderer/components/item-object-list/item-list-layout.tsx:199 msgid "Reset filters?" msgstr "Сбросить фильтры?" @@ -2019,7 +2029,7 @@ msgstr "Продолжительность ответа в секундах" msgid "Restart session" msgstr "Перезагрузить сессию" -#: src/renderer/components/+workloads-pods/pods.tsx:77 +#: src/renderer/components/+workloads-pods/pods.tsx:78 msgid "Restarts" msgstr "Перезагрузки" @@ -2037,7 +2047,7 @@ msgstr "" msgid "Role" msgstr "Role" -#: src/renderer/components/+user-management/user-management.tsx:32 +#: src/renderer/components/+user-management/user-management.tsx:31 #: src/renderer/components/+user-management-roles-bindings/role-bindings.tsx:34 msgid "Role Bindings" msgstr "Role Bindings" @@ -2050,8 +2060,8 @@ msgstr "Идентификатор роли" msgid "Role name" msgstr "Имя роли" -#: src/renderer/components/+nodes/nodes.tsx:117 -#: src/renderer/components/+user-management/user-management.tsx:37 +#: src/renderer/components/+nodes/nodes.tsx:124 +#: src/renderer/components/+user-management/user-management.tsx:36 #: src/renderer/components/+user-management-roles/roles.tsx:32 msgid "Roles" msgstr "Roles" @@ -2118,11 +2128,11 @@ msgstr "Расписание" msgid "Scope" msgstr "" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:60 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:57 msgid "Scope Selector" msgstr "Селектор области" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:64 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:61 msgid "Scope name" msgstr "Имя области" @@ -2170,7 +2180,7 @@ msgstr "Secrets" msgid "Select a quota.." msgstr "Выберите квоту..." -#: src/renderer/components/+add-cluster/add-cluster.tsx:169 +#: src/renderer/components/+add-cluster/add-cluster.tsx:172 msgid "Select kubeconfig" msgstr "" @@ -2207,7 +2217,7 @@ msgstr "Сервер" msgid "Service" msgstr "Service" -#: src/renderer/components/+user-management/user-management.tsx:27 +#: src/renderer/components/+user-management/user-management.tsx:26 #: src/renderer/components/+user-management-service-accounts/service-accounts.tsx:35 msgid "Service Accounts" msgstr "Service Accounts" @@ -2221,7 +2231,7 @@ msgstr "Services" msgid "Session Affinity" msgstr "Направление сессии" -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:43 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:40 msgid "Set" msgstr "Установлено" @@ -2229,7 +2239,7 @@ msgstr "Установлено" msgid "Set quota" msgstr "Установить квоту" -#: src/renderer/components/cluster-manager/clusters-menu.tsx:47 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:53 msgid "Settings" msgstr "" @@ -2281,7 +2291,7 @@ msgid "Stateful Sets" msgstr "" #: src/renderer/components/+workloads/workloads.tsx:61 -#: src/renderer/components/+workloads-overview/overview-statuses.tsx:54 +#: src/renderer/components/+workloads-overview/overview-statuses.tsx:52 msgid "StatefulSets" msgstr "StatefulSets" @@ -2301,10 +2311,10 @@ msgstr "StatefulSets" #: src/renderer/components/+storage-volume-claims/volume-claims.tsx:52 #: src/renderer/components/+storage-volumes/volume-details.tsx:46 #: src/renderer/components/+storage-volumes/volumes.tsx:45 -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:38 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:39 #: src/renderer/components/+workloads-pods/pod-details-list.tsx:97 #: src/renderer/components/+workloads-pods/pod-details.tsx:82 -#: src/renderer/components/+workloads-pods/pods.tsx:81 +#: src/renderer/components/+workloads-pods/pods.tsx:82 msgid "Status" msgstr "Статус" @@ -2313,7 +2323,7 @@ msgid "Status URI" msgstr "Адрес статуса" #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:57 -#: src/renderer/components/layout/sidebar.tsx:90 +#: src/renderer/components/layout/sidebar.tsx:84 msgid "Storage" msgstr "Storage" @@ -2326,7 +2336,7 @@ msgstr "" msgid "Storage Class Name" msgstr "Имя Storage Class" -#: src/renderer/components/+storage/storage.tsx:41 +#: src/renderer/components/+storage/storage.tsx:40 #: src/renderer/components/+storage-classes/storage-classes.tsx:33 msgid "Storage Classes" msgstr "Storage Classes" @@ -2374,20 +2384,20 @@ msgstr "Заморозка" msgid "TLS" msgstr "TLS" -#: src/renderer/components/+nodes/node-details.tsx:104 -#: src/renderer/components/+nodes/nodes.tsx:116 +#: src/renderer/components/+nodes/node-details.tsx:103 +#: src/renderer/components/+nodes/nodes.tsx:123 msgid "Taints" msgstr "Метки блокировки" -#: src/renderer/components/+preferences/preferences.tsx:174 +#: src/renderer/components/+preferences/preferences.tsx:171 msgid "Telemetry & Usage Tracking" msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:177 +#: src/renderer/components/+preferences/preferences.tsx:174 msgid "Telemetry & usage data is collected to continuously improve the Lens experience." msgstr "" -#: src/renderer/components/dock/terminal.store.ts:29 +#: src/renderer/components/dock/terminal.store.ts:28 msgid "Terminal" msgstr "Терминал" @@ -2408,14 +2418,14 @@ msgid "This field is required" msgstr "Это обязательное поле" #: src/renderer/components/input/input.validators.ts:39 -msgid "This field must contain only lowercase latin characters, numbers and dash." +msgid "A System Name must be lowercase DNS labels separated by dots. DNS labels are alphanumerics and dashes enclosed by alphanumerics." msgstr "Это поле может содержать только латинские буквы в нижнем регистре, номера и дефис." -#: src/renderer/components/cluster-manager/clusters-menu.tsx:84 +#: src/renderer/components/cluster-manager/clusters-menu.tsx:104 msgid "This is the quick launch menu." msgstr "" -#: src/renderer/components/+preferences/preferences.tsx:169 +#: src/renderer/components/+preferences/preferences.tsx:166 msgid "This will make Lens to trust ANY certificate authority without any validations." msgstr "" @@ -2458,7 +2468,7 @@ msgstr "Транзит" msgid "Type" msgstr "Тип" -#: src/renderer/components/+preferences/preferences.tsx:161 +#: src/renderer/components/+preferences/preferences.tsx:158 msgid "Type HTTP proxy url (example: http://proxy.acme.org:8080)" msgstr "" @@ -2500,14 +2510,15 @@ msgstr "Обновить версию" #: src/renderer/components/+cluster/cluster-pie-charts.tsx:70 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:113 #: src/renderer/components/+cluster/cluster-pie-charts.tsx:134 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:40 #: src/renderer/components/+nodes/node-charts.tsx:25 #: src/renderer/components/+nodes/node-charts.tsx:49 #: src/renderer/components/+nodes/node-charts.tsx:73 #: src/renderer/components/+nodes/node-charts.tsx:90 #: src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx:24 -#: src/renderer/components/+workloads-pods/container-charts.tsx:25 -#: src/renderer/components/+workloads-pods/container-charts.tsx:49 -#: src/renderer/components/+workloads-pods/container-charts.tsx:73 +#: src/renderer/components/+workloads-pods/container-charts.tsx:26 +#: src/renderer/components/+workloads-pods/container-charts.tsx:50 +#: src/renderer/components/+workloads-pods/container-charts.tsx:74 #: src/renderer/components/+workloads-pods/pod-charts.tsx:34 #: src/renderer/components/+workloads-pods/pod-charts.tsx:58 #: src/renderer/components/+workloads-pods/pod-charts.tsx:99 @@ -2519,8 +2530,8 @@ msgid "Use same name for RoleBinding" msgstr "Использовать тоже имя для привязки ролей" #: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:43 -msgid "Used" -msgstr "Использовано" +#~ msgid "Used" +#~ msgstr "Использовано" #: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:155 msgid "User" @@ -2538,7 +2549,7 @@ msgstr "Значение" #: src/renderer/components/+apps-releases/release-details.tsx:111 #: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:132 -#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:65 +#: src/renderer/components/+config-resource-quotas/resource-quota-details.tsx:62 #: src/renderer/components/+storage-volume-claims/volume-claim-details.tsx:79 msgid "Values" msgstr "Конфигурация" @@ -2553,7 +2564,7 @@ msgstr "Определения" #: src/renderer/components/+apps-releases/releases.tsx:91 #: src/renderer/components/+custom-resources/crd-details.tsx:35 #: src/renderer/components/+custom-resources/crd-list.tsx:75 -#: src/renderer/components/+nodes/nodes.tsx:118 +#: src/renderer/components/+nodes/nodes.tsx:125 #: src/renderer/components/dock/install-chart.tsx:120 #: src/renderer/components/dock/upgrade-chart.tsx:99 msgid "Version" @@ -2589,7 +2600,7 @@ msgstr "Ожидание запуска сервисов" msgid "Warnings: {0}" msgstr "Предупреждения: {0}" -#: src/renderer/components/+landing-page/landing-page.tsx:18 +#: src/renderer/components/+landing-page/landing-page.tsx:20 msgid "Welcome!" msgstr "" @@ -2601,7 +2612,7 @@ msgstr "" msgid "Worker" msgstr "Рабочие" -#: src/renderer/components/layout/sidebar.tsx:87 +#: src/renderer/components/layout/sidebar.tsx:81 msgid "Workloads" msgstr "Ресурсы" @@ -2622,6 +2633,7 @@ msgstr "Неверный формат электронной почты" msgid "Wrong url format" msgstr "Неверный url формат" +#: src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx:28 #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:44 #: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:71 #: src/renderer/components/+pod-security-policies/pod-security-policies.tsx:42 @@ -2647,19 +2659,19 @@ msgstr "Зона" msgid "ago" msgstr "тому назад" -#: src/renderer/components/item-object-list/item-list-layout.tsx:180 +#: src/renderer/components/item-object-list/item-list-layout.tsx:178 msgid "and <0>{tailCount} more" msgstr "и <0>{tailCount} ещё" -#: src/renderer/components/+preferences/preferences.tsx:129 +#: src/renderer/components/+preferences/preferences.tsx:126 msgid "applicable to all clusters" msgstr "" -#: src/renderer/components/+nodes/nodes.tsx:55 +#: src/renderer/components/+nodes/nodes.tsx:57 msgid "cores:" msgstr "ядер:" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:41 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:42 msgid "exit code" msgstr "код выхода" @@ -2676,11 +2688,15 @@ msgstr "" msgid "never" msgstr "" +#: src/renderer/components/cluster-manager/clusters-menu.tsx:119 +msgid "new" +msgstr "" + #: src/renderer/components/+custom-resources/crd-details.tsx:64 msgid "plural" msgstr "" -#: src/renderer/components/+workloads-pods/pod-details-container.tsx:40 +#: src/renderer/components/+workloads-pods/pod-details-container.tsx:41 msgid "ready" msgstr "готово" @@ -2728,7 +2744,7 @@ msgstr "{0} недоступно" msgid "{accountName} kubeconfig" msgstr "{accountName} конфигурация" -#: src/renderer/components/item-object-list/item-list-layout.tsx:230 +#: src/renderer/components/item-object-list/item-list-layout.tsx:228 msgid "{allItemsCount, plural, one {# item} other {# items}}" msgstr "{allItemsCount, plural, one {# элемент} few {# элемента} many {# элементов} other {# элементов}}" @@ -2744,7 +2760,7 @@ msgstr "{podName} логи" msgid "{resourceType} <0>{resourceName} updated." msgstr "{resourceType} <0>{resourceName} обновлен." -#: src/renderer/components/item-object-list/item-list-layout.tsx:181 +#: src/renderer/components/item-object-list/item-list-layout.tsx:179 msgid "{selectedCount, plural, one {<0>Remove item <1>{selectedNames}?} other {<2>Remove <3>{selectedCount} items <4>{selectedNames} {tail}?}}" msgstr "" "{\n" diff --git a/package.json b/package.json index 9983c3eb66..e583925b68 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "Lens", "description": "Lens - The Kubernetes IDE", "version": "3.6.0-dev", - "main": "out/main.js", + "main": "static/build/main.js", "copyright": "© 2020, Lakend Labs, Inc.", "license": "MIT", "author": { @@ -12,29 +12,28 @@ }, "scripts": { "dev": "concurrently -k \"yarn dev-run -C\" \"yarn dev:main\" \"yarn dev:renderer\"", - "dev-run": "nodemon --watch out/main.* --exec \"electron --inspect .\" $@", + "dev-run": "nodemon --watch static/build/main.js --exec \"electron --inspect .\" $@", "dev:main": "env DEBUG=true yarn compile:main --watch $@", "dev:renderer": "env DEBUG=true yarn compile:renderer --watch $@", - "compile": "concurrently \"yarn i18n:compile\" \"yarn compile:main -p\" \"yarn compile:renderer -p\"", - "compile:main": "webpack --progress --config webpack.main.ts", - "compile:renderer": "webpack --progress --config webpack.renderer.ts", - "compile:dll": "webpack --config webpack.dll.ts", - "build:linux": "yarn compile && electron-builder --linux --dir -c.productName=LensDev", - "build:mac": "yarn compile && electron-builder --mac --dir -c.productName=LensDev", - "build:win": "yarn compile && electron-builder --win --dir -c.productName=LensDev", + "compile": "env NODE_ENV=production concurrently yarn:compile:*", + "compile:main": "webpack --config webpack.main.ts", + "compile:renderer": "webpack --config webpack.renderer.ts", + "compile:i18n": "lingui compile", + "build:linux": "yarn compile && electron-builder --linux --dir -c.productName=Lens", + "build:mac": "yarn compile && electron-builder --mac --dir -c.productName=Lens", + "build:win": "yarn compile && electron-builder --win --dir -c.productName=Lens", "test": "jest --env=jsdom src $@", "integration": "jest --coverage integration $@", - "dist": "yarn compile && electron-builder -p onTag", - "dist:win": "yarn compile && electron-builder -p onTag --x64 --ia32", + "dist": "yarn compile && electron-builder --publish onTag", + "dist:win": "yarn compile && electron-builder --publish onTag --x64 --ia32", "dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null", "postinstall": "patch-package", "i18n:extract": "lingui extract", - "i18n:compile": "lingui compile", "download-bins": "concurrently yarn:download:*", "download:kubectl": "yarn run ts-node build/download_kubectl.ts", "download:helm": "yarn run ts-node build/download_helm.ts", "lint": "eslint $@ --ext js,ts,tsx --max-warnings=0 src/", - "rebuild-pty": "electron-rebuild -f -w node-pty" + "rebuild-pty": "yarn run electron-rebuild -f -w node-pty" }, "config": { "bundledKubectlVersion": "1.17.4", @@ -88,7 +87,7 @@ { "from": "static/", "to": "static/", - "filter": "**/*" + "filter": "!**/main.js" }, "LICENSE" ], @@ -187,11 +186,15 @@ "mac-ca": "^1.0.4", "marked": "^1.1.0", "md5-file": "^5.0.0", + "mobx": "^5.15.5", + "mobx-observable-history": "^1.0.3", "mock-fs": "^4.12.0", "node-machine-id": "^1.1.12", "node-pty": "^0.9.0", "openid-client": "^3.15.2", + "path-to-regexp": "^6.1.0", "proper-lockfile": "^4.1.1", + "react-router": "^5.2.0", "request": "^2.88.2", "request-promise-native": "^1.0.8", "semver": "^7.3.2", @@ -233,7 +236,6 @@ "@types/md5-file": "^4.0.2", "@types/mini-css-extract-plugin": "^0.9.1", "@types/react": "^16.9.35", - "@types/react-dom": "^16.9.8", "@types/react-router-dom": "^5.1.5", "@types/react-select": "^3.0.13", "@types/react-window": "^1.8.2", @@ -265,7 +267,7 @@ "css-element-queries": "^1.2.3", "css-loader": "^3.5.3", "dompurify": "^2.0.11", - "electron": "^9.1.0", + "electron": "^9.1.2", "electron-builder": "^22.7.0", "electron-notarize": "^0.3.0", "electron-rebuild": "^1.11.0", @@ -281,15 +283,12 @@ "make-plural": "^6.2.1", "material-design-icons": "^3.0.1", "mini-css-extract-plugin": "^0.9.0", - "mobx": "^5.15.4", - "mobx-observable-history": "^1.0.3", "mobx-react": "^6.2.2", "moment": "^2.26.0", "node-loader": "^0.6.0", "node-sass": "^4.14.1", "nodemon": "^2.0.4", "patch-package": "^6.2.2", - "path-to-regexp": "^6.1.0", "postinstall-postinstall": "^2.1.0", "raw-loader": "^4.0.1", "react": "^16.13.1", @@ -298,7 +297,7 @@ "react-select": "^3.1.0", "react-window": "^1.8.5", "sass-loader": "^8.0.2", - "spectron": "^8.0.0", + "spectron": "11.0.0", "style-loader": "^1.2.1", "terser-webpack-plugin": "^3.0.3", "ts-jest": "^26.1.0", diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 722698fa67..0cc087eb9f 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -135,8 +135,4 @@ export class BaseStore extends Singleton { recurseEverything: true, }) } - - * [Symbol.iterator]() { - yield* Object.entries(this.toJSON()); - } } diff --git a/src/common/cluster-ipc.ts b/src/common/cluster-ipc.ts index 5d5dfe206d..5e1b86992b 100644 --- a/src/common/cluster-ipc.ts +++ b/src/common/cluster-ipc.ts @@ -3,16 +3,26 @@ import { ClusterId, clusterStore } from "./cluster-store"; import { tracker } from "./tracker"; export const clusterIpc = { + init: createIpcChannel({ + channel: "cluster:init", + handle: async (clusterId: ClusterId, frameId: number) => { + const cluster = clusterStore.getById(clusterId); + if (cluster) { + cluster.frameId = frameId; // save cluster's webFrame.routingId to be able to send push-updates + return cluster.pushState(); + } + }, + }), activate: createIpcChannel({ channel: "cluster:activate", - handle: async (clusterId: ClusterId = clusterStore.activeClusterId) => { + handle: (clusterId: ClusterId) => { return clusterStore.getById(clusterId)?.activate(); }, }), disconnect: createIpcChannel({ channel: "cluster:disconnect", - handle: (clusterId: ClusterId = clusterStore.activeClusterId) => { + handle: (clusterId: ClusterId) => { tracker.event("cluster", "stop"); return clusterStore.getById(clusterId)?.disconnect(); }, @@ -23,7 +33,6 @@ export const clusterIpc = { handle: async (clusterId: ClusterId, feature: string, config?: any) => { tracker.event("cluster", "install", feature); const cluster = clusterStore.getById(clusterId); - if (cluster) { await cluster.installFeature(feature, config) } else { diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index bef96f9b5d..ad25f43f26 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -62,11 +62,10 @@ export class ClusterStore extends BaseStore { migrations: migrations, }); if (ipcRenderer) { - ipcRenderer.on("cluster:state", (event, clusterState: ClusterState) => { + ipcRenderer.on("cluster:state", (event, model: ClusterState) => { this.applyWithoutSync(() => { - logger.debug(`[CLUSTER-STORE]: received state update for cluster=${clusterState.id}`, clusterState); - const cluster = this.getById(clusterState.id); - if (cluster) cluster.updateModel(clusterState) + logger.debug(`[CLUSTER-STORE]: received push-state at ${location.host}`, model); + this.getById(model.id)?.updateModel(model); }) }) } @@ -84,6 +83,14 @@ export class ClusterStore extends BaseStore { return Array.from(this.clusters.values()); } + isActive(id: ClusterId) { + return this.activeClusterId === id; + } + + setActive(id: ClusterId) { + this.activeClusterId = id; + } + hasClusters() { return this.clusters.size > 0; } @@ -156,11 +163,6 @@ export class ClusterStore extends BaseStore { this.activeClusterId = newClusters.has(activeCluster) ? activeCluster : null; this.clusters.replace(newClusters); this.removedClusters.replace(removedClusters); - - // "auto-select" first cluster if available - if (!this.activeClusterId && newClusters.size) { - this.activeClusterId = Array.from(newClusters.values())[0].id; - } } toJSON(): ClusterStoreModel { diff --git a/src/common/cluster-store_test.ts b/src/common/cluster-store_test.ts new file mode 100644 index 0000000000..3fc3e0b60e --- /dev/null +++ b/src/common/cluster-store_test.ts @@ -0,0 +1,333 @@ +import fs from "fs"; +import mockFs from "mock-fs"; +import yaml from "js-yaml"; +import { Cluster } from "../main/cluster"; +import { ClusterStore } from "./cluster-store"; +import { workspaceStore } from "./workspace-store"; +import { saveConfigToAppFiles } from "./kube-helpers"; + +let clusterStore: ClusterStore; + +describe("empty config", () => { + beforeAll(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({}) + } + } + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterAll(() => { + mockFs.restore(); + }) + + it("adds new cluster to store", async () => { + const cluster = new Cluster({ + id: "foo", + preferences: { + terminalCWD: "/tmp", + icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5", + clusterName: "minikube" + }, + kubeConfigPath: saveConfigToAppFiles("foo", "fancy foo config"), + workspace: workspaceStore.currentWorkspaceId + }); + clusterStore.addCluster(cluster); + const storedCluster = clusterStore.getById(cluster.id); + expect(storedCluster.id).toBe(cluster.id); + expect(storedCluster.preferences.terminalCWD).toBe(cluster.preferences.terminalCWD); + expect(storedCluster.preferences.icon).toBe(cluster.preferences.icon); + }) + + it("adds cluster to default workspace", () => { + const storedCluster = clusterStore.getById("foo"); + expect(storedCluster.workspace).toBe("default"); + }) + + it("check if store can contain multiple clusters", () => { + const prodCluster = new Cluster({ + id: "prod", + preferences: { + clusterName: "prod" + }, + kubeConfigPath: saveConfigToAppFiles("prod", "fancy config"), + workspace: "workstation" + }); + const devCluster = new Cluster({ + id: "dev", + preferences: { + clusterName: "dev" + }, + kubeConfigPath: saveConfigToAppFiles("dev", "fancy config"), + workspace: "workstation" + }); + clusterStore.addCluster(prodCluster); + clusterStore.addCluster(devCluster); + expect(clusterStore.hasClusters()).toBeTruthy(); + expect(clusterStore.clusters.size).toBe(3); + }); + + it("gets clusters by workspaces", () => { + const wsClusters = clusterStore.getByWorkspaceId("workstation"); + const defaultClusters = clusterStore.getByWorkspaceId("default"); + expect(defaultClusters.length).toBe(1); + expect(wsClusters.length).toBe(2); + expect(wsClusters[0].id).toBe("prod"); + expect(wsClusters[1].id).toBe("dev"); + }) + + it("checks if last added cluster becomes active", () => { + expect(clusterStore.activeCluster.id).toBe("dev"); + }) + + it("sets active cluster", () => { + clusterStore.setActive("foo"); + expect(clusterStore.activeCluster.id).toBe("foo"); + }) + + it("check if cluster's kubeconfig file saved", () => { + const file = saveConfigToAppFiles("boo", "kubeconfig"); + expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig"); + }) + + it("removes cluster from store", async () => { + await clusterStore.removeById("foo"); + expect(clusterStore.getById("foo")).toBeUndefined(); + }) +}) + +describe("config with existing clusters", () => { + beforeEach(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({ + __internal__: { + migrations: { + version: "99.99.99" + } + }, + clusters: [ + { + id: 'cluster1', + kubeConfig: 'foo', + preferences: { terminalCWD: '/foo' } + }, + { + id: 'cluster2', + kubeConfig: 'foo2', + preferences: { terminalCWD: '/foo2' } + } + ] + }) + } + } + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterEach(() => { + mockFs.restore(); + }) + + it("allows to retrieve a cluster", () => { + const storedCluster = clusterStore.getById('cluster1'); + expect(storedCluster.id).toBe('cluster1'); + expect(storedCluster.preferences.terminalCWD).toBe('/foo'); + }) + + it("allows to delete a cluster", () => { + clusterStore.removeById('cluster2'); + const storedCluster = clusterStore.getById('cluster1'); + expect(storedCluster).toBeTruthy(); + const storedCluster2 = clusterStore.getById('cluster2'); + expect(storedCluster2).toBeUndefined(); + }) + + it("allows getting all of the clusters", async () => { + const storedClusters = clusterStore.clustersList; + expect(storedClusters[0].id).toBe('cluster1') + expect(storedClusters[0].preferences.terminalCWD).toBe('/foo') + expect(storedClusters[1].id).toBe('cluster2') + expect(storedClusters[1].preferences.terminalCWD).toBe('/foo2') + }) +}) + +describe("pre 2.0 config with an existing cluster", () => { + beforeEach(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({ + __internal__: { + migrations: { + version: "1.0.0" + } + }, + cluster1: 'kubeconfig content' + }) + } + }; + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterEach(() => { + mockFs.restore(); + }) + + it("migrates to modern format with kubeconfig in a file", async () => { + const config = clusterStore.clustersList[0].kubeConfigPath; + expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content"); + }) +}) + +describe("pre 2.6.0 config with a cluster that has arrays in auth config", () => { + beforeEach(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({ + __internal__: { + migrations: { + version: "2.4.1" + } + }, + cluster1: { + kubeConfig: "apiVersion: v1\nclusters:\n- cluster:\n server: https://10.211.55.6:8443\n name: minikube\ncontexts:\n- context:\n cluster: minikube\n user: minikube\n name: minikube\ncurrent-context: minikube\nkind: Config\npreferences: {}\nusers:\n- name: minikube\n user:\n client-certificate: /Users/kimmo/.minikube/client.crt\n client-key: /Users/kimmo/.minikube/client.key\n auth-provider:\n config:\n access-token:\n - should be string\n expiry:\n - should be string\n" + }, + }) + } + } + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterEach(() => { + mockFs.restore(); + }) + + it("replaces array format access token and expiry into string", async () => { + const file = clusterStore.clustersList[0].kubeConfigPath; + const config = fs.readFileSync(file, "utf8"); + const kc = yaml.safeLoad(config); + expect(kc.users[0].user['auth-provider'].config['access-token']).toBe("should be string"); + expect(kc.users[0].user['auth-provider'].config['expiry']).toBe("should be string"); + }) +}) + +describe("pre 2.6.0 config with a cluster icon", () => { + beforeEach(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({ + __internal__: { + migrations: { + version: "2.4.1" + } + }, + cluster1: { + kubeConfig: "foo", + icon: "icon path", + preferences: { + terminalCWD: "/tmp" + } + }, + }) + } + } + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterEach(() => { + mockFs.restore(); + }) + + it("moves the icon into preferences", async () => { + const storedClusterData = clusterStore.clustersList[0]; + expect(storedClusterData.hasOwnProperty('icon')).toBe(false); + expect(storedClusterData.preferences.hasOwnProperty('icon')).toBe(true); + expect(storedClusterData.preferences.icon).toBe("icon path"); + }) +}) + +describe("for a pre 2.7.0-beta.0 config without a workspace", () => { + beforeEach(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({ + __internal__: { + migrations: { + version: "2.6.6" + } + }, + cluster1: { + kubeConfig: "foo", + icon: "icon path", + preferences: { + terminalCWD: "/tmp" + } + }, + }) + } + } + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterEach(() => { + mockFs.restore(); + }) + + it("adds cluster to default workspace", async () => { + const storedClusterData = clusterStore.clustersList[0]; + expect(storedClusterData.workspace).toBe('default'); + }) +}) + +describe("pre 3.6.0-beta.1 config with an existing cluster", () => { + beforeEach(() => { + ClusterStore.resetInstance(); + const mockOpts = { + 'tmp': { + 'lens-cluster-store.json': JSON.stringify({ + __internal__: { + migrations: { + version: "2.7.0" + } + }, + clusters: [ + { + id: 'cluster1', + kubeConfig: 'kubeconfig content' + } + ] + }) + } + }; + mockFs(mockOpts); + clusterStore = ClusterStore.getInstance(); + return clusterStore.load(); + }) + + afterEach(() => { + mockFs.restore(); + }) + + it("migrates to modern format with kubeconfig in a file", async () => { + const config = clusterStore.clustersList[0].kubeConfigPath; + expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content"); + }) +}) \ No newline at end of file diff --git a/src/common/ipc.ts b/src/common/ipc.ts index 95e982f56c..8dfb2c45b2 100644 --- a/src/common/ipc.ts +++ b/src/common/ipc.ts @@ -7,23 +7,59 @@ import logger from "../main/logger"; export type IpcChannel = string; -export interface IpcHandleOpts { - timeout?: number; +export interface IpcChannelOptions { + channel: IpcChannel; // main <-> renderer communication channel name + handle?: (...args: any[]) => Promise | any; // message handler + autoBind?: boolean; // auto-bind message handler in main-process, default: true + timeout?: number; // timeout for waiting response from the sender + once?: boolean; // one-time event } -export interface IpcMessageHandler { - (...args: T): any; +export function createIpcChannel({ autoBind = true, once, timeout = 0, handle, channel }: IpcChannelOptions) { + const ipcChannel = { + channel: channel, + handleInMain: () => { + logger.info(`[IPC]: setup channel "${channel}"`); + const ipcHandler = once ? ipcMain.handleOnce : ipcMain.handle; + ipcHandler(channel, async (event, ...args) => { + let timerId: any; + try { + if (timeout > 0) { + timerId = setTimeout(() => { + throw new Error(`[IPC]: response timeout in ${timeout}ms`) + }, timeout); + } + return await handle(...args); // todo: maybe exec in separate thread/worker + } catch (error) { + throw error + } finally { + clearTimeout(timerId); + } + }) + }, + removeHandler() { + ipcMain.removeHandler(channel); + }, + invokeFromRenderer: async (...args: any[]): Promise => { + return ipcRenderer.invoke(channel, ...args); + }, + } + if (autoBind && ipcMain) { + ipcChannel.handleInMain(); + } + return ipcChannel; } -export interface IpcMessageOpts { +export interface IpcBroadcastParams { channel: IpcChannel - webContentId?: number; // sends to single webContents view + webContentId?: number; // send to single webContents view + frameId?: number; // send to inner frame of webContents filter?: (webContent: WebContents) => boolean timeout?: number; // todo: add support args?: A; } -export function broadcastIpc({ channel, webContentId, filter, args = [] }: IpcMessageOpts) { +export function broadcastIpc({ channel, frameId, webContentId, filter, args = [] }: IpcBroadcastParams) { const singleView = webContentId ? webContents.fromId(webContentId) : null; let views = singleView ? [singleView] : webContents.getAllWebContents(); if (filter) { @@ -31,65 +67,10 @@ export function broadcastIpc({ channel, webContentId, filter, args = [] }: IpcMe } views.forEach(webContent => { const type = webContent.getType(); - logger.debug(`[IPC]: sending message "${channel}" to ${type}=${webContent.id}`, { args }); - webContent.send(channel, ...[args].flat()); + logger.debug(`[IPC]: broadcasting "${channel}" to ${type}=${webContent.id}`, { args }); + webContent.send(channel, ...args); + if (frameId) { + webContent.sendToFrame(frameId, channel, ...args) + } }) } - -// todo: support timeout + merge with sendMessage? -export async function invokeIpc(channel: IpcChannel, ...args: any[]): Promise { - logger.info(`[IPC]: invoke channel "${channel}"`, { args }); - return ipcRenderer.invoke(channel, ...args); -} - -// todo: make isomorphic api -export function handleIpc(channel: IpcChannel, handler: IpcMessageHandler, options: IpcHandleOpts = {}) { - const { timeout = 0 } = options; - logger.info(`[IPC]: setup to handle "${channel}"`); - - ipcMain.handle(channel, async (event, ...args) => { - logger.info(`[IPC]: handle "${channel}"`, { args }); - return new Promise(async (resolve, reject) => { - let timerId; - if (timeout) { - timerId = setTimeout(() => { - const timeoutError = new Error("[IPC]: response timeout"); - reject(timeoutError); - }, timeout); - } - try { - const result = await handler(...args); // todo: maybe exec in separate thread/worker - resolve(result); - clearTimeout(timerId); - } catch (err) { - reject(err); - } - }) - }) -} - -export interface IpcPairOptions { - channel: IpcChannel - handle?: IpcMessageHandler - autoBind?: boolean; - timeout?: number; -} - -// todo: improve api -export function createIpcChannel({ channel, autoBind, ...initOpts }: IpcPairOptions) { - const bindHandler = (opts: { handler?: IpcMessageHandler, options?: IpcHandleOpts } = {}) => { - const handler = opts.handler || initOpts.handle || Function; - const options = opts.options || { timeout: initOpts.timeout }; - handleIpc(channel, handler, options); - }; - if (autoBind) { - bindHandler(); - } - return { - channel: channel, - handleInMain: bindHandler, - invokeFromRenderer(...args: any[]) { - return invokeIpc(channel, ...args); - }, - } -} diff --git a/src/common/kube-helpers.ts b/src/common/kube-helpers.ts index 65737b6134..26e73db4a8 100644 --- a/src/common/kube-helpers.ts +++ b/src/common/kube-helpers.ts @@ -1,11 +1,10 @@ import { app, remote } from "electron"; import { KubeConfig, V1Node, V1Pod } from "@kubernetes/client-node" -import { ensureDirSync, readFile, writeFileSync } from "fs-extra"; +import fse, { ensureDirSync, readFile, writeFileSync } from "fs-extra"; import path from "path" import os from "os" import yaml from "js-yaml" import logger from "../main/logger"; -import fse from "fs-extra" function resolveTilde(filePath: string) { if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) { @@ -135,8 +134,6 @@ export function podHasIssues(pod: V1Pod) { ) } -// Logic adapted from dashboard -// see: https://github.com/kontena/kontena-k8s-dashboard/blob/7d8f9cb678cc817a22dd1886c5e79415b212b9bf/client/api/endpoints/nodes.api.ts#L147 export function getNodeWarningConditions(node: V1Node) { return node.status.conditions.filter(c => c.status.toLowerCase() === "true" && c.type !== "Ready" && c.type !== "HostUpgrades" diff --git a/src/common/tracker.ts b/src/common/tracker.ts index c904d2c806..bc9a8e191b 100644 --- a/src/common/tracker.ts +++ b/src/common/tracker.ts @@ -3,6 +3,7 @@ import ua from "universal-analytics" import { machineIdSync } from "node-machine-id" import Singleton from "./utils/singleton"; import { userStore } from "./user-store" +import logger from "../main/logger"; export class Tracker extends Singleton { static readonly GA_ID = "UA-159377374-1" @@ -40,7 +41,7 @@ export class Tracker extends Singleton { ...otherParams, }).send() } catch (err) { - console.error(`Failed to track "${eventCategory}:${eventAction}"`, err) + logger.error(`Failed to track "${eventCategory}:${eventAction}"`, err) } } } diff --git a/src/common/user-store.ts b/src/common/user-store.ts index 67c779aadb..d88ee204cb 100644 --- a/src/common/user-store.ts +++ b/src/common/user-store.ts @@ -71,12 +71,10 @@ export class UserStore extends BaseStore { if (kubeConfig) { this.newContexts.clear(); const localContexts = loadConfig(kubeConfig).getContexts(); - localContexts.forEach(({ cluster, name }) => { - if (!cluster) return; - if (!this.seenContexts.has(name)) { - this.newContexts.add(name) - } - }) + localContexts + .filter(ctx => ctx.cluster) + .filter(ctx => !this.seenContexts.has(ctx.name)) + .forEach(ctx => this.newContexts.add(ctx.name)); } } diff --git a/src/common/user-store_test.ts b/src/common/user-store_test.ts new file mode 100644 index 0000000000..4e9efe97d8 --- /dev/null +++ b/src/common/user-store_test.ts @@ -0,0 +1,102 @@ +import mockFs from "mock-fs" + +jest.mock("electron", () => { + return { + app: { + getVersion: () => '99.99.99', + getPath: () => 'tmp', + getLocale: () => 'en' + } + } +}) + +import { UserStore } from "./user-store" +import { SemVer } from "semver" +import electron from "electron" + +describe("user store tests", () => { + describe("for an empty config", () => { + beforeEach(() => { + UserStore.resetInstance() + mockFs({ tmp: { 'config.json': "{}" } }) + }) + + afterEach(() => { + mockFs.restore() + }) + + it("allows setting and retrieving lastSeenAppVersion", () => { + const us = UserStore.getInstance(); + + us.lastSeenAppVersion = "1.2.3"; + expect(us.lastSeenAppVersion).toBe("1.2.3"); + }) + + it("allows adding and listing seen contexts", () => { + const us = UserStore.getInstance(); + + us.seenContexts.add('foo') + expect(us.seenContexts.size).toBe(1) + + us.seenContexts.add('foo') + us.seenContexts.add('bar') + expect(us.seenContexts.size).toBe(2) // check 'foo' isn't added twice + expect(us.seenContexts.has('foo')).toBe(true) + expect(us.seenContexts.has('bar')).toBe(true) + }) + + it("allows setting and getting preferences", () => { + const us = UserStore.getInstance(); + + us.preferences.httpsProxy = 'abcd://defg'; + + expect(us.preferences.httpsProxy).toBe('abcd://defg') + expect(us.preferences.colorTheme).toBe(UserStore.defaultTheme) + + us.preferences.colorTheme = "light"; + expect(us.preferences.colorTheme).toBe('light') + }) + + it("correctly resets theme to default value", () => { + const us = UserStore.getInstance(); + + us.preferences.colorTheme = "some other theme"; + us.resetTheme(); + expect(us.preferences.colorTheme).toBe(UserStore.defaultTheme); + }) + + it("correctly calculates if the last seen version is an old release", () => { + const us = UserStore.getInstance(); + + expect(us.isNewVersion).toBe(true); + + us.lastSeenAppVersion = (new SemVer(electron.app.getVersion())).inc("major").format(); + expect(us.isNewVersion).toBe(false); + }) + }) + + describe("migrations", () => { + beforeEach(() => { + UserStore.resetInstance() + mockFs({ + 'tmp': { + 'config.json': JSON.stringify({ + user: { username: 'foobar' }, + preferences: { colorTheme: 'light' }, + lastSeenAppVersion: '1.2.3' + }) + } + }) + }) + + afterEach(() => { + mockFs.restore() + }) + + it("sets last seen app version to 0.0.0", () => { + const us = UserStore.getInstance(); + + expect(us.lastSeenAppVersion).toBe('0.0.0') + }) + }) +}) \ No newline at end of file diff --git a/src/common/utils/defineGlobal.ts b/src/common/utils/defineGlobal.ts new file mode 100755 index 0000000000..29e2e60ea0 --- /dev/null +++ b/src/common/utils/defineGlobal.ts @@ -0,0 +1,12 @@ +// Setup variable in global scope (top-level object) +// Global type definition must be added separately to `mocks.d.ts` in form: +// declare const __globalName: any; + +export function defineGlobal(propName: string, descriptor: PropertyDescriptor) { + const scope = typeof global !== "undefined" ? global : window; + if (scope.hasOwnProperty(propName)) { + console.info(`Global variable "${propName}" already exists. Skipping.`) + return; + } + Object.defineProperty(scope, propName, descriptor); +} diff --git a/src/common/vars.ts b/src/common/vars.ts index d7e18e3467..1df1e0f5df 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -1,6 +1,7 @@ // App's common configuration for any process (main, renderer, build pipeline, etc.) -import packageInfo from "../../package.json" import path from "path"; +import packageInfo from "../../package.json" +import { defineGlobal } from "./utils/defineGlobal"; export const isMac = process.platform === "darwin" export const isWindows = process.platform === "win32" @@ -10,16 +11,26 @@ export const isDevelopment = isDebugging || !isProduction; export const isTestEnv = !!process.env.JEST_WORKER_ID; export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}` +export const publicPath = "/build/" -// System paths +// Webpack build paths export const contextDir = process.cwd(); -export const staticDir = path.join(contextDir, "static"); -export const outDir = path.join(contextDir, "out"); +export const buildDir = path.join(contextDir, "static", publicPath); export const mainDir = path.join(contextDir, "src/main"); export const rendererDir = path.join(contextDir, "src/renderer"); export const htmlTemplate = path.resolve(rendererDir, "template.html"); export const sassCommonVars = path.resolve(rendererDir, "components/vars.scss"); +// Special runtime paths +defineGlobal("__static", { + get() { + if (isDevelopment) { + return path.resolve(contextDir, "static"); + } + return path.resolve(process.resourcesPath, "static") + } +}) + // Apis export const apiPrefix = "/api" // local router apis export const apiKubePrefix = "/api-kube" // k8s cluster apis diff --git a/src/common/workspace-store.ts b/src/common/workspace-store.ts index 047d0dfedd..dd10a4c433 100644 --- a/src/common/workspace-store.ts +++ b/src/common/workspace-store.ts @@ -1,4 +1,4 @@ -import { action, computed, observable, reaction, toJS } from "mobx"; +import { action, computed, observable, toJS } from "mobx"; import { BaseStore } from "./base-store"; import { clusterStore } from "./cluster-store" @@ -22,15 +22,6 @@ export class WorkspaceStore extends BaseStore { super({ configName: "lens-workspace-store", }); - - // switch to first available cluster in current workspace - reaction(() => this.currentWorkspaceId, workspaceId => { - const clusters = clusterStore.getByWorkspaceId(workspaceId); - const activeClusterInWorkspace = clusters.some(cluster => cluster.id === clusterStore.activeClusterId); - if (!activeClusterInWorkspace) { - clusterStore.activeClusterId = clusters.length ? clusters[0].id : null; - } - }) } @observable currentWorkspaceId = WorkspaceStore.defaultId; @@ -60,6 +51,10 @@ export class WorkspaceStore extends BaseStore { @action setActive(id = WorkspaceStore.defaultId) { + if (!this.getById(id)) { + throw new Error(`workspace ${id} doesn't exist`); + } + this.currentWorkspaceId = id; } diff --git a/src/common/workspace-store_test.ts b/src/common/workspace-store_test.ts new file mode 100644 index 0000000000..55e9672663 --- /dev/null +++ b/src/common/workspace-store_test.ts @@ -0,0 +1,128 @@ +import mockFs from "mock-fs" + +jest.mock("electron", () => { + return { + app: { + getVersion: () => '99.99.99', + getPath: () => 'tmp', + getLocale: () => 'en' + } + } +}) + +import { WorkspaceStore } from "./workspace-store" + +describe("workspace store tests", () => { + describe("for an empty config", () => { + beforeEach(async () => { + WorkspaceStore.resetInstance() + mockFs({ tmp: { 'lens-workspace-store.json': "{}" } }) + + await WorkspaceStore.getInstance().load(); + }) + + afterEach(() => { + mockFs.restore() + }) + + it("default workspace should always exist", () => { + const ws = WorkspaceStore.getInstance(); + + expect(ws.workspaces.size).toBe(1); + expect(ws.getById(WorkspaceStore.defaultId)).not.toBe(null); + }) + + it("cannot remove the default workspace", () => { + const ws = WorkspaceStore.getInstance(); + + expect(() => ws.removeWorkspace(WorkspaceStore.defaultId)).toThrowError("Cannot remove"); + }) + + it("can update default workspace name", () => { + const ws = WorkspaceStore.getInstance(); + + ws.saveWorkspace({ + id: WorkspaceStore.defaultId, + name: "foobar", + }); + + expect(ws.currentWorkspace.name).toBe("foobar"); + }) + + it("can add workspaces", () => { + const ws = WorkspaceStore.getInstance(); + + ws.saveWorkspace({ + id: "123", + name: "foobar", + }); + + expect(ws.getById("123").name).toBe("foobar"); + }) + + it("cannot set a non-existent workspace to be active", () => { + const ws = WorkspaceStore.getInstance(); + + expect(() => ws.setActive("abc")).toThrow("doesn't exist"); + }) + + it("can set a existent workspace to be active", () => { + const ws = WorkspaceStore.getInstance(); + + ws.saveWorkspace({ + id: "abc", + name: "foobar", + }); + + expect(() => ws.setActive("abc")).not.toThrowError(); + }) + + it("can remove a workspace", () => { + const ws = WorkspaceStore.getInstance(); + + ws.saveWorkspace({ + id: "123", + name: "foobar", + }); + ws.saveWorkspace({ + id: "1234", + name: "foobar 1", + }); + ws.removeWorkspace("123"); + + expect(ws.workspaces.size).toBe(2); + }) + }) + + describe("for a non-empty config", () => { + beforeEach(async () => { + WorkspaceStore.resetInstance() + mockFs({ + tmp: { + 'lens-workspace-store.json': JSON.stringify({ + currentWorkspace: "abc", + workspaces: [{ + id: "abc", + name: "test" + }, { + id: "default", + name: "default" + }] + }) + } + }) + + await WorkspaceStore.getInstance().load(); + }) + + afterEach(() => { + mockFs.restore() + }) + + it("doesn't revert to default workspace", async () => { + const ws = WorkspaceStore.getInstance(); + + expect(ws.currentWorkspaceId).toBe("abc"); + }) + }) +}) \ No newline at end of file diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 97b9a80871..af1e0d5657 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -1,9 +1,10 @@ +import "../common/cluster-ipc"; import type http from "http" import { autorun } from "mobx"; import { ClusterId, clusterStore } from "../common/cluster-store" import { Cluster } from "./cluster" -import { clusterIpc } from "../common/cluster-ipc"; import logger from "./logger"; +import { apiKubePrefix } from "../common/vars"; export class ClusterManager { constructor(public readonly port: number) { @@ -29,13 +30,6 @@ export class ClusterManager { }, { delay: 250 }); - - // listen for ipc-events that must/can be handled *only* in main-process (nodeIntegration=true) - clusterIpc.activate.handleInMain(); - clusterIpc.disconnect.handleInMain(); - clusterIpc.installFeature.handleInMain(); - clusterIpc.uninstallFeature.handleInMain(); - clusterIpc.upgradeFeature.handleInMain(); } stop() { @@ -49,8 +43,23 @@ export class ClusterManager { } getClusterForRequest(req: http.IncomingMessage): Cluster { - logger.info(`getClusterForRequest(): ${req.headers.host}${req.url}`) - const clusterId = req.headers.host.split(".")[0] - return this.getCluster(clusterId) + let cluster: Cluster = null + + // lens-server is connecting to 127.0.0.1:/ + if (req.headers.host.startsWith("127.0.0.1")) { + const clusterId = req.url.split("/")[1] + if (clusterId) { + cluster = this.getCluster(clusterId) + if (cluster) { + // we need to swap path prefix so that request is proxied to kube api + req.url = req.url.replace(`/${clusterId}`, apiKubePrefix) + } + } + } else { + const id = req.headers.host.split(".")[0] + cluster = this.getCluster(id) + } + + return cluster; } } diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 82037a1fb4..6ba0fb1f48 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -40,6 +40,7 @@ export interface ClusterState extends ClusterModel { export class Cluster implements ClusterModel { public id: ClusterId; + public frameId: number; public kubeCtl: Kubectl public contextHandler: ContextHandler; protected kubeconfigManager: KubeconfigManager; @@ -67,9 +68,8 @@ export class Cluster implements ClusterModel { @observable allowedNamespaces: string[] = []; @observable allowedResources: string[] = []; - @computed get host() { - const proxyHost = new URL(this.kubeProxyUrl).host; - return `${this.id}.${proxyHost}` + @computed get available() { + return this.accessible && !this.disconnected; } constructor(model: ClusterModel) { @@ -79,7 +79,7 @@ export class Cluster implements ClusterModel { @action updateModel(model: ClusterModel) { Object.assign(this, model); - this.apiUrl = this.getKubeconfig().getCurrentCluster().server; + this.apiUrl = this.getKubeconfig().getCurrentCluster()?.server; this.contextName = this.contextName || this.preferences.clusterName; } @@ -222,8 +222,9 @@ export class Cluster implements ClusterModel { return request(apiUrl, { json: true, timeout: 5000, + ...options, headers: { - Host: this.host, // provide cluster-id for ClusterManager.getClusterForRequest() + Host: `${this.id}.${new URL(this.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest() ...(options.headers || {}), }, }) @@ -233,6 +234,7 @@ export class Cluster implements ClusterModel { const prometheusPrefix = this.preferences.prometheus?.prefix || ""; const metricsPath = `/api/v1/namespaces/${prometheusPath}/proxy${prometheusPrefix}/api/v1/query_range`; return this.k8sRequest(metricsPath, { + timeout: 0, resolveWithFullResponse: false, json: true, qs: queryParams, @@ -388,8 +390,8 @@ export class Cluster implements ClusterModel { pushState = (state = this.getState()): ClusterState => { logger.debug(`[CLUSTER]: push-state`, state); broadcastIpc({ - // webContentId: viewId, // todo: send to cluster-view only channel: "cluster:state", + frameId: this.frameId, args: [state], }); return state; diff --git a/src/main/index.ts b/src/main/index.ts index 0c5558ec33..3014b78c41 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -3,7 +3,7 @@ import "../common/system-ca" import "../common/prometheus-providers" import { app, dialog } from "electron" -import { appName, staticDir } from "../common/vars"; +import { appName } from "../common/vars"; import path from "path" import { LensProxy } from "./lens-proxy" import { WindowManager } from "./window-manager"; @@ -19,6 +19,12 @@ import { workspaceStore } from "../common/workspace-store"; import { tracker } from "../common/tracker"; import logger from "./logger" +const workingDir = path.join(app.getPath("appData"), appName); +app.setName(appName); +if(!process.env.CICD) { + app.setPath("userData", workingDir); +} + let windowManager: WindowManager; let clusterManager: ClusterManager; let proxyServer: LensProxy; @@ -30,17 +36,13 @@ if (app.commandLine.getSwitchValue("proxy-server") !== "") { async function main() { await shellSync(); - - const workingDir = path.join(app.getPath("appData"), appName); - app.setName(appName); - app.setPath("userData", workingDir); logger.info(`🚀 Starting Lens from "${workingDir}"`) tracker.event("app", "start"); const updater = new AppUpdater() updater.start(); - registerFileProtocol("static", staticDir); + registerFileProtocol("static", __static); // find free port let proxyPort: number diff --git a/src/main/menu.ts b/src/main/menu.ts index 67daf37fc2..202f61475e 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -1,8 +1,7 @@ -import type { WindowManager } from "./window-manager"; import { app, BrowserWindow, dialog, Menu, MenuItem, MenuItemConstructorOptions, shell, webContents } from "electron" import { autorun } from "mobx"; +import { WindowManager } from "./window-manager"; import { appName, isMac, issuesTrackerUrl, isWindows, slackUrl } from "../common/vars"; -import { clusterStore } from "../common/cluster-store"; import { addClusterURL } from "../renderer/components/+add-cluster/add-cluster.route"; import { preferencesURL } from "../renderer/components/+preferences/preferences.route"; import { whatsNewURL } from "../renderer/components/+whats-new/whats-new.route"; @@ -10,53 +9,119 @@ import { clusterSettingsURL } from "../renderer/components/+cluster-settings/clu import logger from "./logger"; export function initMenu(windowManager: WindowManager) { - autorun(() => { - logger.debug(`[MENU]: building menu, cluster=${clusterStore.activeClusterId}`); - buildMenu(windowManager); + autorun(() => buildMenu(windowManager), { + delay: 100 }); } export function buildMenu(windowManager: WindowManager) { - function macOnly(menuItems: MenuItemConstructorOptions[]): MenuItemConstructorOptions[] { - if (!isMac) return []; + function ignoreOnMac(menuItems: MenuItemConstructorOptions[]) { + if (isMac) return []; return menuItems; } - const fileMenu: MenuItemConstructorOptions = { - label: isMac ? app.getName() : "File", + function activeClusterOnly(menuItems: MenuItemConstructorOptions[]) { + if (!windowManager.activeClusterId) { + menuItems.forEach(item => { + item.enabled = false + }); + } + return menuItems; + } + + function navigate(url: string) { + logger.info(`[MENU]: navigating to ${url}`); + windowManager.navigate({ + channel: "menu:navigate", + url: url, + }) + } + + function showAbout(browserWindow: BrowserWindow) { + const appInfo = [ + `${appName}: ${app.getVersion()}`, + `Electron: ${process.versions.electron}`, + `Chrome: ${process.versions.chrome}`, + `Copyright 2020 Lakend Labs, Inc.`, + ] + dialog.showMessageBoxSync(browserWindow, { + title: `${isWindows ? " ".repeat(2) : ""}${appName}`, + type: "info", + buttons: ["Close"], + message: `Lens`, + detail: appInfo.join("\r\n") + }) + } + + const mt: MenuItemConstructorOptions[] = []; + + const macAppMenu: MenuItemConstructorOptions = { + label: app.getName(), submenu: [ { - label: 'Add Cluster', - click() { - windowManager.navigateMain(addClusterURL()) + label: "About Lens", + click(menuItem: MenuItem, browserWindow: BrowserWindow) { + showAbout(browserWindow) } }, - ...(clusterStore.activeCluster ? [{ - label: 'Cluster Settings', - click() { - windowManager.navigateMain(clusterSettingsURL()) - } - }] : []), { type: 'separator' }, { label: 'Preferences', click() { - windowManager.navigateMain(preferencesURL()) + navigate(preferencesURL()) } }, - ...macOnly([ - { type: 'separator' }, - { role: 'services' }, - { type: 'separator' }, - { role: 'hide' }, - { role: 'hideOthers' }, - { role: 'unhide' }, - ]), + { type: 'separator' }, + { role: 'services' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' }, + { role: 'unhide' }, { type: 'separator' }, { role: 'quit' } ] }; + if (isMac) { + mt.push(macAppMenu); + } + + const fileMenu: MenuItemConstructorOptions = { + label: "File", + submenu: [ + { + label: 'Add Cluster', + click() { + navigate(addClusterURL()) + } + }, + ...activeClusterOnly([ + { + label: 'Cluster Settings', + click() { + navigate(clusterSettingsURL({ + params: { + clusterId: windowManager.activeClusterId + } + })) + } + } + ]), + ...ignoreOnMac([ + { type: 'separator' }, + { + label: 'Preferences', + click() { + navigate(preferencesURL()) + } + }, + { type: 'separator' }, + { role: 'quit' } + ]) + ] + }; + mt.push(fileMenu) + const editMenu: MenuItemConstructorOptions = { label: 'Edit', submenu: [ @@ -71,7 +136,7 @@ export function buildMenu(windowManager: WindowManager) { { role: 'selectAll' }, ] }; - + mt.push(editMenu) const viewMenu: MenuItemConstructorOptions = { label: 'View', submenu: [ @@ -79,21 +144,21 @@ export function buildMenu(windowManager: WindowManager) { label: 'Back', accelerator: 'CmdOrCtrl+[', click() { - webContents.getFocusedWebContents().executeJavaScript('window.history.back()') + webContents.getFocusedWebContents()?.goBack(); } }, { label: 'Forward', accelerator: 'CmdOrCtrl+]', click() { - webContents.getFocusedWebContents().executeJavaScript('window.history.forward()') + webContents.getFocusedWebContents()?.goForward(); } }, { label: 'Reload', accelerator: 'CmdOrCtrl+R', click() { - webContents.getFocusedWebContents().reload() + webContents.getFocusedWebContents()?.reload(); } }, { role: 'toggleDevTools' }, @@ -105,16 +170,11 @@ export function buildMenu(windowManager: WindowManager) { { role: 'togglefullscreen' } ] }; + mt.push(viewMenu) const helpMenu: MenuItemConstructorOptions = { role: 'help', submenu: [ - { - label: "What's new?", - click() { - windowManager.navigateMain(whatsNewURL()) - }, - }, { label: "License", click: async () => { @@ -134,27 +194,23 @@ export function buildMenu(windowManager: WindowManager) { }, }, { - label: "About Lens", - click(menuItem: MenuItem, browserWindow: BrowserWindow) { - const appInfo = [ - `${appName}: ${app.getVersion()}`, - `Electron: ${process.versions.electron}`, - `Chrome: ${process.versions.chrome}`, - `Copyright 2020 Lakend Labs, Inc.`, - ] - dialog.showMessageBoxSync(browserWindow, { - title: `${isWindows ? " ".repeat(2) : ""}${appName}`, - type: "info", - buttons: ["Close"], - message: `Lens`, - detail: appInfo.join("\r\n") - }) + label: "What's new?", + click() { + navigate(whatsNewURL()) + }, + }, + ...ignoreOnMac([ + { + label: "About Lens", + click(menuItem: MenuItem, browserWindow: BrowserWindow) { + showAbout(browserWindow) + } } - } + ]) ] }; - Menu.setApplicationMenu(Menu.buildFromTemplate([ - fileMenu, editMenu, viewMenu, helpMenu - ])); + mt.push(helpMenu) + + Menu.setApplicationMenu(Menu.buildFromTemplate(mt)); } diff --git a/src/main/router.ts b/src/main/router.ts index 7c5d48e1d6..976d7cac9c 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -4,7 +4,7 @@ import http from "http" import path from "path" import { readFile } from "fs-extra" import { Cluster } from "./cluster" -import { apiPrefix, appName, outDir } from "../common/vars"; +import { apiPrefix, appName, publicPath } from "../common/vars"; import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; export interface RouterRequestOpts { @@ -95,14 +95,14 @@ export class Router { } async handleStaticFile(filePath: string, res: http.ServerResponse) { - const asset = path.join(outDir, filePath); + const asset = path.join(__static, filePath); try { const data = await readFile(asset); res.setHeader("Content-Type", this.getMimeType(asset)); res.write(data) res.end() } catch (err) { - this.handleStaticFile(`${appName}.html`, res); + this.handleStaticFile(`${publicPath}/${appName}.html`, res); } } @@ -121,7 +121,7 @@ export class Router { this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)) // Port-forward API - this.router.add({ method: "post", path: `${apiPrefix}/services/{namespace}/{service}/port-forward/{port}` }, portForwardRoute.routeServicePortForward.bind(portForwardRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)) // Helm API this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)) diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index 9cf4a280e2..2665fca5f2 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -16,8 +16,10 @@ class MetricsRoute extends LensApi { let prometheusPath: string let prometheusProvider: PrometheusProvider try { - prometheusPath = await cluster.contextHandler.getPrometheusPath() - prometheusProvider = await cluster.contextHandler.getPrometheusProvider() + [prometheusPath, prometheusProvider] = await Promise.all([ + cluster.contextHandler.getPrometheusPath(), + cluster.contextHandler.getPrometheusProvider() + ]) } catch { this.respondJson(response, {}) return diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index a5fe683cc2..86cf4f0917 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -14,7 +14,7 @@ class PortForward { return PortForward.portForwards.find((pf) => { return ( pf.clusterId == forward.clusterId && - pf.kind == "service" && + pf.kind == forward.kind && pf.name == forward.name && pf.namespace == forward.namespace && pf.port == forward.port @@ -42,7 +42,7 @@ class PortForward { "--kubeconfig", this.kubeConfig, "port-forward", "-n", this.namespace, - `service/${this.name}`, + `${this.kind}/${this.name}`, `${this.localPort}:${this.port}` ] @@ -72,21 +72,22 @@ class PortForward { class PortForwardRoute extends LensApi { - public async routeServicePortForward(request: LensApiRequest) { + public async routePortForward(request: LensApiRequest) { const { params, response, cluster} = request + const { namespace, port, resourceType, resourceName } = params let portForward = PortForward.getPortforward({ - clusterId: cluster.id, kind: "service", name: params.service, - namespace: params.namespace, port: params.port + clusterId: cluster.id, kind: resourceType, name: resourceName, + namespace: namespace, port: port }) if (!portForward) { - logger.info(`Creating a new port-forward ${params.namespace}/${params.service}:${params.port}`) + logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`) portForward = new PortForward({ clusterId: cluster.id, - kind: "service", - namespace: params.namespace, - name: params.service, - port: params.port, + kind: resourceType, + namespace: namespace, + name: resourceName, + port: port, kubeConfig: cluster.getProxyKubeconfigPath() }) const started = await portForward.start() diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index c4ae9a0d96..166f512b70 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -1,5 +1,7 @@ -import { BrowserWindow, shell } from "electron" +import type { ClusterId } from "../common/cluster-store"; +import { BrowserWindow, dialog, ipcMain, shell, WebContents, webContents } from "electron" import windowStateKeeper from "electron-window-state" +import { observable } from "mobx"; import { initMenu } from "./menu"; export class WindowManager { @@ -7,9 +9,9 @@ export class WindowManager { protected splashWindow: BrowserWindow; protected windowState: windowStateKeeper.State; - constructor(protected proxyPort: number) { - initMenu(this); + @observable activeClusterId: ClusterId; + constructor(protected proxyPort: number) { // Manage main window size and position with state persistence this.windowState = windowStateKeeper({ defaultHeight: 900, @@ -26,6 +28,7 @@ export class WindowManager { backgroundColor: "#1e2124", webPreferences: { nodeIntegration: true, + nodeIntegrationInSubFrames: true, enableRemoteModule: true, }, }); @@ -37,20 +40,33 @@ export class WindowManager { shell.openExternal(url); }); + // track visible cluster from ui + ipcMain.on("cluster-view:change", (event, clusterId: ClusterId) => { + this.activeClusterId = clusterId; + }); + // load & show app this.showMain(); + initMenu(this); } - // fixme - navigateMain(url: string) { - this.mainView.webContents.executeJavaScript("console.log('implement me!')") + navigate({ url, channel, frameId }: { url: string, channel: string, frameId?: number }) { + if (frameId) { + this.mainView.webContents.sendToFrame(frameId, channel, url); + } else { + this.mainView.webContents.send(channel, url); + } } async showMain() { - await this.showSplash(); - await this.mainView.loadURL(`http://localhost:${this.proxyPort}`) - this.mainView.show(); - this.splashWindow.hide(); + try { + await this.showSplash(); + await this.mainView.loadURL(`http://localhost:${this.proxyPort}`) + this.mainView.show(); + this.splashWindow.close(); + } catch (err) { + dialog.showErrorBox("ERROR!", err.toString()) + } } async showSplash() { @@ -63,6 +79,9 @@ export class WindowManager { frame: false, resizable: false, show: false, + webPreferences: { + nodeIntegration: true + } }); await this.splashWindow.loadURL("static://splash.html"); } diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index df75eea2c4..d5e61c2305 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -50,6 +50,9 @@ export function parseKubeApi(path: string): IKubeApiParsed { apiGroup = left.join("/"); } else { switch (left.length) { + case 4: + [apiGroup, apiVersion, resource, name] = left + break; case 2: resource = left.pop(); // fallthrough @@ -66,7 +69,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { * - `GROUP` is /^D(\.D)*$/ where D is `DNS_LABEL` and length <= 253 * * There is no well defined selection from an array of items that were - * seperated by '/' + * separated by '/' * * Solution is to create a huristic. Namely: * 1. if '.' in left[0] then apiGroup <- left[0] diff --git a/src/renderer/api/kube-api-parse_test.ts b/src/renderer/api/kube-api-parse_test.ts index b33c833bfa..dee3bf031d 100644 --- a/src/renderer/api/kube-api-parse_test.ts +++ b/src/renderer/api/kube-api-parse_test.ts @@ -6,6 +6,19 @@ interface KubeApi_Parse_Test { } const tests: KubeApi_Parse_Test[] = [ + { + url: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com", + expected: { + apiBase: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions", + apiPrefix: "/apis", + apiGroup: "apiextensions.k8s.io", + apiVersion: "v1beta1", + apiVersionWithGroup: "apiextensions.k8s.io/v1beta1", + namespace: undefined, + resource: "customresourcedefinitions", + name: "prometheuses.monitoring.coreos.com" + }, + }, { url: "/api/v1/namespaces/kube-system/pods/coredns-6955765f44-v8p27", expected: { diff --git a/src/renderer/browser-check.tsx b/src/renderer/browser-check.tsx deleted file mode 100644 index ce6c9ecad6..0000000000 --- a/src/renderer/browser-check.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from "react"; -import { Notifications } from "./components/notifications"; -import { Trans } from "@lingui/macro"; - -export function browserCheck() { - const ua = window.navigator.userAgent - const msie = ua.indexOf('MSIE ') // IE < 11 - const trident = ua.indexOf('Trident/') // IE 11 - const edge = ua.indexOf('Edge') // Edge - if (msie > 0 || trident > 0 || edge > 0) { - Notifications.info( -

- - Your browser does not support all Lens features. {" "} - Please consider using another browser. - -

- ) - } -} \ No newline at end of file diff --git a/src/renderer/components/+add-cluster/add-cluster.scss b/src/renderer/components/+add-cluster/add-cluster.scss index 8dc192d25b..17b6a09d82 100644 --- a/src/renderer/components/+add-cluster/add-cluster.scss +++ b/src/renderer/components/+add-cluster/add-cluster.scss @@ -1,2 +1,11 @@ .AddCluster { + .Select { + &__control { + box-shadow: 0 0 0 1px $borderFaintColor; + } + } + + code { + color: $pink-400; + } } \ No newline at end of file diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 221f695425..0672a1a91a 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -15,8 +15,9 @@ import { getKubeConfigLocal, loadConfig, saveConfigToAppFiles, splitConfig, vali import { clusterStore } from "../../../common/cluster-store"; import { workspaceStore } from "../../../common/workspace-store"; import { v4 as uuid } from "uuid" -import { navigation } from "../../navigation"; +import { navigate } from "../../navigation"; import { userStore } from "../../../common/user-store"; +import { clusterViewURL } from "../cluster-manager/cluster-view.route"; @observer export class AddCluster extends React.Component { @@ -70,8 +71,9 @@ export class AddCluster extends React.Component { if (value instanceof KubeConfig) { const context = value.currentContext; const isNew = userStore.newContexts.has(context); + const className = `${context} kube-context flex gaps align-center` return ( -
+
{context} {isNew && }
@@ -102,7 +104,7 @@ export class AddCluster extends React.Component { httpsProxy: proxyServer || undefined, }, }); - navigation.goBack(); // return to previous opened page for the cluster view + navigate(clusterViewURL({ params: { clusterId } })) } catch (err) { this.error = String(err); } finally { @@ -124,7 +126,7 @@ export class AddCluster extends React.Component { to allow you to operate easily on multiple clusters and/or contexts.

- For more information on kubeconfig see Kubernetes docs + For more information on kubeconfig see Kubernetes docs.

NOTE: Any manually added cluster is not merged into your kubeconfig file. @@ -137,22 +139,20 @@ export class AddCluster extends React.Component { app.

-

OIDC (OpenID Connect)

+

OIDC (OpenID Connect)

-
-

- When connecting Lens to OIDC enabled cluster, there's few things you as a user need to take into account. -

- Dedicated refresh token -

- As Lens app utilized kubeconfig is "disconnected" from your main kubeconfig Lens needs to have it's own refresh token it utilizes. - If you share the refresh token with e.g. kubectl who ever uses the token first will invalidate it for the next user. - One way to achieve this is with kubelogin tool by removing the tokens - (both id_token and refresh_token) from - the config and issuing kubelogin command. That'll take you through the login process and will result you having "dedicated" refresh token. -

-
-

Exec auth plugins

+

+ When connecting Lens to OIDC enabled cluster, there's few things you as a user need to take into account. +

+

Dedicated refresh token

+

+ As Lens app utilized kubeconfig is "disconnected" from your main kubeconfig Lens needs to have it's own refresh token it utilizes. + If you share the refresh token with e.g. kubectl who ever uses the token first will invalidate it for the next user. + One way to achieve this is with kubelogin tool by removing the tokens + (both id_token and refresh_token) from + the config and issuing kubelogin command. That'll take you through the login process and will result you having "dedicated" refresh token. +

+

Exec auth plugins

When using exec auth plugins make sure the paths that are used to call any binaries @@ -167,12 +167,14 @@ export class AddCluster extends React.Component { return (

Add Cluster

+

Choose config:

:)`)} value={this.proxyServer} onChange={value => this.proxyServer = value} + theme="round-black" /> - HTTP Proxy server. Used for communicating with Kubernetes API. + {'A HTTP proxy server URL (format: http://
:).'}
)} @@ -197,6 +200,7 @@ export class AddCluster extends React.Component {

Kubeconfig:

this.customConfig = value} @@ -209,7 +213,7 @@ export class AddCluster extends React.Component {
+ if (this.props.cluster.preferences.icon) { + return } } render() { - return <> -

Cluster Icon

-

Set cluster icon. By default it is automatically generated. {this.getIconRight()}

-
- + - {this.getClearButton()} -
- ; - } - - getIconRight(): React.ReactNode { - switch (this.status) { - case GeneralInputStatus.CLEAN: - return null; - case GeneralInputStatus.ERROR: - return - } + {"Browse for new icon..."} + + ); + return ( + <> + +

Define cluster icon. By default automatically generated.

+
+ + {this.getClearButton()} +
+ + ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx index e605864030..8e2f8a2afa 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx @@ -1,85 +1,40 @@ import React from "react"; import { Cluster } from "../../../../main/cluster"; import { Input } from "../../input"; -import { Spinner } from "../../spinner"; -import { clusterStore } from "../../../../common/cluster-store" -import { Icon } from "../../icon"; -import { Tooltip, TooltipPosition } from "../../tooltip"; -import { autobind } from "../../../utils"; -import { TextInputStatus } from "./statuses" import { observable } from "mobx"; import { observer } from "mobx-react"; +import { SubTitle } from "../../layout/sub-title"; +import { isRequired } from "../../input/input.validators"; interface Props { - cluster: Cluster; + cluster: Cluster; } @observer export class ClusterNameSetting extends React.Component { @observable name = this.props.cluster.preferences.clusterName || ""; - @observable status = TextInputStatus.CLEAN; - @observable errorText?: string; + + save = () => { + this.props.cluster.preferences.clusterName = this.name; + }; + + onChange = (value: string) => { + this.name = value; + } render() { - return <> -

Cluster Name

-

Change cluster name:

- - ; - } - - @autobind() - onClusterNameChange(name: string, _e: React.ChangeEvent) { - if (this.status === TextInputStatus.UPDATING) { - console.log("prevent changing cluster name while updating"); - return; - } - - this.status = this.nameDiffers(name) - this.name = name; - } - - nameDiffers(name: string): TextInputStatus { - const { clusterName } = this.props.cluster.preferences; - - return name === clusterName ? TextInputStatus.CLEAN : TextInputStatus.DIRTY; - } - - getIconRight(): React.ReactNode { - switch (this.status) { - case TextInputStatus.CLEAN: - return null; - case TextInputStatus.DIRTY: - return ; - case TextInputStatus.UPDATED: - return ; - case TextInputStatus.UPDATING: - return ; - case TextInputStatus.ERROR: - return - - {this.errorText} - - - } - } - - @autobind() - onClusterNameSubmit(name: string) { - if (this.nameDiffers(name) !== TextInputStatus.DIRTY) { - return; - } - - this.status = TextInputStatus.UPDATING - this.props.cluster.preferences.clusterName = name; - this.name = name; - this.status = TextInputStatus.UPDATED + return ( + <> + +

Define cluster name.

+ + + ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx index 7596cc245b..729090629d 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx @@ -1,41 +1,105 @@ import React from "react"; -import { Cluster } from "../../../../main/cluster"; -import { clusterStore } from "../../../../common/cluster-store" -import { Select, SelectOption, SelectProps } from "../../select"; -import { prometheusProviders } from "../../../../common/prometheus-providers"; -import { autobind } from "../../../utils"; -import { observable } from "mobx"; import { observer } from "mobx-react"; +import { prometheusProviders } from "../../../../common/prometheus-providers"; +import { Cluster } from "../../../../main/cluster"; +import { SubTitle } from "../../layout/sub-title"; +import { Select, SelectOption } from "../../select"; +import { Input } from "../../input"; +import { observable, computed } from "mobx"; -const prometheusGuide = "https://github.com/lensapp/lens/blob/master/troubleshooting/custom-prometheus.md"; const options: SelectOption[] = [ - { value: "", label: "Auto detect" }, + { value: "", label: "Auto detect" }, ...prometheusProviders.map(pp => ({value: pp.id, label: pp.name})) ]; interface Props { - cluster: Cluster; + cluster: Cluster; } @observer export class ClusterPrometheusSetting extends React.Component { - @observable prometheusProvider = this.props.cluster.preferences.prometheusProvider?.type || ""; - - render() { - return <> -

Cluster Prometheus

-

Use pre-installed Prometheus service for metrics. Please refer to this guide for possible configuration changes.

- { + this.provider = value; + this.onSaveProvider(); + }} + options={options} + /> + What query format is used to fetch metrics from Prometheus + {this.canEditPrometheusPath && ( + <> +

Prometheus service address.

+ this.path = value} + onBlur={this.onSavePath} + placeholder="/:" + /> + + An address to an existing Prometheus installation{" "} + ({'/:'}). Lens tries to auto-detect address if left empty. + + + )} + + ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx index 3ddcf25c7f..1b94992e5b 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx @@ -1,105 +1,41 @@ import React from "react"; -import { Cluster } from "../../../../main/cluster"; -import { Input } from "../../input"; -import { Spinner } from "../../spinner"; -import { clusterStore } from "../../../../common/cluster-store" -import { Icon } from "../../icon"; -import { Tooltip, TooltipPosition } from "../../tooltip"; -import { autobind } from "../../../utils"; -import { TextInputStatus } from "./statuses" import { observable } from "mobx"; import { observer } from "mobx-react"; +import { Cluster } from "../../../../main/cluster"; +import { Input } from "../../input"; +import { isUrl } from "../../input/input.validators"; +import { SubTitle } from "../../layout/sub-title"; interface Props { - cluster: Cluster; + cluster: Cluster; } @observer export class ClusterProxySetting extends React.Component { @observable proxy = this.props.cluster.preferences.httpsProxy || ""; - @observable status = TextInputStatus.CLEAN; - @observable errorText?: string; + + save = () => { + this.props.cluster.preferences.httpsProxy = this.proxy; + }; + + onChange = (value: string) => { + this.proxy = value; + } render() { - return <> -

HTTPS Proxy

-

HTTPS Proxy server. Used for communicating with Kubernetes API.

- - ; - } - - @autobind() - changeProxyState(proxy: string, _e: React.ChangeEvent) { - if (this.status === TextInputStatus.UPDATING) { - console.log("prevent changing cluster proxy while updating"); - return; - } - - this.status = this.proxyDiffers(proxy); - this.proxy = proxy; - } - - proxyDiffers(proxy: string): TextInputStatus { - const { httpsProxy = "" } = this.props.cluster.preferences; - - return proxy === httpsProxy ? TextInputStatus.CLEAN : TextInputStatus.DIRTY; - } - - getIconRight(): React.ReactNode { - switch (this.status) { - case TextInputStatus.CLEAN: - return null; - case TextInputStatus.DIRTY: - return ; - case TextInputStatus.UPDATED: - return ; - case TextInputStatus.UPDATING: - return ; - case TextInputStatus.ERROR: - return - - {this.errorText} - - - } - } - - @autobind() - updateClusterProxy(proxy: string) { - if (this.proxyDiffers(proxy) !== TextInputStatus.DIRTY) { - return; - } - - try { - const url = new URL(proxy); - - if (url.protocol !== "https") { - this.status = TextInputStatus.ERROR - this.errorText= `Proxy's protocol should be "https"` - return - } - if (url.port === "") { - this.status = TextInputStatus.ERROR - this.errorText= "Proxy should include a port" - return - } - } catch (e) { - this.status = TextInputStatus.ERROR - this.errorText= "Invalid URL" - return - } - - this.status = TextInputStatus.UPDATING - this.props.cluster.preferences.httpsProxy = proxy; - this.proxy = proxy; - this.status = TextInputStatus.UPDATED + return ( + <> + +

HTTP Proxy server. Used for communicating with Kubernetes API.

+ + + ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/cluster-workspace-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-workspace-setting.tsx index 6337f56aa0..6cd933ca11 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-workspace-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-workspace-setting.tsx @@ -1,36 +1,36 @@ import React from "react"; -import { Cluster } from "../../../../main/cluster"; -import { clusterStore } from "../../../../common/cluster-store" -import { workspaceStore } from "../../../../common/workspace-store" -import { Select, SelectOption } from "../../../components/select"; -import { GeneralInputStatus } from "./statuses" -import { observable } from "mobx"; -import { autobind } from "../../../utils"; import { observer } from "mobx-react"; +import { Link } from "react-router-dom"; +import { workspacesURL } from "../../+workspaces"; +import { workspaceStore } from "../../../../common/workspace-store"; +import { Cluster } from "../../../../main/cluster"; +import { Select } from "../../../components/select"; +import { SubTitle } from "../../layout/sub-title"; interface Props { - cluster: Cluster; + cluster: Cluster; } @observer export class ClusterWorkspaceSetting extends React.Component { - @observable workspace = this.props.cluster.workspace; - render() { - return <> -

Cluster Workspace

-

Change cluster workspace:

- this.props.cluster.workspace = value} + options={workspaceStore.workspacesList.map(w => + ({value: w.id, label: w.name}) + )} + /> + + ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/install-feature.tsx b/src/renderer/components/+cluster-settings/components/install-feature.tsx new file mode 100644 index 0000000000..a04b8fed63 --- /dev/null +++ b/src/renderer/components/+cluster-settings/components/install-feature.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { observable, reaction, comparer } from "mobx"; +import { observer, disposeOnUnmount } from "mobx-react"; +import { clusterIpc } from "../../../../common/cluster-ipc"; +import { Cluster } from "../../../../main/cluster"; +import { Button } from "../../button"; +import { Notifications } from "../../notifications"; +import { Spinner } from "../../spinner"; + +interface Props { + cluster: Cluster + feature: string +} + +@observer +export class InstallFeature extends React.Component { + @observable loading = false; + + componentDidMount() { + disposeOnUnmount(this, + reaction(() => this.props.cluster.features[this.props.feature], () => { + this.loading = false; + }, { equals: comparer.structural }) + ); + } + + getActionButtons() { + const { cluster, feature } = this.props; + const features = cluster.features[feature]; + const disabled = !cluster.isAdmin || this.loading; + const loadingIcon = this.loading ? : null; + if (!features) return null; + return ( +
+ {features.canUpgrade && + + } + {features.installed && + + } + {!features.installed && !features.canUpgrade && + + } + {loadingIcon} + {!cluster.isAdmin && Actions can only be performed by admins.} +
+ ); + } + + runAction(action: () => Promise): () => Promise { + return async () => { + try { + this.loading = true; + await action(); + } catch (err) { + Notifications.error(err.toString()); + } + }; + } + + render() { + return ( + <> + {this.props.children} +
{this.getActionButtons()}
+ + ); + } +} \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/install-metrics.tsx b/src/renderer/components/+cluster-settings/components/install-metrics.tsx deleted file mode 100644 index 171adc6034..0000000000 --- a/src/renderer/components/+cluster-settings/components/install-metrics.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React from "react"; -import { Cluster } from "../../../../main/cluster"; -import { Button } from "../../button"; -import { autobind } from "../../../utils"; -import { Tooltip, TooltipPosition } from "../../tooltip"; -import { MetricsFeature } from "../../../../features/metrics"; -import { Spinner } from "../../spinner"; -import { Icon } from "../../icon"; -import { clusterIpc } from "../../../../common/cluster-ipc"; -import { observable } from "mobx"; -import { ActionStatus } from "./statuses" -import { observer } from "mobx-react"; - -interface Props { - cluster: Cluster; -} - -@observer -export class InstallMetrics extends React.Component { - @observable status = ActionStatus.IDLE; - @observable errorText?: string; - - render() { - return <> -

Metrics

-

- User Mode feature enables non-admin users to see namespaces they have access to. - This is achieved by configuring RBAC rules so that every authenticated user is granted to list namespaces. -

-
- {this.getActionButtons()} -
- ; - } - - getStatusIcon(): React.ReactNode { - switch (this.status) { - case ActionStatus.IDLE: - return null; - case ActionStatus.PROCESSING: - return ; - case ActionStatus.ERROR: - return - } - } - - getDisabledToolTip(id: string, action: string): React.ReactNode { - const { cluster } = this.props; - if (cluster.isAdmin) { - return null; - } - - return ( - - {action} only allowed by admins - - ); - } - - getActionButtons(): React.ReactNode[] { - const { cluster } = this.props - const buttons = []; - - if (cluster.features[MetricsFeature.id]?.canUpgrade) { - buttons.push( - - ); - } - - if (cluster.features[MetricsFeature.id]?.installed) { - buttons.push( - - ); - } else { - buttons.push( - - ); - } - - return buttons; - } - - runAction(action: keyof typeof clusterIpc): () => Promise { - return async () => { - const { cluster } = this.props; - console.log(`running ${action} ${MetricsFeature.id} onto ${cluster.preferences.clusterName}`); - - try { - this.status = ActionStatus.PROCESSING - await clusterIpc[action].invokeFromRenderer(cluster.id, MetricsFeature.id); - try { - await cluster.refresh(); - } catch (err) { - console.error(err); - } - this.status = ActionStatus.IDLE - } catch (err) { - this.status = ActionStatus.ERROR - this.errorText = err.toString() - } - }; - } -} \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/install-user-mode.tsx b/src/renderer/components/+cluster-settings/components/install-user-mode.tsx deleted file mode 100644 index faf7562336..0000000000 --- a/src/renderer/components/+cluster-settings/components/install-user-mode.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React from "react"; -import { Cluster } from "../../../../main/cluster"; -import { Button } from "../../button"; -import { autobind } from "../../../utils"; -import { Tooltip, TooltipPosition } from "../../tooltip"; -import { Spinner } from "../../spinner"; -import { Icon } from "../../icon"; -import { UserModeFeature } from "../../../../features/user-mode"; -import { clusterIpc } from "../../../../common/cluster-ipc"; -import { observable } from "mobx"; -import { ActionStatus } from "./statuses" -import { observer } from "mobx-react"; - -interface Props { - cluster: Cluster; -} - -@observer -export class InstallUserMode extends React.Component { - @observable status = ActionStatus.IDLE; - @observable errorText?: string; - - render() { - return <> -

User Mode

-

- User Mode feature enables non-admin users to see namespaces they have access to. - This is achieved by configuring RBAC rules so that every authenticated user is granted to list namespaces. -

-
- {this.getActionButtons()} -
- ; - } - - - getStatusIcon(): React.ReactNode { - switch (this.status) { - case ActionStatus.IDLE: - return null; - case ActionStatus.PROCESSING: - return ; - case ActionStatus.ERROR: - return - } - } - - getDisabledToolTip(id: string, action: string): React.ReactNode { - const { cluster } = this.props; - if (cluster.isAdmin) { - return null; - } - - return - {action} only allowed by admins - ; - } - - getActionButtons(): React.ReactNode[] { - const { cluster } = this.props - const buttons = []; - - if (cluster.features[UserModeFeature.id]?.canUpgrade) { - buttons.push( - - ); - } - - if (cluster.features[UserModeFeature.id]?.installed) { - buttons.push( - - ); - } else { - buttons.push( - - ); - } - - return buttons; - } - - runAction(action: keyof typeof clusterIpc): () => Promise { - return async () => { - const { cluster } = this.props; - console.log(`running ${action} ${UserModeFeature.id} onto ${cluster.preferences.clusterName}`); - - try { - this.status = ActionStatus.PROCESSING - await clusterIpc[action].invokeFromRenderer(cluster.id, UserModeFeature.id); - try { - await cluster.refresh(); - } catch (err) { - console.error(err); - } - this.status = ActionStatus.IDLE - } catch (err) { - this.status = ActionStatus.ERROR - this.errorText = err.toString() - } - }; - } -} \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx b/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx index 0c57196330..fe62ef4899 100644 --- a/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx +++ b/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx @@ -1,63 +1,37 @@ import React from "react"; -import { Cluster } from "../../../../main/cluster"; -import { Button } from "../../button"; -import { autobind } from "../../../utils"; -import { Spinner } from "../../spinner"; -import { Icon } from "../../icon"; -import { ConfirmDialog } from "../../confirm-dialog"; import { Trans } from "@lingui/macro"; +import { observer } from "mobx-react"; import { clusterIpc } from "../../../../common/cluster-ipc"; import { clusterStore } from "../../../../common/cluster-store"; -import { observable } from "mobx"; -import { observer } from "mobx-react"; -import { RemovalStatus } from "./statuses" +import { Cluster } from "../../../../main/cluster"; +import { autobind } from "../../../utils"; +import { Button } from "../../button"; +import { ConfirmDialog } from "../../confirm-dialog"; interface Props { - cluster: Cluster; + cluster: Cluster; } @observer export class RemoveClusterButton extends React.Component { - @observable status = RemovalStatus.PRESENT; - @observable errorText?: string; - - render() { - return ( -
- -
- ); - } - - getStatusIcon(): React.ReactNode { - switch (this.status) { - case RemovalStatus.PRESENT: - return null; - case RemovalStatus.PROCESSING: - return ; - case RemovalStatus.ERROR: - return ; - } - } - - @autobind() + @autobind() confirmRemoveCluster() { const { cluster } = this.props; - ConfirmDialog.open({ message:

Are you sure you want to remove {cluster.preferences.clusterName} from Lens?

, labelOk: Yes, labelCancel: No, ok: async () => { - try { - this.status = RemovalStatus.PROCESSING; - await clusterIpc.disconnect.invokeFromRenderer(cluster.id); - await clusterStore.removeById(cluster.id); - } catch (err) { - this.status = RemovalStatus.ERROR; - this.errorText = err.toString(); - } + await clusterStore.removeById(cluster.id); } }) } + + render() { + return ( + + ); + } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/components/statuses.ts b/src/renderer/components/+cluster-settings/components/statuses.ts deleted file mode 100644 index d9d897c430..0000000000 --- a/src/renderer/components/+cluster-settings/components/statuses.ts +++ /dev/null @@ -1,24 +0,0 @@ -export enum TextInputStatus { - CLEAN = "clean", - DIRTY = "dirty", - UPDATING = "updating", - ERROR = "error", - UPDATED = "updated", -} - -export enum GeneralInputStatus { - CLEAN = "clean", - ERROR = "error", -} - -export enum ActionStatus { - IDLE = "idle", - PROCESSING = "processing", - ERROR = "error" -} - -export enum RemovalStatus { - PRESENT = "present", - PROCESSING = "processing", - ERROR = "error", -} \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/features.tsx b/src/renderer/components/+cluster-settings/features.tsx index b049fa90ff..f1b3cdada8 100644 --- a/src/renderer/components/+cluster-settings/features.tsx +++ b/src/renderer/components/+cluster-settings/features.tsx @@ -1,7 +1,9 @@ import React from "react"; import { Cluster } from "../../../main/cluster"; -import { InstallMetrics } from "./components/install-metrics"; -import { InstallUserMode } from "./components/install-user-mode"; +import { InstallFeature } from "./components/install-feature"; +import { SubTitle } from "../layout/sub-title"; +import { MetricsFeature } from "../../../features/metrics"; +import { UserModeFeature } from "../../../features/user-mode"; interface Props { cluster: Cluster; @@ -11,10 +13,30 @@ export class Features extends React.Component { render() { const { cluster } = this.props; - return
-

Features

- - -
; + return ( +
+

Features

+ + <> + +

+ Enable timeseries data visualization (Prometheus stack) for your cluster. + Install this only if you don't have existing Prometheus stack installed. + You can see preview of manifests{" "} + here. +

+ +
+ + <> + +

+ User Mode feature enables non-admin users to see namespaces they have access to.{" "} + This is achieved by configuring RBAC rules so that every authenticated user is granted to list namespaces. +

+ +
+
+ ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/general.tsx b/src/renderer/components/+cluster-settings/general.tsx index e03c6e2195..5fb6e9b81f 100644 --- a/src/renderer/components/+cluster-settings/general.tsx +++ b/src/renderer/components/+cluster-settings/general.tsx @@ -15,8 +15,6 @@ export class General extends React.Component { render() { return

General

-
- diff --git a/src/renderer/components/+cluster-settings/removal.tsx b/src/renderer/components/+cluster-settings/removal.tsx index f1d613c694..7d97e9c515 100644 --- a/src/renderer/components/+cluster-settings/removal.tsx +++ b/src/renderer/components/+cluster-settings/removal.tsx @@ -3,16 +3,18 @@ import { Cluster } from "../../../main/cluster"; import { RemoveClusterButton } from "./components/remove-cluster-button"; interface Props { - cluster: Cluster; + cluster: Cluster; } export class Removal extends React.Component { render() { const { cluster } = this.props; - return
-

Removal

- -
; + return ( +
+

Removal

+ +
+ ); } } \ No newline at end of file diff --git a/src/renderer/components/+cluster-settings/status.tsx b/src/renderer/components/+cluster-settings/status.tsx index 6e0bf528fc..ff0436598c 100644 --- a/src/renderer/components/+cluster-settings/status.tsx +++ b/src/renderer/components/+cluster-settings/status.tsx @@ -1,41 +1,40 @@ import React from "react"; -import { Spinner } from "../spinner"; import { Cluster } from "../../../main/cluster"; +import { SubTitle } from "../layout/sub-title"; +import { Table, TableCell, TableRow } from "../table"; interface Props { cluster: Cluster; } export class Status extends React.Component { - renderStatusRows(): JSX.Element[] { + renderStatusRows() { const { cluster } = this.props; - - const rows: [string, React.ReactNode][] = [ - ["Online Status", cluster.online ? "online" : `offline (${cluster.failureReason || "unknown reason"}`], + const rows = [ + ["Online Status", cluster.online ? "online" : `offline (${cluster.failureReason || "unknown reason"})`], ["Distribution", cluster.distribution], ["Kerbel Version", cluster.version], ["API Address", cluster.apiUrl], + ["Nodes Count", cluster.nodes || "0"] ]; - - if (cluster.nodes > 0) { - rows.push(["Nodes Count", cluster.nodes]); - } - - return rows - .map(([header, value]) => [ -
{header}
, - {value} - ]) - .flat(); + return ( + + {rows.map(([name, value]) => { + return ( + + {name} + {value} + + ); + })} +
+ ); } render() { - const { cluster } = this.props; - return

Status

-
-

Cluster status

+

Cluster status information including: detected distribution, kernel version, and online status.

diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index 6a2665e741..3da8c7112a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -4,7 +4,7 @@ import kebabCase from "lodash/kebabCase"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { DrawerItem, DrawerTitle } from "../drawer"; -import { cpuUnitsToNumber, cssNames, unitsToBytes } from "../../utils"; +import { cpuUnitsToNumber, cssNames, unitsToBytes, metricUnitsToNumber } from "../../utils"; import { KubeObjectDetailsProps } from "../kube-object"; import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; import { LineProgress } from "../line-progress"; @@ -15,24 +15,30 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta"; interface Props extends KubeObjectDetailsProps { } -@observer -export class ResourceQuotaDetails extends React.Component { - renderQuotas = (quota: ResourceQuota) => { - const { hard, used } = quota.status - if (!hard || !used) return null - const transformUnit = (name: string, value: string) => { - if (name.includes("memory") || name.includes("storage")) { - return unitsToBytes(value) - } - if (name.includes("cpu")) { - return cpuUnitsToNumber(value) - } - return parseInt(value) - } - return Object.entries(hard).map(([name, value]) => { - if (!used[name]) return null +const onlyNumbers = /$[0-9]*^/g; + +function transformUnit(name: string, value: string): number { + if (name.includes("memory") || name.includes("storage")) { + return unitsToBytes(value) + } + + if (name.includes("cpu")) { + return cpuUnitsToNumber(value) + } + + return metricUnitsToNumber(value); +} + +function renderQuotas(quota: ResourceQuota): JSX.Element[] { + const { hard = {}, used = {} } = quota.status + + return Object.entries(hard) + .filter(([name]) => used[name]) + .map(([name, value]) => { const current = transformUnit(name, used[name]) const max = transformUnit(name, value) + const usage = max === 0 ? 100 : Math.ceil(current / max * 100); // special case 0 max as always 100% usage + return (
{name} @@ -41,14 +47,16 @@ export class ResourceQuotaDetails extends React.Component { max={max} value={current} tooltip={ -

Set: {value}. Used: {Math.ceil(current / max * 100) + "%"}

+

Set: {value}. Usage: {usage + "%"}

} />
) }) - } +} +@observer +export class ResourceQuotaDetails extends React.Component { render() { const { object: quota } = this.props; if (!quota) return null; @@ -57,7 +65,7 @@ export class ResourceQuotaDetails extends React.Component { Quotas} className="quota-list"> - {this.renderQuotas(quota)} + {renderQuotas(quota)} {quota.getScopeSelector().length > 0 && ( diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index 0c158c9e6b..df37d6238e 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -11,7 +11,7 @@ import { Service, serviceApi, endpointApi } from "../../api/endpoints"; import { _i18n } from "../../i18n"; import { apiManager } from "../../api/api-manager"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { ServicePorts } from "./service-ports"; +import { ServicePortComponent } from "./service-port-component"; import { endpointStore } from "../+network-endpoints/endpoints.store"; import { ServiceDetailsEndpoint } from "./service-details-endpoint"; @@ -61,7 +61,13 @@ export class ServiceDetails extends React.Component { )} Ports}> - +
+ { + service.getPorts().map((port) => ( + + )) + } +
{spec.type === "LoadBalancer" && spec.loadBalancerIP && ( diff --git a/src/renderer/components/+network-services/service-port-component.scss b/src/renderer/components/+network-services/service-port-component.scss new file mode 100644 index 0000000000..0e9945631d --- /dev/null +++ b/src/renderer/components/+network-services/service-port-component.scss @@ -0,0 +1,22 @@ +.ServicePortComponent { + &.waiting { + opacity: 0.5; + pointer-events: none; + } + + &:not(:last-child) { + margin-bottom: $margin; + } + + span { + cursor: pointer; + color: $primary; + text-decoration: underline; + } + + .Spinner { + --spinner-size: #{$unit * 2}; + margin-left: $margin; + position: absolute; + } +} diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx new file mode 100644 index 0000000000..252bf8eb16 --- /dev/null +++ b/src/renderer/components/+network-services/service-port-component.tsx @@ -0,0 +1,48 @@ +import "./service-port-component.scss" + +import React from "react"; +import { observer } from "mobx-react"; +import { t } from "@lingui/macro"; +import { Service, ServicePort } from "../../api/endpoints"; +import { _i18n } from "../../i18n"; +import { apiBase } from "../../api" +import { observable } from "mobx"; +import { cssNames } from "../../utils"; +import { Notifications } from "../notifications"; +import { Spinner } from "../spinner" + +interface Props { + service: Service; + port: ServicePort; +} + +@observer +export class ServicePortComponent extends React.Component { + @observable waiting = false; + + async portForward() { + const { service, port } = this.props; + this.waiting = true; + try { + await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {}) + } catch(error) { + Notifications.error(error); + } finally { + this.waiting = false; + } + } + + render() { + const { port } = this.props; + return ( +
+ this.portForward() }> + {port.toString()} + {this.waiting && ( + + )} + +
+ ); + } +} diff --git a/src/renderer/components/+network-services/service-ports.scss b/src/renderer/components/+network-services/service-ports.scss deleted file mode 100644 index 5a683af86c..0000000000 --- a/src/renderer/components/+network-services/service-ports.scss +++ /dev/null @@ -1,24 +0,0 @@ -.ServicePorts { - &.waiting { - opacity: 0.5; - pointer-events: none; - } - - p { - &:not(:last-child) { - margin-bottom: $margin; - } - - span { - cursor: pointer; - color: $primary; - text-decoration: underline; - } - } - - .Spinner { - --spinner-size: #{$unit * 2}; - margin-left: $margin; - position: absolute; - } -} diff --git a/src/renderer/components/+network-services/service-ports.tsx b/src/renderer/components/+network-services/service-ports.tsx deleted file mode 100644 index 3335be6907..0000000000 --- a/src/renderer/components/+network-services/service-ports.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import "./service-ports.scss" - -import React from "react"; -import { observer } from "mobx-react"; -import { t } from "@lingui/macro"; -import { Service, ServicePort } from "../../api/endpoints"; -import { _i18n } from "../../i18n"; -import { apiBase } from "../../api" -import { observable } from "mobx"; -import { cssNames } from "../../utils"; -import { Notifications } from "../notifications"; -import { Spinner } from "../spinner" - -interface Props { - service: Service; -} - -@observer -export class ServicePorts extends React.Component { - @observable waiting = false; - - async portForward(port: ServicePort) { - const { service } = this.props; - this.waiting = true; - apiBase.post(`/services/${service.getNs()}/${service.getName()}/port-forward/${port.port}`, {}) - .catch(error => { - Notifications.error(error); - }) - .finally(() => { - this.waiting = false; - }); - } - - render() { - const { service } = this.props; - return ( -
- { - service.getPorts().map((port) => { - return( -

- this.portForward(port) }> - {port.toString()} - {this.waiting && ( - - )} - -

- ); - })} -
- ); - } -} diff --git a/src/renderer/components/+preferences/preferences.scss b/src/renderer/components/+preferences/preferences.scss index 859315cc8a..94c08e8f53 100644 --- a/src/renderer/components/+preferences/preferences.scss +++ b/src/renderer/components/+preferences/preferences.scss @@ -1,23 +1,51 @@ .Preferences { - h2 { - &:not(:first-child) { - margin-top: $padding * 3; + position: fixed!important; // Allows to cover ClustersMenu + z-index: 1; + + .WizardLayout { + grid-template-columns: unset; + grid-template-rows: 76px 1fr; + padding: 0; + + .content-col { + background-color: transparent; + padding: $padding * 8 0; + + h2 { + margin-bottom: $margin * 2; + + &:not(:first-child) { + margin-top: $margin * 3; + } + } + + .repos { + position: relative; + + .Badge { + display: flex; + margin: 0; + margin-bottom: 1px; + padding: $padding $padding * 2; + } + } + + .hint { + margin-top: -$margin; + } } } - .info-block { - --flex-gap: #{$padding}; + .is-mac & { + .WizardLayout .head-col { + padding-top: 32px; + overflow: hidden; + } } - .repos { - --flex-gap: #{$padding}; - - > .title { - font-style: italic; - } - - .Badge { - margin: $padding / 2; + .Select { + &__control { + box-shadow: 0 0 0 1px $borderFaintColor; } } } \ No newline at end of file diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 02e66b7342..fc91952213 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -1,5 +1,5 @@ import "./preferences.scss" -import React, { Fragment } from "react"; +import React from "react"; import { observer } from "mobx-react"; import { action, computed, observable } from "mobx"; import { t, Trans } from "@lingui/macro"; @@ -15,11 +15,12 @@ import { Notifications } from "../notifications"; import { Badge } from "../badge"; import { Spinner } from "../spinner"; import { themeStore } from "../../theme.store"; +import { history } from "../../navigation"; +import { Tooltip } from "../tooltip"; @observer export class Preferences extends React.Component { @observable helmLoading = false; - @observable helmUpdating = false; @observable helmRepos: HelmRepo[] = []; @observable helmAddedRepos = observable.map(); @@ -88,9 +89,9 @@ export class Preferences extends React.Component { Notifications.ok(Helm branch {repo.name} already in use) return; } - this.helmUpdating = false; + this.helmLoading = true; await this.addRepo(repo); - this.helmUpdating = false; + this.helmLoading = false; } formatHelmOptionLabel = ({ value: repo }: SelectOption) => { @@ -103,104 +104,95 @@ export class Preferences extends React.Component { ) } - renderInfo() { - return ( - -

- Preferences -

-
- -

- Lens Global Settings (applicable to all clusters) -

-
-
- ) - } - render() { const { preferences } = userStore; + const header = ( + <> +

Preferences

+ + + ); return ( - -

Color Theme

- preferences.colorTheme = value} + /> -

Download Mirror

- Download mirror for kubectl} + options={this.downloadMirrorOptions} + value={preferences.downloadMirror} + onChange={({ value }: SelectOption) => preferences.downloadMirror = value} + /> -

Helm

- Repositories} + isLoading={this.helmLoading} + isDisabled={this.helmLoading} + options={this.helmOptions} + onChange={this.onRepoSelect} + formatOptionLabel={this.formatHelmOptionLabel} + controlShouldRenderValue={false} + /> +
{Array.from(this.helmAddedRepos).map(([name, repo]) => { + const tooltipId = `message-${name}`; return ( - - {name} + + {name} this.removeRepo(repo)} tooltip={Remove} /> + + {repo.url} + ) })}
-
-

HTTP Proxy

- preferences.httpsProxy = v} - /> - - Proxy is used only for non-cluster communication. - +

HTTP Proxy

+ preferences.httpsProxy = v} + /> + + Proxy is used only for non-cluster communication. + -

Certificate Trust

- Allow untrusted Certificate Authorities} - value={preferences.allowUntrustedCAs} - onChange={v => preferences.allowUntrustedCAs = v} - /> - - This will make Lens to trust ANY certificate authority without any validations.{" "} - Needed with some corporate proxies that do certificate re-writing.{" "} - Does not affect cluster communications! - +

Certificate Trust

+ Allow untrusted Certificate Authorities} + value={preferences.allowUntrustedCAs} + onChange={v => preferences.allowUntrustedCAs = v} + /> + + This will make Lens to trust ANY certificate authority without any validations.{" "} + Needed with some corporate proxies that do certificate re-writing.{" "} + Does not affect cluster communications! + -

Telemetry & Usage Tracking

- Allow telemetry & usage tracking} - value={preferences.allowTelemetry} - onChange={v => preferences.allowTelemetry = v} - /> - - Telemetry & usage data is collected to continuously improve the Lens experience. - - - ) +

Telemetry & Usage Tracking

+ Allow telemetry & usage tracking} + value={preferences.allowTelemetry} + onChange={v => preferences.allowTelemetry = v} + /> + + Telemetry & usage data is collected to continuously improve the Lens experience. + + +
+ ); } } diff --git a/src/renderer/components/+whats-new/whats-new.tsx b/src/renderer/components/+whats-new/whats-new.tsx index 9bde7da141..c63e8f25d1 100644 --- a/src/renderer/components/+whats-new/whats-new.tsx +++ b/src/renderer/components/+whats-new/whats-new.tsx @@ -7,12 +7,11 @@ import { userStore } from "../../../common/user-store" import { navigate } from "../../navigation"; import { Button } from "../button"; import { Trans } from "@lingui/macro"; -import { staticDir } from "../../../common/vars"; import marked from "marked" @observer export class WhatsNew extends React.Component { - releaseNotes = fs.readFileSync(path.join(staticDir, "RELEASE_NOTES.md")).toString(); + releaseNotes = fs.readFileSync(path.join(__static, "RELEASE_NOTES.md")).toString(); ok = () => { navigate("/"); diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index 32fb1ec10c..5a3031787a 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -98,7 +98,7 @@ export function DeploymentMenu(props: KubeObjectMenuProps) { return ( DeploymentScaleDialog.open(object)}> - + Scale diff --git a/src/renderer/components/+workloads-pods/pod-container-port.scss b/src/renderer/components/+workloads-pods/pod-container-port.scss new file mode 100644 index 0000000000..081f0b1090 --- /dev/null +++ b/src/renderer/components/+workloads-pods/pod-container-port.scss @@ -0,0 +1,23 @@ +.PodContainerPort { + &.waiting { + opacity: 0.5; + pointer-events: none; + } + + &:not(:last-child) { + margin-bottom: $margin; + } + + span { + cursor: pointer; + color: $primary; + text-decoration: underline; + position: relative; + } + + .Spinner { + --spinner-size: #{$unit * 2}; + margin-left: $margin; + position: absolute; + } +} \ No newline at end of file diff --git a/src/renderer/components/+workloads-pods/pod-container-port.tsx b/src/renderer/components/+workloads-pods/pod-container-port.tsx new file mode 100644 index 0000000000..9ebaed4fd7 --- /dev/null +++ b/src/renderer/components/+workloads-pods/pod-container-port.tsx @@ -0,0 +1,54 @@ +import "./pod-container-port.scss" + +import React from "react"; +import { observer } from "mobx-react"; +import { t } from "@lingui/macro"; +import { Pod, IPodContainer } from "../../api/endpoints"; +import { _i18n } from "../../i18n"; +import { apiBase } from "../../api" +import { observable } from "mobx"; +import { cssNames } from "../../utils"; +import { Notifications } from "../notifications"; +import { Spinner } from "../spinner" + +interface Props { + pod: Pod; + port: { + name?: string; + containerPort: number; + protocol: string; + } +} + +@observer +export class PodContainerPort extends React.Component { + @observable waiting = false; + + async portForward() { + const { pod, port } = this.props; + this.waiting = true; + try { + await apiBase.post(`/pods/${pod.getNs()}/pod/${pod.getName()}/port-forward/${port.containerPort}`, {}) + } catch(error) { + Notifications.error(error); + } finally { + this.waiting = false; + } + } + + render() { + const { port } = this.props; + const { name, containerPort, protocol } = port; + const text = (name ? name + ': ' : '')+`${containerPort}/${protocol}` + return ( +
+ this.portForward() }> + {text} + {this.waiting && ( + + )} + +
+ ) + } +} diff --git a/src/renderer/components/+workloads-pods/pod-details-container.tsx b/src/renderer/components/+workloads-pods/pod-details-container.tsx index a5cdcc1fbd..79180b1130 100644 --- a/src/renderer/components/+workloads-pods/pod-details-container.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-container.tsx @@ -8,6 +8,7 @@ import { cssNames } from "../../utils"; import { StatusBrick } from "../status-brick"; import { Badge } from "../badge"; import { ContainerEnvironment } from "./pod-container-env"; +import { PodContainerPort } from "./pod-container-port"; import { ResourceMetrics } from "../resource-metrics"; import { IMetrics } from "../../api/endpoints/metrics.api"; import { ContainerCharts } from "./container-charts"; @@ -64,13 +65,10 @@ export class PodDetailsContainer extends React.Component { {ports && ports.length > 0 && Ports}> { - ports.map(port => { - const { name, containerPort, protocol } = port; - const key = `${container.name}-port-${containerPort}-${protocol}` - return ( -
- {name ? name + ': ' : ''}{containerPort}/{protocol} -
+ ports.map((port) => { + const key = `${container.name}-port-${port.containerPort}-${port.protocol}` + return( + ) }) } diff --git a/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx b/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx index e6e9708002..d7ff3863cc 100644 --- a/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx +++ b/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx @@ -226,7 +226,7 @@ export class PodLogsDialog extends React.Component { tooltip={(showTimestamps ? _i18n._(t`Hide`) : _i18n._(t`Show`)) + " " + _i18n._(t`timestamps`)} /> diff --git a/src/renderer/components/app-init/app-init.tsx b/src/renderer/components/app-init/app-init.tsx index fe46a8a6d5..e5a740ebc4 100644 --- a/src/renderer/components/app-init/app-init.tsx +++ b/src/renderer/components/app-init/app-init.tsx @@ -13,7 +13,6 @@ interface Props { export class AppInit extends React.Component { static async start(rootElem: HTMLElement) { - render(, rootElem); // show loading indicator asap await AppInit.readyStateCheck(rootElem); // wait while all good to run } diff --git a/src/renderer/components/app.scss b/src/renderer/components/app.scss index 3fcbce9613..59d9b632d0 100755 --- a/src/renderer/components/app.scss +++ b/src/renderer/components/app.scss @@ -82,7 +82,7 @@ hr { h1 { color: white; font-size: 28px; - font-weight: 300; + font-weight: normal; letter-spacing: -.010em; margin: 0; } @@ -99,13 +99,13 @@ h3 { h4 { @extend h3; - font-size: 16px; + font-size: 18px; } h5 { @extend h4; padding: $padding / 2 0; - font-size: 14px; + font-size: 16px; } h6 { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index c51afbdc14..0c3044fc12 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -28,14 +28,21 @@ import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale import { CustomResources } from "./+custom-resources/custom-resources"; import { crdRoute } from "./+custom-resources"; import { isAllowedResource } from "../../common/rbac"; -import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings"; import { ErrorBoundary } from "./error-boundary"; import { Terminal } from "./dock/terminal"; +import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store"; +import logger from "../../main/logger"; +import { clusterIpc } from "../../common/cluster-ipc"; +import { webFrame } from "electron"; @observer export class App extends React.Component { static async init() { + const clusterId = getHostedClusterId(); + logger.info(`[APP]: Init dashboard, clusterId=${clusterId}`) await Terminal.preloadFonts() + await clusterIpc.init.invokeFromRenderer(clusterId, webFrame.routingId); + await getHostedCluster().whenInitialized; } get startURL() { @@ -52,7 +59,6 @@ export class App extends React.Component { - @@ -66,9 +72,9 @@ export class App extends React.Component { - + diff --git a/src/renderer/components/cluster-icon/cluster-icon.scss b/src/renderer/components/cluster-icon/cluster-icon.scss index f7e159a7c5..b8a87a07de 100644 --- a/src/renderer/components/cluster-icon/cluster-icon.scss +++ b/src/renderer/components/cluster-icon/cluster-icon.scss @@ -7,6 +7,12 @@ user-select: none; cursor: pointer; + &.interactive { + img { + opacity: .55; + } + } + &.active, &.interactive:hover { background-color: #fff; @@ -16,7 +22,6 @@ } img { - opacity: .55; width: var(--size); height: var(--size); } diff --git a/src/renderer/components/cluster-icon/cluster-icon.tsx b/src/renderer/components/cluster-icon/cluster-icon.tsx index 9d9a359670..ccc65892de 100644 --- a/src/renderer/components/cluster-icon/cluster-icon.tsx +++ b/src/renderer/components/cluster-icon/cluster-icon.tsx @@ -42,12 +42,12 @@ export class ClusterIcon extends React.Component { active: isActive, }); return ( -
+
{showTooltip && ( {clusterName} )} {icon && {clusterName}/} - {!icon && } + {!icon && } {showErrors && isAdmin && eventCount > 0 && ( * { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + display: flex; + background-color: $mainBackground; + + > * { + flex: 1; + } + } } .ClustersMenu { diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index 4b72704aa3..6011549e8c 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -1,43 +1,68 @@ import "./cluster-manager.scss" import React from "react"; -import { observer } from "mobx-react"; +import { Redirect, Route, Switch } from "react-router"; +import { reaction } from "mobx"; +import { disposeOnUnmount, observer } from "mobx-react"; import { ClustersMenu } from "./clusters-menu"; import { BottomBar } from "./bottom-bar"; -import { cssNames, IClassName } from "../../utils"; -import { ClusterId } from "../../../common/cluster-store"; -import { Route, Switch } from "react-router"; -import { LandingPage, landingRoute } from "../+landing-page"; +import { LandingPage, landingRoute, landingURL } from "../+landing-page"; import { Preferences, preferencesRoute } from "../+preferences"; import { Workspaces, workspacesRoute } from "../+workspaces"; import { AddCluster, addClusterRoute } from "../+add-cluster"; -import { ClusterStatus } from "./cluster-status"; -import { clusterStatusRoute } from "./cluster-status.route"; - -interface Props { - className?: IClassName; - contentClass?: IClassName; -} +import { ClusterView } from "./cluster-view"; +import { ClusterSettings, clusterSettingsRoute } from "../+cluster-settings"; +import { clusterViewRoute, clusterViewURL, getMatchedCluster, getMatchedClusterId } from "./cluster-view.route"; +import { clusterStore } from "../../../common/cluster-store"; +import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views"; @observer -export class ClusterManager extends React.Component { - activateView(clusterId: ClusterId) { +export class ClusterManager extends React.Component { + componentDidMount() { + disposeOnUnmount(this, [ + reaction(getMatchedClusterId, initView, { + fireImmediately: true + }), + reaction(() => [ + hasLoadedView(getMatchedClusterId()), // refresh when cluster's webview loaded + getMatchedCluster()?.available, // refresh on disconnect active-cluster + ], refreshViews, { + fireImmediately: true + }) + ]) + } + + componentWillUnmount() { + lensViews.clear(); + } + + get startUrl() { + const { activeClusterId } = clusterStore; + if (activeClusterId) { + return clusterViewURL({ + params: { + clusterId: activeClusterId + } + }) + } + return landingURL() } render() { - const { className } = this.props; return ( -
+
-
+
+
- -

Lens

}/> + + +
-
+
diff --git a/src/renderer/components/cluster-manager/cluster-status.route.ts b/src/renderer/components/cluster-manager/cluster-status.route.ts deleted file mode 100644 index c3443f0e99..0000000000 --- a/src/renderer/components/cluster-manager/cluster-status.route.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { RouteProps } from "react-router"; -import { buildURL } from "../../navigation"; - -export const clusterStatusRoute: RouteProps = { - path: "/cluster-status" -} - -export const clusterStatusURL = buildURL(clusterStatusRoute.path) diff --git a/src/renderer/components/cluster-manager/cluster-status.scss b/src/renderer/components/cluster-manager/cluster-status.scss index 59a0103db8..0c4f161155 100644 --- a/src/renderer/components/cluster-manager/cluster-status.scss +++ b/src/renderer/components/cluster-manager/cluster-status.scss @@ -1,14 +1,17 @@ .ClusterStatus { --flex-gap: #{$padding * 2}; + position: relative; min-width: 350px; margin: auto; text-align: center; + z-index: 1; pre { @include hidden-scrollbar; max-width: 70vw; max-height: 40vh; + white-space: pre-line; } .Icon { diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index db7b318d2e..1f5d52f814 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -2,102 +2,107 @@ import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy"; import "./cluster-status.scss" import React from "react"; -import { disposeOnUnmount, observer } from "mobx-react"; +import { observer } from "mobx-react"; import { ipcRenderer } from "electron"; -import { autorun, computed, observable } from "mobx"; +import { computed, observable } from "mobx"; import { clusterIpc } from "../../../common/cluster-ipc"; import { Icon } from "../icon"; import { Button } from "../button"; -import { cssNames } from "../../utils"; -import { navigate } from "../../navigation"; +import { cssNames, IClassName } from "../../utils"; import { Cluster } from "../../../main/cluster"; +import { ClusterId, clusterStore } from "../../../common/cluster-store"; +import { CubeSpinner } from "../spinner"; + +interface Props { + className?: IClassName; + clusterId: ClusterId; +} @observer -export class ClusterStatus extends React.Component { +export class ClusterStatus extends React.Component { @observable authOutput: KubeAuthProxyLog[] = []; @observable isReconnecting = false; - // fixme - @computed get cluster(): Cluster { - return null; + get cluster(): Cluster { + return clusterStore.getById(this.props.clusterId); } @computed get hasErrors(): boolean { return this.authOutput.some(({ error }) => error) || !!this.cluster.failureReason; } - @disposeOnUnmount - autoRedirectToMain = autorun(() => { - if (this.cluster.accessible && !this.hasErrors) { - navigate("/"); - } - }) - async componentDidMount() { - if (this.cluster.disconnected) { - return; - } - this.authOutput = [{ data: "Connecting..." }]; ipcRenderer.on(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => { this.authOutput.push({ data: res.data.trimRight(), error: res.error, }); }) - await this.refreshClusterState(); + if (!this.cluster.initialized || this.cluster.disconnected) { + await this.refreshCluster(); + } } componentWillUnmount() { - ipcRenderer.removeAllListeners(`kube-auth:${this.cluster.id}`); + ipcRenderer.removeAllListeners(`kube-auth:${this.props.clusterId}`); } - async refreshClusterState() { - return clusterIpc.activate.invokeFromRenderer(); + refreshCluster = async () => { + await clusterIpc.activate.invokeFromRenderer(this.props.clusterId); } reconnect = async () => { - this.authOutput = [{ data: "Reconnecting..." }]; this.isReconnecting = true; - await this.refreshClusterState(); + await this.refreshCluster(); this.isReconnecting = false; } - render() { + renderContent() { const { authOutput, cluster, hasErrors } = this; - const isDisconnected = !!cluster.disconnected; const failureReason = cluster.failureReason; - const isError = hasErrors || isDisconnected; - return ( -
- {isError && ( - - )} -

- {cluster.contextName} -

- {!isDisconnected && ( + if (!hasErrors || this.isReconnecting) { + return ( + <> +
+            

{this.isReconnecting ? "Reconnecting..." : "Connecting..."}

{authOutput.map(({ data, error }, index) => { return

{data}

})}
- )} + + ); + } + return ( + <> + +

+ {cluster.preferences.clusterName} +

+
+          {authOutput.map(({ data, error }, index) => {
+            return 

{data}

+ })} +
{failureReason && (
{failureReason}
)} - {isError && ( -