@rancher/shell 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/base/_basic.scss +0 -1
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/global/_labeled-input.scss +6 -1
- package/assets/styles/global/_select.scss +9 -0
- package/assets/styles/vendor/vue-js-modal.scss +4 -0
- package/assets/translations/en-us.yaml +240 -16
- package/assets/translations/zh-hans.yaml +335 -111
- package/chart/example.vue +1 -1
- package/chart/istio.vue +2 -2
- package/chart/logging/index.vue +2 -2
- package/chart/monitoring/alerting/index.vue +2 -2
- package/chart/monitoring/grafana/index.vue +2 -2
- package/chart/monitoring/index.vue +2 -2
- package/chart/monitoring/prometheus/index.vue +4 -4
- package/chart/rancher-alerting-drivers.vue +17 -3
- package/chart/rancher-backup/S3.vue +37 -4
- package/chart/rancher-backup/index.vue +3 -3
- package/cloud-credential/aws.vue +1 -1
- package/cloud-credential/azure.vue +1 -1
- package/cloud-credential/digitalocean.vue +1 -1
- package/cloud-credential/gcp.vue +1 -1
- package/cloud-credential/generic.vue +1 -1
- package/cloud-credential/harvester.vue +2 -2
- package/cloud-credential/linode.vue +1 -1
- package/cloud-credential/s3.vue +2 -2
- package/cloud-credential/vmwarevsphere.vue +1 -1
- package/components/ActionMenu.vue +11 -1
- package/components/Alert.vue +1 -1
- package/components/AssignTo.vue +2 -2
- package/components/AsyncButton.vue +25 -12
- package/components/AwsComplianceBanner.vue +44 -0
- package/components/BannerGraphic.vue +11 -2
- package/components/ChartReadme.vue +10 -2
- package/components/CompoundStatusBadge.vue +50 -0
- package/components/CopyToClipboardText.vue +25 -4
- package/components/CruResource.vue +185 -16
- package/components/CruResourceFooter.vue +17 -1
- package/components/EtcdInfoBanner.vue +1 -1
- package/components/FilterLabel.vue +254 -0
- package/components/GlobalRoleBindings.vue +2 -2
- package/components/GrafanaDashboard.vue +1 -1
- package/components/GrowlManager.vue +20 -9
- package/components/HarvesterServiceAddOnConfig.vue +2 -2
- package/components/Import.vue +2 -2
- package/components/LandingPagePreference.vue +2 -2
- package/components/Markdown.vue +44 -12
- package/components/ModalWithCard.vue +2 -2
- package/components/MoveModal.vue +1 -1
- package/components/PercentageBar.vue +1 -1
- package/components/PromptChangePassword.vue +1 -1
- package/components/PromptModal.vue +13 -2
- package/components/PromptRemove.vue +64 -33
- package/components/PromptRestore.vue +3 -3
- package/components/Questions/Boolean.vue +1 -1
- package/components/Questions/Float.vue +1 -1
- package/components/Questions/Int.vue +1 -1
- package/components/Questions/Reference.vue +1 -1
- package/components/Questions/String.vue +1 -1
- package/components/RelatedResources.vue +1 -1
- package/components/RelatedWorkloadsTable.vue +3 -1
- package/components/ResourceDetail/Masthead.vue +27 -9
- package/components/ResourceDetail/index.vue +72 -7
- package/components/ResourceList/Masthead.vue +22 -0
- package/components/ResourceList/ResourceLoadingIndicator.vue +137 -0
- package/components/ResourceList/index.vue +42 -7
- package/components/ResourceTable.vue +11 -2
- package/components/ResourceYaml.vue +7 -1
- package/components/SelectIconGrid.vue +14 -1
- package/components/SortableTable/THead.vue +1 -1
- package/components/SortableTable/debug.js +117 -0
- package/components/SortableTable/index.vue +200 -43
- package/components/SortableTable/paging.js +2 -12
- package/components/SortableTable/selection.js +3 -0
- package/components/SortableTable/sorting.js +3 -1
- package/components/Tabbed/Tab.vue +25 -4
- package/components/Tabbed/index.vue +133 -119
- package/components/TypeDescription.vue +1 -1
- package/components/VMConsoleBar.vue +1 -1
- package/components/Wizard.vue +53 -14
- package/components/YamlEditor.vue +10 -0
- package/components/__tests__/CopyCode.test.ts +1 -7
- package/components/__tests__/CruResource.test.ts +1 -8
- package/components/auth/AllowedPrincipals.vue +1 -1
- package/components/auth/AuthBanner.vue +2 -1
- package/components/auth/AzureWarning.vue +69 -0
- package/components/auth/RoleDetailEdit.vue +4 -4
- package/components/auth/login/ldap.vue +1 -1
- package/components/cards/ApplicationCard.vue +140 -0
- package/components/dialog/AddClusterMemberDialog.vue +1 -1
- package/components/dialog/AddCustomBadgeDialog.vue +4 -4
- package/components/dialog/AddProjectMemberDialog.vue +2 -2
- package/components/dialog/AddonConfigConfirmationDialog.vue +1 -1
- package/components/dialog/DrainNode.vue +3 -3
- package/components/dialog/ForceMachineRemoveDialog.vue +2 -2
- package/components/dialog/GenericPrompt.vue +2 -2
- package/components/dialog/RollbackWorkloadDialog.vue +2 -2
- package/components/dialog/RotateCertificatesDialog.vue +3 -3
- package/components/dialog/RotateEncryptionKeyDialog.vue +11 -6
- package/components/dialog/SaveAsRKETemplateDialog.vue +3 -3
- package/components/dialog/harvester/AddHotplugModal.vue +3 -3
- package/components/dialog/harvester/BackupModal.vue +3 -3
- package/components/dialog/harvester/CloneTemplate.vue +3 -3
- package/components/dialog/harvester/EjectCDROMDialog.vue +3 -3
- package/components/dialog/harvester/ExportImageDialog.vue +3 -3
- package/components/dialog/harvester/MaintenanceDialog.vue +2 -2
- package/components/dialog/harvester/MigrationDialog.vue +2 -2
- package/components/dialog/harvester/RestoreDialog.vue +2 -2
- package/components/dialog/harvester/SupportBundle.vue +2 -2
- package/components/dialog/harvester/UnplugVolume.vue +2 -2
- package/components/fleet/FleetBundleResources.vue +1 -1
- package/components/fleet/FleetBundles.vue +1 -1
- package/components/fleet/FleetResources.vue +5 -3
- package/components/fleet/ForceDirectedTreeChart/chartIcons.js +17 -0
- package/components/fleet/ForceDirectedTreeChart/index.vue +553 -0
- package/components/form/ArrayList.vue +22 -3
- package/components/form/BannerSettings.vue +3 -3
- package/components/form/ChangePassword.vue +2 -2
- package/components/form/Command.vue +28 -9
- package/components/form/Error.vue +50 -0
- package/components/form/Footer.vue +2 -5
- package/components/form/HealthCheck.vue +2 -2
- package/components/form/HookOption.vue +2 -2
- package/components/form/InputWithSelect.vue +12 -2
- package/components/form/KeyValue.vue +5 -2
- package/components/form/LabeledSelect.vue +27 -14
- package/components/form/Labels.vue +12 -0
- package/components/form/MatchExpressions.vue +44 -10
- package/components/form/Members/ClusterPermissionsEditor.vue +3 -3
- package/components/form/Members/MembershipEditor.vue +10 -1
- package/components/form/Members/ProjectMembershipEditor.vue +1 -0
- package/components/form/NameNsDescription.vue +202 -79
- package/components/form/Networking.vue +1 -1
- package/components/form/NodeAffinity.vue +41 -26
- package/components/form/NodeScheduling.vue +29 -3
- package/components/form/NotificationSettings.vue +2 -2
- package/components/form/Password.vue +1 -1
- package/components/form/PodAffinity.vue +64 -6
- package/components/form/PodSecurity.vue +2 -2
- package/components/form/Ports.vue +1 -1
- package/components/form/Probe.vue +60 -17
- package/components/form/ProjectMemberEditor.vue +3 -3
- package/components/form/ResourceQuota/NamespaceRow.vue +46 -2
- package/components/form/ResourceQuota/Project.vue +4 -0
- package/components/form/ResourceTabs/index.vue +19 -7
- package/components/form/RuleSelector.vue +1 -1
- package/components/form/Security.vue +56 -14
- package/components/form/Select.vue +52 -10
- package/components/form/SelectOrCreateAuthSecret.vue +70 -31
- package/components/form/ServiceNameSelect.vue +1 -1
- package/components/form/ServicePorts.vue +10 -2
- package/components/form/ShellInput.vue +1 -1
- package/components/form/SimpleSecretSelector.vue +2 -2
- package/components/form/Tolerations.vue +1 -1
- package/components/form/UnitInput.vue +12 -3
- package/components/form/ValueFromResource.vue +1 -1
- package/components/form/WorkloadPorts.vue +1 -1
- package/components/form/__tests__/Command.test.ts +63 -0
- package/components/form/__tests__/Error.test.ts +56 -0
- package/components/form/__tests__/MatchExpressions.test.ts +79 -0
- package/components/form/__tests__/Probe.test.ts +62 -0
- package/components/form/__tests__/Security.test.ts +55 -0
- package/components/form/__tests__/UnitInput.test.ts +31 -23
- package/components/formatter/BadgeStateFormatter.vue +1 -1
- package/components/formatter/Capitalize.vue +7 -0
- package/components/formatter/ClusterLink.vue +6 -2
- package/components/formatter/ClusterProvider.vue +36 -0
- package/components/formatter/DelayedValue.vue +43 -0
- package/components/formatter/Endpoints.vue +2 -2
- package/components/formatter/HarvesterDiskState.vue +1 -1
- package/components/formatter/HarvesterIpAddress.vue +37 -18
- package/components/formatter/HarvesterMigrationState.vue +1 -1
- package/components/formatter/HarvesterVmState.vue +1 -1
- package/components/formatter/LinkDetail.vue +11 -2
- package/components/formatter/LinkName.vue +2 -2
- package/components/formatter/LiveExpiryBadgeState.vue +1 -1
- package/components/formatter/LivePodRestarts.vue +47 -0
- package/components/formatter/MachineSummaryGraph.vue +51 -5
- package/components/formatter/PodsUsage.vue +5 -3
- package/components/formatter/Weight.vue +1 -1
- package/components/formatter/WorkloadHealthScale.vue +17 -6
- package/components/nav/HarvesterUpgrade.vue +15 -5
- package/components/nav/Header.vue +15 -6
- package/components/nav/Jump.vue +1 -1
- package/components/nav/NamespaceFilter.vue +30 -10
- package/components/nav/TopLevelMenu.vue +52 -14
- package/components/nav/WindowManager/ContainerLogs.vue +14 -2
- package/components/nav/WorkspaceSwitcher.vue +1 -1
- package/components/{NovncConsole.vue → novnc/NovncConsole.vue} +0 -0
- package/components/novnc/NovncConsoleItem.vue +89 -0
- package/components/novnc/NovncConsoleWrapper.vue +243 -0
- package/config/labels-annotations.js +6 -2
- package/config/product/explorer.js +7 -3
- package/config/product/fleet.js +4 -1
- package/config/product/manager.js +5 -6
- package/config/product/settings.js +12 -1
- package/config/query-params.js +2 -0
- package/config/roles.ts +5 -0
- package/config/settings.js +60 -63
- package/config/table-headers.js +47 -18
- package/config/types.js +24 -8
- package/content/docs/en-us/whats-new.md +25 -0
- package/core/plugin.ts +12 -2
- package/creators/app/init +7 -1
- package/creators/pkg/tsconfig.json +2 -3
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/cis.cattle.io.clusterscan.vue +1 -1
- package/detail/fleet.cattle.io.bundle.vue +73 -21
- package/detail/fleet.cattle.io.gitrepo.vue +5 -4
- package/detail/harvesterhci.io.host/HarvesterHostBasic.vue +25 -4
- package/detail/harvesterhci.io.host/HarvesterHostDisk.vue +2 -2
- package/detail/harvesterhci.io.virtualmachinebackup/index.vue +1 -1
- package/detail/helm.cattle.io.projecthelmchart.vue +1 -1
- package/detail/networking.k8s.io.ingress.vue +10 -2
- package/detail/pod.vue +37 -1
- package/detail/provisioning.cattle.io.cluster.vue +102 -15
- package/detail/workload/index.vue +163 -15
- package/edit/auth/azuread.vue +146 -34
- package/edit/auth/github.vue +3 -3
- package/edit/auth/googleoauth.vue +3 -3
- package/edit/auth/ldap/config.vue +15 -7
- package/edit/auth/ldap/index.vue +2 -2
- package/edit/auth/oidc.vue +3 -3
- package/edit/auth/saml.vue +3 -3
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
- package/edit/autoscaling.horizontalpodautoscaler/metric-identifier.vue +1 -1
- package/edit/autoscaling.horizontalpodautoscaler/metric-object-reference.vue +1 -1
- package/edit/autoscaling.horizontalpodautoscaler/metric-target.vue +1 -1
- package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +1 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +2 -2
- package/edit/cis.cattle.io.clusterscan.vue +4 -4
- package/edit/cis.cattle.io.clusterscanbenchmark.vue +1 -1
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -1
- package/edit/fleet.cattle.io.cluster.vue +1 -0
- package/edit/fleet.cattle.io.clustergroup.vue +1 -1
- package/edit/fleet.cattle.io.gitrepo.vue +290 -157
- package/edit/harvesterhci.io.host/HarvesterDisk.vue +4 -5
- package/edit/harvesterhci.io.host/index.vue +28 -19
- package/edit/harvesterhci.io.keypair.vue +1 -1
- package/edit/harvesterhci.io.managedchart/rancher-monitoring.vue +1 -1
- package/edit/harvesterhci.io.management.cluster.vue +1 -1
- package/edit/harvesterhci.io.networkattachmentdefinition.vue +2 -2
- package/edit/harvesterhci.io.setting/additional-ca.vue +1 -1
- package/edit/harvesterhci.io.setting/backup-target.vue +1 -1
- package/edit/harvesterhci.io.setting/http-proxy.vue +1 -1
- package/edit/harvesterhci.io.setting/index.vue +3 -3
- package/edit/harvesterhci.io.setting/overcommit-config.vue +4 -1
- package/edit/harvesterhci.io.setting/ssl-parameters.vue +1 -1
- package/edit/harvesterhci.io.setting/support-bundle-image.vue +1 -1
- package/edit/harvesterhci.io.setting/vip-pools.vue +1 -1
- package/edit/harvesterhci.io.setting/vm-force-reset-policy.vue +2 -2
- package/edit/harvesterhci.io.virtualmachinebackup.vue +2 -2
- package/edit/harvesterhci.io.virtualmachineimage.vue +2 -2
- package/edit/harvesterhci.io.virtualmachinetemplateversion.vue +26 -18
- package/edit/helm.cattle.io.projecthelmchart.vue +3 -3
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +2 -2
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/AccessCredentialsUsers.vue +1 -1
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/index.vue +1 -1
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/DataTemplate.vue +1 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/index.vue +2 -1
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +3 -1
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/__tests__/HarvesterEditNetwork.test.ts +41 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/base.vue +79 -36
- package/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue +54 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineSSHKey.vue +1 -1
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/index.vue +2 -3
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditContainer.test.ts +40 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditExisting.test.ts +102 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVMImage.test.ts +117 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVolume.test.ts +74 -0
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue +59 -13
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue +72 -16
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue +74 -14
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +35 -9
- package/edit/kubevirt.io.virtualmachine/index.vue +33 -24
- package/edit/logging-flow/index.vue +1 -1
- package/edit/logging.banzaicloud.io.output/index.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/awsElasticsearch.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/azurestorage.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/cloudwatch.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/datadog.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/elasticsearch.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/file.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/forward.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/gcs.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/gelf.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/kafka.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/kinesisStream.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/logdna.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/logz.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/loki.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/newrelic.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/s3.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/splunkHec.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/sumologic.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/syslog.vue +2 -2
- package/edit/management.cattle.io.clusterroletemplatebinding.vue +2 -0
- package/edit/management.cattle.io.node.vue +71 -0
- package/edit/management.cattle.io.project.vue +28 -23
- package/edit/management.cattle.io.setting.vue +14 -3
- package/edit/management.cattle.io.user.vue +1 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -4
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +13 -13
- package/edit/monitoring.coreos.com.alertmanagerconfig/routeConfig.vue +18 -10
- package/edit/monitoring.coreos.com.alertmanagerconfig/tls.vue +2 -2
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +12 -7
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/opsgenie.vue +12 -7
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +20 -11
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/slack.vue +13 -8
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +25 -7
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +2 -2
- package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +20 -7
- package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +1 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +19 -8
- package/edit/monitoring.coreos.com.receiver/auth.vue +1 -1
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/tls.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/types/email.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/types/opsgenie.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/types/pagerduty.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/types/slack.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/types/webhook.banner.vue +1 -1
- package/edit/monitoring.coreos.com.receiver/types/webhook.vue +3 -3
- package/edit/monitoring.coreos.com.route.vue +2 -2
- package/edit/namespace.vue +0 -8
- package/edit/network.harvesterhci.io.clusternetwork/vlan.vue +1 -1
- package/edit/networking.istio.io.destinationrule/LoadBalancer.vue +2 -2
- package/edit/networking.istio.io.destinationrule/index.vue +1 -1
- package/edit/networking.k8s.io.ingress/Certificate.vue +5 -1
- package/edit/networking.k8s.io.ingress/Certificates.vue +5 -0
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +17 -2
- package/edit/networking.k8s.io.ingress/IngressClass.vue +63 -0
- package/edit/networking.k8s.io.ingress/Rule.vue +42 -6
- package/edit/networking.k8s.io.ingress/RulePath.vue +29 -5
- package/edit/networking.k8s.io.ingress/Rules.vue +11 -0
- package/edit/networking.k8s.io.ingress/index.vue +104 -15
- package/edit/networking.k8s.io.networkpolicy/PolicyRulePort.vue +1 -1
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +2 -2
- package/edit/networking.k8s.io.networkpolicy/index.vue +2 -2
- package/edit/persistentvolume/index.vue +1 -1
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +2 -2
- package/edit/persistentvolume/plugins/azureDisk.vue +2 -2
- package/edit/persistentvolume/plugins/azureFile.vue +2 -2
- package/edit/persistentvolume/plugins/cephfs.vue +4 -4
- package/edit/persistentvolume/plugins/cinder.vue +2 -2
- package/edit/persistentvolume/plugins/csi.vue +2 -2
- package/edit/persistentvolume/plugins/fc.vue +4 -4
- package/edit/persistentvolume/plugins/flexVolume.vue +2 -2
- package/edit/persistentvolume/plugins/flocker.vue +1 -1
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +2 -2
- package/edit/persistentvolume/plugins/glusterfs.vue +2 -2
- package/edit/persistentvolume/plugins/hostPath.vue +1 -1
- package/edit/persistentvolume/plugins/iscsi.vue +4 -4
- package/edit/persistentvolume/plugins/local.vue +1 -1
- package/edit/persistentvolume/plugins/longhorn.vue +2 -2
- package/edit/persistentvolume/plugins/nfs.vue +2 -2
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -1
- package/edit/persistentvolume/plugins/portworxVolume.vue +2 -2
- package/edit/persistentvolume/plugins/quobyte.vue +2 -2
- package/edit/persistentvolume/plugins/rbd.vue +4 -4
- package/edit/persistentvolume/plugins/scaleIO.vue +2 -2
- package/edit/persistentvolume/plugins/storageos.vue +2 -2
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -1
- package/edit/persistentvolumeclaim.vue +24 -8
- package/edit/provisioning.cattle.io.cluster/ACE.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -3
- package/edit/provisioning.cattle.io.cluster/DrainOptions.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +15 -3
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +16 -3
- package/edit/provisioning.cattle.io.cluster/S3Config.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.tests.ts +1 -7
- package/edit/provisioning.cattle.io.cluster/import.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +26 -7
- package/edit/provisioning.cattle.io.cluster/rke2.vue +136 -48
- package/edit/resources.cattle.io.backup.vue +26 -8
- package/edit/resources.cattle.io.restore.vue +3 -3
- package/edit/secret/basic.vue +1 -1
- package/edit/secret/index.vue +80 -2
- package/edit/secret/registry.vue +2 -2
- package/edit/secret/ssh.vue +1 -1
- package/edit/secret/tls.vue +1 -1
- package/edit/service.vue +47 -11
- package/edit/serviceaccount.vue +1 -1
- package/edit/storage.k8s.io.storageclass/index.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/aws-ebs.vue +7 -3
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/azure-disk.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/azure-file.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/cinder.vue +2 -2
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/gce-pd.vue +2 -2
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/glusterfs.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/portworx-volume.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/quobyte.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/rbd.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/scaleio.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/storageos.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/vsphere-volume.vue +1 -1
- package/edit/token.vue +3 -3
- package/edit/ui.cattle.io.navlink.vue +2 -2
- package/edit/workload/Job.vue +111 -23
- package/edit/workload/Upgrading.vue +77 -22
- package/edit/workload/__tests__/Job.test.ts +72 -0
- package/edit/workload/__tests__/Upgrading.test.ts +60 -0
- package/edit/workload/index.vue +13 -1085
- package/edit/workload/mixins/workload.js +900 -0
- package/edit/workload/storage/Mount.vue +2 -2
- package/edit/workload/storage/awsElasticBlockStore.vue +1 -1
- package/edit/workload/storage/azureDisk.vue +2 -2
- package/edit/workload/storage/azureFile.vue +1 -1
- package/edit/workload/storage/ephemeralVolume/index.vue +2 -2
- package/edit/workload/storage/gcePersistentDisk.vue +1 -1
- package/edit/workload/storage/hostPath.vue +1 -1
- package/edit/workload/storage/nfs.vue +2 -2
- package/edit/workload/storage/persistentVolumeClaim/index.vue +2 -2
- package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +3 -3
- package/edit/workload/storage/secret.vue +2 -2
- package/edit/workload/storage/vsphereVolume.vue +1 -1
- package/edit/workload/types/Deployment.vue +377 -0
- package/edit/workload/types/Generic.vue +295 -0
- package/layouts/default.vue +26 -7
- package/layouts/error.vue +3 -2
- package/layouts/home.vue +12 -2
- package/layouts/plain.vue +18 -2
- package/layouts/unauthenticated.vue +2 -1
- package/list/catalog.cattle.io.clusterrepo.vue +1 -1
- package/list/fleet.cattle.io.bundle.vue +1 -1
- package/list/fleet.cattle.io.cluster.vue +1 -1
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +1 -1
- package/list/harvesterhci.io.dashboard/HarvesterUpgrade.vue +9 -8
- package/list/harvesterhci.io.dashboard/UpgradeInfo.vue +40 -0
- package/list/harvesterhci.io.dashboard/index.vue +14 -36
- package/list/harvesterhci.io.host/index.vue +24 -12
- package/list/harvesterhci.io.networkattachmentdefinition.vue +1 -1
- package/list/harvesterhci.io.setting.vue +1 -1
- package/list/harvesterhci.io.virtualmachinebackup.vue +1 -1
- package/list/harvesterhci.io.virtualmachineimage.vue +36 -3
- package/list/harvesterhci.io.virtualmachinetemplateversion.vue +1 -5
- package/list/helm.cattle.io.projecthelmchart.vue +1 -1
- package/list/kubevirt.io.virtualmachine.vue +4 -2
- package/list/management.cattle.io.feature.vue +3 -3
- package/list/management.cattle.io.setting.vue +2 -2
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +1 -1
- package/list/namespace.vue +3 -1
- package/list/node.vue +10 -3
- package/list/persistentvolumeclaim.vue +42 -0
- package/list/provisioning.cattle.io.cluster.vue +22 -20
- package/list/workload.vue +31 -6
- package/machine-config/amazonec2.vue +37 -12
- package/machine-config/azure.vue +3 -3
- package/machine-config/digitalocean.vue +2 -2
- package/machine-config/generic.vue +1 -1
- package/machine-config/harvester.vue +124 -25
- package/machine-config/linode.vue +2 -2
- package/machine-config/vmwarevsphere.vue +5 -5
- package/middleware/authenticated.js +36 -6
- package/middleware/unauthenticated.js +22 -0
- package/mixins/brand.js +50 -3
- package/mixins/browser-tab-visibility.js +37 -0
- package/mixins/chart.js +36 -4
- package/mixins/{compact-input.js → compact-input.ts} +5 -3
- package/mixins/form-validation.js +122 -0
- package/mixins/harvester-vm/index.js +134 -90
- package/mixins/labeled-form-element.ts +193 -0
- package/mixins/resource-fetch.js +173 -0
- package/models/cluster.x-k8s.io.machine.js +6 -2
- package/models/etcdbackup.js +4 -0
- package/models/event.js +4 -0
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/fleet.cattle.io.gitrepo.js +10 -0
- package/models/harvester/harvesterhci.io.virtualmachinebackup.js +5 -2
- package/models/harvester/harvesterhci.io.virtualmachineimage.js +11 -8
- package/models/harvester/harvesterhci.io.virtualmachinetemplateversion.js +11 -2
- package/models/harvester/kubevirt.io.virtualmachine.js +2 -2
- package/models/harvester/kubevirt.io.virtualmachineinstance.js +1 -1
- package/models/harvester/node.js +27 -32
- package/models/harvester/persistentvolumeclaim.js +1 -1
- package/models/management.cattle.io.cluster.js +17 -11
- package/models/management.cattle.io.clusterroletemplatebinding.js +2 -2
- package/models/management.cattle.io.globalrole.js +19 -0
- package/models/management.cattle.io.node.js +10 -11
- package/models/management.cattle.io.project.js +60 -26
- package/models/management.cattle.io.roletemplate.js +19 -0
- package/models/monitoring.coreos.com.alertmanagerconfig.js +3 -2
- package/models/monitoring.coreos.com.prometheusrule.js +9 -0
- package/models/namespace.js +9 -1
- package/models/networking.k8s.io.ingress.js +17 -5
- package/models/persistentvolumeclaim.js +47 -1
- package/models/projectroletemplatebinding.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +92 -13
- package/models/rke.cattle.io.etcdsnapshot.js +4 -0
- package/models/service.js +11 -5
- package/models/storage.k8s.io.storageclass.js +14 -1
- package/models/workload.js +7 -2
- package/nuxt.config.js +27 -7
- package/package.json +10 -14
- package/pages/about.vue +15 -1
- package/pages/account/index.vue +1 -1
- package/pages/auth/login.vue +17 -5
- package/pages/auth/setup.vue +47 -9
- package/pages/c/_cluster/_product/_resource/create.vue +1 -1
- package/pages/c/_cluster/_product/members/index.vue +6 -1
- package/pages/c/_cluster/_product/projectsnamespaces.vue +113 -11
- package/pages/c/_cluster/apps/charts/chart.vue +1 -1
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +197 -19
- package/pages/c/_cluster/auth/config/index.vue +1 -1
- package/pages/c/_cluster/explorer/EventsTable.vue +1 -15
- package/pages/c/_cluster/explorer/index.vue +64 -35
- package/pages/c/_cluster/explorer/tools/index.vue +1 -1
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +249 -0
- package/pages/c/_cluster/fleet/index.vue +47 -65
- package/pages/c/_cluster/harvester/airgapupgrade/index.vue +7 -4
- package/pages/c/_cluster/harvester/console/_uid/vnc.vue +7 -1
- package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +8 -14
- package/pages/c/_cluster/monitoring/index.vue +1 -1
- package/pages/c/_cluster/monitoring/route-receiver/index.vue +1 -1
- package/pages/c/_cluster/settings/banners.vue +2 -2
- package/pages/c/_cluster/settings/brand.vue +62 -7
- package/pages/c/_cluster/settings/performance.vue +167 -0
- package/pages/diagnostic.vue +468 -0
- package/pages/fail-whale.vue +17 -5
- package/pages/home.vue +36 -22
- package/pages/plugins.vue +1 -1
- package/pages/prefs.vue +20 -7
- package/pages/support/index.vue +51 -9
- package/pkg/auto-import.js +1 -1
- package/pkg/dynamic-importer.lib.js +8 -0
- package/pkg/tsconfig.json +26 -9
- package/pkg/vue.config.js +8 -0
- package/plugins/console.js +29 -0
- package/plugins/dashboard-store/actions.js +171 -28
- package/plugins/dashboard-store/getters.js +13 -1
- package/plugins/dashboard-store/index.js +5 -1
- package/plugins/dashboard-store/mutations.js +72 -22
- package/plugins/dashboard-store/resource-class.js +259 -184
- package/plugins/i18n.js +9 -3
- package/plugins/steve/actions.js +16 -1
- package/plugins/steve/getters.js +9 -1
- package/plugins/steve/index.js +6 -2
- package/plugins/steve/mutations.js +100 -5
- package/plugins/steve/norman-class.js +8 -0
- package/plugins/steve/performanceTesting.js +5 -0
- package/plugins/steve/subscribe.js +144 -12
- package/plugins/steve/web-worker.steve-sub-worker.js +129 -0
- package/promptRemove/kubevirt.io.virtualmachine.vue +3 -17
- package/promptRemove/management.cattle.io.project.vue +128 -0
- package/promptRemove/pod.vue +131 -0
- package/rancher-components/BadgeState/BadgeState.spec.ts +12 -0
- package/{components → rancher-components/BadgeState}/BadgeState.vue +18 -10
- package/rancher-components/BadgeState/index.ts +1 -0
- package/{components/__tests__ → rancher-components/Banner}/Banner.test.ts +1 -1
- package/{components → rancher-components/Banner}/Banner.vue +22 -7
- package/rancher-components/Banner/index.ts +1 -0
- package/{components → rancher-components/Card}/Card.vue +58 -12
- package/rancher-components/Card/index.ts +1 -0
- package/{components/form → rancher-components/Form/Checkbox}/Checkbox.vue +118 -25
- package/rancher-components/Form/Checkbox/index.ts +1 -0
- package/{components/form/__tests__ → rancher-components/Form/LabeledInput}/LabeledInput.test.ts +13 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +341 -0
- package/rancher-components/Form/LabeledInput/index.ts +1 -0
- package/{components/form → rancher-components/Form/Radio}/RadioButton.vue +50 -22
- package/{components/form → rancher-components/Form/Radio}/RadioGroup.vue +76 -28
- package/rancher-components/Form/Radio/index.ts +2 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +169 -0
- package/rancher-components/Form/TextArea/index.ts +1 -0
- package/rancher-components/Form/index.ts +4 -0
- package/{components/form → rancher-components/LabeledTooltip}/LabeledTooltip.vue +32 -11
- package/rancher-components/LabeledTooltip/index.ts +1 -0
- package/scripts/build-pkg.sh +4 -0
- package/scripts/publish-shell.sh +37 -18
- package/scripts/test-plugins-build.sh +115 -0
- package/store/catalog.js +4 -0
- package/store/growl.js +6 -0
- package/store/i18n.js +18 -9
- package/store/index.js +190 -107
- package/store/prefs.js +8 -2
- package/store/resource-fetch.js +44 -0
- package/store/type-map.js +43 -7
- package/store/uiplugins.ts +1 -1
- package/utils/favicon.js +40 -0
- package/utils/object.js +26 -9
- package/utils/promise.js +20 -0
- package/utils/socket.js +10 -1
- package/utils/string.js +16 -0
- package/utils/validators/formRules/__tests__/index.test.ts +928 -0
- package/utils/validators/formRules/index.ts +447 -0
- package/utils/validators/prometheusrule.js +1 -1
- package/utils/validators/vm.js +12 -5
- package/utils/width.js +39 -0
- package/yarn-error.log +196 -0
- package/components/NovncConsoleWrapper.vue +0 -150
- package/components/form/Container.vue +0 -143
- package/components/form/LabeledInput.vue +0 -245
- package/components/form/Scheduling.vue +0 -115
- package/components/form/TextAreaAutoGrow.vue +0 -127
- package/mixins/labeled-form-element.js +0 -137
package/plugins/i18n.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Vue from 'vue';
|
|
2
2
|
import { escapeHtml } from '../utils/string';
|
|
3
3
|
|
|
4
|
-
function stringFor(store, key, args, raw = false) {
|
|
4
|
+
function stringFor(store, key, args, raw = false, escapehtml = true) {
|
|
5
5
|
const translation = store.getters['i18n/t'](key, args);
|
|
6
6
|
|
|
7
7
|
let out;
|
|
@@ -19,8 +19,10 @@ function stringFor(store, key, args, raw = false) {
|
|
|
19
19
|
|
|
20
20
|
if ( raw ) {
|
|
21
21
|
return out;
|
|
22
|
-
} else {
|
|
22
|
+
} else if (escapehtml) {
|
|
23
23
|
return escapeHtml(out);
|
|
24
|
+
} else {
|
|
25
|
+
return out;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -81,10 +83,14 @@ Vue.component('t', {
|
|
|
81
83
|
type: [String, Object],
|
|
82
84
|
default: 'span'
|
|
83
85
|
},
|
|
86
|
+
escapehtml: {
|
|
87
|
+
type: Boolean,
|
|
88
|
+
default: true,
|
|
89
|
+
}
|
|
84
90
|
},
|
|
85
91
|
|
|
86
92
|
render(h) {
|
|
87
|
-
const msg = stringFor(this.$store, this.k, this.$attrs, this.raw);
|
|
93
|
+
const msg = stringFor(this.$store, this.k, this.$attrs, this.raw, this.escapehtml);
|
|
88
94
|
|
|
89
95
|
if ( this.raw ) {
|
|
90
96
|
return h(
|
package/plugins/steve/actions.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import https from 'https';
|
|
2
2
|
import { addParam, parse as parseUrl, stringify as unParseUrl } from '@shell/utils/url';
|
|
3
|
-
import { handleSpoofedRequest } from '@shell/plugins/dashboard-store/actions';
|
|
3
|
+
import { handleSpoofedRequest, loadSchemas } from '@shell/plugins/dashboard-store/actions';
|
|
4
4
|
import { set } from '@shell/utils/object';
|
|
5
5
|
import { deferred } from '@shell/utils/promise';
|
|
6
6
|
import { streamJson, streamingSupported } from '@shell/utils/stream';
|
|
7
7
|
import isObject from 'lodash/isObject';
|
|
8
|
+
import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
9
|
+
import { NAMESPACE } from '@shell/config/types';
|
|
8
10
|
|
|
9
11
|
export default {
|
|
12
|
+
|
|
13
|
+
// Need to override this, so that thhe 'this' context is correct (this class not the base class)
|
|
14
|
+
async loadSchemas(ctx, watch = true) {
|
|
15
|
+
return await loadSchemas(ctx, watch);
|
|
16
|
+
},
|
|
17
|
+
|
|
10
18
|
async request({ state, dispatch, rootGetters }, pOpt ) {
|
|
11
19
|
const opt = pOpt.opt || pOpt;
|
|
12
20
|
|
|
@@ -255,6 +263,13 @@ export default {
|
|
|
255
263
|
}
|
|
256
264
|
},
|
|
257
265
|
|
|
266
|
+
createNamespace(ctx, obj) {
|
|
267
|
+
return classify(ctx, {
|
|
268
|
+
type: NAMESPACE,
|
|
269
|
+
metadata: { name: obj.name }
|
|
270
|
+
});
|
|
271
|
+
},
|
|
272
|
+
|
|
258
273
|
cleanForNew(ctx, obj) {
|
|
259
274
|
const m = obj.metadata || {};
|
|
260
275
|
|
package/plugins/steve/getters.js
CHANGED
|
@@ -101,5 +101,13 @@ export default {
|
|
|
101
101
|
const typeSuperClass = Object.getPrototypeOf(Object.getPrototypeOf(existing))?.constructor;
|
|
102
102
|
|
|
103
103
|
return typeSuperClass === HybridModel ? cleanHybridResources(data) : data;
|
|
104
|
-
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
// Return all the pods for a given namespace
|
|
107
|
+
podsByNamespace: state => (namespace) => {
|
|
108
|
+
const map = state.podsByNamespace[namespace];
|
|
109
|
+
|
|
110
|
+
return map?.list || [];
|
|
111
|
+
},
|
|
112
|
+
|
|
105
113
|
};
|
package/plugins/steve/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store/index';
|
|
2
|
-
|
|
3
2
|
import {
|
|
3
|
+
createWorker,
|
|
4
4
|
mutations as subscribeMutations,
|
|
5
5
|
actions as subscribeActions,
|
|
6
6
|
getters as subscribeGetters
|
|
@@ -26,6 +26,7 @@ function SteveFactory(namespace, baseUrl) {
|
|
|
26
26
|
deferredRequests: {},
|
|
27
27
|
started: [],
|
|
28
28
|
inError: {},
|
|
29
|
+
podsByNamespace: {}, // Cache of pods by namespace
|
|
29
30
|
};
|
|
30
31
|
},
|
|
31
32
|
|
|
@@ -64,7 +65,10 @@ export default (config) => {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
return coreStore(
|
|
67
|
-
SteveFactory(config),
|
|
68
|
+
SteveFactory(config.namespace, config.baseUrl),
|
|
68
69
|
config,
|
|
70
|
+
(store, ctx) => {
|
|
71
|
+
createWorker(store, ctx);
|
|
72
|
+
}
|
|
69
73
|
);
|
|
70
74
|
};
|
|
@@ -1,17 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { addObject, removeObject } from '@shell/utils/array';
|
|
2
|
+
import { NAMESPACE, POD, SCHEMA } from '@shell/config/types';
|
|
3
|
+
import {
|
|
4
|
+
forgetType,
|
|
5
|
+
resetStore,
|
|
6
|
+
loadAll,
|
|
7
|
+
load,
|
|
8
|
+
remove
|
|
9
|
+
} from '@shell/plugins/dashboard-store/mutations';
|
|
2
10
|
import { keyForSubscribe } from '@shell/plugins/steve/subscribe';
|
|
3
11
|
import { perfLoadAll } from '@shell/plugins/steve/performanceTesting';
|
|
12
|
+
import Vue from 'vue';
|
|
13
|
+
|
|
14
|
+
function registerNamespace(state, namespace) {
|
|
15
|
+
let cache = state.podsByNamespace[namespace];
|
|
16
|
+
|
|
17
|
+
if (!cache) {
|
|
18
|
+
cache = {
|
|
19
|
+
list: [],
|
|
20
|
+
map: new Map()
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
Vue.set(state.podsByNamespace, namespace, cache);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return cache;
|
|
27
|
+
}
|
|
4
28
|
|
|
5
29
|
export default {
|
|
6
|
-
loadAll(state, {
|
|
30
|
+
loadAll(state, {
|
|
31
|
+
type,
|
|
32
|
+
data,
|
|
33
|
+
ctx,
|
|
34
|
+
skipHaveAll
|
|
35
|
+
}) {
|
|
7
36
|
// Performance testing in dev and when env var is set
|
|
8
|
-
if (process.env.dev && process.env.perfTest) {
|
|
37
|
+
if (process.env.dev && !!process.env.perfTest) {
|
|
9
38
|
data = perfLoadAll(type, data);
|
|
10
39
|
}
|
|
11
40
|
|
|
12
|
-
|
|
13
|
-
type, data, ctx
|
|
41
|
+
const proxies = loadAll(state, {
|
|
42
|
+
type, data, ctx, skipHaveAll
|
|
14
43
|
});
|
|
44
|
+
|
|
45
|
+
// If we loaded a set of pods, then update the podsByNamespace cache
|
|
46
|
+
if (type === POD) {
|
|
47
|
+
// Clear the entire cache - this is a fresh load
|
|
48
|
+
Object.keys(state.podsByNamespace).forEach((ns) => {
|
|
49
|
+
delete state.podsByNamespace[ns];
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Go through all of the pods and populate cache by namespace
|
|
53
|
+
proxies.forEach((entry) => {
|
|
54
|
+
const cache = registerNamespace(state, entry.namespace);
|
|
55
|
+
|
|
56
|
+
addObject(cache.list, entry);
|
|
57
|
+
cache.map.set(entry.id, entry);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Notify the web worker of the initial load of schemas
|
|
62
|
+
if (type === SCHEMA) {
|
|
63
|
+
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
64
|
+
|
|
65
|
+
if (worker) {
|
|
66
|
+
// Store raw json objects, not the proxies
|
|
67
|
+
worker.loadSchema(data);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
15
70
|
},
|
|
16
71
|
|
|
17
72
|
forgetType(state, type) {
|
|
@@ -23,5 +78,45 @@ export default {
|
|
|
23
78
|
reset(state) {
|
|
24
79
|
resetStore(state, this.commit);
|
|
25
80
|
this.commit(`${ state.config.namespace }/resetSubscriptions`);
|
|
81
|
+
|
|
82
|
+
// Clear the podsByNamespace cache
|
|
83
|
+
state.podsByNamespace = {};
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
clearFromQueue(state, type) {
|
|
87
|
+
// Remove anything in the queue that is a resource update for the given type
|
|
88
|
+
state.queue = state.queue.filter((item) => {
|
|
89
|
+
return item.body?.type !== type;
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
loadMulti(state, { data, ctx }) {
|
|
94
|
+
for (const entry of data) {
|
|
95
|
+
const resource = load(state, { data: entry, ctx });
|
|
96
|
+
|
|
97
|
+
if (resource.type === POD && resource.metadata) {
|
|
98
|
+
const cache = registerNamespace(state, resource.namespace);
|
|
99
|
+
|
|
100
|
+
addObject(cache.list, resource);
|
|
101
|
+
cache.map.set(resource.id, resource);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
remove(state, obj) {
|
|
107
|
+
remove(state, obj, this.getters);
|
|
108
|
+
|
|
109
|
+
if (obj && obj.type === POD) {
|
|
110
|
+
const cache = state.podsByNamespace[obj.namespace];
|
|
111
|
+
|
|
112
|
+
// Extra defensive check that the cache exists for the namespace being removed
|
|
113
|
+
if (cache) {
|
|
114
|
+
removeObject(cache.list, obj);
|
|
115
|
+
cache.map.delete(obj.id);
|
|
116
|
+
}
|
|
117
|
+
} else if (obj && obj.type === NAMESPACE) {
|
|
118
|
+
// Namespace deleted
|
|
119
|
+
delete state.podsByNamespace[obj.namespace];
|
|
120
|
+
}
|
|
26
121
|
}
|
|
27
122
|
};
|
|
@@ -48,4 +48,12 @@ export default class NormanModel extends Resource {
|
|
|
48
48
|
delete this.annotations[key];
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
setResourceQuotas(spec) {
|
|
53
|
+
const keys = ['resourceQuota', 'namespaceDefaultResourceQuota'];
|
|
54
|
+
|
|
55
|
+
keys.forEach((key) => {
|
|
56
|
+
Vue.set(this, key, { ...spec[key] });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
51
59
|
}
|
|
@@ -19,6 +19,11 @@ const PERF_DATA = {
|
|
|
19
19
|
},
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
// Log a warning when performance data simulation is enabled
|
|
23
|
+
if (!!process.env.perfTest && process.env.dev ) {
|
|
24
|
+
console.warn('Performance Testing data enabled', PERF_DATA); // eslint-disable-line no-console
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
const DEFAULTS = {
|
|
23
28
|
count: 1, // One copy of each resource
|
|
24
29
|
statusRow: 0, // Don't add any status rows (0 = None, 1 = All, N = 1 out of N)
|
|
@@ -1,17 +1,56 @@
|
|
|
1
1
|
import { addObject, clear, removeObject } from '@shell/utils/array';
|
|
2
2
|
import { get } from '@shell/utils/object';
|
|
3
|
+
import { COUNT, SCHEMA } from '@shell/config/types';
|
|
3
4
|
import Socket, {
|
|
4
5
|
EVENT_CONNECTED,
|
|
5
6
|
EVENT_DISCONNECTED,
|
|
6
7
|
EVENT_MESSAGE,
|
|
7
8
|
// EVENT_FRAME_TIMEOUT,
|
|
8
|
-
EVENT_CONNECT_ERROR
|
|
9
|
+
EVENT_CONNECT_ERROR,
|
|
10
|
+
EVENT_DISCONNECT_ERROR
|
|
9
11
|
} from '@shell/utils/socket';
|
|
10
12
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
13
|
+
import day from 'dayjs';
|
|
14
|
+
import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
|
|
15
|
+
import { escapeHtml } from '@shell/utils/string';
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line
|
|
18
|
+
import Worker from './web-worker.steve-sub-worker.js'
|
|
19
|
+
import * as Comlink from 'comlink';
|
|
11
20
|
|
|
12
21
|
export const NO_WATCH = 'NO_WATCH';
|
|
13
22
|
export const NO_SCHEMA = 'NO_SCHEMA';
|
|
14
23
|
|
|
24
|
+
// minimum length of time a disconnect notification is shown
|
|
25
|
+
const MINIMUM_TIME_NOTIFIED = 3000;
|
|
26
|
+
|
|
27
|
+
// minimum time a socket must be disconnected for before sending a growl
|
|
28
|
+
const MINIMUM_TIME_DISCONNECTED = 10000;
|
|
29
|
+
|
|
30
|
+
// We only create a worker for the cluster store
|
|
31
|
+
export function createWorker(store, ctx) {
|
|
32
|
+
const { getters } = ctx;
|
|
33
|
+
const storeName = getters.storeName;
|
|
34
|
+
|
|
35
|
+
store.$workers = store.$workers || {};
|
|
36
|
+
|
|
37
|
+
if (storeName !== 'cluster') {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function callback(resource) {
|
|
42
|
+
queueChange(ctx, resource, true, 'Change');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!store.$workers[storeName]) {
|
|
46
|
+
const worker = Comlink.wrap(new Worker());
|
|
47
|
+
|
|
48
|
+
store.$workers[storeName] = worker;
|
|
49
|
+
|
|
50
|
+
worker.initWorker(storeName, Comlink.proxy(callback));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
15
54
|
export function keyForSubscribe({
|
|
16
55
|
resourceType, type, namespace, id, selector
|
|
17
56
|
} = {}) {
|
|
@@ -68,7 +107,7 @@ function queueChange({ getters, state }, { data, revision }, load, label) {
|
|
|
68
107
|
});
|
|
69
108
|
}
|
|
70
109
|
|
|
71
|
-
if ( type ===
|
|
110
|
+
if ( type === SCHEMA ) {
|
|
72
111
|
// Clear the current records in the store when a type disappears
|
|
73
112
|
state.queue.push({
|
|
74
113
|
action: 'commit',
|
|
@@ -108,7 +147,6 @@ export const actions = {
|
|
|
108
147
|
socket = new Socket(`${ state.config.baseUrl }/subscribe`);
|
|
109
148
|
|
|
110
149
|
commit('setSocket', socket);
|
|
111
|
-
|
|
112
150
|
socket.addEventListener(EVENT_CONNECTED, (e) => {
|
|
113
151
|
dispatch('opened', e);
|
|
114
152
|
});
|
|
@@ -118,7 +156,11 @@ export const actions = {
|
|
|
118
156
|
});
|
|
119
157
|
|
|
120
158
|
socket.addEventListener(EVENT_CONNECT_ERROR, (e) => {
|
|
121
|
-
dispatch('error', e
|
|
159
|
+
dispatch('error', e );
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
socket.addEventListener(EVENT_DISCONNECT_ERROR, (e) => {
|
|
163
|
+
dispatch('error', e );
|
|
122
164
|
});
|
|
123
165
|
|
|
124
166
|
socket.addEventListener(EVENT_MESSAGE, (e) => {
|
|
@@ -137,11 +179,23 @@ export const actions = {
|
|
|
137
179
|
socket.connect(get(opt, 'metadata'));
|
|
138
180
|
},
|
|
139
181
|
|
|
140
|
-
unsubscribe({ state, commit }) {
|
|
182
|
+
unsubscribe({ state, commit, getters }) {
|
|
141
183
|
const socket = state.socket;
|
|
184
|
+
const worker = (this.$workers || {})[getters.storeName];
|
|
142
185
|
|
|
143
186
|
commit('setWantSocket', false);
|
|
144
187
|
|
|
188
|
+
if (worker) {
|
|
189
|
+
try {
|
|
190
|
+
worker.destroyWorker();
|
|
191
|
+
worker[Comlink.releaseProxy]();
|
|
192
|
+
} catch (e) {
|
|
193
|
+
console.error(e); // eslint-disable-line no-console
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
delete this.$workers[getters.storeName];
|
|
197
|
+
}
|
|
198
|
+
|
|
145
199
|
if ( socket ) {
|
|
146
200
|
return socket.disconnect();
|
|
147
201
|
}
|
|
@@ -338,7 +392,7 @@ export const actions = {
|
|
|
338
392
|
},
|
|
339
393
|
|
|
340
394
|
async opened({
|
|
341
|
-
commit, dispatch, state, getters
|
|
395
|
+
commit, dispatch, state, getters, rootGetters
|
|
342
396
|
}, event) {
|
|
343
397
|
state.debugSocket && console.info(`WebSocket Opened [${ getters.storeName }]`); // eslint-disable-line no-console
|
|
344
398
|
|
|
@@ -364,6 +418,21 @@ export const actions = {
|
|
|
364
418
|
|
|
365
419
|
if ( socket.hasReconnected ) {
|
|
366
420
|
await dispatch('reconnectWatches');
|
|
421
|
+
// Check for disconnect notifications and clear them
|
|
422
|
+
const growlErr = rootGetters['growl/find']({ key: 'url', val: this.$socket.url });
|
|
423
|
+
|
|
424
|
+
if (growlErr) {
|
|
425
|
+
const now = Date.now();
|
|
426
|
+
|
|
427
|
+
// even if the socket reconnected, keep the error growl for at least a few seconds to ensure its readable
|
|
428
|
+
if (now >= growlErr.earliestClose) {
|
|
429
|
+
dispatch('growl/remove', growlErr.id, { root: true });
|
|
430
|
+
} else {
|
|
431
|
+
setTimeout(() => {
|
|
432
|
+
dispatch('growl/remove', growlErr.id, { root: true });
|
|
433
|
+
}, growlErr.earliestClose - now);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
367
436
|
}
|
|
368
437
|
|
|
369
438
|
// Try resending any frames that were attempted to be sent while the socket was down, once.
|
|
@@ -381,10 +450,38 @@ export const actions = {
|
|
|
381
450
|
state.queueTimer = null;
|
|
382
451
|
},
|
|
383
452
|
|
|
384
|
-
error({
|
|
385
|
-
|
|
453
|
+
error({
|
|
454
|
+
getters, state, dispatch, rootGetters
|
|
455
|
+
}, e) {
|
|
386
456
|
clearTimeout(state.queueTimer);
|
|
387
457
|
state.queueTimer = null;
|
|
458
|
+
if (e.type === EVENT_DISCONNECT_ERROR) {
|
|
459
|
+
// do not send a growl notification unless the socket stays disconnected for more than MINIMUM_TIME_DISCONNECTED
|
|
460
|
+
setTimeout(() => {
|
|
461
|
+
if (state.socket.isConnected()) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const dateFormat = escapeHtml( rootGetters['prefs/get'](DATE_FORMAT));
|
|
465
|
+
const timeFormat = escapeHtml( rootGetters['prefs/get'](TIME_FORMAT));
|
|
466
|
+
const time = e?.srcElement?.disconnectedAt || Date.now();
|
|
467
|
+
|
|
468
|
+
const timeFormatted = `${ day(time).format(`${ dateFormat } ${ timeFormat }`) }`;
|
|
469
|
+
const url = e?.srcElement?.url;
|
|
470
|
+
|
|
471
|
+
const t = rootGetters['i18n/t'];
|
|
472
|
+
|
|
473
|
+
dispatch('growl/error', {
|
|
474
|
+
title: t('growl.disconnected.title'),
|
|
475
|
+
message: t('growl.disconnected.message', { url, time: timeFormatted }, { raw: true }),
|
|
476
|
+
icon: 'error',
|
|
477
|
+
earliestClose: time + MINIMUM_TIME_NOTIFIED + MINIMUM_TIME_DISCONNECTED,
|
|
478
|
+
url
|
|
479
|
+
}, { root: true });
|
|
480
|
+
}, MINIMUM_TIME_DISCONNECTED);
|
|
481
|
+
} else {
|
|
482
|
+
// if the error is not a disconnect error, the socket never worked: log whether the current browser is safari
|
|
483
|
+
console.error(`WebSocket Connection Error [${ getters.storeName }]`, e.detail); // eslint-disable-line no-console
|
|
484
|
+
}
|
|
388
485
|
},
|
|
389
486
|
|
|
390
487
|
send({ state, commit }, obj) {
|
|
@@ -467,10 +564,36 @@ export const actions = {
|
|
|
467
564
|
},
|
|
468
565
|
|
|
469
566
|
'ws.resource.change'(ctx, msg) {
|
|
470
|
-
queueChange(ctx, msg, true, 'Change');
|
|
471
|
-
|
|
472
567
|
const data = msg.data;
|
|
473
568
|
const type = data.type;
|
|
569
|
+
|
|
570
|
+
// Debounce count changes so we send at most 1 every 5 seconds
|
|
571
|
+
if (type === COUNT) {
|
|
572
|
+
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
573
|
+
|
|
574
|
+
if (worker) {
|
|
575
|
+
worker.countsUpdate(msg);
|
|
576
|
+
|
|
577
|
+
// No further processing - let the web worker debounce the counts
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Web worker can process schemas to check that they are actually changing and
|
|
583
|
+
// only load updates if the schema did actually change
|
|
584
|
+
if (type === SCHEMA) {
|
|
585
|
+
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
586
|
+
|
|
587
|
+
if (worker) {
|
|
588
|
+
worker.updateSchema(data);
|
|
589
|
+
|
|
590
|
+
// No further processing - let the web worker check the schema updates
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
queueChange(ctx, msg, true, 'Change');
|
|
596
|
+
|
|
474
597
|
const typeOption = ctx.rootGetters['type-map/optionsFor'](type);
|
|
475
598
|
|
|
476
599
|
if (typeOption?.alias?.length > 0) {
|
|
@@ -490,10 +613,19 @@ export const actions = {
|
|
|
490
613
|
},
|
|
491
614
|
|
|
492
615
|
'ws.resource.remove'(ctx, msg) {
|
|
493
|
-
queueChange(ctx, msg, false, 'Remove');
|
|
494
|
-
|
|
495
616
|
const data = msg.data;
|
|
496
617
|
const type = data.type;
|
|
618
|
+
|
|
619
|
+
if (type === SCHEMA) {
|
|
620
|
+
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
621
|
+
|
|
622
|
+
if (worker) {
|
|
623
|
+
worker.removeSchema(data.id);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
queueChange(ctx, msg, false, 'Remove');
|
|
628
|
+
|
|
497
629
|
const typeOption = ctx.rootGetters['type-map/optionsFor'](type);
|
|
498
630
|
|
|
499
631
|
if (typeOption?.alias?.length > 0) {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as Comlink from 'comlink';
|
|
2
|
+
import { SCHEMA } from '@shell/config/types';
|
|
3
|
+
|
|
4
|
+
const COUNTS_FLUSH_TIMEOUT = 5000;
|
|
5
|
+
const SCHEMA_FLUSH_TIMEOUT = 2500;
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
store: '', // Store name
|
|
9
|
+
load: undefined, // Load callback to load a resource into the store
|
|
10
|
+
counts: [], // Buffer of count resources recieved in a given window
|
|
11
|
+
countTimer: undefined, // Tiemr to flush the count buffer
|
|
12
|
+
flushTimer: undefined, // Timer to flush the schema chaneg queue
|
|
13
|
+
queue: [], // Schema change queue
|
|
14
|
+
schemas: {} // Map of schema id to hash to track when a schema actually changes
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Quick, simple hash function
|
|
18
|
+
function hash(str) {
|
|
19
|
+
let hash = 0;
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < str.length; i++) {
|
|
22
|
+
const char = str.charCodeAt(i);
|
|
23
|
+
|
|
24
|
+
hash = (hash << 5) - hash + char;
|
|
25
|
+
hash &= hash;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return new Uint32Array([hash])[0].toString(36);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Quick, simple hash function to generate hash for an object
|
|
32
|
+
function hashObj(obj) {
|
|
33
|
+
return hash(JSON.stringify(obj, null, 2));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function flush() {
|
|
37
|
+
state.queue.forEach((schema) => {
|
|
38
|
+
const hash = hashObj(schema);
|
|
39
|
+
const existing = state.schemas[schema.id];
|
|
40
|
+
|
|
41
|
+
if (!existing || (existing && existing !== hash)) {
|
|
42
|
+
// console.log(`${ schema.id } CHANGED ${ hash } > ${ existing }`);
|
|
43
|
+
state.schemas[schema.id] = hash;
|
|
44
|
+
|
|
45
|
+
const msg = {
|
|
46
|
+
data: schema,
|
|
47
|
+
resourceType: SCHEMA,
|
|
48
|
+
type: 'resource.change'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
load(msg);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
state.queue = [];
|
|
56
|
+
|
|
57
|
+
state.flushTimer = setTimeout(flush, SCHEMA_FLUSH_TIMEOUT);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
state.flushTimer = setTimeout(flush, SCHEMA_FLUSH_TIMEOUT);
|
|
61
|
+
|
|
62
|
+
// Callback to the store's load function (in the main thread) to process a load
|
|
63
|
+
function load(data) {
|
|
64
|
+
if (state.load) {
|
|
65
|
+
state.load(data);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Web Worker API
|
|
70
|
+
const fns = {
|
|
71
|
+
initWorker(storeName, loadFn) {
|
|
72
|
+
state.store = storeName;
|
|
73
|
+
state.load = loadFn;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
destroyWorker() {
|
|
77
|
+
clearTimeout(state.countTimer);
|
|
78
|
+
clearTimeout(state.flushTimer);
|
|
79
|
+
|
|
80
|
+
// Web worker global function to terminate the web worker
|
|
81
|
+
close();
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
// Debounce counts messages so we only process at most 1 every 5 seconds
|
|
85
|
+
countsUpdate(resource) {
|
|
86
|
+
state.counts.push(resource);
|
|
87
|
+
|
|
88
|
+
if (!state.countTimer) {
|
|
89
|
+
state.countTimer = setTimeout(() => {
|
|
90
|
+
const last = state.counts.pop();
|
|
91
|
+
|
|
92
|
+
state.counts = [];
|
|
93
|
+
state.countTimer = null;
|
|
94
|
+
|
|
95
|
+
load(last);
|
|
96
|
+
}, COUNTS_FLUSH_TIMEOUT);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// Called to load schema
|
|
101
|
+
loadSchema(schemas) {
|
|
102
|
+
schemas.forEach((schema) => {
|
|
103
|
+
// These properties are added to the object, but aren't on the raw object, so remove them
|
|
104
|
+
// otherwise our comparison will show changes when there aren't any
|
|
105
|
+
delete schema._id;
|
|
106
|
+
delete schema._group;
|
|
107
|
+
|
|
108
|
+
state.schemas[schema.id] = hashObj(schema);
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
// Called when schema is updated
|
|
113
|
+
updateSchema(schema) {
|
|
114
|
+
// Add the schema to the queue to be checked to see if the schema really changed
|
|
115
|
+
state.queue.push(schema);
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Remove the cached schema
|
|
119
|
+
removeSchema(id) {
|
|
120
|
+
// Remove anything in the queue related to the schema - we don't want to send any pending updates later for a schema that has been removed
|
|
121
|
+
state.queue = state.queue.filter(schema => schema.id !== id);
|
|
122
|
+
|
|
123
|
+
// Delete the schema from the map, so if it comes back we don't ignore it if the hash is the same
|
|
124
|
+
delete state.schemas[id];
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Expose the Web Worker API - see: https://github.com/GoogleChromeLabs/comlink
|
|
129
|
+
Comlink.expose(fns);
|
|
@@ -3,6 +3,7 @@ import { mapState, mapGetters } from 'vuex';
|
|
|
3
3
|
import { HCI } from '@shell/config/types';
|
|
4
4
|
import { isEmpty } from '@shell/utils/object';
|
|
5
5
|
import Parse from 'url-parse';
|
|
6
|
+
import { resourceNames } from '@shell/utils/string';
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
9
|
name: 'HarvesterPromptRemove',
|
|
@@ -64,22 +65,6 @@ export default {
|
|
|
64
65
|
|
|
65
66
|
return this.t('promptRemove.andOthers', { count: remaining });
|
|
66
67
|
},
|
|
67
|
-
|
|
68
|
-
resourceNames() {
|
|
69
|
-
return this.names.reduce((res, name, i) => {
|
|
70
|
-
if (i >= 5) {
|
|
71
|
-
return res;
|
|
72
|
-
}
|
|
73
|
-
res += `<b>${ name }</b>`;
|
|
74
|
-
if (i === this.names.length - 1) {
|
|
75
|
-
res += this.plusMore;
|
|
76
|
-
} else {
|
|
77
|
-
res += i === this.toRemove.length - 2 ? ' and ' : ', ';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return res;
|
|
81
|
-
}, '');
|
|
82
|
-
}
|
|
83
68
|
},
|
|
84
69
|
|
|
85
70
|
watch: {
|
|
@@ -97,6 +82,7 @@ export default {
|
|
|
97
82
|
},
|
|
98
83
|
|
|
99
84
|
methods: {
|
|
85
|
+
resourceNames,
|
|
100
86
|
remove() {
|
|
101
87
|
const parentComponent = this.$parent.$parent.$parent;
|
|
102
88
|
|
|
@@ -148,7 +134,7 @@ export default {
|
|
|
148
134
|
<template>
|
|
149
135
|
<div class="mt-10">
|
|
150
136
|
{{ t('promptRemove.attemptingToRemove', {type}) }}
|
|
151
|
-
<span v-html="resourceNames"></span>
|
|
137
|
+
<span v-html="resourceNames(names, plusMore, t)"></span>
|
|
152
138
|
|
|
153
139
|
<div class="mt-10">
|
|
154
140
|
{{ t('harvester.virtualMachine.promptRemove.title') }}
|