@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.
Files changed (199) hide show
  1. package/assets/styles/base/_color.scss +4 -1
  2. package/assets/styles/global/_tooltip.scss +7 -4
  3. package/assets/styles/themes/_dark.scss +11 -0
  4. package/assets/styles/themes/_light.scss +13 -1
  5. package/assets/styles/themes/_modern.scss +22 -0
  6. package/assets/translations/en-us.yaml +147 -19
  7. package/assets/translations/zh-hans.yaml +0 -1
  8. package/chart/monitoring/grafana/index.vue +8 -2
  9. package/components/ActionMenuShell.vue +3 -1
  10. package/components/Cron/CronExpressionEditor.vue +299 -0
  11. package/components/Cron/CronExpressionEditorModal.vue +247 -0
  12. package/components/Cron/CronTooltip.vue +87 -0
  13. package/components/Cron/types.ts +13 -0
  14. package/components/ForceDirectedTreeChart/composable.ts +11 -0
  15. package/components/PodSecurityAdmission.vue +2 -0
  16. package/components/PromptModal.vue +1 -1
  17. package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +1 -0
  18. package/components/Resource/Detail/CopyToClipboard.vue +78 -0
  19. package/components/Resource/Detail/FetchLoader/__tests__/composables.test.ts +69 -0
  20. package/components/Resource/Detail/FetchLoader/composables.ts +27 -0
  21. package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
  22. package/components/Resource/Detail/Metadata/Annotations/index.vue +1 -1
  23. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +13 -61
  24. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +33 -6
  25. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +24 -38
  26. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +25 -5
  27. package/components/Resource/Detail/Metadata/KeyValue.vue +12 -23
  28. package/components/Resource/Detail/Metadata/KeyValueRow.vue +144 -0
  29. package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -0
  30. package/components/Resource/Detail/Metadata/Labels/index.vue +1 -0
  31. package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +30 -32
  32. package/components/Resource/Detail/Metadata/__tests__/KeyValueRow.test.ts +108 -0
  33. package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +0 -3
  34. package/components/Resource/Detail/Metadata/__tests__/index.test.ts +12 -5
  35. package/components/Resource/Detail/Metadata/composables.ts +1 -4
  36. package/components/Resource/Detail/Metadata/index.vue +1 -0
  37. package/components/Resource/Detail/Preview/Content.vue +63 -0
  38. package/components/Resource/Detail/Preview/Preview.vue +128 -0
  39. package/components/Resource/Detail/Preview/__tests__/Content.spec.ts +71 -0
  40. package/components/Resource/Detail/Preview/__tests__/Preview.spec.ts +121 -0
  41. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +141 -0
  42. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +136 -0
  43. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +245 -0
  44. package/components/Resource/Detail/ResourcePopover/index.vue +226 -0
  45. package/components/Resource/Detail/SpacedRow.vue +1 -0
  46. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +0 -5
  47. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
  48. package/components/Resource/Detail/TitleBar/composables.ts +1 -3
  49. package/components/Resource/Detail/TitleBar/index.vue +2 -29
  50. package/components/Resource/Detail/ViewOptions/composable.ts +9 -0
  51. package/components/Resource/Detail/ViewOptions/index.vue +41 -0
  52. package/components/Resource/Detail/__tests__/CopyToClipboard.spec.ts +82 -0
  53. package/components/ResourceDetail/Masthead/legacy.vue +0 -19
  54. package/components/ResourceDetail/index.vue +1 -26
  55. package/components/ResourceTable.vue +24 -0
  56. package/components/SortableTable/index.vue +7 -1
  57. package/components/SortableTable/paging.js +3 -0
  58. package/components/Tabbed/Tab.vue +43 -1
  59. package/components/Tabbed/index.vue +3 -1
  60. package/components/__tests__/Cron/CronExpressionEditor.test.ts +151 -0
  61. package/components/__tests__/Cron/CronExpressionEditorModal.test.ts +81 -0
  62. package/components/auth/login/saml.vue +86 -0
  63. package/components/form/LabeledSelect.vue +8 -8
  64. package/components/form/ProjectMemberEditor.vue +2 -0
  65. package/components/form/ResourceTabs/composable.ts +54 -0
  66. package/components/form/ResourceTabs/index.vue +10 -7
  67. package/components/form/Select.vue +13 -10
  68. package/components/form/__tests__/LabeledSelect.test.ts +133 -0
  69. package/components/form/__tests__/Select.test.ts +134 -0
  70. package/components/nav/Header.vue +6 -5
  71. package/composables/useExtensionManager.ts +17 -0
  72. package/config/home-links.js +12 -0
  73. package/config/labels-annotations.js +0 -1
  74. package/config/page-actions.js +0 -1
  75. package/config/product/explorer.js +3 -1
  76. package/config/product/fleet.js +2 -7
  77. package/config/product/manager.js +0 -5
  78. package/config/query-params.js +1 -0
  79. package/config/router/navigation-guards/clusters.js +2 -1
  80. package/config/router/navigation-guards/products.js +1 -1
  81. package/config/store.js +2 -0
  82. package/core/extension-manager-impl.js +518 -0
  83. package/core/plugins.js +35 -468
  84. package/core/types.ts +8 -2
  85. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +1 -0
  86. package/detail/catalog.cattle.io.app.vue +7 -4
  87. package/detail/fleet.cattle.io.bundle.vue +1 -5
  88. package/detail/fleet.cattle.io.cluster.vue +3 -2
  89. package/detail/fleet.cattle.io.gitrepo.vue +76 -49
  90. package/detail/fleet.cattle.io.helmop.vue +78 -49
  91. package/dialog/AddonConfigConfirmationDialog.vue +1 -1
  92. package/dialog/GenericPrompt.vue +1 -1
  93. package/dialog/ImportDialog.vue +9 -2
  94. package/dialog/InstallExtensionDialog.vue +18 -10
  95. package/dialog/SloDialog.vue +1 -1
  96. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -1
  97. package/edit/__tests__/resources.cattle.io.restore.test.ts +106 -0
  98. package/edit/auth/oidc.vue +106 -6
  99. package/edit/auth/saml.vue +5 -5
  100. package/edit/cloudcredential.vue +31 -17
  101. package/edit/constraints.gatekeeper.sh.constraint/index.vue +10 -2
  102. package/edit/fleet.cattle.io.cluster.vue +19 -0
  103. package/edit/fleet.cattle.io.gitrepo.vue +23 -16
  104. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +12 -11
  105. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -1
  106. package/edit/provisioning.cattle.io.cluster/index.vue +14 -19
  107. package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -3
  108. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +1 -0
  109. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +1 -0
  110. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
  111. package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
  112. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -0
  113. package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +6 -0
  114. package/edit/resources.cattle.io.restore.vue +5 -8
  115. package/initialize/install-plugins.js +1 -3
  116. package/list/__tests__/workload.test.ts +1 -0
  117. package/list/workload.vue +8 -1
  118. package/machine-config/components/GCEImage.vue +6 -5
  119. package/machine-config/google.vue +11 -6
  120. package/mixins/__tests__/auth-config.test.ts +4 -6
  121. package/mixins/__tests__/chart.test.ts +139 -1
  122. package/mixins/auth-config.js +33 -10
  123. package/mixins/chart.js +58 -18
  124. package/models/__tests__/namespace.test.ts +69 -0
  125. package/models/apps.statefulset.js +8 -10
  126. package/models/chart.js +5 -1
  127. package/models/fleet-application.js +16 -46
  128. package/models/fleet.cattle.io.bundle.js +1 -38
  129. package/models/fleet.cattle.io.gitrepo.js +4 -0
  130. package/models/fleet.cattle.io.helmop.js +4 -0
  131. package/models/management.cattle.io.cluster.js +1 -1
  132. package/models/management.cattle.io.project.js +12 -0
  133. package/models/namespace.js +30 -0
  134. package/models/workload.js +4 -1
  135. package/package.json +10 -10
  136. package/pages/auth/login.vue +8 -3
  137. package/pages/auth/logout.vue +6 -5
  138. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +26 -11
  139. package/pages/c/_cluster/apps/charts/chart.vue +29 -20
  140. package/pages/c/_cluster/apps/charts/index.vue +1 -0
  141. package/pages/c/_cluster/apps/charts/install.vue +6 -5
  142. package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +102 -12
  143. package/pages/c/_cluster/explorer/tools/index.vue +145 -254
  144. package/pages/c/_cluster/manager/cloudCredential/index.vue +18 -1
  145. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +12 -2
  146. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  147. package/pages/c/_cluster/uiplugins/__tests__/index.spec.ts +318 -0
  148. package/pages/c/_cluster/uiplugins/index.vue +221 -363
  149. package/pages/home.vue +1 -9
  150. package/plugins/axios.js +3 -2
  151. package/plugins/dashboard-store/resource-class.js +49 -0
  152. package/plugins/ember-cookie.js +7 -3
  153. package/plugins/steve/subscribe.js +4 -2
  154. package/public/index.html +2 -1
  155. package/rancher-components/Card/Card.vue +1 -1
  156. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  157. package/rancher-components/Form/Radio/RadioButton.vue +1 -1
  158. package/rancher-components/Form/Radio/RadioGroup.vue +1 -1
  159. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -11
  160. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.test.ts +53 -0
  161. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +65 -0
  162. package/rancher-components/Pill/RcCounterBadge/index.ts +1 -0
  163. package/rancher-components/Pill/RcCounterBadge/types.ts +7 -0
  164. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +1 -1
  165. package/rancher-components/Pill/RcStatusBadge/index.ts +1 -1
  166. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -3
  167. package/rancher-components/Pill/RcStatusIndicator/types.ts +1 -1
  168. package/rancher-components/Pill/RcTag/RcTag.test.ts +64 -0
  169. package/rancher-components/Pill/RcTag/RcTag.vue +94 -0
  170. package/rancher-components/Pill/RcTag/index.ts +1 -0
  171. package/rancher-components/Pill/RcTag/types.ts +9 -0
  172. package/rancher-components/Pill/types.ts +1 -0
  173. package/rancher-components/RcItemCard/RcItemCard.vue +1 -0
  174. package/rancher-components/RcItemCard/RcItemCardAction.vue +12 -0
  175. package/scripts/test-plugins-build.sh +0 -1
  176. package/store/__tests__/catalog.test.ts +63 -0
  177. package/store/__tests__/cookies.test.ts +72 -0
  178. package/store/auth.js +33 -10
  179. package/store/catalog.js +2 -2
  180. package/store/cookies.ts +30 -0
  181. package/store/prefs.js +10 -5
  182. package/store/type-map.js +3 -15
  183. package/types/extension-manager.ts +26 -0
  184. package/types/shell/index.d.ts +123 -27
  185. package/utils/__tests__/product.test.ts +129 -0
  186. package/utils/__tests__/resource.test.ts +87 -0
  187. package/utils/alertmanagerconfig.js +2 -2
  188. package/utils/auth.js +4 -77
  189. package/utils/product.ts +39 -0
  190. package/utils/resource.ts +35 -0
  191. package/utils/select.js +0 -24
  192. package/utils/validators/formRules/__tests__/index.test.ts +3 -0
  193. package/utils/validators/formRules/index.ts +2 -1
  194. package/vue.config.js +1 -1
  195. package/components/Resource/Detail/Metadata/Rectangle.vue +0 -34
  196. package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +0 -24
  197. package/components/ResourceDetail/Masthead/__tests__/legacy.test.ts +0 -65
  198. package/utils/cookie-universal.js +0 -10
  199. /package/components/{ForceDirectedTreeChart.vue → ForceDirectedTreeChart/index.vue} +0 -0
