@rancher/shell 3.0.5-rc.8 → 3.0.5
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/_color.scss +4 -1
- package/assets/styles/global/_tooltip.scss +7 -4
- package/assets/styles/themes/_dark.scss +11 -0
- package/assets/styles/themes/_light.scss +13 -1
- package/assets/styles/themes/_modern.scss +22 -0
- package/assets/translations/en-us.yaml +147 -19
- package/assets/translations/zh-hans.yaml +0 -1
- package/chart/monitoring/grafana/index.vue +8 -2
- package/components/ActionMenuShell.vue +3 -1
- package/components/Cron/CronExpressionEditor.vue +299 -0
- package/components/Cron/CronExpressionEditorModal.vue +247 -0
- package/components/Cron/CronTooltip.vue +87 -0
- package/components/Cron/types.ts +13 -0
- package/components/ForceDirectedTreeChart/composable.ts +11 -0
- package/components/PodSecurityAdmission.vue +2 -0
- package/components/PromptModal.vue +1 -1
- package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +1 -0
- package/components/Resource/Detail/CopyToClipboard.vue +78 -0
- package/components/Resource/Detail/FetchLoader/__tests__/composables.test.ts +69 -0
- package/components/Resource/Detail/FetchLoader/composables.ts +27 -0
- package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
- package/components/Resource/Detail/Metadata/Annotations/index.vue +1 -1
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +13 -61
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +33 -6
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +24 -38
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +25 -5
- package/components/Resource/Detail/Metadata/KeyValue.vue +12 -23
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +144 -0
- package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -0
- package/components/Resource/Detail/Metadata/Labels/index.vue +1 -0
- package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +30 -32
- package/components/Resource/Detail/Metadata/__tests__/KeyValueRow.test.ts +108 -0
- package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +0 -3
- package/components/Resource/Detail/Metadata/__tests__/index.test.ts +12 -5
- package/components/Resource/Detail/Metadata/composables.ts +1 -4
- package/components/Resource/Detail/Metadata/index.vue +1 -0
- package/components/Resource/Detail/Preview/Content.vue +63 -0
- package/components/Resource/Detail/Preview/Preview.vue +128 -0
- package/components/Resource/Detail/Preview/__tests__/Content.spec.ts +71 -0
- package/components/Resource/Detail/Preview/__tests__/Preview.spec.ts +121 -0
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +141 -0
- package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +136 -0
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +245 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +226 -0
- package/components/Resource/Detail/SpacedRow.vue +1 -0
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +0 -5
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
- package/components/Resource/Detail/TitleBar/composables.ts +1 -3
- package/components/Resource/Detail/TitleBar/index.vue +2 -29
- package/components/Resource/Detail/ViewOptions/composable.ts +9 -0
- package/components/Resource/Detail/ViewOptions/index.vue +41 -0
- package/components/Resource/Detail/__tests__/CopyToClipboard.spec.ts +82 -0
- package/components/ResourceDetail/Masthead/legacy.vue +0 -19
- package/components/ResourceDetail/index.vue +1 -26
- package/components/ResourceTable.vue +24 -0
- package/components/SortableTable/index.vue +7 -1
- package/components/SortableTable/paging.js +3 -0
- package/components/Tabbed/Tab.vue +43 -1
- package/components/Tabbed/index.vue +3 -1
- package/components/__tests__/Cron/CronExpressionEditor.test.ts +151 -0
- package/components/__tests__/Cron/CronExpressionEditorModal.test.ts +81 -0
- package/components/auth/login/saml.vue +86 -0
- package/components/form/LabeledSelect.vue +8 -8
- package/components/form/ProjectMemberEditor.vue +2 -0
- package/components/form/ResourceTabs/composable.ts +54 -0
- package/components/form/ResourceTabs/index.vue +10 -7
- package/components/form/Select.vue +13 -10
- package/components/form/__tests__/LabeledSelect.test.ts +133 -0
- package/components/form/__tests__/Select.test.ts +134 -0
- package/components/nav/Header.vue +6 -5
- package/composables/useExtensionManager.ts +17 -0
- package/config/home-links.js +12 -0
- package/config/labels-annotations.js +0 -1
- package/config/page-actions.js +0 -1
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +2 -7
- package/config/product/manager.js +0 -5
- package/config/query-params.js +1 -0
- package/config/router/navigation-guards/clusters.js +2 -1
- package/config/router/navigation-guards/products.js +1 -1
- package/config/store.js +2 -0
- package/core/extension-manager-impl.js +518 -0
- package/core/plugins.js +35 -468
- package/core/types.ts +8 -2
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +1 -0
- package/detail/catalog.cattle.io.app.vue +7 -4
- package/detail/fleet.cattle.io.bundle.vue +1 -5
- package/detail/fleet.cattle.io.cluster.vue +3 -2
- package/detail/fleet.cattle.io.gitrepo.vue +76 -49
- package/detail/fleet.cattle.io.helmop.vue +78 -49
- package/dialog/AddonConfigConfirmationDialog.vue +1 -1
- package/dialog/GenericPrompt.vue +1 -1
- package/dialog/ImportDialog.vue +9 -2
- package/dialog/InstallExtensionDialog.vue +18 -10
- package/dialog/SloDialog.vue +1 -1
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -1
- package/edit/__tests__/resources.cattle.io.restore.test.ts +106 -0
- package/edit/auth/oidc.vue +106 -6
- package/edit/auth/saml.vue +5 -5
- package/edit/cloudcredential.vue +31 -17
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +10 -2
- package/edit/fleet.cattle.io.cluster.vue +19 -0
- package/edit/fleet.cattle.io.gitrepo.vue +23 -16
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +12 -11
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +14 -19
- package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -3
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +6 -0
- package/edit/resources.cattle.io.restore.vue +5 -8
- package/initialize/install-plugins.js +1 -3
- package/list/__tests__/workload.test.ts +1 -0
- package/list/workload.vue +8 -1
- package/machine-config/components/GCEImage.vue +6 -5
- package/machine-config/google.vue +11 -6
- package/mixins/__tests__/auth-config.test.ts +4 -6
- package/mixins/__tests__/chart.test.ts +139 -1
- package/mixins/auth-config.js +33 -10
- package/mixins/chart.js +58 -18
- package/models/__tests__/namespace.test.ts +69 -0
- package/models/apps.statefulset.js +8 -10
- package/models/chart.js +5 -1
- package/models/fleet-application.js +16 -46
- package/models/fleet.cattle.io.bundle.js +1 -38
- package/models/fleet.cattle.io.gitrepo.js +4 -0
- package/models/fleet.cattle.io.helmop.js +4 -0
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.project.js +12 -0
- package/models/namespace.js +30 -0
- package/models/workload.js +4 -1
- package/package.json +10 -10
- package/pages/auth/login.vue +8 -3
- package/pages/auth/logout.vue +6 -5
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +26 -11
- package/pages/c/_cluster/apps/charts/chart.vue +29 -20
- package/pages/c/_cluster/apps/charts/index.vue +1 -0
- package/pages/c/_cluster/apps/charts/install.vue +6 -5
- package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +102 -12
- package/pages/c/_cluster/explorer/tools/index.vue +145 -254
- package/pages/c/_cluster/manager/cloudCredential/index.vue +18 -1
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +12 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
- package/pages/c/_cluster/uiplugins/__tests__/index.spec.ts +318 -0
- package/pages/c/_cluster/uiplugins/index.vue +221 -363
- package/pages/home.vue +1 -9
- package/plugins/axios.js +3 -2
- package/plugins/dashboard-store/resource-class.js +49 -0
- package/plugins/ember-cookie.js +7 -3
- package/plugins/steve/subscribe.js +4 -2
- package/public/index.html +2 -1
- package/rancher-components/Card/Card.vue +1 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/Radio/RadioButton.vue +1 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +1 -1
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -11
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.test.ts +53 -0
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +65 -0
- package/rancher-components/Pill/RcCounterBadge/index.ts +1 -0
- package/rancher-components/Pill/RcCounterBadge/types.ts +7 -0
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/index.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -3
- package/rancher-components/Pill/RcStatusIndicator/types.ts +1 -1
- package/rancher-components/Pill/RcTag/RcTag.test.ts +64 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +94 -0
- package/rancher-components/Pill/RcTag/index.ts +1 -0
- package/rancher-components/Pill/RcTag/types.ts +9 -0
- package/rancher-components/Pill/types.ts +1 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -0
- package/rancher-components/RcItemCard/RcItemCardAction.vue +12 -0
- package/scripts/test-plugins-build.sh +0 -1
- package/store/__tests__/catalog.test.ts +63 -0
- package/store/__tests__/cookies.test.ts +72 -0
- package/store/auth.js +33 -10
- package/store/catalog.js +2 -2
- package/store/cookies.ts +30 -0
- package/store/prefs.js +10 -5
- package/store/type-map.js +3 -15
- package/types/extension-manager.ts +26 -0
- package/types/shell/index.d.ts +123 -27
- package/utils/__tests__/product.test.ts +129 -0
- package/utils/__tests__/resource.test.ts +87 -0
- package/utils/alertmanagerconfig.js +2 -2
- package/utils/auth.js +4 -77
- package/utils/product.ts +39 -0
- package/utils/resource.ts +35 -0
- package/utils/select.js +0 -24
- package/utils/validators/formRules/__tests__/index.test.ts +3 -0
- package/utils/validators/formRules/index.ts +2 -1
- package/vue.config.js +1 -1
- package/components/Resource/Detail/Metadata/Rectangle.vue +0 -34
- package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +0 -24
- package/components/ResourceDetail/Masthead/__tests__/legacy.test.ts +0 -65
- package/utils/cookie-universal.js +0 -10
- /package/components/{ForceDirectedTreeChart.vue → ForceDirectedTreeChart/index.vue} +0 -0
|
@@ -629,19 +629,19 @@ export default {
|
|
|
629
629
|
step1Description() {
|
|
630
630
|
const descriptionKey = this.steps.find((s) => s.name === 'basics').descriptionKey;
|
|
631
631
|
|
|
632
|
-
return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action, existing: !!this.existing }, '');
|
|
632
|
+
return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action.name, existing: !!this.existing }, '');
|
|
633
633
|
},
|
|
634
634
|
|
|
635
635
|
step2Description() {
|
|
636
636
|
const descriptionKey = this.steps.find((s) => s.name === 'helmValues').descriptionKey;
|
|
637
637
|
|
|
638
|
-
return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action, existing: !!this.existing }, '');
|
|
638
|
+
return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action.name, existing: !!this.existing }, '');
|
|
639
639
|
},
|
|
640
640
|
|
|
641
641
|
step3Description() {
|
|
642
642
|
const descriptionKey = this.steps.find((s) => s.name === 'helmCli').descriptionKey;
|
|
643
643
|
|
|
644
|
-
return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action, existing: !!this.existing }, '');
|
|
644
|
+
return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action.name, existing: !!this.existing }, '');
|
|
645
645
|
},
|
|
646
646
|
|
|
647
647
|
steps() {
|
|
@@ -1299,7 +1299,8 @@ export default {
|
|
|
1299
1299
|
:edit-first-step="true"
|
|
1300
1300
|
:banner-title="stepperName"
|
|
1301
1301
|
:banner-title-subtext="stepperSubtext"
|
|
1302
|
-
:finish-mode="action"
|
|
1302
|
+
:finish-mode="action.name"
|
|
1303
|
+
:header-mode="action.tKey"
|
|
1303
1304
|
class="wizard"
|
|
1304
1305
|
:class="{'windowsIncompatible': windowsIncompatible}"
|
|
1305
1306
|
@cancel="cancel"
|
|
@@ -1427,7 +1428,7 @@ export default {
|
|
|
1427
1428
|
<Checkbox
|
|
1428
1429
|
v-model:value="showCommandStep"
|
|
1429
1430
|
class="mb-20"
|
|
1430
|
-
:label="t('catalog.install.steps.helmCli.checkbox', { action, existing: !!existing })"
|
|
1431
|
+
:label="t('catalog.install.steps.helmCli.checkbox', { action: action.name, existing: !!existing })"
|
|
1431
1432
|
/>
|
|
1432
1433
|
|
|
1433
1434
|
<Checkbox
|
|
@@ -2,23 +2,29 @@ import { clone } from '@shell/utils/object';
|
|
|
2
2
|
import ClusterTools from '@shell/pages/c/_cluster/explorer/tools/index.vue';
|
|
3
3
|
import { shallowMount } from '@vue/test-utils';
|
|
4
4
|
import { MANAGEMENT } from '@shell/config/types';
|
|
5
|
+
import { RcItemCard } from '@components/RcItemCard';
|
|
6
|
+
import { APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
|
5
7
|
|
|
6
8
|
describe('page: cluster tools', () => {
|
|
7
9
|
const mountOptions = {
|
|
8
10
|
computed: {
|
|
9
|
-
|
|
11
|
+
appChartCards: () => [
|
|
10
12
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
|
|
13
|
+
id: 'cluster/rancher-charts/rancher-alerting-drivers',
|
|
14
|
+
header: { title: { text: 'Rancher Alerting Drivers' } },
|
|
15
|
+
content: { text: 'Some description' },
|
|
16
|
+
image: { src: '' },
|
|
17
|
+
subHeaderItems: [],
|
|
18
|
+
installedApp: { spec: { chart: { metadata: { version: '1.0.0' } } } },
|
|
19
|
+
rawChart: { versions: [{ version: '1.0.0' }], blocked: false }
|
|
16
20
|
}
|
|
17
21
|
]
|
|
18
22
|
},
|
|
19
|
-
|
|
23
|
+
methods: { getCardActions: (ClusterTools as any).methods.getCardActions },
|
|
24
|
+
global: {
|
|
20
25
|
mocks: {
|
|
21
26
|
$route: { query: {} },
|
|
27
|
+
t: (key: string) => key,
|
|
22
28
|
$fetchState: {
|
|
23
29
|
pending: false, error: true, timestamp: Date.now()
|
|
24
30
|
},
|
|
@@ -36,7 +42,7 @@ describe('page: cluster tools', () => {
|
|
|
36
42
|
}
|
|
37
43
|
},
|
|
38
44
|
currentCluster: { id: 'cluster', status: { provider: 'provider' } },
|
|
39
|
-
'i18n/t':
|
|
45
|
+
'i18n/t': (key: string) => key,
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
48
|
},
|
|
@@ -44,10 +50,10 @@ describe('page: cluster tools', () => {
|
|
|
44
50
|
};
|
|
45
51
|
|
|
46
52
|
it('should show apps catalog', async() => {
|
|
47
|
-
const wrapper = shallowMount(ClusterTools, mountOptions);
|
|
53
|
+
const wrapper = shallowMount(ClusterTools, { ...mountOptions, methods: { getCardActions: () => [] } });
|
|
48
54
|
|
|
49
55
|
await (ClusterTools as any).fetch.call(wrapper.vm);
|
|
50
|
-
const cards = wrapper.
|
|
56
|
+
const cards = wrapper.findComponent(RcItemCard);
|
|
51
57
|
|
|
52
58
|
expect(cards.exists()).toBe(true);
|
|
53
59
|
});
|
|
@@ -61,11 +67,95 @@ describe('page: cluster tools', () => {
|
|
|
61
67
|
}
|
|
62
68
|
};
|
|
63
69
|
|
|
64
|
-
const wrapper = shallowMount(ClusterTools, options);
|
|
70
|
+
const wrapper = shallowMount(ClusterTools, { ...options, methods: { getCardActions: () => [] } });
|
|
65
71
|
|
|
66
72
|
await (ClusterTools as any).fetch.call(wrapper.vm);
|
|
67
|
-
const cards = wrapper.
|
|
73
|
+
const cards = wrapper.findComponent(RcItemCard);
|
|
68
74
|
|
|
69
75
|
expect(cards.exists()).toBe(true);
|
|
70
76
|
});
|
|
77
|
+
|
|
78
|
+
describe('getCardActions', () => {
|
|
79
|
+
it('should return "install" action for an uninstalled chart', () => {
|
|
80
|
+
const wrapper = shallowMount(ClusterTools, mountOptions);
|
|
81
|
+
const card = {
|
|
82
|
+
installedApp: null,
|
|
83
|
+
rawChart: { blocked: false }
|
|
84
|
+
};
|
|
85
|
+
const actions = wrapper.vm.getCardActions(card);
|
|
86
|
+
|
|
87
|
+
expect(actions).toHaveLength(1);
|
|
88
|
+
expect(actions[0]).toStrictEqual({
|
|
89
|
+
label: 'catalog.tools.action.install',
|
|
90
|
+
action: 'install',
|
|
91
|
+
icon: 'icon-plus',
|
|
92
|
+
enabled: true
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should return all actions for an installed chart', () => {
|
|
97
|
+
const wrapper = shallowMount(ClusterTools, mountOptions);
|
|
98
|
+
const card = {
|
|
99
|
+
installedApp: {
|
|
100
|
+
spec: { chart: { metadata: { version: '1.0.1' } } },
|
|
101
|
+
upgradeAvailable: APP_UPGRADE_STATUS.SINGLE_UPGRADE
|
|
102
|
+
},
|
|
103
|
+
rawChart: { versions: [{ version: '1.0.2' }, { version: '1.0.1' }, { version: '1.0.0' }] }
|
|
104
|
+
};
|
|
105
|
+
const actions = wrapper.vm.getCardActions(card);
|
|
106
|
+
|
|
107
|
+
expect(actions).toHaveLength(5); // Upgrade, Edit, Downgrade, separator, Remove
|
|
108
|
+
expect(actions[0]).toStrictEqual({
|
|
109
|
+
label: 'catalog.tools.action.upgrade',
|
|
110
|
+
icon: 'icon-upgrade-alt',
|
|
111
|
+
action: 'upgrade'
|
|
112
|
+
});
|
|
113
|
+
expect(actions[1]).toStrictEqual({
|
|
114
|
+
label: 'catalog.tools.action.edit',
|
|
115
|
+
icon: 'icon-edit',
|
|
116
|
+
action: 'edit'
|
|
117
|
+
});
|
|
118
|
+
expect(actions[2]).toStrictEqual({
|
|
119
|
+
label: 'catalog.tools.action.downgrade',
|
|
120
|
+
icon: 'icon-downgrade-alt',
|
|
121
|
+
action: 'downgrade'
|
|
122
|
+
});
|
|
123
|
+
expect(actions[3]).toStrictEqual({ divider: true });
|
|
124
|
+
expect(actions[4]).toStrictEqual({
|
|
125
|
+
label: 'catalog.tools.action.remove',
|
|
126
|
+
icon: 'icon-delete',
|
|
127
|
+
action: 'remove'
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should not show upgrade if not available', () => {
|
|
132
|
+
const wrapper = shallowMount(ClusterTools, mountOptions);
|
|
133
|
+
const card = {
|
|
134
|
+
installedApp: {
|
|
135
|
+
spec: { chart: { metadata: { version: '1.0.2' } } },
|
|
136
|
+
upgradeAvailable: APP_UPGRADE_STATUS.NO_UPGRADE
|
|
137
|
+
},
|
|
138
|
+
rawChart: { versions: [{ version: '1.0.2' }, { version: '1.0.1' }, { version: '1.0.0' }] }
|
|
139
|
+
};
|
|
140
|
+
const actions = wrapper.vm.getCardActions(card);
|
|
141
|
+
|
|
142
|
+
expect(actions.find((a) => a.action === 'upgrade')).toBeUndefined();
|
|
143
|
+
expect(actions).toHaveLength(4); // Edit, Downgrade, separator, Remove
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should not show downgrade if not available', () => {
|
|
147
|
+
const wrapper = shallowMount(ClusterTools, mountOptions);
|
|
148
|
+
const card = {
|
|
149
|
+
installedApp: {
|
|
150
|
+
spec: { chart: { metadata: { version: '1.0.0' } } },
|
|
151
|
+
upgradeAvailable: APP_UPGRADE_STATUS.SINGLE_UPGRADE
|
|
152
|
+
},
|
|
153
|
+
rawChart: { versions: [{ version: '1.0.1' }, { version: '1.0.0' }] }
|
|
154
|
+
};
|
|
155
|
+
const actions = wrapper.vm.getCardActions(card);
|
|
156
|
+
|
|
157
|
+
expect(actions.find((a) => a.action === 'downgrade')).toBeUndefined();
|
|
158
|
+
expect(actions).toHaveLength(4); // Upgrade, Edit, separator, Remove
|
|
159
|
+
});
|
|
160
|
+
});
|
|
71
161
|
});
|
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
import { mapGetters } from 'vuex';
|
|
3
3
|
import Loading from '@shell/components/Loading';
|
|
4
4
|
import { _FLAGGED, DEPRECATED as DEPRECATED_QUERY, HIDDEN, FROM_TOOLS } from '@shell/config/query-params';
|
|
5
|
-
import { filterAndArrangeCharts } from '@shell/store/catalog';
|
|
5
|
+
import { filterAndArrangeCharts, APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
|
6
6
|
import { CATALOG, NORMAN } from '@shell/config/types';
|
|
7
7
|
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
8
|
-
import LazyImage from '@shell/components/LazyImage';
|
|
9
8
|
import { isAlternate } from '@shell/utils/platform';
|
|
10
9
|
import IconMessage from '@shell/components/IconMessage';
|
|
11
|
-
import TypeDescription from '@shell/components/TypeDescription';
|
|
12
10
|
import TabTitle from '@shell/components/TabTitle';
|
|
11
|
+
import { get } from '@shell/utils/object';
|
|
12
|
+
import { RcItemCard } from '@components/RcItemCard';
|
|
13
|
+
import AppChartCardSubHeader from '@shell/pages/c/_cluster/apps/charts/AppChartCardSubHeader';
|
|
14
|
+
import AppChartCardFooter from '@shell/pages/c/_cluster/apps/charts/AppChartCardFooter';
|
|
13
15
|
|
|
14
16
|
export default {
|
|
15
17
|
components: {
|
|
16
|
-
|
|
18
|
+
Loading, IconMessage, TabTitle, RcItemCard, AppChartCardSubHeader, AppChartCardFooter
|
|
17
19
|
},
|
|
18
20
|
|
|
19
21
|
async fetch() {
|
|
@@ -72,7 +74,7 @@ export default {
|
|
|
72
74
|
return out;
|
|
73
75
|
},
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
appChartCards() {
|
|
76
78
|
const clusterProvider = this.currentCluster.status.provider || 'other';
|
|
77
79
|
const enabledCharts = (this.allCharts || []);
|
|
78
80
|
|
|
@@ -86,14 +88,28 @@ export default {
|
|
|
86
88
|
|
|
87
89
|
charts = charts.filter((c) => c.sideLabel !== 'Experimental');
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
return charts.map((chart) => {
|
|
92
|
+
const installedApp = this.installedAppForChart[chart.id];
|
|
93
|
+
const card = {
|
|
94
|
+
id: chart.id,
|
|
95
|
+
header: {
|
|
96
|
+
title: { text: chart.chartNameDisplay },
|
|
97
|
+
statuses: chart.cardContent.statuses
|
|
98
|
+
},
|
|
99
|
+
subHeaderItems: chart.cardContent.subHeaderItems.slice(0, 1),
|
|
100
|
+
footerItems: chart.deploysOnWindows ? [{
|
|
101
|
+
icon: 'icon-tag-alt',
|
|
102
|
+
iconTooltip: { key: 'generic.tags' },
|
|
103
|
+
labels: [this.t('catalog.charts.deploysOnWindows')],
|
|
104
|
+
}] : [],
|
|
105
|
+
image: { src: chart.versions[0].icon, alt: { text: this.t('catalog.charts.iconAlt', { app: get(chart, 'chartNameDisplay') }) } },
|
|
106
|
+
content: { text: chart.chartDescription },
|
|
107
|
+
rawChart: chart,
|
|
108
|
+
installedApp,
|
|
93
109
|
};
|
|
94
|
-
});
|
|
95
110
|
|
|
96
|
-
|
|
111
|
+
return card;
|
|
112
|
+
});
|
|
97
113
|
},
|
|
98
114
|
},
|
|
99
115
|
|
|
@@ -114,6 +130,77 @@ export default {
|
|
|
114
130
|
},
|
|
115
131
|
|
|
116
132
|
methods: {
|
|
133
|
+
getCardActions(card) {
|
|
134
|
+
const { installedApp, rawChart } = card;
|
|
135
|
+
|
|
136
|
+
if (installedApp) {
|
|
137
|
+
const actions = [];
|
|
138
|
+
const upgradeAvailable = installedApp.upgradeAvailable === APP_UPGRADE_STATUS.SINGLE_UPGRADE;
|
|
139
|
+
|
|
140
|
+
if (upgradeAvailable) {
|
|
141
|
+
actions.push({
|
|
142
|
+
label: this.t('catalog.tools.action.upgrade'),
|
|
143
|
+
icon: 'icon-upgrade-alt',
|
|
144
|
+
action: 'upgrade',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
actions.push({
|
|
149
|
+
label: this.t('catalog.tools.action.edit'),
|
|
150
|
+
icon: 'icon-edit',
|
|
151
|
+
action: 'edit',
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const currentVersion = installedApp.spec.chart.metadata.version;
|
|
155
|
+
const versions = rawChart.versions;
|
|
156
|
+
const currentIndex = versions.findIndex((v) => v.version === currentVersion);
|
|
157
|
+
|
|
158
|
+
if (currentIndex !== -1 && currentIndex < versions.length - 1) {
|
|
159
|
+
actions.push({
|
|
160
|
+
label: this.t('catalog.tools.action.downgrade'),
|
|
161
|
+
icon: 'icon-downgrade-alt',
|
|
162
|
+
action: 'downgrade',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
actions.push({ divider: true });
|
|
167
|
+
|
|
168
|
+
actions.push({
|
|
169
|
+
label: this.t('catalog.tools.action.remove'),
|
|
170
|
+
icon: 'icon-delete',
|
|
171
|
+
action: 'remove',
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return actions;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return [
|
|
178
|
+
{
|
|
179
|
+
label: this.t('catalog.tools.action.install'),
|
|
180
|
+
action: 'install',
|
|
181
|
+
icon: 'icon-plus',
|
|
182
|
+
enabled: !rawChart.blocked
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
},
|
|
186
|
+
upgrade(app, chart) {
|
|
187
|
+
const latestVersion = chart.versions[0].version;
|
|
188
|
+
|
|
189
|
+
this.edit(app, latestVersion);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
downgrade(app, chart) {
|
|
193
|
+
const currentVersion = app.spec.chart.metadata.version;
|
|
194
|
+
const versions = chart.versions;
|
|
195
|
+
const currentIndex = versions.findIndex((v) => v.version === currentVersion);
|
|
196
|
+
|
|
197
|
+
if (currentIndex !== -1 && currentIndex < versions.length - 1) {
|
|
198
|
+
const downgradeVersion = versions[currentIndex + 1].version;
|
|
199
|
+
|
|
200
|
+
this.edit(app, downgradeVersion);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
|
|
117
204
|
edit(app, version) {
|
|
118
205
|
app.goToUpgrade(version, true);
|
|
119
206
|
},
|
|
@@ -132,260 +219,49 @@ export default {
|
|
|
132
219
|
install(chart) {
|
|
133
220
|
chart.goToInstall(FROM_TOOLS);
|
|
134
221
|
},
|
|
135
|
-
|
|
136
|
-
openV1Tool(id) {
|
|
137
|
-
const cluster = this.$store.getters['currentCluster'];
|
|
138
|
-
const route = {
|
|
139
|
-
name: 'c-cluster-explorer-tools-pages-page',
|
|
140
|
-
params: {
|
|
141
|
-
cluster: cluster.id,
|
|
142
|
-
product: 'explorer',
|
|
143
|
-
page: id,
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
this.$router.replace(route);
|
|
148
|
-
},
|
|
149
222
|
}
|
|
150
223
|
};
|
|
151
224
|
</script>
|
|
152
225
|
|
|
153
|
-
<style lang="scss" scoped>
|
|
154
|
-
$margin: 10px;
|
|
155
|
-
$logo: 50px;
|
|
156
|
-
|
|
157
|
-
.grid {
|
|
158
|
-
display: flex;
|
|
159
|
-
justify-content: flex-start;
|
|
160
|
-
flex-wrap: wrap;
|
|
161
|
-
margin: 0 -1*$margin;
|
|
162
|
-
|
|
163
|
-
@media only screen and (min-width: map-get($breakpoints, '--viewport-4')) {
|
|
164
|
-
.item {
|
|
165
|
-
width: 100%;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
@media only screen and (min-width: map-get($breakpoints, '--viewport-7')) {
|
|
169
|
-
.item {
|
|
170
|
-
width: 100%;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
@media only screen and (min-width: map-get($breakpoints, '--viewport-9')) {
|
|
174
|
-
.item {
|
|
175
|
-
width: calc(50% - 2 * #{$margin});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
@media only screen and (min-width: map-get($breakpoints, '--viewport-12')) {
|
|
179
|
-
.item {
|
|
180
|
-
width: calc(33.33333% - 2 * #{$margin});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.item {
|
|
185
|
-
display: grid;
|
|
186
|
-
grid-template-areas: "logo name-version name-version"
|
|
187
|
-
"description description description"
|
|
188
|
-
"state state action";
|
|
189
|
-
grid-template-columns: $logo auto min-content;
|
|
190
|
-
grid-template-rows: 50px 55px 35px;
|
|
191
|
-
row-gap: $margin;
|
|
192
|
-
column-gap: $margin;
|
|
193
|
-
|
|
194
|
-
margin: $margin;
|
|
195
|
-
padding: $margin;
|
|
196
|
-
position: relative;
|
|
197
|
-
border: 1px solid var(--border);
|
|
198
|
-
border-radius: calc( 1.5 * var(--border-radius));
|
|
199
|
-
|
|
200
|
-
.logo {
|
|
201
|
-
grid-area: logo;
|
|
202
|
-
text-align: center;
|
|
203
|
-
width: $logo;
|
|
204
|
-
height: $logo;
|
|
205
|
-
border-radius: calc(2 * var(--border-radius));
|
|
206
|
-
overflow: hidden;
|
|
207
|
-
background-color: white;
|
|
208
|
-
|
|
209
|
-
img {
|
|
210
|
-
width: $logo - 4px;
|
|
211
|
-
height: $logo - 4px;
|
|
212
|
-
object-fit: contain;
|
|
213
|
-
position: relative;
|
|
214
|
-
top: 2px;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
> i {
|
|
218
|
-
background-color: var(--box-bg);
|
|
219
|
-
border-radius: 50%;
|
|
220
|
-
font-size: 32px;
|
|
221
|
-
line-height: 50px;
|
|
222
|
-
width: 50px;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
.name-version {
|
|
227
|
-
grid-area: name-version;
|
|
228
|
-
padding: 10px 0 0 0;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
.name {
|
|
232
|
-
white-space: nowrap;
|
|
233
|
-
overflow: hidden;
|
|
234
|
-
text-overflow: ellipsis;
|
|
235
|
-
margin: 0;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
.os-label {
|
|
239
|
-
position: absolute;
|
|
240
|
-
top: 10px;
|
|
241
|
-
right: 10px;
|
|
242
|
-
padding: 3px;
|
|
243
|
-
font-size: 12px;
|
|
244
|
-
line-height: 12px;
|
|
245
|
-
background-color: var(--primary);
|
|
246
|
-
color: var(--primary-text);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
.version {
|
|
250
|
-
color: var(--muted);
|
|
251
|
-
white-space: nowrap;
|
|
252
|
-
overflow: hidden;
|
|
253
|
-
text-overflow: ellipsis;
|
|
254
|
-
font-size: 0.9em;
|
|
255
|
-
margin-top: 4px;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.description {
|
|
259
|
-
grid-area: description;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.description-content {
|
|
263
|
-
display: -webkit-box;
|
|
264
|
-
-webkit-box-orient: vertical;
|
|
265
|
-
-webkit-line-clamp: 3;
|
|
266
|
-
line-clamp: 3;
|
|
267
|
-
overflow: hidden;
|
|
268
|
-
text-overflow: ellipsis;
|
|
269
|
-
color: var(--text-muted);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
.state {
|
|
273
|
-
grid-area: state;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
.action {
|
|
277
|
-
grid-area: action;
|
|
278
|
-
white-space: nowrap;
|
|
279
|
-
|
|
280
|
-
button {
|
|
281
|
-
height: 30px;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
</style>
|
|
287
|
-
|
|
288
226
|
<template>
|
|
289
227
|
<Loading v-if="$fetchState.pending" />
|
|
290
|
-
<div v-else-if="
|
|
291
|
-
<h1>
|
|
228
|
+
<div v-else-if="appChartCards.length">
|
|
229
|
+
<h1 class="mmb-6">
|
|
292
230
|
<TabTitle>{{ t('catalog.tools.header') }}</TabTitle>
|
|
293
231
|
</h1>
|
|
294
|
-
<TypeDescription
|
|
295
|
-
resource="chart"
|
|
296
|
-
/>
|
|
297
232
|
|
|
298
|
-
<div
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
233
|
+
<div
|
|
234
|
+
class="tools-app-chart-cards"
|
|
235
|
+
data-testid="tools-app-chart-cards"
|
|
236
|
+
>
|
|
237
|
+
<rc-item-card
|
|
238
|
+
v-for="card in appChartCards"
|
|
239
|
+
:id="card.id"
|
|
240
|
+
:key="card.id"
|
|
241
|
+
:header="card.header"
|
|
242
|
+
:image="card.image"
|
|
243
|
+
:content="card.content"
|
|
244
|
+
:actions="getCardActions(card)"
|
|
245
|
+
:class="{ 'single-card': appChartCards.length === 1 }"
|
|
246
|
+
@upgrade="() => upgrade(card.installedApp, card.rawChart)"
|
|
247
|
+
@downgrade="() => downgrade(card.installedApp, card.rawChart)"
|
|
248
|
+
@edit="() => edit(card.installedApp)"
|
|
249
|
+
@remove="(payload) => remove(card.installedApp, payload.event)"
|
|
250
|
+
@install="() => install(card.rawChart)"
|
|
304
251
|
>
|
|
305
|
-
<
|
|
306
|
-
|
|
252
|
+
<template
|
|
253
|
+
v-once
|
|
254
|
+
#item-card-sub-header
|
|
307
255
|
>
|
|
308
|
-
<
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
<
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
:src="opt.chart.icon"
|
|
318
|
-
/>
|
|
319
|
-
</div>
|
|
320
|
-
<div class="name-version">
|
|
321
|
-
<div>
|
|
322
|
-
<h3 class="name">
|
|
323
|
-
{{ opt.chart.chartNameDisplay }}
|
|
324
|
-
</h3>
|
|
325
|
-
<label
|
|
326
|
-
v-if="opt.chart.deploysOnWindows"
|
|
327
|
-
class="os-label"
|
|
328
|
-
>{{ t('catalog.charts.deploysOnWindows') }}</label>
|
|
329
|
-
</div>
|
|
330
|
-
<div class="version">
|
|
331
|
-
<template v-if="opt.app && opt.app.upgradeAvailableVersion">
|
|
332
|
-
v{{ opt.app.currentVersion }} <b><i class="icon icon-chevron-right" /> v{{ opt.app.upgradeAvailableVersion }}</b>
|
|
333
|
-
</template>
|
|
334
|
-
<template v-else-if="opt.app">
|
|
335
|
-
v{{ opt.app.currentVersion }}
|
|
336
|
-
</template>
|
|
337
|
-
<template v-else-if="opt.chart.versions.length">
|
|
338
|
-
v{{ opt.chart.versions[0].version }}
|
|
339
|
-
</template>
|
|
340
|
-
</div>
|
|
341
|
-
</div>
|
|
342
|
-
<div class="description">
|
|
343
|
-
<div
|
|
344
|
-
v-clean-html="opt.chart.chartDescription"
|
|
345
|
-
class="description-content"
|
|
346
|
-
/>
|
|
347
|
-
</div>
|
|
348
|
-
<div class="action">
|
|
349
|
-
<template v-if="opt.blocked">
|
|
350
|
-
<button
|
|
351
|
-
v-clean-html="t('catalog.tools.action.install')"
|
|
352
|
-
role="button"
|
|
353
|
-
:aria-label="t('catalog.tools.action.install')"
|
|
354
|
-
disabled="true"
|
|
355
|
-
class="btn btn-sm role-primary"
|
|
356
|
-
/>
|
|
357
|
-
</template>
|
|
358
|
-
<template v-else-if="opt.app">
|
|
359
|
-
<button
|
|
360
|
-
class="btn btn-sm role-secondary"
|
|
361
|
-
role="button"
|
|
362
|
-
:aria-label="t('catalog.tools.action.remove')"
|
|
363
|
-
@click="remove(opt.app, $event)"
|
|
364
|
-
>
|
|
365
|
-
<i
|
|
366
|
-
class="icon icon-delete icon-lg"
|
|
367
|
-
:alt="t('catalog.tools.action.remove')"
|
|
368
|
-
/>
|
|
369
|
-
</button>
|
|
370
|
-
<button
|
|
371
|
-
v-clean-html="t('catalog.tools.action.edit')"
|
|
372
|
-
role="button"
|
|
373
|
-
:aria-label="t('catalog.tools.action.edit')"
|
|
374
|
-
class="btn btn-sm role-secondary"
|
|
375
|
-
@click="edit(opt.app)"
|
|
376
|
-
/>
|
|
377
|
-
</template>
|
|
378
|
-
<template v-else>
|
|
379
|
-
<button
|
|
380
|
-
v-clean-html="t('catalog.tools.action.install')"
|
|
381
|
-
role="button"
|
|
382
|
-
:aria-label="t('catalog.tools.action.install')"
|
|
383
|
-
class="btn btn-sm role-primary"
|
|
384
|
-
@click="install(opt.chart)"
|
|
385
|
-
/>
|
|
386
|
-
</template>
|
|
387
|
-
</div>
|
|
388
|
-
</div>
|
|
256
|
+
<AppChartCardSubHeader :items="card.subHeaderItems" />
|
|
257
|
+
</template>
|
|
258
|
+
<template
|
|
259
|
+
v-once
|
|
260
|
+
#item-card-footer
|
|
261
|
+
>
|
|
262
|
+
<AppChartCardFooter :items="card.footerItems" />
|
|
263
|
+
</template>
|
|
264
|
+
</rc-item-card>
|
|
389
265
|
</div>
|
|
390
266
|
</div>
|
|
391
267
|
<div v-else>
|
|
@@ -395,3 +271,18 @@ export default {
|
|
|
395
271
|
/>
|
|
396
272
|
</div>
|
|
397
273
|
</template>
|
|
274
|
+
|
|
275
|
+
<style lang="scss" scoped>
|
|
276
|
+
.tools-app-chart-cards {
|
|
277
|
+
display: grid;
|
|
278
|
+
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|
279
|
+
grid-gap: var(--gap-md);
|
|
280
|
+
width: 100%;
|
|
281
|
+
height: max-content;
|
|
282
|
+
overflow: hidden;
|
|
283
|
+
|
|
284
|
+
.single-card {
|
|
285
|
+
max-width: 500px;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
</style>
|