@rancher/shell 0.3.4 → 0.3.6
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/images/providers/outscale.svg +19 -0
- package/assets/styles/app.scss +1 -1
- package/assets/styles/base/_basic.scss +18 -0
- package/assets/styles/base/_mixins.scss +0 -11
- package/assets/styles/base/_variables.scss +2 -4
- package/assets/styles/fonts/_fontstack.scss +11 -11
- package/assets/styles/global/_button.scss +12 -2
- package/assets/styles/vendor/vue-js-modal.scss +3 -3
- package/assets/translations/en-us.yaml +113 -22
- package/assets/translations/zh-hans.yaml +113 -24
- package/babel.config.js +13 -0
- package/chart/gatekeeper.vue +78 -0
- package/chart/istio.vue +135 -112
- package/chart/logging/index.vue +13 -4
- package/chart/monitoring/index.vue +15 -5
- package/chart/monitoring/steps/uninstall-v1.vue +2 -2
- package/chart/rancher-backup/index.vue +10 -3
- package/cloud-credential/aws.vue +1 -1
- package/cloud-credential/digitalocean.vue +1 -1
- package/cloud-credential/gcp.vue +1 -1
- package/cloud-credential/generic.vue +2 -2
- package/cloud-credential/linode.vue +1 -1
- package/cloud-credential/pnap.vue +1 -1
- package/components/ActionMenu.vue +3 -4
- package/components/AssignTo.vue +1 -1
- package/components/AsyncButton.vue +1 -1
- package/components/BannerGraphic.vue +1 -1
- package/components/BrandImage.vue +1 -4
- package/components/ButtonDropdown.vue +2 -3
- package/components/Carousel.vue +85 -37
- package/components/ChartPsp.vue +76 -0
- package/components/CruResource.vue +6 -2
- package/components/DashboardMetrics.vue +12 -10
- package/components/DetailText.vue +1 -1
- package/components/DisableAuthProviderModal.vue +1 -1
- package/components/EmberPage.vue +1 -1
- package/components/EtcdInfoBanner.vue +12 -7
- package/components/ExplorerMembers.vue +101 -6
- package/components/ExplorerProjectsNamespaces.vue +46 -3
- package/components/FileDiff.vue +6 -7
- package/components/GrafanaDashboard.vue +27 -23
- package/components/LazyImage.vue +10 -12
- package/components/LogItem.vue +1 -1
- package/components/Markdown.vue +1 -1
- package/components/PromptRemove.vue +2 -2
- package/components/PromptRestore.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +16 -0
- package/components/ResourceDetail/index.vue +21 -4
- package/components/ResourceList/index.vue +1 -1
- package/components/ResourceTable.vue +4 -1
- package/components/SingleClusterInfo.vue +2 -2
- package/components/SortableTable/THead.vue +1 -1
- package/components/SortableTable/index.vue +28 -13
- package/components/SortableTable/selection.js +58 -50
- package/components/Wizard.vue +4 -2
- package/components/__tests__/AsyncButton.test.ts +3 -1
- package/components/__tests__/ChartPsp.test.ts +75 -0
- package/components/__tests__/CruResource.test.ts +3 -1
- package/components/auth/Principal.vue +1 -1
- package/components/auth/RoleDetailEdit.vue +2 -2
- package/components/fleet/FleetBundles.vue +3 -1
- package/components/fleet/FleetClusters.vue +1 -2
- package/components/fleet/FleetIntro.vue +9 -1
- package/components/fleet/FleetNoWorkspaces.vue +62 -0
- package/components/fleet/FleetSummary.vue +7 -1
- package/components/form/HookOption.vue +14 -10
- package/components/form/LabeledSelect.vue +14 -11
- package/components/form/Labels.vue +32 -27
- package/components/form/MatchExpressions.vue +19 -4
- package/components/form/Members/ClusterPermissionsEditor.vue +32 -7
- package/components/form/NameNsDescription.vue +32 -46
- package/components/form/ProjectMemberEditor.vue +46 -21
- package/components/form/ResourceSelector.vue +1 -1
- package/components/form/SecretSelector.vue +5 -1
- package/components/form/ServiceNameSelect.vue +1 -1
- package/components/form/SimpleSecretSelector.vue +9 -9
- package/components/form/Tolerations.vue +4 -1
- package/components/form/ValueFromResource.vue +14 -9
- package/components/form/WorkloadPorts.vue +2 -2
- package/components/form/__tests__/LabeledSelect.test.ts +138 -0
- package/components/form/__tests__/NameNsDescription.ts +59 -0
- package/components/formatter/InternalExternalIP.vue +6 -0
- package/components/formatter/InvolvedObjectLink.vue +54 -0
- package/components/formatter/Link.vue +20 -4
- package/components/formatter/LinkName.vue +6 -1
- package/components/formatter/ServiceTargets.vue +1 -1
- package/components/formatter/WorkloadHealthScale.vue +8 -2
- package/components/nav/Group.vue +2 -2
- package/components/nav/NamespaceFilter.vue +23 -11
- package/components/nav/TopLevelMenu.vue +2 -4
- package/components/nav/Type.vue +1 -1
- package/components/nav/WorkspaceSwitcher.vue +46 -5
- package/components/nuxt/nuxt-build-indicator.vue +143 -0
- package/components/nuxt/nuxt-child.js +122 -0
- package/components/nuxt/nuxt-error.vue +98 -0
- package/components/nuxt/nuxt-link.client.js +98 -0
- package/components/nuxt/nuxt-link.server.js +16 -0
- package/components/nuxt/nuxt-loading.vue +154 -0
- package/components/nuxt/nuxt.js +101 -0
- package/config/labels-annotations.js +17 -0
- package/config/middleware.js +12 -0
- package/config/product/auth.js +3 -2
- package/config/product/explorer.js +34 -6
- package/config/product/fleet.js +2 -0
- package/config/query-params.js +1 -0
- package/config/router.js +414 -0
- package/config/store.js +181 -0
- package/config/table-headers.js +54 -12
- package/config/types.js +18 -8
- package/config/uiplugins.js +30 -0
- package/content/docs/en-us/whats-new.md +10 -0
- package/content/docs/zh-hans/whats-new.md +11 -1
- package/core/plugin-routes.ts +23 -0
- package/core/plugin.ts +4 -2
- package/core/types.ts +258 -1
- package/creators/app/app.package.json +2 -1
- package/creators/app/files/.eslintrc.js +1 -1
- package/creators/app/files/babel.config.js +1 -18
- package/creators/app/files/tsconfig.json +0 -1
- package/creators/app/files/vue.config.js +6 -0
- package/creators/app/init +5 -5
- package/creators/pkg/files/.github/workflows/build-extension.yml +110 -0
- package/creators/pkg/files/tsconfig.json +0 -1
- package/creators/pkg/init +35 -4
- package/creators/pkg/pkg.package.json +3 -3
- package/creators/update/init +1 -1
- package/detail/constraints.gatekeeper.sh.constraint.vue +34 -17
- package/detail/fleet.cattle.io.clustergroup.vue +7 -1
- package/detail/fleet.cattle.io.gitrepo.vue +19 -11
- package/detail/harvesterhci.io.management.cluster.vue +3 -3
- package/detail/provisioning.cattle.io.cluster.vue +54 -12
- package/detail/workload/index.vue +3 -3
- package/dialog/AddClusterMemberDialog.vue +1 -1
- package/dialog/AddProjectMemberDialog.vue +2 -2
- package/dialog/AddonConfigConfirmationDialog.vue +27 -15
- package/dialog/DiagnosticTimingsDialog.vue +1 -1
- package/dialog/ForceMachineRemoveDialog.vue +1 -1
- package/dialog/GenericPrompt.vue +18 -6
- package/dialog/RotateEncryptionKeyDialog.vue +1 -1
- package/dialog/SaveAsRKETemplateDialog.vue +1 -1
- package/dialog/ScaleMachineDownDialog.vue +1 -1
- package/edit/auth/github.vue +8 -8
- package/edit/auth/googleoauth.vue +5 -5
- package/edit/auth/ldap/index.vue +1 -1
- package/edit/auth/oidc.vue +1 -1
- package/edit/auth/saml.vue +1 -1
- package/edit/cis.cattle.io.clusterscan.vue +1 -1
- package/edit/fleet.cattle.io.clustergroup.vue +6 -4
- package/edit/fleet.cattle.io.gitrepo.vue +32 -4
- package/edit/helm.cattle.io.projecthelmchart.vue +5 -1
- package/edit/logging.banzaicloud.io.output/index.vue +18 -5
- package/edit/logging.banzaicloud.io.output/providers/loki.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +141 -6
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +4 -1
- package/edit/management.cattle.io.setting.vue +1 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/tls.vue +18 -18
- package/edit/monitoring.coreos.com.receiver/types/webhook.banner.vue +4 -4
- package/edit/monitoring.coreos.com.receiver/types/webhook.vue +1 -1
- package/edit/namespace.vue +14 -10
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +126 -45
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +21 -4
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +202 -2
- package/edit/provisioning.cattle.io.cluster/import.vue +23 -25
- package/edit/provisioning.cattle.io.cluster/rke2.vue +344 -102
- package/edit/resources.cattle.io.backup.vue +1 -1
- package/edit/service.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +2 -2
- package/edit/workload/__tests__/Job.test.ts +3 -1
- package/edit/workload/index.vue +8 -3
- package/edit/workload/mixins/workload.js +22 -7
- package/edit/workload/storage/Mount.vue +3 -3
- package/initialize/App.js +206 -0
- package/initialize/client.js +863 -0
- package/initialize/index.js +364 -0
- package/layouts/default.vue +7 -3
- package/layouts/standalone.vue +13 -0
- package/list/catalog.cattle.io.clusterrepo.vue +1 -0
- package/list/fleet.cattle.io.bundle.vue +6 -3
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +3 -1
- package/list/fleet.cattle.io.gitrepo.vue +44 -5
- package/list/management.cattle.io.fleetworkspace.vue +45 -0
- package/list/node.vue +69 -16
- package/list/provisioning.cattle.io.cluster.vue +30 -1
- package/list/rbac.authorization.k8s.io.clusterrolebinding.vue +48 -0
- package/list/workload.vue +6 -4
- package/machine-config/azure.vue +97 -38
- package/middleware/authenticated.js +34 -0
- package/mixins/chart.js +101 -2
- package/mixins/fetch.client.js +95 -0
- package/mixins/fetch.server.js +73 -0
- package/mixins/labeled-form-element.ts +2 -2
- package/mixins/resource-fetch.js +2 -2
- package/models/apps.statefulset.js +28 -0
- package/models/cluster/node.js +23 -2
- package/models/cluster.x-k8s.io.machine.js +4 -2
- package/models/clusterroletemplatebinding.js +7 -0
- package/models/constraints.gatekeeper.sh.constraint.js +46 -0
- package/models/fleet.cattle.io.cluster.js +19 -10
- package/models/fleet.cattle.io.gitrepo.js +7 -2
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.fleetworkspace.js +12 -0
- package/models/management.cattle.io.gitreporestriction.js +5 -0
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.js +3 -0
- package/models/pod.js +4 -0
- package/models/provisioning.cattle.io.cluster.js +7 -5
- package/models/rbac.authorization.k8s.io.clusterrolebinding.js +16 -0
- package/models/rbac.authorization.k8s.io.rolebinding.js +16 -0
- package/package.json +13 -21
- package/pages/auth/setup.vue +2 -2
- package/pages/c/_cluster/apps/charts/__tests__/install.helper.test.ts +33 -0
- package/pages/c/_cluster/apps/charts/chart.vue +4 -4
- package/pages/c/_cluster/apps/charts/install.helpers.js +26 -0
- package/pages/c/_cluster/apps/charts/install.vue +98 -102
- package/pages/c/_cluster/explorer/EventsTable.vue +5 -19
- package/pages/c/_cluster/explorer/index.vue +29 -25
- package/pages/c/_cluster/explorer/tools/index.vue +8 -8
- package/pages/c/_cluster/fleet/index.vue +95 -34
- package/pages/c/_cluster/gatekeeper/index.vue +1 -1
- package/pages/c/_cluster/istio/index.vue +5 -5
- package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
- package/pages/c/_cluster/monitoring/index.vue +7 -0
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +8 -8
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +20 -7
- package/pages/c/_cluster/uiplugins/index.vue +49 -17
- package/pages/diagnostic.vue +32 -25
- package/pages/home.vue +9 -4
- package/pages/index.vue +10 -1
- package/pages/rio/mesh.vue +1 -2
- package/pkg/tsconfig.json +0 -1
- package/plugins/clean-html-directive.js +34 -0
- package/plugins/dashboard-store/actions.js +32 -9
- package/plugins/dashboard-store/index.js +1 -1
- package/plugins/dashboard-store/mutations.js +5 -2
- package/plugins/dashboard-store/resource-class.js +8 -1
- package/plugins/plugin.js +0 -14
- package/plugins/portal-vue.js +4 -0
- package/plugins/steve/mutations.js +3 -2
- package/plugins/steve/steve-description-class.js +5 -1
- package/plugins/steve/subscribe.js +63 -54
- package/plugins/steve-create-worker.js +14 -0
- package/promptRemove/management.cattle.io.globalrole.vue +2 -2
- package/promptRemove/management.cattle.io.project.vue +2 -2
- package/promptRemove/management.cattle.io.roletemplate.vue +2 -2
- package/promptRemove/pod.vue +1 -1
- package/public/index.html +65 -0
- package/rancher-components/components/Banner/Banner.test.ts +7 -1
- package/rancher-components/components/Banner/Banner.vue +2 -1
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -0
- package/rancher-components/components/Form/Radio/RadioButton.test.ts +31 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +14 -3
- package/scripts/build-pkg.sh +1 -0
- package/scripts/clean +6 -0
- package/scripts/extension/bundle +58 -0
- package/scripts/extension/helmpatch +89 -0
- package/scripts/extension/publish +333 -0
- package/scripts/serve-pkgs +6 -2
- package/scripts/test-plugins-build.sh +4 -0
- package/store/__tests__/index.test.ts +110 -0
- package/store/index.js +145 -58
- package/store/type-map.js +6 -2
- package/tsconfig.default.json +36 -0
- package/tsconfig.json +23 -0
- package/types/rancher/index.d.ts +2 -0
- package/types/shell/index.d.ts +466 -320
- package/utils/__tests__/grafana.test.ts +44 -0
- package/utils/__tests__/string.test.ts +12 -0
- package/utils/auth.js +65 -0
- package/utils/axios.js +190 -0
- package/utils/cookie-universal-nuxt.js +10 -0
- package/utils/dom.js +15 -0
- package/utils/grafana.js +35 -16
- package/utils/monitoring.js +2 -1
- package/utils/nuxt.js +659 -0
- package/utils/position.js +5 -8
- package/utils/router.scrollBehavior.js +80 -0
- package/utils/select.js +1 -3
- package/utils/socket.js +1 -0
- package/utils/string.js +13 -0
- package/utils/time.js +9 -0
- package/vue.config.js +690 -0
- package/chart/rancher-alerting-drivers.vue +0 -53
- package/chart/rancher-gatekeeper.vue +0 -37
- package/creators/app/files/nuxt.config.js +0 -6
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +0 -4
- package/nuxt.config.js +0 -798
- package/plugins/dashboard-store/extensions.js +0 -22
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
|
|
3
|
+
|
|
4
|
+
describe('component: LabeledSelect', () => {
|
|
5
|
+
describe('should display correct label', () => {
|
|
6
|
+
it('given an existing value and option', () => {
|
|
7
|
+
const label = 'Foo';
|
|
8
|
+
const value = 'foo';
|
|
9
|
+
const wrapper = mount(LabeledSelect, {
|
|
10
|
+
propsData: {
|
|
11
|
+
value,
|
|
12
|
+
options: [
|
|
13
|
+
{ label, value },
|
|
14
|
+
],
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Component is from a library and class is not going to be changed
|
|
19
|
+
expect(wrapper.find('.vs__selected').text()).toBe(label);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('using value as label if no options', () => {
|
|
23
|
+
const value = 'foo';
|
|
24
|
+
const wrapper = mount(LabeledSelect, {
|
|
25
|
+
propsData: {
|
|
26
|
+
value,
|
|
27
|
+
options: [],
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Component is from a library and class is not going to be changed
|
|
32
|
+
expect(wrapper.find('.vs__selected').text()).toBe(value);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('using custom key as label for option object', () => {
|
|
36
|
+
const value = 'foo';
|
|
37
|
+
const label = 'Foo';
|
|
38
|
+
const customLabelKey = 'bananas';
|
|
39
|
+
const wrapper = mount(LabeledSelect, {
|
|
40
|
+
propsData: {
|
|
41
|
+
value,
|
|
42
|
+
optionLabel: customLabelKey,
|
|
43
|
+
options: [{
|
|
44
|
+
[customLabelKey]: label,
|
|
45
|
+
value
|
|
46
|
+
}],
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Component is from a library and class is not going to be changed
|
|
51
|
+
expect(wrapper.find('.vs__selected').text()).toBe(label);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('translating localized cases', () => {
|
|
55
|
+
const value = 'foo';
|
|
56
|
+
const translation = 'bananas';
|
|
57
|
+
const wrapper = mount(LabeledSelect, {
|
|
58
|
+
propsData: {
|
|
59
|
+
localizedLabel: true,
|
|
60
|
+
value,
|
|
61
|
+
options: [{ label: 'whatever', value }],
|
|
62
|
+
},
|
|
63
|
+
mocks: { $store: { getters: { 'i18n/t': () => translation } } }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Component is from a library and class is not going to be changed
|
|
67
|
+
expect(wrapper.find('.vs__selected').text()).toBe(translation);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('updating the value on options change', () => {
|
|
71
|
+
it('using new label', async() => {
|
|
72
|
+
const value = 'foo';
|
|
73
|
+
const oldLabel = 'Foo';
|
|
74
|
+
const newLabel = 'Baz';
|
|
75
|
+
const wrapper = mount(LabeledSelect, {
|
|
76
|
+
propsData: {
|
|
77
|
+
value,
|
|
78
|
+
options: [
|
|
79
|
+
{ label: oldLabel, value },
|
|
80
|
+
],
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await wrapper.setProps({
|
|
85
|
+
options: [
|
|
86
|
+
{ label: newLabel, value },
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Component is from a library and class is not going to be changed
|
|
91
|
+
expect(wrapper.find('.vs__selected').text()).toBe(newLabel);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('using values only and no labels', async() => {
|
|
95
|
+
const value = 'foo';
|
|
96
|
+
const newValue = 'bananas';
|
|
97
|
+
const wrapper = mount(LabeledSelect, {
|
|
98
|
+
propsData: {
|
|
99
|
+
value,
|
|
100
|
+
options: [value],
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await wrapper.setProps({ options: [newValue] });
|
|
105
|
+
|
|
106
|
+
// Component is from a library and class is not going to be changed
|
|
107
|
+
expect(wrapper.find('.vs__selected').text()).toBe(value);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('using translated value', async() => {
|
|
111
|
+
const value = 'foo';
|
|
112
|
+
const oldLabel = 'Foo';
|
|
113
|
+
const newLabel = 'Baz';
|
|
114
|
+
const translation = 'bananas';
|
|
115
|
+
const i18nMap: Record<string, string> = { [newLabel]: translation };
|
|
116
|
+
const wrapper = mount(LabeledSelect, {
|
|
117
|
+
propsData: {
|
|
118
|
+
value,
|
|
119
|
+
localizedLabel: true,
|
|
120
|
+
options: [
|
|
121
|
+
{ label: oldLabel, value },
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
mocks: { $store: { getters: { 'i18n/t': (text: string) => i18nMap[text] } } }
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
await wrapper.setProps({
|
|
128
|
+
options: [
|
|
129
|
+
{ label: newLabel, value },
|
|
130
|
+
]
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Component is from a library and class is not going to be changed
|
|
134
|
+
expect(wrapper.find('.vs__selected').text()).toBe(translation);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import NameNsDescription from '@shell/components/form/NameNsDescription.vue';
|
|
3
|
+
|
|
4
|
+
describe('component: NameNsDescription', () => {
|
|
5
|
+
// Accessing to computed value due code complexity
|
|
6
|
+
it('should map namespaces to options', () => {
|
|
7
|
+
const namespaceName = 'test';
|
|
8
|
+
const result = [{
|
|
9
|
+
label: namespaceName,
|
|
10
|
+
value: namespaceName
|
|
11
|
+
}];
|
|
12
|
+
const wrapper = mount(NameNsDescription, {
|
|
13
|
+
propsData: {
|
|
14
|
+
value: {},
|
|
15
|
+
mode: 'create',
|
|
16
|
+
},
|
|
17
|
+
mocks: {
|
|
18
|
+
$store: {
|
|
19
|
+
getters: {
|
|
20
|
+
namespaces: jest.fn(),
|
|
21
|
+
allowedNamespaces: () => ({ [namespaceName]: true }),
|
|
22
|
+
currentStore: () => 'cluster',
|
|
23
|
+
'cluster/schemaFor': jest.fn(),
|
|
24
|
+
'i18n/t': jest.fn()
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect((wrapper.vm as any).options).toStrictEqual(result);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should emit in case of new namespace', () => {
|
|
34
|
+
const namespaceName = 'test';
|
|
35
|
+
const newNamespaceName = 'bananas';
|
|
36
|
+
const wrapper = mount(NameNsDescription, {
|
|
37
|
+
propsData: {
|
|
38
|
+
value: { metadata: {} },
|
|
39
|
+
mode: 'create',
|
|
40
|
+
},
|
|
41
|
+
mocks: {
|
|
42
|
+
$store: {
|
|
43
|
+
getters: {
|
|
44
|
+
namespaces: jest.fn(),
|
|
45
|
+
allowedNamespaces: () => ({ [namespaceName]: true }),
|
|
46
|
+
currentStore: () => 'cluster',
|
|
47
|
+
'cluster/schemaFor': jest.fn(),
|
|
48
|
+
'i18n/t': jest.fn()
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
$refs: { name: { focus: jest.fn() } }
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
(wrapper.vm as any).updateNamespace(newNamespaceName);
|
|
56
|
+
|
|
57
|
+
expect(wrapper.emitted().isNamespaceNew?.[0][0]).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
|
|
3
|
+
import LinkName from '@shell/components/formatter/LinkName.vue';
|
|
4
|
+
import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
components: { LinkName },
|
|
8
|
+
|
|
9
|
+
props: {
|
|
10
|
+
value: {
|
|
11
|
+
type: null,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
product: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: EXPLORER,
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
computed: {
|
|
21
|
+
kind() {
|
|
22
|
+
// this cover most of the usecases for events
|
|
23
|
+
if (this.value?.apiVersion && typeof this.value?.apiVersion === 'string') {
|
|
24
|
+
const versionParts = this.value.apiVersion.split('/');
|
|
25
|
+
|
|
26
|
+
if (versionParts.length === 1) {
|
|
27
|
+
return this.value.kind.toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return `${ versionParts[0] }.${ this.value.kind.toLowerCase() }`;
|
|
31
|
+
// covers Node events usecase
|
|
32
|
+
} else if (this.value?.kind && typeof this.value?.kind === 'string') {
|
|
33
|
+
return this.value?.kind.toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<span v-if="kind && value.kind && value.name">
|
|
44
|
+
<LinkName
|
|
45
|
+
:type="kind"
|
|
46
|
+
:value="`${value.kind} ${value.name}`"
|
|
47
|
+
:object-id="value.name"
|
|
48
|
+
:namespace="value.namespace"
|
|
49
|
+
:product="product"
|
|
50
|
+
:show-type="true"
|
|
51
|
+
/>
|
|
52
|
+
</span>
|
|
53
|
+
<span v-else />
|
|
54
|
+
</template>
|
|
@@ -138,17 +138,18 @@ export default {
|
|
|
138
138
|
<n-link
|
|
139
139
|
v-if="isInternal && href"
|
|
140
140
|
:to="href"
|
|
141
|
+
class="link-text-icon"
|
|
141
142
|
>
|
|
142
143
|
<i
|
|
143
144
|
v-if="beforeIconClass"
|
|
144
145
|
:class="beforeIconClass"
|
|
145
|
-
|
|
146
|
+
class="prefix"
|
|
146
147
|
/>
|
|
147
148
|
{{ label }}
|
|
148
149
|
<i
|
|
149
150
|
v-if="afterIconClass"
|
|
150
151
|
:class="afterIconClass"
|
|
151
|
-
|
|
152
|
+
class="suffix"
|
|
152
153
|
/>
|
|
153
154
|
</n-link>
|
|
154
155
|
<a
|
|
@@ -156,18 +157,33 @@ export default {
|
|
|
156
157
|
:href="href"
|
|
157
158
|
:rel="rel"
|
|
158
159
|
:target="target"
|
|
160
|
+
class="link-text-icon"
|
|
159
161
|
>
|
|
160
162
|
<i
|
|
161
163
|
v-if="beforeIconClass"
|
|
162
164
|
:class="beforeIconClass"
|
|
163
|
-
|
|
165
|
+
class="prefix"
|
|
164
166
|
/>
|
|
165
167
|
{{ label }}
|
|
166
168
|
<i
|
|
167
169
|
v-if="afterIconClass"
|
|
168
170
|
:class="afterIconClass"
|
|
169
|
-
|
|
171
|
+
class="suffix"
|
|
170
172
|
/>
|
|
171
173
|
</a>
|
|
172
174
|
<span v-else> {{ href }} {{ label }}</span>
|
|
173
175
|
</template>
|
|
176
|
+
<style lang="scss" scoped>
|
|
177
|
+
.link-text-icon {
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: top;
|
|
180
|
+
|
|
181
|
+
.prefix {
|
|
182
|
+
margin: 2px 2px 0 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.suffix {
|
|
186
|
+
margin: 2px 0 0 2px;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
</style>
|
|
@@ -18,6 +18,11 @@ export default {
|
|
|
18
18
|
default: '',
|
|
19
19
|
},
|
|
20
20
|
|
|
21
|
+
objectId: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: '',
|
|
24
|
+
},
|
|
25
|
+
|
|
21
26
|
product: {
|
|
22
27
|
type: String,
|
|
23
28
|
default: EXPLORER,
|
|
@@ -31,7 +36,7 @@ export default {
|
|
|
31
36
|
const params = {
|
|
32
37
|
resource: this.type,
|
|
33
38
|
namespace: this.namespace,
|
|
34
|
-
id: this.value,
|
|
39
|
+
id: this.objectId ? this.objectId : this.value,
|
|
35
40
|
product: this.product || EXPLORER,
|
|
36
41
|
};
|
|
37
42
|
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import Vue from 'vue';
|
|
3
3
|
import ProgressBarMulti from '@shell/components/ProgressBarMulti';
|
|
4
4
|
import PlusMinus from '@shell/components/form/PlusMinus';
|
|
5
|
-
import { SCALABLE_WORKLOAD_TYPES } from '@shell/config/types';
|
|
5
|
+
import { POD, SCALABLE_WORKLOAD_TYPES } from '@shell/config/types';
|
|
6
6
|
import { ucFirst } from '@shell/utils/string';
|
|
7
7
|
|
|
8
8
|
const SCALABLE_TYPES = Object.values(SCALABLE_WORKLOAD_TYPES);
|
|
9
|
+
const INVALID_TYPES = [POD];
|
|
9
10
|
|
|
10
11
|
export default {
|
|
11
12
|
components: { PlusMinus, ProgressBarMulti },
|
|
@@ -47,6 +48,10 @@ export default {
|
|
|
47
48
|
return !!SCALABLE_TYPES.includes(this.row.type) && this.row.canUpdate;
|
|
48
49
|
},
|
|
49
50
|
|
|
51
|
+
canShow() {
|
|
52
|
+
return !INVALID_TYPES.includes(this.row.type);
|
|
53
|
+
},
|
|
54
|
+
|
|
50
55
|
parts() {
|
|
51
56
|
return this.cParts;
|
|
52
57
|
},
|
|
@@ -162,8 +167,9 @@ export default {
|
|
|
162
167
|
</script>
|
|
163
168
|
|
|
164
169
|
<template>
|
|
170
|
+
<div v-if="!canShow" />
|
|
165
171
|
<div
|
|
166
|
-
v-if="loading"
|
|
172
|
+
v-else-if="loading"
|
|
167
173
|
class="hs-popover__loader"
|
|
168
174
|
>
|
|
169
175
|
<i class="icon icon-spinner" />
|
package/components/nav/Group.vue
CHANGED
|
@@ -202,11 +202,11 @@ export default {
|
|
|
202
202
|
:to="group.children[0].route"
|
|
203
203
|
:exact="group.children[0].exact"
|
|
204
204
|
>
|
|
205
|
-
<h6 v-html="group.labelDisplay || group.label" />
|
|
205
|
+
<h6 v-clean-html="group.labelDisplay || group.label" />
|
|
206
206
|
</n-link>
|
|
207
207
|
<h6
|
|
208
208
|
v-else
|
|
209
|
-
v-html="group.labelDisplay || group.label"
|
|
209
|
+
v-clean-html="group.labelDisplay || group.label"
|
|
210
210
|
/>
|
|
211
211
|
</slot>
|
|
212
212
|
<i
|
|
@@ -105,13 +105,27 @@ export default {
|
|
|
105
105
|
const t = this.$store.getters['i18n/t'];
|
|
106
106
|
let out = [];
|
|
107
107
|
|
|
108
|
+
const params = { ...this.$route.params };
|
|
109
|
+
const resource = params.resource;
|
|
110
|
+
// Sometimes, different pages may have different namespaces to filter
|
|
111
|
+
const notFilterNamespaces = this.$store.getters[`type-map/optionsFor`](resource).notFilterNamespace || [];
|
|
112
|
+
|
|
108
113
|
// TODO: Add return info
|
|
109
114
|
if (this.currentProduct?.customNamespaceFilter && this.currentProduct?.inStore) {
|
|
110
115
|
// Sometimes the component can show before the 'currentProduct' has caught up, so access the product via the getter rather
|
|
111
116
|
// than caching it in the `fetch`
|
|
117
|
+
|
|
118
|
+
// The namespace display on the list and edit pages should be the same as in the namespaceFilter component
|
|
119
|
+
if (this.$store.getters[`${ this.currentProduct.inStore }/filterNamespace`]) {
|
|
120
|
+
const allNamespaces = this.$store.getters[`${ this.currentProduct.inStore }/filterNamespace`](notFilterNamespaces);
|
|
121
|
+
|
|
122
|
+
this.$store.commit('changeAllNamespaces', allNamespaces);
|
|
123
|
+
}
|
|
124
|
+
|
|
112
125
|
return this.$store.getters[`${ this.currentProduct.inStore }/namespaceFilterOptions`]({
|
|
113
126
|
addNamespace,
|
|
114
|
-
divider
|
|
127
|
+
divider,
|
|
128
|
+
notFilterNamespaces
|
|
115
129
|
});
|
|
116
130
|
}
|
|
117
131
|
|
|
@@ -371,17 +385,7 @@ export default {
|
|
|
371
385
|
return namespaces;
|
|
372
386
|
}
|
|
373
387
|
|
|
374
|
-
const isVirtualCluster = this.$store.getters['isVirtualCluster'];
|
|
375
|
-
|
|
376
388
|
return namespaces.filter((namespace) => {
|
|
377
|
-
const isSettingSystemNamespace = this.$store.getters['systemNamespaces'].includes(namespace.metadata.name);
|
|
378
|
-
const systemNS = namespace.isSystem || namespace.isFleetManaged || isSettingSystemNamespace;
|
|
379
|
-
|
|
380
|
-
// For Harvester, filter out system namespaces AND obscure namespaces.
|
|
381
|
-
if (isVirtualCluster) {
|
|
382
|
-
return !systemNS && !namespace.isObscure;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
389
|
// Otherwise only filter out obscure namespaces, such as namespaces
|
|
386
390
|
// that Rancher uses to manage RBAC for projects, which should not be
|
|
387
391
|
// edited or deleted by Rancher users.
|
|
@@ -949,6 +953,14 @@ export default {
|
|
|
949
953
|
color: var(--dropdown-hover-bg);
|
|
950
954
|
}
|
|
951
955
|
}
|
|
956
|
+
|
|
957
|
+
&:focus {
|
|
958
|
+
.ns-item {
|
|
959
|
+
> * {
|
|
960
|
+
color: var(--dropdown-hover-text);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
952
964
|
}
|
|
953
965
|
}
|
|
954
966
|
|
|
@@ -3,7 +3,6 @@ import BrandImage from '@shell/components/BrandImage';
|
|
|
3
3
|
import ClusterProviderIcon from '@shell/components/ClusterProviderIcon';
|
|
4
4
|
import IconOrSvg from '../IconOrSvg';
|
|
5
5
|
import { mapGetters } from 'vuex';
|
|
6
|
-
import $ from 'jquery';
|
|
7
6
|
import { CAPI, MANAGEMENT } from '@shell/config/types';
|
|
8
7
|
import { mapPref, MENU_MAX_CLUSTERS } from '@shell/store/prefs';
|
|
9
8
|
import { sortBy } from '@shell/utils/sort';
|
|
@@ -188,11 +187,10 @@ export default {
|
|
|
188
187
|
const max = Math.min(maxToShow, this.clusters.length);
|
|
189
188
|
|
|
190
189
|
if (el) {
|
|
191
|
-
const $el = $(el);
|
|
192
190
|
const h = 33 * max;
|
|
193
191
|
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
el.style.minHeight = `${ h }px`;
|
|
193
|
+
el.style.maxHeight = `${ h }px`;
|
|
196
194
|
}
|
|
197
195
|
},
|
|
198
196
|
handler(e) {
|
package/components/nav/Type.vue
CHANGED
|
@@ -90,9 +90,9 @@ export default {
|
|
|
90
90
|
><t :k="type.labelKey" /></span>
|
|
91
91
|
<span
|
|
92
92
|
v-else
|
|
93
|
+
v-clean-html="type.labelDisplay || type.label"
|
|
93
94
|
class="label"
|
|
94
95
|
:class="{'no-icon': !type.icon}"
|
|
95
|
-
v-html="type.labelDisplay || type.label"
|
|
96
96
|
/>
|
|
97
97
|
<span
|
|
98
98
|
v-if="showFavorite || showCount"
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { WORKSPACE } from '@shell/store/prefs';
|
|
2
|
+
import { LAST_NAMESPACE, WORKSPACE } from '@shell/store/prefs';
|
|
3
3
|
import { mapState } from 'vuex';
|
|
4
4
|
import Select from '@shell/components/form/Select';
|
|
5
|
+
import { WORKSPACE_ANNOTATION } from '@shell/config/labels-annotations';
|
|
5
6
|
|
|
6
7
|
export default {
|
|
8
|
+
name: 'WorkspaceSwitcher',
|
|
7
9
|
components: { Select },
|
|
8
10
|
|
|
9
11
|
computed: {
|
|
10
|
-
...mapState(['allWorkspaces', 'workspace']),
|
|
12
|
+
...mapState(['allWorkspaces', 'workspace', 'allNamespaces', 'defaultNamespace', 'getActiveNamespaces']),
|
|
11
13
|
|
|
12
14
|
value: {
|
|
13
15
|
get() {
|
|
14
|
-
return this.workspace;
|
|
16
|
+
return this.workspace || this.namespace || this.options[0]?.value;
|
|
15
17
|
},
|
|
16
18
|
|
|
17
19
|
set(value) {
|
|
@@ -23,17 +25,56 @@ export default {
|
|
|
23
25
|
},
|
|
24
26
|
|
|
25
27
|
options() {
|
|
26
|
-
|
|
28
|
+
if (this.allWorkspaces.length) {
|
|
29
|
+
const out = this.allWorkspaces.map((obj) => {
|
|
30
|
+
return {
|
|
31
|
+
label: obj.nameDisplay,
|
|
32
|
+
value: obj.id,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// If doesn't have workspaces (e.g. no permissions)
|
|
40
|
+
// Then find the workspaces from the annotation.
|
|
41
|
+
return this.allNamespaces.filter((item) => {
|
|
42
|
+
return item.metadata.annotations[WORKSPACE_ANNOTATION] === WORKSPACE;
|
|
43
|
+
}).map((obj) => {
|
|
27
44
|
return {
|
|
28
45
|
label: obj.nameDisplay,
|
|
29
46
|
value: obj.id,
|
|
30
47
|
};
|
|
31
48
|
});
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
watch: {
|
|
53
|
+
options(curr, prev) {
|
|
54
|
+
if (curr.length === 0) {
|
|
55
|
+
this.value = '';
|
|
56
|
+
}
|
|
32
57
|
|
|
33
|
-
|
|
58
|
+
const currentExists = curr.find(item => item.value === this.value);
|
|
59
|
+
|
|
60
|
+
if (curr.length && !currentExists) {
|
|
61
|
+
this.value = curr[0]?.value;
|
|
62
|
+
}
|
|
34
63
|
},
|
|
35
64
|
},
|
|
36
65
|
|
|
66
|
+
created() {
|
|
67
|
+
// in fleet standard user with just the project owner and global git repo permissions
|
|
68
|
+
// returns 'default'
|
|
69
|
+
const initValue = !this.workspace ? this.$store.getters['prefs/get'](LAST_NAMESPACE) : '';
|
|
70
|
+
|
|
71
|
+
this.value = (initValue === 'default' || initValue === '') && this.options.length ? this.options[0].value : initValue;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
data() {
|
|
75
|
+
return { namespace: this.$store.getters['prefs/get'](LAST_NAMESPACE) };
|
|
76
|
+
},
|
|
77
|
+
|
|
37
78
|
methods: {
|
|
38
79
|
focus() {
|
|
39
80
|
this.$refs.select.$refs.search.focus();
|