@@ -37,6 +37,17 @@ export default {
37
37
  allCredentials: null,
38
38
  resource: NORMAN.CLOUD_CREDENTIAL,
39
39
  schema: this.$store.getters['rancher/schemaFor'](NORMAN.CLOUD_CREDENTIAL),
40
+ groupOptions: [{
41
+ tooltipKey: 'resourceTable.groupBy.none',
42
+ icon: 'icon-list-flat',
43
+ value: 'none',
44
+ }, {
45
+ tooltipKey: 'manager.cloudCredentials.list.groupBy.provider',
46
+ hideColumn: 'provider',
47
+ icon: 'icon-folder',
48
+ value: 'providerDisplay',
49
+ field: 'providerDisplay',
50
+ }],
40
51
  };
41
52
  },
42
53
 
@@ -56,6 +67,12 @@ export default {
56
67
  sort: 'publicData',
57
68
  search: 'publicData',
58
69
  formatter: 'CloudCredPublicData',
70
+ }, {
71
+ name: 'provider',
72
+ labelKey: 'manager.cloudCredentials.list.headers.provider',
73
+ value: 'providerDisplay',
74
+ sort: 'providerDisplay',
75
+ search: 'providerDisplay',
59
76
  },
60
77
  DESCRIPTION,
61
78
  AGE_NORMAN
