mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Allow user to select Kubeconfig from filesystem (#740)
* Allow user to select Kubeconfig from filesystem, fix #738 Signed-off-by: Roman <ixrock@gmail.com> Co-authored-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
parent
0a1f952e13
commit
b8994a453f
@ -37,6 +37,10 @@ msgstr "(empty) (Allowing the specific traffic to all pods in this namespace)"
|
|||||||
#~ msgid "(new)"
|
#~ msgid "(new)"
|
||||||
#~ msgstr "(new)"
|
#~ msgstr "(new)"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:213
|
||||||
|
#~ msgid "* Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
#~ msgstr "* Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
|
||||||
#: src/renderer/components/item-object-list/item-list-layout.tsx:224
|
#: src/renderer/components/item-object-list/item-list-layout.tsx:224
|
||||||
msgid "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
msgid "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
||||||
msgstr "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
msgstr "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
||||||
@ -83,8 +87,8 @@ msgstr "Account Name"
|
|||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Active"
|
msgstr "Active"
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:171
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:303
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:116
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:118
|
||||||
msgid "Add Cluster"
|
msgid "Add Cluster"
|
||||||
msgstr "Add Cluster"
|
msgstr "Add Cluster"
|
||||||
|
|
||||||
@ -108,7 +112,7 @@ msgstr "Add bindings to {name}"
|
|||||||
#~ msgid "Add cluster"
|
#~ msgid "Add cluster"
|
||||||
#~ msgstr "Add cluster"
|
#~ msgstr "Add cluster"
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:192
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:320
|
||||||
msgid "Add cluster(s)"
|
msgid "Add cluster(s)"
|
||||||
msgstr "Add cluster(s)"
|
msgstr "Add cluster(s)"
|
||||||
|
|
||||||
@ -128,6 +132,10 @@ msgstr "Add field"
|
|||||||
#~ msgid "Added repos:"
|
#~ msgid "Added repos:"
|
||||||
#~ msgstr "Added repos:"
|
#~ msgstr "Added repos:"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Adding clusters: <0>{0}</0>"
|
||||||
|
#~ msgstr "Adding clusters: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/renderer/components/+preferences/preferences.tsx:103
|
#: src/renderer/components/+preferences/preferences.tsx:103
|
||||||
msgid "Adding helm branch <0>{0}</0> has failed: {1}"
|
msgid "Adding helm branch <0>{0}</0> has failed: {1}"
|
||||||
msgstr "Adding helm branch <0>{0}</0> has failed: {1}"
|
msgstr "Adding helm branch <0>{0}</0> has failed: {1}"
|
||||||
@ -285,7 +293,7 @@ msgstr "Are you sure you want to drain <0>{nodeName}</0>?"
|
|||||||
msgid "Arguments"
|
msgid "Arguments"
|
||||||
msgstr "Arguments"
|
msgstr "Arguments"
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:106
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:108
|
||||||
msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button."
|
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."
|
msgstr "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button."
|
||||||
|
|
||||||
@ -315,6 +323,10 @@ msgstr "Binding targets"
|
|||||||
msgid "Bindings"
|
msgid "Bindings"
|
||||||
msgstr "Bindings"
|
msgstr "Bindings"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:251
|
||||||
|
msgid "Browse"
|
||||||
|
msgstr "Browse"
|
||||||
|
|
||||||
#: src/renderer/components/error-boundary/error-boundary.tsx:37
|
#: src/renderer/components/error-boundary/error-boundary.tsx:37
|
||||||
#~ msgid "Build version"
|
#~ msgid "Build version"
|
||||||
#~ msgstr "Build version"
|
#~ msgstr "Build version"
|
||||||
@ -440,6 +452,18 @@ msgstr "Charts"
|
|||||||
#~ msgid "Checking update"
|
#~ msgid "Checking update"
|
||||||
#~ msgstr "Checking update"
|
#~ msgstr "Checking update"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
#~ msgstr "Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or from manually pasted configuration contents"
|
||||||
|
#~ msgstr "Choose how to import clusters: from selected kube-config file or from manually pasted configuration contents"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or from pasted yaml configuration"
|
||||||
|
#~ msgstr "Choose how to import clusters: from selected kube-config file or from pasted yaml configuration"
|
||||||
|
|
||||||
#: src/renderer/components/+storage-volumes/volume-details.tsx:68
|
#: src/renderer/components/+storage-volumes/volume-details.tsx:68
|
||||||
#: src/renderer/components/+storage-volumes/volumes.tsx:43
|
#: src/renderer/components/+storage-volumes/volumes.tsx:43
|
||||||
msgid "Claim"
|
msgid "Claim"
|
||||||
@ -451,7 +475,7 @@ msgstr "Claim Name"
|
|||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:243
|
#: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:243
|
||||||
#: src/renderer/components/dialog/logs-dialog.tsx:39
|
#: src/renderer/components/dialog/logs-dialog.tsx:39
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:94
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:93
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Close"
|
msgstr "Close"
|
||||||
|
|
||||||
@ -522,7 +546,7 @@ msgstr "Conditions"
|
|||||||
msgid "Config Maps"
|
msgid "Config Maps"
|
||||||
msgstr "Config Maps"
|
msgstr "Config Maps"
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:55
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:54
|
||||||
msgid "Config copied to clipboard"
|
msgid "Config copied to clipboard"
|
||||||
msgstr "Config copied to clipboard"
|
msgstr "Config copied to clipboard"
|
||||||
|
|
||||||
@ -580,6 +604,14 @@ msgstr "Containers"
|
|||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr "Context"
|
msgstr "Context"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Contexts: <0>{0}</0>"
|
||||||
|
#~ msgstr "Contexts: <0>{0}</0>"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:249
|
||||||
|
#~ msgid "Contexts: {0}"
|
||||||
|
#~ msgstr "Contexts: {0}"
|
||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pods.tsx:79
|
#: src/renderer/components/+workloads-pods/pods.tsx:79
|
||||||
#: src/renderer/components/kube-object/kube-object-meta.tsx:39
|
#: src/renderer/components/kube-object/kube-object-meta.tsx:39
|
||||||
msgid "Controlled By"
|
msgid "Controlled By"
|
||||||
@ -594,7 +626,7 @@ msgid "Conversion"
|
|||||||
msgstr "Conversion"
|
msgstr "Conversion"
|
||||||
|
|
||||||
#: src/renderer/components/dialog/logs-dialog.tsx:36
|
#: src/renderer/components/dialog/logs-dialog.tsx:36
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:88
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:87
|
||||||
msgid "Copy to clipboard"
|
msgid "Copy to clipboard"
|
||||||
msgstr "Copy to clipboard"
|
msgstr "Copy to clipboard"
|
||||||
|
|
||||||
@ -710,9 +742,9 @@ msgstr "Currently applied filters:"
|
|||||||
msgid "Custom Resources"
|
msgid "Custom Resources"
|
||||||
msgstr "Custom Resources"
|
msgstr "Custom Resources"
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:116
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:155
|
||||||
msgid "Custom.."
|
#~ msgid "Custom.."
|
||||||
msgstr "Custom.."
|
#~ msgstr "Custom.."
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95
|
||||||
msgid "DNS Provider"
|
msgid "DNS Provider"
|
||||||
@ -811,7 +843,7 @@ msgstr "Domains"
|
|||||||
msgid "Download Mirror"
|
msgid "Download Mirror"
|
||||||
msgstr "Download Mirror"
|
msgstr "Download Mirror"
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:91
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:90
|
||||||
msgid "Download file"
|
msgid "Download file"
|
||||||
msgstr "Download file"
|
msgstr "Download file"
|
||||||
|
|
||||||
@ -883,6 +915,10 @@ msgstr "Environment"
|
|||||||
msgid "Error stack"
|
msgid "Error stack"
|
||||||
msgstr "Error stack"
|
msgstr "Error stack"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:109
|
||||||
|
msgid "Error while adding cluster(s): {0}"
|
||||||
|
msgstr "Error while adding cluster(s): {0}"
|
||||||
|
|
||||||
#: src/renderer/components/+events/events.tsx:56
|
#: src/renderer/components/+events/events.tsx:56
|
||||||
#: src/renderer/components/+events/kube-event-details.tsx:34
|
#: src/renderer/components/+events/kube-event-details.tsx:34
|
||||||
#: src/renderer/components/+events/kube-event-details.tsx:39
|
#: src/renderer/components/+events/kube-event-details.tsx:39
|
||||||
@ -1201,7 +1237,7 @@ msgstr "Kind"
|
|||||||
msgid "Kubeconfig"
|
msgid "Kubeconfig"
|
||||||
msgstr "Kubeconfig"
|
msgstr "Kubeconfig"
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:85
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:84
|
||||||
msgid "Kubeconfig File"
|
msgid "Kubeconfig File"
|
||||||
msgstr "Kubeconfig File"
|
msgstr "Kubeconfig File"
|
||||||
|
|
||||||
@ -1586,6 +1622,14 @@ msgstr "No"
|
|||||||
msgid "No Nodes Available."
|
msgid "No Nodes Available."
|
||||||
msgstr "No Nodes Available."
|
msgstr "No Nodes Available."
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:275
|
||||||
|
#~ msgid "No contexts available or they already added"
|
||||||
|
#~ msgstr "No contexts available or they already added"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:275
|
||||||
|
msgid "No contexts available or they have been added already"
|
||||||
|
msgstr "No contexts available or they have been added already"
|
||||||
|
|
||||||
#: src/renderer/components/item-object-list/page-filters-select.tsx:84
|
#: src/renderer/components/item-object-list/page-filters-select.tsx:84
|
||||||
msgid "No filters available."
|
msgid "No filters available."
|
||||||
msgstr "No filters available."
|
msgstr "No filters available."
|
||||||
@ -1714,6 +1758,10 @@ msgstr "Parallelism"
|
|||||||
msgid "Parameters"
|
msgid "Parameters"
|
||||||
msgstr "Parameters"
|
msgstr "Parameters"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:245
|
||||||
|
msgid "Paste as text"
|
||||||
|
msgstr "Paste as text"
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:94
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:94
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:102
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:102
|
||||||
#: src/renderer/components/+network-ingresses/ingress-details.tsx:42
|
#: src/renderer/components/+network-ingresses/ingress-details.tsx:42
|
||||||
@ -1734,9 +1782,29 @@ msgstr "Persistent Volume Claims"
|
|||||||
msgid "Persistent Volumes"
|
msgid "Persistent Volumes"
|
||||||
msgstr "Persistent Volumes"
|
msgstr "Persistent Volumes"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:72
|
||||||
|
msgid "Please select at least one cluster context"
|
||||||
|
msgstr "Please select at least one cluster context"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:146
|
||||||
|
#~ msgid "Please select at least one context to add a cluster"
|
||||||
|
#~ msgstr "Please select at least one context to add a cluster"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:106
|
||||||
|
#~ msgid "Please select kube-config's context"
|
||||||
|
#~ msgstr "Please select kube-config's context"
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
msgid "Please select kubeconfig"
|
#~ msgid "Please select kubeconfig"
|
||||||
msgstr "Please select kubeconfig"
|
#~ msgstr "Please select kubeconfig"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:64
|
||||||
|
#~ msgid "Please select kubeconfig context"
|
||||||
|
#~ msgstr "Please select kubeconfig context"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:106
|
||||||
|
#~ msgid "Please select kubeconfig's context"
|
||||||
|
#~ msgstr "Please select kubeconfig's context"
|
||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pod-menu.tsx:50
|
#: src/renderer/components/+workloads-pods/pod-menu.tsx:50
|
||||||
msgid "Pod"
|
msgid "Pod"
|
||||||
@ -1823,6 +1891,34 @@ msgstr "Private Key Secret"
|
|||||||
msgid "Privileged"
|
msgid "Privileged"
|
||||||
msgstr "Privileged"
|
msgstr "Privileged"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig (text/yaml) to get available contexts"
|
||||||
|
#~ msgstr "Pro-Tip: paste kubeconfig (text/yaml) to get available contexts"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig to collect available contexts"
|
||||||
|
#~ msgstr "Pro-Tip: paste kubeconfig to collect available contexts"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:263
|
||||||
|
msgid "Pro-Tip: paste kubeconfig to get available contexts"
|
||||||
|
msgstr "Pro-Tip: paste kubeconfig to get available contexts"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig to parse available contexts"
|
||||||
|
#~ msgstr "Pro-Tip: paste kubeconfig to parse available contexts"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:254
|
||||||
|
msgid "Pro-Tip: you can also drag-n-drop kubeconfig file to this area"
|
||||||
|
msgstr "Pro-Tip: you can also drag-n-drop kubeconfig file to this area"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:225
|
||||||
|
#~ msgid "Pro-tip: you can also drag-n-drop kube-config file in the left-side area"
|
||||||
|
#~ msgstr "Pro-tip: you can also drag-n-drop kube-config file in the left-side area"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:229
|
||||||
|
#~ msgid "Pro-tip: you can also drag-n-drop kube-config file to this area"
|
||||||
|
#~ msgstr "Pro-tip: you can also drag-n-drop kube-config file to this area"
|
||||||
|
|
||||||
#: src/renderer/components/+storage-classes/storage-class-details.tsx:28
|
#: src/renderer/components/+storage-classes/storage-class-details.tsx:28
|
||||||
#: src/renderer/components/+storage-classes/storage-classes.tsx:35
|
#: src/renderer/components/+storage-classes/storage-classes.tsx:35
|
||||||
msgid "Provisioner"
|
msgid "Provisioner"
|
||||||
@ -1832,7 +1928,7 @@ msgstr "Provisioner"
|
|||||||
msgid "Proxy is used only for non-cluster communication."
|
msgid "Proxy is used only for non-cluster communication."
|
||||||
msgstr "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:176
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:308
|
||||||
msgid "Proxy settings"
|
msgid "Proxy settings"
|
||||||
msgstr "Proxy settings"
|
msgstr "Proxy settings"
|
||||||
|
|
||||||
@ -2013,6 +2109,7 @@ msgstr "Required Drop Capabilities"
|
|||||||
msgid "Required field"
|
msgid "Required field"
|
||||||
msgstr "Required field"
|
msgstr "Required field"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:250
|
||||||
#: src/renderer/components/item-object-list/page-filters-list.tsx:31
|
#: src/renderer/components/item-object-list/page-filters-list.tsx:31
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Reset"
|
msgstr "Reset"
|
||||||
@ -2021,6 +2118,18 @@ msgstr "Reset"
|
|||||||
msgid "Reset filters?"
|
msgid "Reset filters?"
|
||||||
msgstr "Reset filters?"
|
msgstr "Reset filters?"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:65
|
||||||
|
#~ msgid "Resetting config to {0}"
|
||||||
|
#~ msgstr "Resetting config to {0}"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:68
|
||||||
|
#~ msgid "Resetting kube-config to current {0}"
|
||||||
|
#~ msgstr "Resetting kube-config to current {0}"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:68
|
||||||
|
#~ msgid "Resetting kube-config to default: {kubeConfigDefaultPath}"
|
||||||
|
#~ msgstr "Resetting kube-config to default: {kubeConfigDefaultPath}"
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/crd-details.tsx:44
|
#: src/renderer/components/+custom-resources/crd-details.tsx:44
|
||||||
#: src/renderer/components/+custom-resources/crd-list.tsx:73
|
#: src/renderer/components/+custom-resources/crd-list.tsx:73
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
@ -2216,13 +2325,59 @@ msgstr "Secret type"
|
|||||||
msgid "Secrets"
|
msgid "Secrets"
|
||||||
msgstr "Secrets"
|
msgstr "Secrets"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:253
|
||||||
|
#~ msgid "Select a context"
|
||||||
|
#~ msgstr "Select a context"
|
||||||
|
|
||||||
#: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:134
|
#: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:134
|
||||||
msgid "Select a quota.."
|
msgid "Select a quota.."
|
||||||
msgstr "Select a quota.."
|
msgstr "Select a quota.."
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
||||||
msgid "Select kubeconfig"
|
#~ msgid "Select context"
|
||||||
msgstr "Select kubeconfig"
|
#~ msgstr "Select context"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:245
|
||||||
|
#~ msgid "Select context(s)"
|
||||||
|
#~ msgstr "Select context(s)"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:272
|
||||||
|
#~ msgid "Select contexts"
|
||||||
|
#~ msgstr "Select contexts"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:272
|
||||||
|
msgid "Select contexts (available: {0})"
|
||||||
|
msgstr "Select contexts (available: {0})"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:76
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:76
|
||||||
|
#~ msgid "Select custom kube-config file"
|
||||||
|
#~ msgstr "Select custom kube-config file"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:62
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:62
|
||||||
|
msgid "Select custom kubeconfig file"
|
||||||
|
msgstr "Select custom kubeconfig file"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:212
|
||||||
|
#~ msgid "Select file"
|
||||||
|
#~ msgstr "Select file"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:221
|
||||||
|
#~ msgid "Select kube-config file"
|
||||||
|
#~ msgstr "Select kube-config file"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
||||||
|
#~ msgid "Select kubeconfig"
|
||||||
|
#~ msgstr "Select kubeconfig"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
msgid "Select kubeconfig file"
|
||||||
|
msgstr "Select kubeconfig file"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:224
|
||||||
|
#~ msgid "Select or drop file"
|
||||||
|
#~ msgstr "Select or drop file"
|
||||||
|
|
||||||
#: src/renderer/components/+preferences/preferences.tsx:88
|
#: src/renderer/components/+preferences/preferences.tsx:88
|
||||||
#~ msgid "Select repository"
|
#~ msgid "Select repository"
|
||||||
@ -2236,6 +2391,22 @@ msgstr "Select role.."
|
|||||||
msgid "Select service accounts"
|
msgid "Select service accounts"
|
||||||
msgstr "Select service accounts"
|
msgstr "Select service accounts"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Selected clusters: <0>{0}</0>"
|
||||||
|
#~ msgstr "Selected clusters: <0>{0}</0>"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Selected contexts ({0}): <0>{1}</0>"
|
||||||
|
#~ msgstr "Selected contexts ({0}): <0>{1}</0>"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:271
|
||||||
|
msgid "Selected contexts: <0>{0}</0>"
|
||||||
|
msgstr "Selected contexts: <0>{0}</0>"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:246
|
||||||
|
#~ msgid "Selected contexts: {0}"
|
||||||
|
#~ msgstr "Selected contexts: {0}"
|
||||||
|
|
||||||
#: src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx:27
|
#: src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx:27
|
||||||
#: src/renderer/components/+network-services/service-details.tsx:37
|
#: src/renderer/components/+network-services/service-details.tsx:37
|
||||||
#: src/renderer/components/+network-services/services.tsx:50
|
#: src/renderer/components/+network-services/services.tsx:50
|
||||||
@ -2412,6 +2583,10 @@ msgstr "Submitting.."
|
|||||||
msgid "Subsets"
|
msgid "Subsets"
|
||||||
msgstr "Subsets"
|
msgstr "Subsets"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:102
|
||||||
|
msgid "Successfully imported <0>{0}</0> cluster(s)"
|
||||||
|
msgstr "Successfully imported <0>{0}</0> cluster(s)"
|
||||||
|
|
||||||
#: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:128
|
#: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:128
|
||||||
msgid "Supplemental Groups"
|
msgid "Supplemental Groups"
|
||||||
msgstr "Supplemental Groups"
|
msgstr "Supplemental Groups"
|
||||||
@ -2458,7 +2633,7 @@ msgstr "There are no logs available."
|
|||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr "This field is required"
|
msgstr "This field is required"
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:104
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:106
|
||||||
msgid "This is the quick launch menu."
|
msgid "This is the quick launch menu."
|
||||||
msgstr "This is the quick launch menu."
|
msgstr "This is the quick launch menu."
|
||||||
|
|
||||||
@ -2572,6 +2747,11 @@ msgstr "Upgrade version"
|
|||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Usage"
|
msgstr "Usage"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
msgid "Use configuration"
|
||||||
|
msgstr "Use configuration"
|
||||||
|
|
||||||
#: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:190
|
#: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:190
|
||||||
msgid "Use same name for RoleBinding"
|
msgid "Use same name for RoleBinding"
|
||||||
msgstr "Use same name for RoleBinding"
|
msgstr "Use same name for RoleBinding"
|
||||||
@ -2735,7 +2915,7 @@ msgstr "listKind"
|
|||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr "never"
|
msgstr "never"
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:119
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:121
|
||||||
msgid "new"
|
msgid "new"
|
||||||
msgstr "new"
|
msgstr "new"
|
||||||
|
|
||||||
@ -2787,7 +2967,7 @@ msgstr "{0} total, {1} available"
|
|||||||
msgid "{0} unavailable"
|
msgid "{0} unavailable"
|
||||||
msgstr "{0} unavailable"
|
msgstr "{0} unavailable"
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:129
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:128
|
||||||
msgid "{accountName} kubeconfig"
|
msgid "{accountName} kubeconfig"
|
||||||
msgstr "{accountName} kubeconfig"
|
msgstr "{accountName} kubeconfig"
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,10 @@ msgstr ""
|
|||||||
#~ msgid "(new)"
|
#~ msgid "(new)"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:213
|
||||||
|
#~ msgid "* Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/item-object-list/item-list-layout.tsx:224
|
#: src/renderer/components/item-object-list/item-list-layout.tsx:224
|
||||||
msgid "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
msgid "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -83,8 +87,8 @@ msgstr ""
|
|||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:171
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:303
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:116
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:118
|
||||||
msgid "Add Cluster"
|
msgid "Add Cluster"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -108,7 +112,7 @@ msgstr ""
|
|||||||
#~ msgid "Add cluster"
|
#~ msgid "Add cluster"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:192
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:320
|
||||||
msgid "Add cluster(s)"
|
msgid "Add cluster(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -128,6 +132,10 @@ msgstr ""
|
|||||||
#~ msgid "Added repos:"
|
#~ msgid "Added repos:"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Adding clusters: <0>{0}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+preferences/preferences.tsx:103
|
#: src/renderer/components/+preferences/preferences.tsx:103
|
||||||
msgid "Adding helm branch <0>{0}</0> has failed: {1}"
|
msgid "Adding helm branch <0>{0}</0> has failed: {1}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -285,7 +293,7 @@ msgstr ""
|
|||||||
msgid "Arguments"
|
msgid "Arguments"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:106
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:108
|
||||||
msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button."
|
msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -315,6 +323,10 @@ msgstr ""
|
|||||||
msgid "Bindings"
|
msgid "Bindings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:251
|
||||||
|
msgid "Browse"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/error-boundary/error-boundary.tsx:37
|
#: src/renderer/components/error-boundary/error-boundary.tsx:37
|
||||||
#~ msgid "Build version"
|
#~ msgid "Build version"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
@ -436,6 +448,18 @@ msgstr ""
|
|||||||
msgid "Charts"
|
msgid "Charts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or from manually pasted configuration contents"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or from pasted yaml configuration"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+storage-volumes/volume-details.tsx:68
|
#: src/renderer/components/+storage-volumes/volume-details.tsx:68
|
||||||
#: src/renderer/components/+storage-volumes/volumes.tsx:43
|
#: src/renderer/components/+storage-volumes/volumes.tsx:43
|
||||||
msgid "Claim"
|
msgid "Claim"
|
||||||
@ -447,7 +471,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:243
|
#: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:243
|
||||||
#: src/renderer/components/dialog/logs-dialog.tsx:39
|
#: src/renderer/components/dialog/logs-dialog.tsx:39
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:94
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:93
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -518,7 +542,7 @@ msgstr ""
|
|||||||
msgid "Config Maps"
|
msgid "Config Maps"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:55
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:54
|
||||||
msgid "Config copied to clipboard"
|
msgid "Config copied to clipboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -576,6 +600,14 @@ msgstr ""
|
|||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Contexts: <0>{0}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:249
|
||||||
|
#~ msgid "Contexts: {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pods.tsx:79
|
#: src/renderer/components/+workloads-pods/pods.tsx:79
|
||||||
#: src/renderer/components/kube-object/kube-object-meta.tsx:39
|
#: src/renderer/components/kube-object/kube-object-meta.tsx:39
|
||||||
msgid "Controlled By"
|
msgid "Controlled By"
|
||||||
@ -590,7 +622,7 @@ msgid "Conversion"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/dialog/logs-dialog.tsx:36
|
#: src/renderer/components/dialog/logs-dialog.tsx:36
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:88
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:87
|
||||||
msgid "Copy to clipboard"
|
msgid "Copy to clipboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -706,9 +738,9 @@ msgstr ""
|
|||||||
msgid "Custom Resources"
|
msgid "Custom Resources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:116
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:155
|
||||||
msgid "Custom.."
|
#~ msgid "Custom.."
|
||||||
msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95
|
||||||
msgid "DNS Provider"
|
msgid "DNS Provider"
|
||||||
@ -807,7 +839,7 @@ msgstr ""
|
|||||||
msgid "Download Mirror"
|
msgid "Download Mirror"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:91
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:90
|
||||||
msgid "Download file"
|
msgid "Download file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -879,6 +911,10 @@ msgstr ""
|
|||||||
msgid "Error stack"
|
msgid "Error stack"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:109
|
||||||
|
msgid "Error while adding cluster(s): {0}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+events/events.tsx:56
|
#: src/renderer/components/+events/events.tsx:56
|
||||||
#: src/renderer/components/+events/kube-event-details.tsx:34
|
#: src/renderer/components/+events/kube-event-details.tsx:34
|
||||||
#: src/renderer/components/+events/kube-event-details.tsx:39
|
#: src/renderer/components/+events/kube-event-details.tsx:39
|
||||||
@ -1192,7 +1228,7 @@ msgstr ""
|
|||||||
msgid "Kubeconfig"
|
msgid "Kubeconfig"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:85
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:84
|
||||||
msgid "Kubeconfig File"
|
msgid "Kubeconfig File"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1569,6 +1605,14 @@ msgstr ""
|
|||||||
msgid "No Nodes Available."
|
msgid "No Nodes Available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:275
|
||||||
|
#~ msgid "No contexts available or they already added"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:275
|
||||||
|
msgid "No contexts available or they have been added already"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/item-object-list/page-filters-select.tsx:84
|
#: src/renderer/components/item-object-list/page-filters-select.tsx:84
|
||||||
msgid "No filters available."
|
msgid "No filters available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -1697,6 +1741,10 @@ msgstr ""
|
|||||||
msgid "Parameters"
|
msgid "Parameters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:245
|
||||||
|
msgid "Paste as text"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:94
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:94
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:102
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:102
|
||||||
#: src/renderer/components/+network-ingresses/ingress-details.tsx:42
|
#: src/renderer/components/+network-ingresses/ingress-details.tsx:42
|
||||||
@ -1717,10 +1765,30 @@ msgstr ""
|
|||||||
msgid "Persistent Volumes"
|
msgid "Persistent Volumes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:72
|
||||||
msgid "Please select kubeconfig"
|
msgid "Please select at least one cluster context"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:146
|
||||||
|
#~ msgid "Please select at least one context to add a cluster"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:106
|
||||||
|
#~ msgid "Please select kube-config's context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
#~ msgid "Please select kubeconfig"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:64
|
||||||
|
#~ msgid "Please select kubeconfig context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:106
|
||||||
|
#~ msgid "Please select kubeconfig's context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pod-menu.tsx:50
|
#: src/renderer/components/+workloads-pods/pod-menu.tsx:50
|
||||||
msgid "Pod"
|
msgid "Pod"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -1806,6 +1874,34 @@ msgstr ""
|
|||||||
msgid "Privileged"
|
msgid "Privileged"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig (text/yaml) to get available contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig to collect available contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:263
|
||||||
|
msgid "Pro-Tip: paste kubeconfig to get available contexts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig to parse available contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:254
|
||||||
|
msgid "Pro-Tip: you can also drag-n-drop kubeconfig file to this area"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:225
|
||||||
|
#~ msgid "Pro-tip: you can also drag-n-drop kube-config file in the left-side area"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:229
|
||||||
|
#~ msgid "Pro-tip: you can also drag-n-drop kube-config file to this area"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+storage-classes/storage-class-details.tsx:28
|
#: src/renderer/components/+storage-classes/storage-class-details.tsx:28
|
||||||
#: src/renderer/components/+storage-classes/storage-classes.tsx:35
|
#: src/renderer/components/+storage-classes/storage-classes.tsx:35
|
||||||
msgid "Provisioner"
|
msgid "Provisioner"
|
||||||
@ -1815,7 +1911,7 @@ msgstr ""
|
|||||||
msgid "Proxy is used only for non-cluster communication."
|
msgid "Proxy is used only for non-cluster communication."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:176
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:308
|
||||||
msgid "Proxy settings"
|
msgid "Proxy settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1996,6 +2092,7 @@ msgstr ""
|
|||||||
msgid "Required field"
|
msgid "Required field"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:250
|
||||||
#: src/renderer/components/item-object-list/page-filters-list.tsx:31
|
#: src/renderer/components/item-object-list/page-filters-list.tsx:31
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -2004,6 +2101,18 @@ msgstr ""
|
|||||||
msgid "Reset filters?"
|
msgid "Reset filters?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:65
|
||||||
|
#~ msgid "Resetting config to {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:68
|
||||||
|
#~ msgid "Resetting kube-config to current {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:68
|
||||||
|
#~ msgid "Resetting kube-config to default: {kubeConfigDefaultPath}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/crd-details.tsx:44
|
#: src/renderer/components/+custom-resources/crd-details.tsx:44
|
||||||
#: src/renderer/components/+custom-resources/crd-list.tsx:73
|
#: src/renderer/components/+custom-resources/crd-list.tsx:73
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
@ -2199,14 +2308,60 @@ msgstr ""
|
|||||||
msgid "Secrets"
|
msgid "Secrets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:253
|
||||||
|
#~ msgid "Select a context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:134
|
#: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:134
|
||||||
msgid "Select a quota.."
|
msgid "Select a quota.."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
||||||
msgid "Select kubeconfig"
|
#~ msgid "Select context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:245
|
||||||
|
#~ msgid "Select context(s)"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:272
|
||||||
|
#~ msgid "Select contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:272
|
||||||
|
msgid "Select contexts (available: {0})"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:76
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:76
|
||||||
|
#~ msgid "Select custom kube-config file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:62
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:62
|
||||||
|
msgid "Select custom kubeconfig file"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:212
|
||||||
|
#~ msgid "Select file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:221
|
||||||
|
#~ msgid "Select kube-config file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
||||||
|
#~ msgid "Select kubeconfig"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
msgid "Select kubeconfig file"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:224
|
||||||
|
#~ msgid "Select or drop file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+preferences/preferences.tsx:88
|
#: src/renderer/components/+preferences/preferences.tsx:88
|
||||||
#~ msgid "Select repository"
|
#~ msgid "Select repository"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
@ -2219,6 +2374,22 @@ msgstr ""
|
|||||||
msgid "Select service accounts"
|
msgid "Select service accounts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Selected clusters: <0>{0}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Selected contexts ({0}): <0>{1}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:271
|
||||||
|
msgid "Selected contexts: <0>{0}</0>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:246
|
||||||
|
#~ msgid "Selected contexts: {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx:27
|
#: src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx:27
|
||||||
#: src/renderer/components/+network-services/service-details.tsx:37
|
#: src/renderer/components/+network-services/service-details.tsx:37
|
||||||
#: src/renderer/components/+network-services/services.tsx:50
|
#: src/renderer/components/+network-services/services.tsx:50
|
||||||
@ -2395,6 +2566,10 @@ msgstr ""
|
|||||||
msgid "Subsets"
|
msgid "Subsets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:102
|
||||||
|
msgid "Successfully imported <0>{0}</0> cluster(s)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:128
|
#: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:128
|
||||||
msgid "Supplemental Groups"
|
msgid "Supplemental Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -2441,7 +2616,7 @@ msgstr ""
|
|||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:104
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:106
|
||||||
msgid "This is the quick launch menu."
|
msgid "This is the quick launch menu."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2555,6 +2730,11 @@ msgstr ""
|
|||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
msgid "Use configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:190
|
#: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:190
|
||||||
msgid "Use same name for RoleBinding"
|
msgid "Use same name for RoleBinding"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -2718,7 +2898,7 @@ msgstr ""
|
|||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:119
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:121
|
||||||
msgid "new"
|
msgid "new"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2770,7 +2950,7 @@ msgstr ""
|
|||||||
msgid "{0} unavailable"
|
msgid "{0} unavailable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:129
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:128
|
||||||
msgid "{accountName} kubeconfig"
|
msgid "{accountName} kubeconfig"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,10 @@ msgstr "(Пусто) (Допускается трафик ко всем пода
|
|||||||
#~ msgid "(new)"
|
#~ msgid "(new)"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:213
|
||||||
|
#~ msgid "* Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/item-object-list/item-list-layout.tsx:224
|
#: src/renderer/components/item-object-list/item-list-layout.tsx:224
|
||||||
msgid "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
msgid "<0>Filtered</0>: {itemsCount} / {allItemsCount}"
|
||||||
msgstr "<0>Отфильтровано</0>: {itemsCount} / {allItemsCount}"
|
msgstr "<0>Отфильтровано</0>: {itemsCount} / {allItemsCount}"
|
||||||
@ -84,8 +88,8 @@ msgstr "Название аккаунта"
|
|||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Активный"
|
msgstr "Активный"
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:171
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:303
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:116
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:118
|
||||||
msgid "Add Cluster"
|
msgid "Add Cluster"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -109,7 +113,7 @@ msgstr "Добавить привязки к {name}"
|
|||||||
#~ msgid "Add cluster"
|
#~ msgid "Add cluster"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:192
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:320
|
||||||
msgid "Add cluster(s)"
|
msgid "Add cluster(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -129,6 +133,10 @@ msgstr "Добавить поле"
|
|||||||
#~ msgid "Added repos:"
|
#~ msgid "Added repos:"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Adding clusters: <0>{0}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+preferences/preferences.tsx:103
|
#: src/renderer/components/+preferences/preferences.tsx:103
|
||||||
msgid "Adding helm branch <0>{0}</0> has failed: {1}"
|
msgid "Adding helm branch <0>{0}</0> has failed: {1}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -286,7 +294,7 @@ msgstr "Выполнить команду drain для ноды <0>{nodeName}</0
|
|||||||
msgid "Arguments"
|
msgid "Arguments"
|
||||||
msgstr "Аргументы"
|
msgstr "Аргументы"
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:106
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:108
|
||||||
msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button."
|
msgid "Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -316,6 +324,10 @@ msgstr "Цели привязки"
|
|||||||
msgid "Bindings"
|
msgid "Bindings"
|
||||||
msgstr "Привязки"
|
msgstr "Привязки"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:251
|
||||||
|
msgid "Browse"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/error-boundary/error-boundary.tsx:37
|
#: src/renderer/components/error-boundary/error-boundary.tsx:37
|
||||||
#~ msgid "Build version"
|
#~ msgid "Build version"
|
||||||
#~ msgstr "Версия билда"
|
#~ msgstr "Версия билда"
|
||||||
@ -441,6 +453,18 @@ msgstr "Чарты"
|
|||||||
#~ msgid "Checking update"
|
#~ msgid "Checking update"
|
||||||
#~ msgstr "Проверка обновлений"
|
#~ msgstr "Проверка обновлений"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or by manually pasting kube-config's content as a text"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or from manually pasted configuration contents"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:218
|
||||||
|
#~ msgid "Choose how to import clusters: from selected kube-config file or from pasted yaml configuration"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+storage-volumes/volume-details.tsx:68
|
#: src/renderer/components/+storage-volumes/volume-details.tsx:68
|
||||||
#: src/renderer/components/+storage-volumes/volumes.tsx:43
|
#: src/renderer/components/+storage-volumes/volumes.tsx:43
|
||||||
msgid "Claim"
|
msgid "Claim"
|
||||||
@ -452,7 +476,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:243
|
#: src/renderer/components/+workloads-pods/pod-logs-dialog.tsx:243
|
||||||
#: src/renderer/components/dialog/logs-dialog.tsx:39
|
#: src/renderer/components/dialog/logs-dialog.tsx:39
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:94
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:93
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Закрыть"
|
msgstr "Закрыть"
|
||||||
|
|
||||||
@ -523,7 +547,7 @@ msgstr "Состояния"
|
|||||||
msgid "Config Maps"
|
msgid "Config Maps"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:55
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:54
|
||||||
msgid "Config copied to clipboard"
|
msgid "Config copied to clipboard"
|
||||||
msgstr "Конфигурация скопирована в буфер"
|
msgstr "Конфигурация скопирована в буфер"
|
||||||
|
|
||||||
@ -581,6 +605,14 @@ msgstr "Контейнеры"
|
|||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr "Контекст"
|
msgstr "Контекст"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Contexts: <0>{0}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:249
|
||||||
|
#~ msgid "Contexts: {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pods.tsx:79
|
#: src/renderer/components/+workloads-pods/pods.tsx:79
|
||||||
#: src/renderer/components/kube-object/kube-object-meta.tsx:39
|
#: src/renderer/components/kube-object/kube-object-meta.tsx:39
|
||||||
msgid "Controlled By"
|
msgid "Controlled By"
|
||||||
@ -595,7 +627,7 @@ msgid "Conversion"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/dialog/logs-dialog.tsx:36
|
#: src/renderer/components/dialog/logs-dialog.tsx:36
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:88
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:87
|
||||||
msgid "Copy to clipboard"
|
msgid "Copy to clipboard"
|
||||||
msgstr "Копировать"
|
msgstr "Копировать"
|
||||||
|
|
||||||
@ -711,9 +743,9 @@ msgstr "Текущие фильтры:"
|
|||||||
msgid "Custom Resources"
|
msgid "Custom Resources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:116
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:155
|
||||||
msgid "Custom.."
|
#~ msgid "Custom.."
|
||||||
msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95
|
||||||
msgid "DNS Provider"
|
msgid "DNS Provider"
|
||||||
@ -812,7 +844,7 @@ msgstr "Домены"
|
|||||||
msgid "Download Mirror"
|
msgid "Download Mirror"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:91
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:90
|
||||||
msgid "Download file"
|
msgid "Download file"
|
||||||
msgstr "Скачать файл"
|
msgstr "Скачать файл"
|
||||||
|
|
||||||
@ -884,6 +916,10 @@ msgstr "Среда"
|
|||||||
msgid "Error stack"
|
msgid "Error stack"
|
||||||
msgstr "Стэк ошибки"
|
msgstr "Стэк ошибки"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:109
|
||||||
|
msgid "Error while adding cluster(s): {0}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+events/events.tsx:56
|
#: src/renderer/components/+events/events.tsx:56
|
||||||
#: src/renderer/components/+events/kube-event-details.tsx:34
|
#: src/renderer/components/+events/kube-event-details.tsx:34
|
||||||
#: src/renderer/components/+events/kube-event-details.tsx:39
|
#: src/renderer/components/+events/kube-event-details.tsx:39
|
||||||
@ -1202,7 +1238,7 @@ msgstr "Тип"
|
|||||||
msgid "Kubeconfig"
|
msgid "Kubeconfig"
|
||||||
msgstr "Файл конфигурации"
|
msgstr "Файл конфигурации"
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:85
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:84
|
||||||
msgid "Kubeconfig File"
|
msgid "Kubeconfig File"
|
||||||
msgstr "Файл конфигурации"
|
msgstr "Файл конфигурации"
|
||||||
|
|
||||||
@ -1587,6 +1623,14 @@ msgstr "Нет"
|
|||||||
msgid "No Nodes Available."
|
msgid "No Nodes Available."
|
||||||
msgstr "Нет доступных нод."
|
msgstr "Нет доступных нод."
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:275
|
||||||
|
#~ msgid "No contexts available or they already added"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:275
|
||||||
|
msgid "No contexts available or they have been added already"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/item-object-list/page-filters-select.tsx:84
|
#: src/renderer/components/item-object-list/page-filters-select.tsx:84
|
||||||
msgid "No filters available."
|
msgid "No filters available."
|
||||||
msgstr "Нет доступных фильтров."
|
msgstr "Нет доступных фильтров."
|
||||||
@ -1715,6 +1759,10 @@ msgstr "Параллелизм"
|
|||||||
msgid "Parameters"
|
msgid "Parameters"
|
||||||
msgstr "Параметры"
|
msgstr "Параметры"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:245
|
||||||
|
msgid "Paste as text"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:94
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:94
|
||||||
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:102
|
#: src/renderer/components/+custom-resources/certmanager.k8s.io/issuer-details.tsx:102
|
||||||
#: src/renderer/components/+network-ingresses/ingress-details.tsx:42
|
#: src/renderer/components/+network-ingresses/ingress-details.tsx:42
|
||||||
@ -1735,10 +1783,30 @@ msgstr "Persistent Volume Claims"
|
|||||||
msgid "Persistent Volumes"
|
msgid "Persistent Volumes"
|
||||||
msgstr "Persistent Volumes"
|
msgstr "Persistent Volumes"
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:72
|
||||||
msgid "Please select kubeconfig"
|
msgid "Please select at least one cluster context"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:146
|
||||||
|
#~ msgid "Please select at least one context to add a cluster"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:106
|
||||||
|
#~ msgid "Please select kube-config's context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
#~ msgid "Please select kubeconfig"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:64
|
||||||
|
#~ msgid "Please select kubeconfig context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:106
|
||||||
|
#~ msgid "Please select kubeconfig's context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+workloads-pods/pod-menu.tsx:50
|
#: src/renderer/components/+workloads-pods/pod-menu.tsx:50
|
||||||
msgid "Pod"
|
msgid "Pod"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -1824,6 +1892,34 @@ msgstr "Секрет приватного ключа"
|
|||||||
msgid "Privileged"
|
msgid "Privileged"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig (text/yaml) to get available contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig to collect available contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:263
|
||||||
|
msgid "Pro-Tip: paste kubeconfig to get available contexts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:264
|
||||||
|
#~ msgid "Pro-Tip: paste kubeconfig to parse available contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:254
|
||||||
|
msgid "Pro-Tip: you can also drag-n-drop kubeconfig file to this area"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:225
|
||||||
|
#~ msgid "Pro-tip: you can also drag-n-drop kube-config file in the left-side area"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:229
|
||||||
|
#~ msgid "Pro-tip: you can also drag-n-drop kube-config file to this area"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+storage-classes/storage-class-details.tsx:28
|
#: src/renderer/components/+storage-classes/storage-class-details.tsx:28
|
||||||
#: src/renderer/components/+storage-classes/storage-classes.tsx:35
|
#: src/renderer/components/+storage-classes/storage-classes.tsx:35
|
||||||
msgid "Provisioner"
|
msgid "Provisioner"
|
||||||
@ -1833,7 +1929,7 @@ msgstr "Комиссия"
|
|||||||
msgid "Proxy is used only for non-cluster communication."
|
msgid "Proxy is used only for non-cluster communication."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:176
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:308
|
||||||
msgid "Proxy settings"
|
msgid "Proxy settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2014,6 +2110,7 @@ msgstr ""
|
|||||||
msgid "Required field"
|
msgid "Required field"
|
||||||
msgstr "Обязательное поле"
|
msgstr "Обязательное поле"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:250
|
||||||
#: src/renderer/components/item-object-list/page-filters-list.tsx:31
|
#: src/renderer/components/item-object-list/page-filters-list.tsx:31
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Сбросить"
|
msgstr "Сбросить"
|
||||||
@ -2022,6 +2119,18 @@ msgstr "Сбросить"
|
|||||||
msgid "Reset filters?"
|
msgid "Reset filters?"
|
||||||
msgstr "Сбросить фильтры?"
|
msgstr "Сбросить фильтры?"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:65
|
||||||
|
#~ msgid "Resetting config to {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:68
|
||||||
|
#~ msgid "Resetting kube-config to current {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:68
|
||||||
|
#~ msgid "Resetting kube-config to default: {kubeConfigDefaultPath}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+custom-resources/crd-details.tsx:44
|
#: src/renderer/components/+custom-resources/crd-details.tsx:44
|
||||||
#: src/renderer/components/+custom-resources/crd-list.tsx:73
|
#: src/renderer/components/+custom-resources/crd-list.tsx:73
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
@ -2217,14 +2326,60 @@ msgstr "Тип секрета"
|
|||||||
msgid "Secrets"
|
msgid "Secrets"
|
||||||
msgstr "Secrets"
|
msgstr "Secrets"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:253
|
||||||
|
#~ msgid "Select a context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:134
|
#: src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx:134
|
||||||
msgid "Select a quota.."
|
msgid "Select a quota.."
|
||||||
msgstr "Выберите квоту..."
|
msgstr "Выберите квоту..."
|
||||||
|
|
||||||
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
||||||
msgid "Select kubeconfig"
|
#~ msgid "Select context"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:245
|
||||||
|
#~ msgid "Select context(s)"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:272
|
||||||
|
#~ msgid "Select contexts"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:272
|
||||||
|
msgid "Select contexts (available: {0})"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:76
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:76
|
||||||
|
#~ msgid "Select custom kube-config file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:62
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:62
|
||||||
|
msgid "Select custom kubeconfig file"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:212
|
||||||
|
#~ msgid "Select file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:221
|
||||||
|
#~ msgid "Select kube-config file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:173
|
||||||
|
#~ msgid "Select kubeconfig"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
msgid "Select kubeconfig file"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:224
|
||||||
|
#~ msgid "Select or drop file"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+preferences/preferences.tsx:88
|
#: src/renderer/components/+preferences/preferences.tsx:88
|
||||||
#~ msgid "Select repository"
|
#~ msgid "Select repository"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
@ -2237,6 +2392,22 @@ msgstr "Выбрать роль.."
|
|||||||
msgid "Select service accounts"
|
msgid "Select service accounts"
|
||||||
msgstr "Выбрать сервисные аккаунты"
|
msgstr "Выбрать сервисные аккаунты"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Selected clusters: <0>{0}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:244
|
||||||
|
#~ msgid "Selected contexts ({0}): <0>{1}</0>"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:271
|
||||||
|
msgid "Selected contexts: <0>{0}</0>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:246
|
||||||
|
#~ msgid "Selected contexts: {0}"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx:27
|
#: src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx:27
|
||||||
#: src/renderer/components/+network-services/service-details.tsx:37
|
#: src/renderer/components/+network-services/service-details.tsx:37
|
||||||
#: src/renderer/components/+network-services/services.tsx:50
|
#: src/renderer/components/+network-services/services.tsx:50
|
||||||
@ -2413,6 +2584,10 @@ msgstr "Применение.."
|
|||||||
msgid "Subsets"
|
msgid "Subsets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:102
|
||||||
|
msgid "Successfully imported <0>{0}</0> cluster(s)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:128
|
#: src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx:128
|
||||||
msgid "Supplemental Groups"
|
msgid "Supplemental Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -2459,7 +2634,7 @@ msgstr "Логи отсутствуют."
|
|||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr "Это обязательное поле"
|
msgstr "Это обязательное поле"
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:104
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:106
|
||||||
msgid "This is the quick launch menu."
|
msgid "This is the quick launch menu."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2573,6 +2748,11 @@ msgstr "Обновить версию"
|
|||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Использование"
|
msgstr "Использование"
|
||||||
|
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
#: src/renderer/components/+add-cluster/add-cluster.tsx:63
|
||||||
|
msgid "Use configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:190
|
#: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:190
|
||||||
msgid "Use same name for RoleBinding"
|
msgid "Use same name for RoleBinding"
|
||||||
msgstr "Использовать тоже имя для привязки ролей"
|
msgstr "Использовать тоже имя для привязки ролей"
|
||||||
@ -2736,7 +2916,7 @@ msgstr ""
|
|||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/renderer/components/cluster-manager/clusters-menu.tsx:119
|
#: src/renderer/components/cluster-manager/clusters-menu.tsx:121
|
||||||
msgid "new"
|
msgid "new"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2788,7 +2968,7 @@ msgstr "{0} всего, {1} доступно"
|
|||||||
msgid "{0} unavailable"
|
msgid "{0} unavailable"
|
||||||
msgstr "{0} недоступно"
|
msgstr "{0} недоступно"
|
||||||
|
|
||||||
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:129
|
#: src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx:128
|
||||||
msgid "{accountName} kubeconfig"
|
msgid "{accountName} kubeconfig"
|
||||||
msgstr "{accountName} конфигурация"
|
msgstr "{accountName} конфигурация"
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import type { WorkspaceId } from "./workspace-store";
|
import type { WorkspaceId } from "./workspace-store";
|
||||||
import { ipcRenderer } from "electron";
|
import path from "path";
|
||||||
|
import { app, ipcRenderer, remote } from "electron";
|
||||||
import { unlink } from "fs-extra";
|
import { unlink } from "fs-extra";
|
||||||
import { action, computed, observable, toJS } from "mobx";
|
import { action, computed, observable, toJS } from "mobx";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
@ -7,6 +8,9 @@ import { Cluster, ClusterState } from "../main/cluster";
|
|||||||
import migrations from "../migrations/cluster-store"
|
import migrations from "../migrations/cluster-store"
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import { tracker } from "./tracker";
|
import { tracker } from "./tracker";
|
||||||
|
import { dumpConfigYaml } from "./kube-helpers";
|
||||||
|
import { saveToAppFiles } from "./utils/saveToAppFiles";
|
||||||
|
import { KubeConfig } from "@kubernetes/client-node";
|
||||||
|
|
||||||
export interface ClusterIconUpload {
|
export interface ClusterIconUpload {
|
||||||
clusterId: string;
|
clusterId: string;
|
||||||
@ -49,6 +53,17 @@ export interface ClusterPreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||||
|
static getCustomKubeConfigPath(clusterId: ClusterId): string {
|
||||||
|
return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs", clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static embedCustomKubeConfig(clusterId: ClusterId, kubeConfig: KubeConfig | string): string {
|
||||||
|
const filePath = ClusterStore.getCustomKubeConfigPath(clusterId);
|
||||||
|
const fileContents = typeof kubeConfig == "string" ? kubeConfig : dumpConfigYaml(kubeConfig);
|
||||||
|
saveToAppFiles(filePath, fileContents);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
super({
|
super({
|
||||||
configName: "lens-cluster-store",
|
configName: "lens-cluster-store",
|
||||||
@ -81,6 +96,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
return this.activeClusterId === id;
|
return this.activeClusterId === id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
setActive(id: ClusterId) {
|
setActive(id: ClusterId) {
|
||||||
this.activeClusterId = id;
|
this.activeClusterId = id;
|
||||||
}
|
}
|
||||||
@ -102,12 +118,12 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async addCluster(model: ClusterModel, activate = true): Promise<Cluster> {
|
addCluster(...models: ClusterModel[]) {
|
||||||
|
models.forEach(model => {
|
||||||
tracker.event("cluster", "add");
|
tracker.event("cluster", "add");
|
||||||
const cluster = new Cluster(model);
|
const cluster = new Cluster(model);
|
||||||
this.clusters.set(model.id, cluster);
|
this.clusters.set(model.id, cluster);
|
||||||
if (activate) this.activeClusterId = model.id;
|
})
|
||||||
return cluster;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -119,9 +135,12 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
if (this.activeClusterId === clusterId) {
|
if (this.activeClusterId === clusterId) {
|
||||||
this.activeClusterId = null;
|
this.activeClusterId = null;
|
||||||
}
|
}
|
||||||
|
// remove only custom kubeconfigs (pasted as text)
|
||||||
|
if (cluster.kubeConfigPath == ClusterStore.getCustomKubeConfigPath(clusterId)) {
|
||||||
unlink(cluster.kubeConfigPath).catch(() => null);
|
unlink(cluster.kubeConfigPath).catch(() => null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
removeByWorkspaceId(workspaceId: string) {
|
removeByWorkspaceId(workspaceId: string) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import yaml from "js-yaml";
|
|||||||
import { Cluster } from "../main/cluster";
|
import { Cluster } from "../main/cluster";
|
||||||
import { ClusterStore } from "./cluster-store";
|
import { ClusterStore } from "./cluster-store";
|
||||||
import { workspaceStore } from "./workspace-store";
|
import { workspaceStore } from "./workspace-store";
|
||||||
import { saveConfigToAppFiles } from "./kube-helpers";
|
|
||||||
|
|
||||||
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png")
|
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png")
|
||||||
|
|
||||||
@ -37,7 +36,7 @@ describe("empty config", () => {
|
|||||||
icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
|
icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
|
||||||
clusterName: "minikube"
|
clusterName: "minikube"
|
||||||
},
|
},
|
||||||
kubeConfigPath: saveConfigToAppFiles("foo", "fancy foo config"),
|
kubeConfigPath: ClusterStore.embedCustomKubeConfig("foo", "fancy foo config"),
|
||||||
workspace: workspaceStore.currentWorkspaceId
|
workspace: workspaceStore.currentWorkspaceId
|
||||||
});
|
});
|
||||||
clusterStore.addCluster(cluster);
|
clusterStore.addCluster(cluster);
|
||||||
@ -58,7 +57,7 @@ describe("empty config", () => {
|
|||||||
preferences: {
|
preferences: {
|
||||||
clusterName: "prod"
|
clusterName: "prod"
|
||||||
},
|
},
|
||||||
kubeConfigPath: saveConfigToAppFiles("prod", "fancy config"),
|
kubeConfigPath: ClusterStore.embedCustomKubeConfig("prod", "fancy config"),
|
||||||
workspace: "workstation"
|
workspace: "workstation"
|
||||||
});
|
});
|
||||||
const devCluster = new Cluster({
|
const devCluster = new Cluster({
|
||||||
@ -66,7 +65,7 @@ describe("empty config", () => {
|
|||||||
preferences: {
|
preferences: {
|
||||||
clusterName: "dev"
|
clusterName: "dev"
|
||||||
},
|
},
|
||||||
kubeConfigPath: saveConfigToAppFiles("dev", "fancy config"),
|
kubeConfigPath: ClusterStore.embedCustomKubeConfig("dev", "fancy config"),
|
||||||
workspace: "workstation"
|
workspace: "workstation"
|
||||||
});
|
});
|
||||||
clusterStore.addCluster(prodCluster);
|
clusterStore.addCluster(prodCluster);
|
||||||
@ -84,17 +83,13 @@ describe("empty config", () => {
|
|||||||
expect(wsClusters[1].id).toBe("dev");
|
expect(wsClusters[1].id).toBe("dev");
|
||||||
})
|
})
|
||||||
|
|
||||||
it("checks if last added cluster becomes active", () => {
|
|
||||||
expect(clusterStore.activeCluster.id).toBe("dev");
|
|
||||||
})
|
|
||||||
|
|
||||||
it("sets active cluster", () => {
|
it("sets active cluster", () => {
|
||||||
clusterStore.setActive("foo");
|
clusterStore.setActive("foo");
|
||||||
expect(clusterStore.activeCluster.id).toBe("foo");
|
expect(clusterStore.activeCluster.id).toBe("foo");
|
||||||
})
|
})
|
||||||
|
|
||||||
it("check if cluster's kubeconfig file saved", () => {
|
it("check if cluster's kubeconfig file saved", () => {
|
||||||
const file = saveConfigToAppFiles("boo", "kubeconfig");
|
const file = ClusterStore.embedCustomKubeConfig("boo", "kubeconfig");
|
||||||
expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig");
|
expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig");
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { app, remote } from "electron";
|
|
||||||
import { KubeConfig, V1Node, V1Pod } from "@kubernetes/client-node"
|
import { KubeConfig, V1Node, V1Pod } from "@kubernetes/client-node"
|
||||||
import fse, { ensureDirSync, readFile, writeFileSync } from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import yaml from "js-yaml"
|
import yaml from "js-yaml"
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
|
|
||||||
|
export const kubeConfigDefaultPath = path.join(os.homedir(), '.kube', 'config');
|
||||||
|
|
||||||
function resolveTilde(filePath: string) {
|
function resolveTilde(filePath: string) {
|
||||||
if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) {
|
if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) {
|
||||||
return filePath.replace("~", os.homedir());
|
return filePath.replace("~", os.homedir());
|
||||||
@ -139,29 +140,3 @@ export function getNodeWarningConditions(node: V1Node) {
|
|||||||
c.status.toLowerCase() === "true" && c.type !== "Ready" && c.type !== "HostUpgrades"
|
c.status.toLowerCase() === "true" && c.type !== "Ready" && c.type !== "HostUpgrades"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write kubeconfigs to "embedded" store, i.e. "/Users/ixrock/Library/Application Support/Lens/kubeconfigs"
|
|
||||||
export function saveConfigToAppFiles(clusterId: string, kubeConfig: KubeConfig | string): string {
|
|
||||||
const userData = (app || remote.app).getPath("userData");
|
|
||||||
const kubeConfigFile = path.join(userData, `kubeconfigs/${clusterId}`)
|
|
||||||
const kubeConfigContents = typeof kubeConfig == "string" ? kubeConfig : dumpConfigYaml(kubeConfig);
|
|
||||||
|
|
||||||
ensureDirSync(path.dirname(kubeConfigFile));
|
|
||||||
writeFileSync(kubeConfigFile, kubeConfigContents);
|
|
||||||
return kubeConfigFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getKubeConfigLocal(): Promise<string> {
|
|
||||||
try {
|
|
||||||
const configFile = path.join(os.homedir(), '.kube', 'config');
|
|
||||||
const file = await readFile(configFile, "utf8");
|
|
||||||
const obj = yaml.safeLoad(file);
|
|
||||||
if (obj.contexts) {
|
|
||||||
obj.contexts = obj.contexts.filter((ctx: any) => ctx?.context?.cluster && ctx?.name)
|
|
||||||
}
|
|
||||||
return yaml.safeDump(obj);
|
|
||||||
} catch (err) {
|
|
||||||
logger.debug(`Cannot read local kube-config: ${err}`)
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
import type { ThemeId } from "../renderer/theme.store";
|
import type { ThemeId } from "../renderer/theme.store";
|
||||||
import semver from "semver"
|
import semver from "semver"
|
||||||
|
import { readFile } from "fs-extra"
|
||||||
import { action, observable, reaction, toJS } from "mobx";
|
import { action, observable, reaction, toJS } from "mobx";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
import migrations from "../migrations/user-store"
|
import migrations from "../migrations/user-store"
|
||||||
import { getAppVersion } from "./utils/app-version";
|
import { getAppVersion } from "./utils/app-version";
|
||||||
import { getKubeConfigLocal, loadConfig } from "./kube-helpers";
|
import { kubeConfigDefaultPath, loadConfig } from "./kube-helpers";
|
||||||
import { tracker } from "./tracker";
|
import { tracker } from "./tracker";
|
||||||
|
import logger from "../main/logger";
|
||||||
|
|
||||||
export interface UserStoreModel {
|
export interface UserStoreModel {
|
||||||
|
kubeConfigPath: string;
|
||||||
lastSeenAppVersion: string;
|
lastSeenAppVersion: string;
|
||||||
seenContexts: string[];
|
seenContexts: string[];
|
||||||
preferences: UserPreferences;
|
preferences: UserPreferences;
|
||||||
@ -37,10 +40,11 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
|
|
||||||
// refresh new contexts
|
// refresh new contexts
|
||||||
this.whenLoaded.then(this.refreshNewContexts);
|
this.whenLoaded.then(this.refreshNewContexts);
|
||||||
reaction(() => this.seenContexts.size, this.refreshNewContexts);
|
reaction(() => this.kubeConfigPath, this.refreshNewContexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable lastSeenAppVersion = "0.0.0"
|
@observable lastSeenAppVersion = "0.0.0"
|
||||||
|
@observable kubeConfigPath = kubeConfigDefaultPath; // used in add-cluster page for providing context
|
||||||
@observable seenContexts = observable.set<string>();
|
@observable seenContexts = observable.set<string>();
|
||||||
@observable newContexts = observable.set<string>();
|
@observable newContexts = observable.set<string>();
|
||||||
|
|
||||||
@ -55,6 +59,11 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
return semver.gt(getAppVersion(), this.lastSeenAppVersion);
|
return semver.gt(getAppVersion(), this.lastSeenAppVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
resetKubeConfigPath() {
|
||||||
|
this.kubeConfigPath = kubeConfigDefaultPath;
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
resetTheme() {
|
resetTheme() {
|
||||||
this.preferences.colorTheme = UserStore.defaultTheme;
|
this.preferences.colorTheme = UserStore.defaultTheme;
|
||||||
@ -67,15 +76,19 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected refreshNewContexts = async () => {
|
protected refreshNewContexts = async () => {
|
||||||
const kubeConfig = await getKubeConfigLocal();
|
try {
|
||||||
|
const kubeConfig = await readFile(this.kubeConfigPath, "utf8");
|
||||||
if (kubeConfig) {
|
if (kubeConfig) {
|
||||||
this.newContexts.clear();
|
this.newContexts.clear();
|
||||||
const localContexts = loadConfig(kubeConfig).getContexts();
|
loadConfig(kubeConfig).getContexts()
|
||||||
localContexts
|
|
||||||
.filter(ctx => ctx.cluster)
|
.filter(ctx => ctx.cluster)
|
||||||
.filter(ctx => !this.seenContexts.has(ctx.name))
|
.filter(ctx => !this.seenContexts.has(ctx.name))
|
||||||
.forEach(ctx => this.newContexts.add(ctx.name));
|
.forEach(ctx => this.newContexts.add(ctx.name));
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err);
|
||||||
|
this.resetKubeConfigPath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -86,17 +99,21 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
protected fromStore(data: Partial<UserStoreModel> = {}) {
|
protected async fromStore(data: Partial<UserStoreModel> = {}) {
|
||||||
const { lastSeenAppVersion, seenContexts = [], preferences } = data
|
const { lastSeenAppVersion, seenContexts = [], preferences, kubeConfigPath } = data
|
||||||
if (lastSeenAppVersion) {
|
if (lastSeenAppVersion) {
|
||||||
this.lastSeenAppVersion = lastSeenAppVersion;
|
this.lastSeenAppVersion = lastSeenAppVersion;
|
||||||
}
|
}
|
||||||
|
if (kubeConfigPath) {
|
||||||
|
this.kubeConfigPath = kubeConfigPath;
|
||||||
|
}
|
||||||
this.seenContexts.replace(seenContexts);
|
this.seenContexts.replace(seenContexts);
|
||||||
Object.assign(this.preferences, preferences);
|
Object.assign(this.preferences, preferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): UserStoreModel {
|
toJSON(): UserStoreModel {
|
||||||
const model: UserStoreModel = {
|
const model: UserStoreModel = {
|
||||||
|
kubeConfigPath: this.kubeConfigPath,
|
||||||
lastSeenAppVersion: this.lastSeenAppVersion,
|
lastSeenAppVersion: this.lastSeenAppVersion,
|
||||||
seenContexts: Array.from(this.seenContexts),
|
seenContexts: Array.from(this.seenContexts),
|
||||||
preferences: this.preferences,
|
preferences: this.preferences,
|
||||||
|
|||||||
11
src/common/utils/saveToAppFiles.ts
Normal file
11
src/common/utils/saveToAppFiles.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Save file to electron app directory (e.g. "/Users/$USER/Library/Application Support/Lens" for MacOS)
|
||||||
|
import path from "path";
|
||||||
|
import { app, remote } from "electron";
|
||||||
|
import { ensureDirSync, writeFileSync } from "fs-extra";
|
||||||
|
|
||||||
|
export function saveToAppFiles(filePath: string, contents: any): string {
|
||||||
|
const absPath = path.resolve((app || remote.app).getPath("userData"), filePath);
|
||||||
|
ensureDirSync(path.dirname(absPath));
|
||||||
|
writeFileSync(absPath, contents);
|
||||||
|
return absPath;
|
||||||
|
}
|
||||||
@ -5,8 +5,8 @@ import path from "path"
|
|||||||
import { app, remote } from "electron"
|
import { app, remote } from "electron"
|
||||||
import { migration } from "../migration-wrapper";
|
import { migration } from "../migration-wrapper";
|
||||||
import fse from "fs-extra"
|
import fse from "fs-extra"
|
||||||
import { ClusterModel } from "../../common/cluster-store";
|
import { ClusterModel, ClusterStore } from "../../common/cluster-store";
|
||||||
import { loadConfig, saveConfigToAppFiles } from "../../common/kube-helpers";
|
import { loadConfig } from "../../common/kube-helpers";
|
||||||
import makeSynchronous from "make-synchronous"
|
import makeSynchronous from "make-synchronous"
|
||||||
|
|
||||||
const AsyncFunction = Object.getPrototypeOf(async function () { return }).constructor;
|
const AsyncFunction = Object.getPrototypeOf(async function () { return }).constructor;
|
||||||
@ -17,7 +17,7 @@ export default migration({
|
|||||||
version: "3.6.0-beta.1",
|
version: "3.6.0-beta.1",
|
||||||
run(store, printLog) {
|
run(store, printLog) {
|
||||||
const userDataPath = (app || remote.app).getPath("userData")
|
const userDataPath = (app || remote.app).getPath("userData")
|
||||||
const kubeConfigBase = path.join(userDataPath, "kubeconfigs")
|
const kubeConfigBase = ClusterStore.getCustomKubeConfigPath("");
|
||||||
const storedClusters: ClusterModel[] = store.get("clusters") || [];
|
const storedClusters: ClusterModel[] = store.get("clusters") || [];
|
||||||
|
|
||||||
if (!storedClusters.length) return;
|
if (!storedClusters.length) return;
|
||||||
@ -31,7 +31,7 @@ export default migration({
|
|||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
// take the embedded kubeconfig and dump it into a file
|
// take the embedded kubeconfig and dump it into a file
|
||||||
cluster.kubeConfigPath = saveConfigToAppFiles(cluster.id, cluster.kubeConfig)
|
cluster.kubeConfigPath = ClusterStore.embedCustomKubeConfig(cluster.id, cluster.kubeConfig);
|
||||||
cluster.contextName = loadConfig(cluster.kubeConfigPath).getCurrentContext();
|
cluster.contextName = loadConfig(cluster.kubeConfigPath).getCurrentContext();
|
||||||
delete cluster.kubeConfig;
|
delete cluster.kubeConfig;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,39 @@
|
|||||||
.AddCluster {
|
.AddCluster {
|
||||||
|
.droppable {
|
||||||
|
box-shadow: 0 0 0 5px inset $primary;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
margin-top: -$padding;
|
||||||
|
color: $textColorSecondary;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.AceEditor {
|
||||||
|
min-height: 200px;
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
.Select {
|
.Select {
|
||||||
|
.kube-context {
|
||||||
|
--flex-gap: #{$padding};
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: extract to component, merge with namespace-select.scss
|
||||||
|
&__placeholder {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
&__control {
|
&__control {
|
||||||
box-shadow: 0 0 0 1px $borderFaintColor;
|
box-shadow: 0 0 0 1px $borderFaintColor;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,112 +1,163 @@
|
|||||||
import "./add-cluster.scss"
|
import "./add-cluster.scss"
|
||||||
|
import os from "os";
|
||||||
import React, { Fragment } from "react";
|
import React, { Fragment } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { computed, observable } from "mobx";
|
import { action, observable, runInAction } from "mobx";
|
||||||
|
import { remote } from "electron";
|
||||||
import { KubeConfig } from "@kubernetes/client-node";
|
import { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { t, Trans } from "@lingui/macro";
|
|
||||||
import { _i18n } from "../../i18n";
|
import { _i18n } from "../../i18n";
|
||||||
|
import { t, Trans } from "@lingui/macro";
|
||||||
import { Select, SelectOption } from "../select";
|
import { Select, SelectOption } from "../select";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { AceEditor } from "../ace-editor";
|
import { AceEditor } from "../ace-editor";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { WizardLayout } from "../layout/wizard-layout";
|
import { WizardLayout } from "../layout/wizard-layout";
|
||||||
import { getKubeConfigLocal, loadConfig, saveConfigToAppFiles, splitConfig, validateConfig } from "../../../common/kube-helpers";
|
import { kubeConfigDefaultPath, loadConfig, splitConfig, validateConfig } from "../../../common/kube-helpers";
|
||||||
import { clusterStore } from "../../../common/cluster-store";
|
import { ClusterModel, ClusterStore, clusterStore } from "../../../common/cluster-store";
|
||||||
import { workspaceStore } from "../../../common/workspace-store";
|
import { workspaceStore } from "../../../common/workspace-store";
|
||||||
import { v4 as uuid } from "uuid"
|
import { v4 as uuid } from "uuid"
|
||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
import { userStore } from "../../../common/user-store";
|
import { userStore } from "../../../common/user-store";
|
||||||
import { clusterViewURL } from "../cluster-manager/cluster-view.route";
|
import { clusterViewURL } from "../cluster-manager/cluster-view.route";
|
||||||
|
import { cssNames } from "../../utils";
|
||||||
|
import { Notifications } from "../notifications";
|
||||||
|
import { Tab, Tabs } from "../tabs";
|
||||||
|
|
||||||
|
enum KubeConfigSourceTab {
|
||||||
|
FILE = "file",
|
||||||
|
TEXT = "text"
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class AddCluster extends React.Component {
|
export class AddCluster extends React.Component {
|
||||||
readonly custom: any = "custom"
|
@observable.ref kubeConfigLocal: KubeConfig;
|
||||||
@observable.ref clusterConfig: KubeConfig;
|
|
||||||
@observable.ref kubeConfig: KubeConfig; // local ~/.kube/config (if available)
|
|
||||||
@observable.ref error: React.ReactNode;
|
@observable.ref error: React.ReactNode;
|
||||||
|
|
||||||
|
@observable kubeContexts = observable.map<string, KubeConfig>(); // available contexts from kubeconfig-file or user-input
|
||||||
|
@observable selectedContexts = observable.array<string>();
|
||||||
|
@observable sourceTab = KubeConfigSourceTab.FILE;
|
||||||
|
@observable kubeConfigPath = "";
|
||||||
|
@observable customConfig = ""
|
||||||
|
@observable proxyServer = ""
|
||||||
@observable isWaiting = false
|
@observable isWaiting = false
|
||||||
@observable showSettings = false
|
@observable showSettings = false
|
||||||
@observable proxyServer = ""
|
@observable dropAreaActive = false;
|
||||||
@observable customConfig = ""
|
|
||||||
|
|
||||||
async componentDidMount() {
|
componentDidMount() {
|
||||||
const kubeConfig: string = await getKubeConfigLocal()
|
this.setKubeConfig(userStore.kubeConfigPath);
|
||||||
if (kubeConfig) {
|
|
||||||
this.kubeConfig = loadConfig(kubeConfig)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
userStore.markNewContextsAsSeen();
|
userStore.markNewContextsAsSeen();
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get isCustom() {
|
@action
|
||||||
return this.clusterConfig === this.custom;
|
setKubeConfig(filePath: string, { throwError = false } = {}) {
|
||||||
}
|
|
||||||
|
|
||||||
@computed get clusterOptions() {
|
|
||||||
const options: SelectOption<KubeConfig>[] = [];
|
|
||||||
if (this.kubeConfig) {
|
|
||||||
splitConfig(this.kubeConfig).forEach(kubeConfig => {
|
|
||||||
const context = kubeConfig.currentContext;
|
|
||||||
const hasContext = clusterStore.hasContext(context);
|
|
||||||
if (!hasContext) {
|
|
||||||
options.push({
|
|
||||||
value: kubeConfig,
|
|
||||||
label: context,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
options.push({
|
|
||||||
label: <Trans>Custom..</Trans>,
|
|
||||||
value: this.custom,
|
|
||||||
});
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected formatClusterContextLabel = ({ value, label }: SelectOption<KubeConfig>) => {
|
|
||||||
if (value instanceof KubeConfig) {
|
|
||||||
const context = value.currentContext;
|
|
||||||
const isNew = userStore.newContexts.has(context);
|
|
||||||
const className = `${context} kube-context flex gaps align-center`
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
<span>{context}</span>
|
|
||||||
{isNew && <Icon material="fiber_new"/>}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
};
|
|
||||||
|
|
||||||
addCluster = async () => {
|
|
||||||
const { clusterConfig, customConfig, proxyServer } = this;
|
|
||||||
const clusterId = uuid();
|
|
||||||
this.isWaiting = true
|
|
||||||
this.error = ""
|
|
||||||
try {
|
try {
|
||||||
const config = this.isCustom ? loadConfig(customConfig) : clusterConfig;
|
this.kubeConfigLocal = loadConfig(filePath);
|
||||||
if (!config) {
|
validateConfig(this.kubeConfigLocal);
|
||||||
this.error = <Trans>Please select kubeconfig</Trans>
|
this.refreshContexts();
|
||||||
return;
|
this.kubeConfigPath = filePath;
|
||||||
|
userStore.kubeConfigPath = filePath; // save to store
|
||||||
|
} catch (err) {
|
||||||
|
Notifications.error(
|
||||||
|
<div>Can't setup <code>{filePath}</code> as kubeconfig: {String(err)}</div>
|
||||||
|
);
|
||||||
|
if (throwError) {
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
validateConfig(config);
|
}
|
||||||
await clusterStore.addCluster({
|
}
|
||||||
id: clusterId,
|
|
||||||
kubeConfigPath: saveConfigToAppFiles(clusterId, config),
|
@action
|
||||||
workspace: workspaceStore.currentWorkspaceId,
|
refreshContexts() {
|
||||||
contextName: config.currentContext,
|
this.selectedContexts.clear();
|
||||||
preferences: {
|
this.kubeContexts.clear();
|
||||||
clusterName: config.currentContext,
|
|
||||||
httpsProxy: proxyServer || undefined,
|
switch (this.sourceTab) {
|
||||||
},
|
case KubeConfigSourceTab.FILE:
|
||||||
});
|
const contexts = this.getContexts(this.kubeConfigLocal);
|
||||||
navigate(clusterViewURL({ params: { clusterId } }))
|
this.kubeContexts.replace(contexts);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KubeConfigSourceTab.TEXT:
|
||||||
|
try {
|
||||||
|
this.error = ""
|
||||||
|
const contexts = this.getContexts(loadConfig(this.customConfig || "{}"));
|
||||||
|
this.kubeContexts.replace(contexts);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.error = String(err);
|
this.error = String(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getContexts(config: KubeConfig): Map<string, KubeConfig> {
|
||||||
|
const contexts = new Map();
|
||||||
|
splitConfig(config).forEach(config => {
|
||||||
|
const isExists = clusterStore.hasContext(config.currentContext);
|
||||||
|
if (!isExists) {
|
||||||
|
contexts.set(config.currentContext, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return contexts
|
||||||
|
}
|
||||||
|
|
||||||
|
selectKubeConfigDialog = async () => {
|
||||||
|
const { dialog, BrowserWindow } = remote;
|
||||||
|
const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), {
|
||||||
|
defaultPath: this.kubeConfigPath,
|
||||||
|
properties: ["openFile", "showHiddenFiles"],
|
||||||
|
message: _i18n._(t`Select custom kubeconfig file`),
|
||||||
|
buttonLabel: _i18n._(t`Use configuration`),
|
||||||
|
});
|
||||||
|
if (!canceled && filePaths.length) {
|
||||||
|
this.setKubeConfig(filePaths[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addClusters = () => {
|
||||||
|
try {
|
||||||
|
if (!this.selectedContexts.length) {
|
||||||
|
this.error = <Trans>Please select at least one cluster context</Trans>
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.error = ""
|
||||||
|
this.isWaiting = true
|
||||||
|
const newClusters: ClusterModel[] = this.selectedContexts.map(context => {
|
||||||
|
const clusterId = uuid();
|
||||||
|
const kubeConfig = this.kubeContexts.get(context);
|
||||||
|
const kubeConfigPath = this.sourceTab === KubeConfigSourceTab.FILE
|
||||||
|
? this.kubeConfigPath // save link to original kubeconfig in file-system
|
||||||
|
: ClusterStore.embedCustomKubeConfig(clusterId, kubeConfig); // save in app-files folder
|
||||||
|
return {
|
||||||
|
id: clusterId,
|
||||||
|
kubeConfigPath: kubeConfigPath,
|
||||||
|
workspace: workspaceStore.currentWorkspaceId,
|
||||||
|
contextName: kubeConfig.currentContext,
|
||||||
|
preferences: {
|
||||||
|
clusterName: kubeConfig.currentContext,
|
||||||
|
httpsProxy: this.proxyServer || undefined,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
runInAction(() => {
|
||||||
|
clusterStore.addCluster(...newClusters);
|
||||||
|
if (newClusters.length === 1) {
|
||||||
|
const clusterId = newClusters[0].id;
|
||||||
|
clusterStore.setActive(clusterId);
|
||||||
|
navigate(clusterViewURL({ params: { clusterId } }));
|
||||||
|
} else {
|
||||||
|
Notifications.ok(
|
||||||
|
<Trans>Successfully imported <b>{newClusters.length}</b> cluster(s)</Trans>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.refreshContexts();
|
||||||
|
} catch (err) {
|
||||||
|
this.error = String(err);
|
||||||
|
Notifications.error(<Trans>Error while adding cluster(s): {this.error}</Trans>);
|
||||||
} finally {
|
} finally {
|
||||||
this.isWaiting = false;
|
this.isWaiting = false;
|
||||||
}
|
}
|
||||||
@ -163,19 +214,156 @@ export class AddCluster extends React.Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderKubeConfigSource() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tabs withBorder onChange={this.onKubeConfigTabChange}>
|
||||||
|
<Tab
|
||||||
|
value={KubeConfigSourceTab.FILE}
|
||||||
|
label={<Trans>Select kubeconfig file</Trans>}
|
||||||
|
active={this.sourceTab == KubeConfigSourceTab.FILE}/>
|
||||||
|
<Tab
|
||||||
|
value={KubeConfigSourceTab.TEXT}
|
||||||
|
label={<Trans>Paste as text</Trans>}
|
||||||
|
active={this.sourceTab == KubeConfigSourceTab.TEXT}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
{this.sourceTab === KubeConfigSourceTab.FILE && (
|
||||||
|
<>
|
||||||
|
<div className="kube-config-select flex gaps align-center">
|
||||||
|
<Input
|
||||||
|
theme="round-black"
|
||||||
|
className="kube-config-path box grow"
|
||||||
|
value={this.kubeConfigPath}
|
||||||
|
onChange={v => this.kubeConfigPath = v}
|
||||||
|
onBlur={this.onKubeConfigInputBlur}
|
||||||
|
/>
|
||||||
|
{this.kubeConfigPath !== kubeConfigDefaultPath && (
|
||||||
|
<Icon
|
||||||
|
material="settings_backup_restore"
|
||||||
|
onClick={() => this.setKubeConfig(kubeConfigDefaultPath)}
|
||||||
|
tooltip={<Trans>Reset</Trans>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Icon
|
||||||
|
material="folder"
|
||||||
|
onClick={this.selectKubeConfigDialog}
|
||||||
|
tooltip={<Trans>Browse</Trans>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<small className="hint">
|
||||||
|
<Trans>Pro-Tip: you can also drag-n-drop kubeconfig file to this area</Trans>
|
||||||
|
</small>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{this.sourceTab === KubeConfigSourceTab.TEXT && (
|
||||||
|
<>
|
||||||
|
<AceEditor
|
||||||
|
autoFocus
|
||||||
|
showGutter={false}
|
||||||
|
mode="yaml"
|
||||||
|
value={this.customConfig}
|
||||||
|
onChange={value => {
|
||||||
|
this.customConfig = value;
|
||||||
|
this.refreshContexts();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<small className="hint">
|
||||||
|
<Trans>Pro-Tip: paste kubeconfig to get available contexts</Trans>
|
||||||
|
</small>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContextSelector() {
|
||||||
|
const allContexts = Array.from(this.kubeContexts.keys());
|
||||||
|
const placeholder = this.selectedContexts.length > 0
|
||||||
|
? <Trans>Selected contexts: <b>{this.selectedContexts.length}</b></Trans>
|
||||||
|
: <Trans>Select contexts</Trans>;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Select
|
||||||
|
id="kubecontext-select" // todo: provide better mapping for integration tests (e.g. data-test-id="..")
|
||||||
|
placeholder={placeholder}
|
||||||
|
controlShouldRenderValue={false}
|
||||||
|
closeMenuOnSelect={false}
|
||||||
|
isOptionSelected={() => false}
|
||||||
|
options={allContexts}
|
||||||
|
formatOptionLabel={this.formatContextLabel}
|
||||||
|
noOptionsMessage={() => _i18n._(t`No contexts available or they have been added already`)}
|
||||||
|
onChange={({ value: ctx }: SelectOption<string>) => {
|
||||||
|
if (this.selectedContexts.includes(ctx)) {
|
||||||
|
this.selectedContexts.remove(ctx)
|
||||||
|
} else {
|
||||||
|
this.selectedContexts.push(ctx);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{this.selectedContexts.length > 0 && (
|
||||||
|
<small className="hint">
|
||||||
|
<span>Applying contexts:</span>{" "}
|
||||||
|
<code>{this.selectedContexts.join(", ")}</code>
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onKubeConfigInputBlur = (evt: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
const isChanged = this.kubeConfigPath !== userStore.kubeConfigPath;
|
||||||
|
if (isChanged) {
|
||||||
|
this.kubeConfigPath = this.kubeConfigPath.replace("~", os.homedir());
|
||||||
|
try {
|
||||||
|
this.setKubeConfig(this.kubeConfigPath, { throwError: true });
|
||||||
|
} catch (err) {
|
||||||
|
this.setKubeConfig(userStore.kubeConfigPath); // revert to previous valid path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKubeConfigTabChange = (tabId: KubeConfigSourceTab) => {
|
||||||
|
this.sourceTab = tabId;
|
||||||
|
this.error = "";
|
||||||
|
this.refreshContexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected formatContextLabel = ({ value: context }: SelectOption<string>) => {
|
||||||
|
const isNew = userStore.newContexts.has(context);
|
||||||
|
const isSelected = this.selectedContexts.includes(context);
|
||||||
|
return (
|
||||||
|
<div className={cssNames("kube-context flex gaps align-center", context)}>
|
||||||
|
<span>{context}</span>
|
||||||
|
{isNew && <Icon small material="fiber_new"/>}
|
||||||
|
{isSelected && <Icon small material="check" className="box right"/>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<WizardLayout className="AddCluster" infoPanel={this.renderInfo()}>
|
<WizardLayout
|
||||||
|
className="AddCluster"
|
||||||
|
infoPanel={this.renderInfo()}
|
||||||
|
contentClass={{ droppable: this.dropAreaActive }}
|
||||||
|
contentProps={{
|
||||||
|
onDragEnter: event => this.dropAreaActive = true,
|
||||||
|
onDragLeave: event => this.dropAreaActive = false,
|
||||||
|
onDragOver: event => {
|
||||||
|
event.preventDefault(); // enable onDrop()-callback
|
||||||
|
event.dataTransfer.dropEffect = "move"
|
||||||
|
},
|
||||||
|
onDrop: event => {
|
||||||
|
this.sourceTab = KubeConfigSourceTab.FILE;
|
||||||
|
this.dropAreaActive = false
|
||||||
|
this.setKubeConfig(event.dataTransfer.files[0].path)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<h2><Trans>Add Cluster</Trans></h2>
|
<h2><Trans>Add Cluster</Trans></h2>
|
||||||
<p>Choose config:</p>
|
{this.renderKubeConfigSource()}
|
||||||
<Select
|
{this.renderContextSelector()}
|
||||||
placeholder={<Trans>Select kubeconfig</Trans>}
|
|
||||||
value={this.clusterConfig}
|
|
||||||
options={this.clusterOptions}
|
|
||||||
onChange={({ value }: SelectOption) => this.clusterConfig = value}
|
|
||||||
formatOptionLabel={this.formatClusterContextLabel}
|
|
||||||
id="kubecontext-select"
|
|
||||||
/>
|
|
||||||
<div className="cluster-settings">
|
<div className="cluster-settings">
|
||||||
<a href="#" onClick={() => this.showSettings = !this.showSettings}>
|
<a href="#" onClick={() => this.showSettings = !this.showSettings}>
|
||||||
<Trans>Proxy settings</Trans>
|
<Trans>Proxy settings</Trans>
|
||||||
@ -195,18 +383,6 @@ export class AddCluster extends React.Component {
|
|||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{this.isCustom && (
|
|
||||||
<div className="custom-kubeconfig flex column gaps box grow">
|
|
||||||
<p>Kubeconfig:</p>
|
|
||||||
<AceEditor
|
|
||||||
autoFocus
|
|
||||||
showGutter={false}
|
|
||||||
mode="yaml"
|
|
||||||
value={this.customConfig}
|
|
||||||
onChange={value => this.customConfig = value}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{this.error && (
|
{this.error && (
|
||||||
<div className="error">{this.error}</div>
|
<div className="error">{this.error}</div>
|
||||||
)}
|
)}
|
||||||
@ -214,7 +390,7 @@ export class AddCluster extends React.Component {
|
|||||||
<Button
|
<Button
|
||||||
primary
|
primary
|
||||||
label={<Trans>Add cluster(s)</Trans>}
|
label={<Trans>Add cluster(s)</Trans>}
|
||||||
onClick={this.addCluster}
|
onClick={this.addClusters}
|
||||||
waiting={this.isWaiting}
|
waiting={this.isWaiting}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,17 +3,19 @@
|
|||||||
import "./ace-editor.scss"
|
import "./ace-editor.scss"
|
||||||
|
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { observer, disposeOnUnmount } from "mobx-react";
|
|
||||||
import AceBuild, { Ace } from "ace-builds"
|
|
||||||
import { autobind, cssNames } from "../../utils";
|
|
||||||
import { themeStore } from "../../theme.store";
|
|
||||||
import { reaction } from "mobx";
|
import { reaction } from "mobx";
|
||||||
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
|
import AceBuild, { Ace } from "ace-builds"
|
||||||
|
import { autobind, cssNames, noop } from "../../utils";
|
||||||
|
import { themeStore } from "../../theme.store";
|
||||||
|
|
||||||
interface Props extends Partial<Ace.EditorOptions> {
|
interface Props extends Partial<Ace.EditorOptions> {
|
||||||
className?: string;
|
className?: string;
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
cursorPos?: Ace.Point;
|
cursorPos?: Ace.Point;
|
||||||
|
onFocus?(evt: FocusEvent, value: string): void;
|
||||||
|
onBlur?(evt: FocusEvent, value: string): void;
|
||||||
onChange?(value: string, delta: Ace.Delta): void;
|
onChange?(value: string, delta: Ace.Delta): void;
|
||||||
onCursorPosChange?(point: Ace.Point): void;
|
onCursorPosChange?(point: Ace.Point): void;
|
||||||
}
|
}
|
||||||
@ -30,6 +32,8 @@ const defaultProps: Partial<Props> = {
|
|||||||
foldStyle: "markbegin",
|
foldStyle: "markbegin",
|
||||||
printMargin: false,
|
printMargin: false,
|
||||||
useWorker: false,
|
useWorker: false,
|
||||||
|
onBlur: noop,
|
||||||
|
onFocus: noop,
|
||||||
};
|
};
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -64,7 +68,7 @@ export class AceEditor extends React.Component<Props, State> {
|
|||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const {
|
const {
|
||||||
mode, autoFocus, className, hidden, cursorPos,
|
mode, autoFocus, className, hidden, cursorPos,
|
||||||
onChange, onCursorPosChange, children,
|
onBlur, onFocus, onChange, onCursorPosChange, children,
|
||||||
...options
|
...options
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@ -75,6 +79,8 @@ export class AceEditor extends React.Component<Props, State> {
|
|||||||
this.setCursorPos(cursorPos);
|
this.setCursorPos(cursorPos);
|
||||||
|
|
||||||
// bind events
|
// bind events
|
||||||
|
this.editor.on("blur", (evt: any) => onBlur(evt, this.getValue()));
|
||||||
|
this.editor.on("focus", (evt: any) => onFocus(evt, this.getValue()));
|
||||||
this.editor.on("change", this.onChange);
|
this.editor.on("change", this.onChange);
|
||||||
this.editor.selection.on("changeCursor", this.onCursorPosChange);
|
this.editor.selection.on("changeCursor", this.onCursorPosChange);
|
||||||
|
|
||||||
|
|||||||
@ -76,8 +76,10 @@ export class ClustersMenu extends React.Component<Props> {
|
|||||||
label: _i18n._(t`Remove`),
|
label: _i18n._(t`Remove`),
|
||||||
},
|
},
|
||||||
ok: () => {
|
ok: () => {
|
||||||
clusterStore.removeById(cluster.id);
|
if (clusterStore.activeClusterId === cluster.id) {
|
||||||
navigate(landingURL());
|
navigate(landingURL());
|
||||||
|
}
|
||||||
|
clusterStore.removeById(cluster.id);
|
||||||
},
|
},
|
||||||
message: <p>Are you sure want to remove cluster <b title={cluster.id}>{cluster.contextName}</b>?</p>,
|
message: <p>Are you sure want to remove cluster <b title={cluster.id}>{cluster.contextName}</b>?</p>,
|
||||||
})
|
})
|
||||||
@ -94,7 +96,7 @@ export class ClustersMenu extends React.Component<Props> {
|
|||||||
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId);
|
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId);
|
||||||
const noClustersInScope = clusters.length === 0;
|
const noClustersInScope = clusters.length === 0;
|
||||||
const isLanding = navigation.getPath() === landingURL();
|
const isLanding = navigation.getPath() === landingURL();
|
||||||
const showStartupHint = this.showHint && isLanding && noClustersInScope;
|
const showStartupHint = this.showHint && isLanding && noClustersInScope; // fixme: broken, move to landing.tsx
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cssNames("ClustersMenu flex column", className)}
|
className={cssNames("ClustersMenu flex column", className)}
|
||||||
|
|||||||
@ -24,10 +24,14 @@
|
|||||||
&:not(.isOpen) {
|
&:not(.isOpen) {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
|
|
||||||
.Tab:not(:focus):after {
|
.Tab {
|
||||||
|
--color-active: inherit;
|
||||||
|
|
||||||
|
&:not(:focus):after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tabs-container {
|
.tabs-container {
|
||||||
padding: 0 $padding * 2;
|
padding: 0 $padding * 2;
|
||||||
|
|||||||
66
src/renderer/components/input/file-input.tsx
Normal file
66
src/renderer/components/input/file-input.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React, { InputHTMLAttributes } from "react";
|
||||||
|
|
||||||
|
export interface FileInputSelection<T = string> {
|
||||||
|
file: File;
|
||||||
|
data?: T | any; // not available when readAsTexts={false}
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props extends InputHTMLAttributes<any> {
|
||||||
|
id?: string; // could be used with <label htmlFor={id}/> to open filesystem dialog
|
||||||
|
accept?: string; // allowed file types to select, e.g. "application/json"
|
||||||
|
readAsText?: boolean; // provide files content as text in selection-callback
|
||||||
|
multiple?: boolean;
|
||||||
|
onSelectFiles(...selectedFiles: FileInputSelection[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FileInput extends React.Component<Props> {
|
||||||
|
protected input: HTMLInputElement;
|
||||||
|
|
||||||
|
protected style: React.CSSProperties = {
|
||||||
|
position: "absolute",
|
||||||
|
display: "none",
|
||||||
|
};
|
||||||
|
|
||||||
|
selectFiles = () => {
|
||||||
|
this.input.click(); // opens system dialog for selecting files
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onChange = async (evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const fileList = Array.from(evt.target.files);
|
||||||
|
if (!fileList.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let selectedFiles: FileInputSelection[] = fileList.map(file => ({ file }));
|
||||||
|
if (this.props.readAsText) {
|
||||||
|
const readingFiles: Promise<FileInputSelection>[] = fileList.map(file => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => {
|
||||||
|
resolve({
|
||||||
|
file: file,
|
||||||
|
data: reader.result,
|
||||||
|
error: reader.error ? String(reader.error) : null,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
selectedFiles = await Promise.all(readingFiles);
|
||||||
|
}
|
||||||
|
this.props.onSelectFiles(...selectedFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { onSelectFiles, readAsText, ...props } = this.props;
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
style={this.style}
|
||||||
|
onChange={this.onChange}
|
||||||
|
ref={e => this.input = e}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './input'
|
export * from './input'
|
||||||
export * from './search-input'
|
export * from './search-input'
|
||||||
|
export * from './file-input'
|
||||||
|
|||||||
@ -17,6 +17,7 @@ export type InputProps<T = string> = Omit<InputElementProps, "onChange" | "onSub
|
|||||||
theme?: "round-black";
|
theme?: "round-black";
|
||||||
className?: string;
|
className?: string;
|
||||||
value?: T;
|
value?: T;
|
||||||
|
autoSelectOnFocus?: boolean
|
||||||
multiLine?: boolean; // use text-area as input field
|
multiLine?: boolean; // use text-area as input field
|
||||||
maxRows?: number; // when multiLine={true} define max rows size
|
maxRows?: number; // when multiLine={true} define max rows size
|
||||||
dirty?: boolean; // show validation errors even if the field wasn't touched yet
|
dirty?: boolean; // show validation errors even if the field wasn't touched yet
|
||||||
@ -112,8 +113,7 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
const result = validator.validate(value, this.props);
|
const result = validator.validate(value, this.props);
|
||||||
if (isBoolean(result) && !result) {
|
if (isBoolean(result) && !result) {
|
||||||
errors.push(this.getValidatorError(value, validator));
|
errors.push(this.getValidatorError(value, validator));
|
||||||
}
|
} else if (result instanceof Promise) {
|
||||||
else if (result instanceof Promise) {
|
|
||||||
if (!validationId) {
|
if (!validationId) {
|
||||||
this.validationId = validationId = uniqueId("validation_id_");
|
this.validationId = validationId = uniqueId("validation_id_");
|
||||||
}
|
}
|
||||||
@ -176,8 +176,9 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
onFocus(evt: React.FocusEvent<InputElement>) {
|
onFocus(evt: React.FocusEvent<InputElement>) {
|
||||||
const { onFocus } = this.props;
|
const { onFocus, autoSelectOnFocus } = this.props;
|
||||||
if (onFocus) onFocus(evt);
|
if (onFocus) onFocus(evt);
|
||||||
|
if (autoSelectOnFocus) this.select();
|
||||||
this.setState({ focused: true });
|
this.setState({ focused: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,13 +256,14 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
/* eslint-disable */
|
const {
|
||||||
let { multiLine, showValidationLine, validators, theme, maxRows, children, iconLeft, iconRight, ...inputProps } = this.props;
|
multiLine, showValidationLine, validators, theme, maxRows, children,
|
||||||
let { className, maxLength, rows, disabled, } = this.props;
|
maxLength, rows, disabled, autoSelectOnFocus, iconLeft, iconRight,
|
||||||
/* eslint-enable */
|
...inputProps
|
||||||
|
} = this.props;
|
||||||
const { focused, dirty, valid, validating, errors } = this.state;
|
const { focused, dirty, valid, validating, errors } = this.state;
|
||||||
|
|
||||||
className = cssNames("Input", className, {
|
const className = cssNames("Input", this.props.className, {
|
||||||
[`theme ${theme}`]: theme,
|
[`theme ${theme}`]: theme,
|
||||||
focused: focused,
|
focused: focused,
|
||||||
disabled: disabled,
|
disabled: disabled,
|
||||||
@ -271,10 +273,6 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
validatingLine: validating && showValidationLine,
|
validatingLine: validating && showValidationLine,
|
||||||
});
|
});
|
||||||
|
|
||||||
// normalize icons
|
|
||||||
if (isString(iconLeft)) iconLeft = <Icon material={iconLeft}/>
|
|
||||||
if (isString(iconRight)) iconRight = <Icon material={iconRight}/>
|
|
||||||
|
|
||||||
// prepare input props
|
// prepare input props
|
||||||
Object.assign(inputProps, {
|
Object.assign(inputProps, {
|
||||||
className: "input box grow",
|
className: "input box grow",
|
||||||
@ -291,9 +289,9 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<label className="input-area flex gaps align-center">
|
<label className="input-area flex gaps align-center">
|
||||||
{iconLeft}
|
{isString(iconLeft) ? <Icon material={iconLeft}/> : iconLeft}
|
||||||
{multiLine ? <textarea {...inputProps as any}/> : <input {...inputProps as any}/>}
|
{multiLine ? <textarea {...inputProps as any}/> : <input {...inputProps as any}/>}
|
||||||
{iconRight}
|
{isString(iconRight) ? <Icon material={iconRight}/> : iconRight}
|
||||||
</label>
|
</label>
|
||||||
<div className="input-info flex gaps">
|
<div className="input-info flex gaps">
|
||||||
{!valid && dirty && (
|
{!valid && dirty && (
|
||||||
|
|||||||
@ -11,10 +11,6 @@
|
|||||||
> .Tabs {
|
> .Tabs {
|
||||||
grid-area: tabs;
|
grid-area: tabs;
|
||||||
background: $layoutTabsBackground;
|
background: $layoutTabsBackground;
|
||||||
|
|
||||||
.Tab {
|
|
||||||
--color-active: #{$layoutTabsActiveColor};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
|
|||||||
@ -48,11 +48,14 @@ export class MainLayout extends React.Component<Props> {
|
|||||||
const { className, contentClass, headerClass, tabs, footer, footerClass, children } = this.props;
|
const { className, contentClass, headerClass, tabs, footer, footerClass, children } = this.props;
|
||||||
const routePath = navigation.location.pathname;
|
const routePath = navigation.location.pathname;
|
||||||
const cluster = getHostedCluster();
|
const cluster = getHostedCluster();
|
||||||
|
if (!cluster) {
|
||||||
|
return null; // fix: skip render when removing active (visible) cluster
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className={cssNames("MainLayout", className)}>
|
<div className={cssNames("MainLayout", className)}>
|
||||||
<header className={cssNames("flex gaps align-center", headerClass)}>
|
<header className={cssNames("flex gaps align-center", headerClass)}>
|
||||||
<span className="cluster">
|
<span className="cluster">
|
||||||
{cluster.preferences?.clusterName || cluster.contextName}
|
{cluster.preferences.clusterName || cluster.contextName}
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import React from "react";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { cssNames, IClassName } from "../../utils";
|
import { cssNames, IClassName } from "../../utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props extends React.DOMAttributes<any> {
|
||||||
className?: IClassName;
|
className?: IClassName;
|
||||||
header?: React.ReactNode;
|
header?: React.ReactNode;
|
||||||
headerClass?: IClassName;
|
headerClass?: IClassName;
|
||||||
@ -11,22 +11,26 @@ interface Props {
|
|||||||
infoPanelClass?: IClassName;
|
infoPanelClass?: IClassName;
|
||||||
infoPanel?: React.ReactNode;
|
infoPanel?: React.ReactNode;
|
||||||
centered?: boolean; // Centering content horizontally
|
centered?: boolean; // Centering content horizontally
|
||||||
|
contentProps?: React.DOMAttributes<HTMLElement>
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class WizardLayout extends React.Component<Props> {
|
export class WizardLayout extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { className, contentClass, infoPanelClass, infoPanel, header, headerClass, centered, children: content } = this.props;
|
const {
|
||||||
|
className, contentClass, infoPanelClass, infoPanel, header, headerClass, centered,
|
||||||
|
children, contentProps = {}, ...props
|
||||||
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<div className={cssNames("WizardLayout", { centered }, className)}>
|
<div {...props} className={cssNames("WizardLayout", { centered }, className)}>
|
||||||
{header && (
|
{header && (
|
||||||
<div className={cssNames("head-col flex gaps align-center", headerClass)}>
|
<div className={cssNames("head-col flex gaps align-center", headerClass)}>
|
||||||
{header}
|
{header}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={cssNames("content-col flex column gaps", contentClass)}>
|
<div {...contentProps} className={cssNames("content-col flex column gaps", contentClass)}>
|
||||||
<div className="flex column gaps">
|
<div className="flex column gaps">
|
||||||
{content}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{infoPanel && (
|
{infoPanel && (
|
||||||
|
|||||||
@ -29,11 +29,12 @@ export class Notifications extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static info(message: IMessage) {
|
static info(message: IMessage, customOpts: Partial<INotification> = {}) {
|
||||||
return notificationsStore.add({
|
return notificationsStore.add({
|
||||||
message: message,
|
status: "info",
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
status: "info"
|
message: message,
|
||||||
|
...customOpts,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export class Select extends React.Component<SelectProps> {
|
|||||||
static defaultProps: SelectProps = {
|
static defaultProps: SelectProps = {
|
||||||
autoConvertOptions: true,
|
autoConvertOptions: true,
|
||||||
menuPortalTarget: document.body,
|
menuPortalTarget: document.body,
|
||||||
|
menuPlacement: "auto",
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get theme() {
|
@computed get theme() {
|
||||||
|
|||||||
@ -4,6 +4,10 @@
|
|||||||
-webkit-user-select: none; /* safari */
|
-webkit-user-select: none; /* safari */
|
||||||
-moz-user-select: none; /* firefox */
|
-moz-user-select: none; /* firefox */
|
||||||
|
|
||||||
|
&.withBorder {
|
||||||
|
border-bottom: 1px solid $borderFaintColor;
|
||||||
|
}
|
||||||
|
|
||||||
&.wrap {
|
&.wrap {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
@ -24,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Tab {
|
.Tab {
|
||||||
--color-active: inherit;
|
--color-active: #{$layoutTabsActiveColor};
|
||||||
--line-color-active: #{$primary};
|
--line-color-active: #{$primary};
|
||||||
--line-color-focus: currentColor;
|
--line-color-focus: currentColor;
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ const TabsContext = React.createContext<TabsContextValue>({});
|
|||||||
|
|
||||||
interface TabsContextValue<D = any> {
|
interface TabsContextValue<D = any> {
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
|
withBorder?: boolean;
|
||||||
value?: D;
|
value?: D;
|
||||||
onChange?(value: D): void;
|
onChange?(value: D): void;
|
||||||
}
|
}
|
||||||
@ -29,16 +30,12 @@ export class Tabs extends React.PureComponent<TabsProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const { center, wrap, onChange, value, autoFocus, scrollable = true, withBorder, ...elemProps } = this.props;
|
||||||
center, wrap, onChange, value, autoFocus,
|
const className = cssNames("Tabs", this.props.className, {
|
||||||
scrollable = true,
|
center: center,
|
||||||
...elemProps
|
wrap: wrap,
|
||||||
} = this.props;
|
scrollable: scrollable,
|
||||||
let { className } = this.props;
|
withBorder: withBorder,
|
||||||
className = cssNames("Tabs", className, {
|
|
||||||
"center": center,
|
|
||||||
"wrap": wrap,
|
|
||||||
"scrollable": scrollable,
|
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<TabsContext.Provider value={{ autoFocus, value, onChange }}>
|
<TabsContext.Provider value={{ autoFocus, value, onChange }}>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user