@@ -91,7 +108,7 @@ export default {
91
108
  :rows="rows"
92
109
  :headers="headers"
93
110
  :namespaced="false"
94
- group-by="providerDisplay"
111
+ :group-options="groupOptions"
95
112
  >
96
113
  <template #cell:id="{row}">
97
114
  {{ row.id.replace('cattle-global-data:', '') }}
@@ -1,13 +1,16 @@
1
1
  <script>
2
2
  import { NORMAN } from '@shell/config/types';
3
+ import { isAdminUser } from '@shell/store/type-map';
3
4
  import ResourceTable from '@shell/components/ResourceTable';
4
5
  import AsyncButton from '@shell/components/AsyncButton';
5
6
  import Loading from '@shell/components/Loading';
6
7
  import Masthead from '@shell/components/ResourceList/Masthead';
8
+ import Banner from '@components/Banner/Banner.vue';
9
+
7
10
  export default {
8
11
  name: 'KontainerDrivers',
9
12
  components: {
10
- ResourceTable, Loading, Masthead, AsyncButton
13
+ ResourceTable, Loading, Masthead, AsyncButton, Banner
11
14
  },
12
15
 
13
16
  async fetch() {
@@ -21,7 +24,8 @@ export default {
21
24
  resource: NORMAN.KONTAINER_DRIVER,
22
25
  schema: this.$store.getters['rancher/schemaFor'](NORMAN.KONTAINER_DRIVER),
23
26
  useQueryParamsForSimpleFiltering: false,
24
- forceUpdateLiveAndDelayed: 10
27
+ forceUpdateLiveAndDelayed: 10,
28
+ showDeprecationBanner: isAdminUser(this.$store.getters),
25
29
  };
26
30
  },
27
31
  computed: {
@@ -69,6 +73,12 @@ export default {
69
73
  />
70
74
  </template>
71
75
  </Masthead>
76
+ <Banner
77
+ v-if="showDeprecationBanner"
78
+ color="warning"
79
+ label-key="drivers.kontainer.emberDeprecationMessage"
80
+ data-testid="kontainer-driver-ember-deprecation-banner"
81
+ />
72
82
  <ResourceTable
73
83
  :schema="schema"
74
84
  :rows="rows"
@@ -223,7 +223,7 @@ export default {
223
223
  :aria-label="t('plugins.closePluginPanel')"
224
224
  tabindex="0"
225
225
  @click="hide()"
226
- @keyup.enter.space="hide()"
226
+ @keydown.enter.space="hide()"
227
227
  >
228
228
  <i class="icon icon-close" />
229
229
  </div>
@@ -0,0 +1,318 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import UiPluginsPage from '@shell/pages/c/_cluster/uiplugins/index.vue';
3
+
4
+ const t = (key: string, args: Object) => {
5
+ if (args) {
6
+ return `${ key } with ${ JSON.stringify(args) }`;
7
+ }
8
+
9
+ return key;
10
+ };
11
+
12
+ describe('page: UI plugins/Extensions', () => {
13
+ let wrapper;
14
+
15
+ const mountComponent = (mocks = {}) => {
16
+ const store = {
17
+ getters: { 'prefs/get': jest.fn() },
18
+ dispatch: () => Promise.resolve(),
19
+ };
20
+
21
+ return shallowMount(UiPluginsPage, {
22
+ global: {
23
+ mocks: {
24
+ $store: store,
25
+ t,
26
+ ...mocks,
27
+ },
28
+ stubs: { ActionMenu: { template: '<div />' } }
29
+ }
30
+ });
31
+ };
32
+
33
+ beforeEach(() => {
34
+ wrapper = mountComponent();
35
+ });
36
+
37
+ describe('getPluginActions', () => {
38
+ it('should return install action for a non-installed plugin with installable versions', () => {
39
+ const plugin = {
40
+ installed: false,
41
+ installableVersions: [{ version: '1.0.0' }],
42
+ builtin: false,
43
+ upgrade: null,
44
+ };
45
+ const actions = wrapper.vm.getPluginActions(plugin);
46
+
47
+ expect(actions).toHaveLength(1);
48
+ expect(actions[0].action).toBe('install');
49
+ });
50
+
51
+ it('should return uninstall action for an installed, non-builtin plugin', () => {
52
+ const plugin = {
53
+ installed: true,
54
+ installableVersions: [],
55
+ builtin: false,
56
+ upgrade: null,
57
+ };
58
+ const actions = wrapper.vm.getPluginActions(plugin);
59
+
60
+ expect(actions).toHaveLength(1);
61
+ expect(actions[0].action).toBe('uninstall');
62
+ });
63
+
64
+ it('should not return uninstall action for a builtin plugin', () => {
65
+ const plugin = {
66
+ installed: true,
67
+ installableVersions: [],
68
+ builtin: true,
69
+ upgrade: null,
70
+ };
71
+ const actions = wrapper.vm.getPluginActions(plugin);
72
+
73
+ expect(actions.some((a) => a.action === 'uninstall')).toBe(false);
74
+ });
75
+
76
+ it('should return update action for an installed plugin with an upgrade', () => {
77
+ const plugin = {
78
+ installed: true,
79
+ installableVersions: [],
80
+ builtin: false,
81
+ upgrade: '1.1.0',
82
+ };
83
+ const actions = wrapper.vm.getPluginActions(plugin);
84
+
85
+ expect(actions.some((a) => a.action === 'update')).toBe(true);
86
+ });
87
+
88
+ it('should return rollback action for an installed plugin with multiple installable versions and no upgrade', () => {
89
+ const plugin = {
90
+ installed: true,
91
+ installableVersions: [{ version: '1.0.0' }, { version: '0.9.0' }],
92
+ builtin: false,
93
+ upgrade: null,
94
+ };
95
+ const actions = wrapper.vm.getPluginActions(plugin);
96
+
97
+ expect(actions.some((a) => a.action === 'rollback')).toBe(true);
98
+ });
99
+
100
+ it('should return all applicable actions', () => {
101
+ const plugin = {
102
+ installed: true,
103
+ installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }],
104
+ builtin: false,
105
+ upgrade: '1.1.0',
106
+ };
107
+ const actions = wrapper.vm.getPluginActions(plugin);
108
+
109
+ expect(actions.map((a) => a.action)).toContain('uninstall');
110
+ expect(actions.map((a) => a.action)).toContain('update');
111
+ expect(actions.map((a) => a.action)).not.toContain('rollback');
112
+ });
113
+ });
114
+
115
+ describe('getSubHeaderItems', () => {
116
+ it('should return version info', () => {
117
+ const plugin = { displayVersionLabel: 'v1.0.0' };
118
+ const items = wrapper.vm.getSubHeaderItems(plugin);
119
+
120
+ expect(items[0].label).toBe('v1.0.0');
121
+ });
122
+
123
+ it('should include upgrade availability in tooltip', () => {
124
+ const plugin = { displayVersionLabel: 'v1.0.0', upgrade: 'v1.1.0' };
125
+ const items = wrapper.vm.getSubHeaderItems(plugin);
126
+
127
+ expect(items[0].labelTooltip).toBe('plugins.upgradeAvailableTooltip with {"version":"v1.1.0"}');
128
+ });
129
+
130
+ it('should show installing status', () => {
131
+ const plugin = { displayVersionLabel: 'v1.0.0', installing: 'install' };
132
+ const items = wrapper.vm.getSubHeaderItems(plugin);
133
+
134
+ expect(items).toHaveLength(2);
135
+ expect(items[1].label).toBe('plugins.labels.installing');
136
+ });
137
+
138
+ it('should show uninstalling status', () => {
139
+ const plugin = { displayVersionLabel: 'v1.0.0', installing: 'uninstall' };
140
+ const items = wrapper.vm.getSubHeaderItems(plugin);
141
+
142
+ expect(items).toHaveLength(2);
143
+ expect(items[1].label).toBe('plugins.labels.uninstalling');
144
+ });
145
+
146
+ it('should show updating status', () => {
147
+ const plugin = { displayVersionLabel: 'v1.0.0', installing: 'update' };
148
+ const items = wrapper.vm.getSubHeaderItems(plugin);
149
+
150
+ expect(items).toHaveLength(2);
151
+ expect(items[1].label).toBe('plugins.labels.updating');
152
+ });
153
+
154
+ it('should show rolling back status', () => {
155
+ const plugin = { displayVersionLabel: 'v1.0.0', installing: 'rollback' };
156
+ const items = wrapper.vm.getSubHeaderItems(plugin);
157
+
158
+ expect(items).toHaveLength(2);
159
+ expect(items[1].label).toBe('plugins.labels.rollingBack');
160
+ });
161
+ });
162
+
163
+ describe('getFooterItems', () => {
164
+ it('should return "builtin" label for builtin plugins', () => {
165
+ const plugin = { builtin: true };
166
+ const items = wrapper.vm.getFooterItems(plugin);
167
+
168
+ expect(items[0].labels).toContain('plugins.labels.builtin');
169
+ });
170
+
171
+ it('should return "third-party" label for non-certified, non-builtin plugins', () => {
172
+ const plugin = { builtin: false, certified: false };
173
+ const items = wrapper.vm.getFooterItems(plugin);
174
+
175
+ expect(items[0].labels).toContain('plugins.labels.third-party');
176
+ });
177
+
178
+ it('should not return "third-party" for certified plugins', () => {
179
+ const plugin = { builtin: false, certified: true };
180
+ const items = wrapper.vm.getFooterItems(plugin);
181
+
182
+ expect(items).toHaveLength(0);
183
+ });
184
+
185
+ it('should return "experimental" label for experimental plugins', () => {
186
+ const plugin = { builtin: false, experimental: true };
187
+ const items = wrapper.vm.getFooterItems(plugin);
188
+
189
+ expect(items[0].labels).toContain('plugins.labels.experimental');
190
+ });
191
+
192
+ it('should return no items if no labels apply', () => {
193
+ const plugin = {
194
+ builtin: false, certified: true, experimental: false
195
+ };
196
+ const items = wrapper.vm.getFooterItems(plugin);
197
+
198
+ expect(items).toHaveLength(0);
199
+ });
200
+ });
201
+
202
+ describe('getStatuses', () => {
203
+ it('should return "installed" status for installed, non-builtin plugins', () => {
204
+ const plugin = {
205
+ installed: true, builtin: false, installing: false
206
+ };
207
+ const statuses = wrapper.vm.getStatuses(plugin);
208
+
209
+ expect(statuses[0].tooltip.key).toBe('generic.installed');
210
+ });
211
+
212
+ it('should return "upgradeable" status for plugins with an upgrade', () => {
213
+ const plugin = { upgrade: '1.1.0' };
214
+ const statuses = wrapper.vm.getStatuses(plugin);
215
+
216
+ expect(statuses[0].tooltip.key).toBe('generic.upgradeable');
217
+ });
218
+
219
+ it('should return "deprecated" status for deprecated plugins', () => {
220
+ const plugin = { chart: { deprecated: true } };
221
+ const statuses = wrapper.vm.getStatuses(plugin);
222
+
223
+ expect(statuses[0].tooltip.key).toBe('generic.deprecated');
224
+ });
225
+
226
+ it('should return error status for installedError', () => {
227
+ const plugin = { installedError: 'An error occurred' };
228
+ const statuses = wrapper.vm.getStatuses(plugin);
229
+
230
+ expect(statuses[0].icon).toBe('icon-alert-alt');
231
+ expect(statuses[0].tooltip.text).toBe('generic.error: An error occurred');
232
+ });
233
+
234
+ it('should return error status for incompatibilityMessage', () => {
235
+ const plugin = { incompatibilityMessage: 'Incompatible version' };
236
+ const statuses = wrapper.vm.getStatuses(plugin);
237
+
238
+ expect(statuses[0].icon).toBe('icon-alert-alt');
239
+ expect(statuses[0].tooltip.text).toBe('generic.error: Incompatible version');
240
+ });
241
+
242
+ it('should return error status for helmError', () => {
243
+ const plugin = { helmError: true };
244
+ const statuses = wrapper.vm.getStatuses(plugin);
245
+
246
+ expect(statuses[0].icon).toBe('icon-alert-alt');
247
+ expect(statuses[0].tooltip.text).toBe('generic.error: plugins.helmError');
248
+ });
249
+
250
+ it('should combine deprecated and other errors in tooltip', () => {
251
+ const plugin = { chart: { deprecated: true }, helmError: true };
252
+ const statuses = wrapper.vm.getStatuses(plugin);
253
+ const warningStatus = statuses.find((s) => s.icon === 'icon-alert-alt');
254
+
255
+ expect(warningStatus.tooltip.text).toBe('generic.deprecated. generic.error: plugins.helmError');
256
+ });
257
+ });
258
+
259
+ describe('watch: helmOps', () => {
260
+ let wrapper;
261
+
262
+ beforeEach(() => {
263
+ const store = {
264
+ getters: {
265
+ 'prefs/get': jest.fn(),
266
+ 'catalog/rawCharts': {},
267
+ 'uiplugins/plugins': [],
268
+ 'uiplugins/errors': {}
269
+ },
270
+ dispatch: () => Promise.resolve(),
271
+ };
272
+
273
+ wrapper = shallowMount(UiPluginsPage, {
274
+ global: {
275
+ mocks: {
276
+ $store: store,
277
+ t,
278
+ },
279
+ stubs: { ActionMenu: { template: '<div />' } }
280
+ }
281
+ });
282
+ });
283
+
284
+ it('should set status to "update" for an upgrade operation', async() => {
285
+ const plugin = { name: 'my-plugin' };
286
+
287
+ wrapper.vm.available = [plugin];
288
+ wrapper.vm.installing['my-plugin'] = 'update';
289
+
290
+ const helmOps = [{
291
+ metadata: { state: { transitioning: true } },
292
+ status: { releaseName: 'my-plugin', action: 'upgrade' }
293
+ }];
294
+
295
+ wrapper.vm.helmOps = helmOps;
296
+ await wrapper.vm.$nextTick();
297
+
298
+ expect(wrapper.vm.installing['my-plugin']).toBe('update');
299
+ });
300
+
301
+ it('should keep status as "rollback" during an upgrade operation if it was already rolling back', async() => {
302
+ const plugin = { name: 'my-plugin' };
303
+
304
+ wrapper.vm.available = [plugin];
305
+ wrapper.vm.installing['my-plugin'] = 'rollback';
306
+
307
+ const helmOps = [{
308
+ metadata: { state: { transitioning: true } },
309
+ status: { releaseName: 'my-plugin', action: 'upgrade' }
310
+ }];
311
+
312
+ wrapper.vm.helmOps = helmOps;
313
+ await wrapper.vm.$nextTick();
314
+
315
+ expect(wrapper.vm.installing['my-plugin']).toBe('rollback');
316
+ });
317
+ });
318
+ });