@rancher/shell 3.0.8-rc.7 → 3.0.8-rc.9

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 (166) hide show
  1. package/assets/brand/suse/dark/rancher-logo.svg +1 -64
  2. package/assets/translations/en-us.yaml +9 -1
  3. package/components/BackLink.vue +8 -0
  4. package/components/BannerGraphic.vue +1 -5
  5. package/components/BrandImage.vue +17 -6
  6. package/components/Cron/CronExpressionEditor.vue +1 -1
  7. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  8. package/components/Drawer/Chrome.vue +2 -6
  9. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
  10. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
  11. package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
  12. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
  13. package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
  14. package/components/Drawer/types.ts +3 -0
  15. package/components/PaginatedResourceTable.vue +2 -6
  16. package/components/Questions/__tests__/index.test.ts +159 -0
  17. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  18. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  19. package/components/Resource/Detail/Metadata/composables.ts +9 -9
  20. package/components/Resource/Detail/Metadata/index.vue +3 -3
  21. package/components/Resource/Detail/TitleBar/composables.ts +2 -1
  22. package/components/Resource/Detail/composables.ts +12 -0
  23. package/components/Tabbed/__tests__/index.test.ts +86 -0
  24. package/components/auth/SelectPrincipal.vue +24 -6
  25. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  26. package/components/formatter/InternalExternalIP.vue +4 -1
  27. package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
  28. package/components/nav/Header.vue +1 -2
  29. package/components/nav/TopLevelMenu.helper.ts +16 -6
  30. package/components/templates/standalone.vue +1 -1
  31. package/composables/useI18n.ts +10 -1
  32. package/config/__test__/uiplugins.test.ts +309 -0
  33. package/config/labels-annotations.js +1 -0
  34. package/config/product/explorer.js +3 -1
  35. package/config/router/routes.js +6 -2
  36. package/config/types.js +7 -0
  37. package/config/uiplugins.js +46 -2
  38. package/core/__test__/extension-manager-impl.test.js +236 -0
  39. package/core/extension-manager-impl.js +23 -6
  40. package/core/types-provisioning.ts +1 -1
  41. package/detail/provisioning.cattle.io.cluster.vue +1 -0
  42. package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
  43. package/dialog/RollbackWorkloadDialog.vue +2 -5
  44. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
  45. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  46. package/edit/configmap.vue +1 -0
  47. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  48. package/edit/fleet.cattle.io.helmop.vue +6 -6
  49. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  50. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  51. package/edit/logging-flow/index.vue +1 -0
  52. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  53. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  54. package/edit/management.cattle.io.project.vue +1 -0
  55. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  56. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  57. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  58. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  59. package/edit/monitoring.coreos.com.route.vue +1 -1
  60. package/edit/namespace.vue +1 -0
  61. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  62. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  63. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  64. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  65. package/edit/node.vue +1 -0
  66. package/edit/persistentvolume/index.vue +27 -22
  67. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  68. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  69. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  70. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  71. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  72. package/edit/persistentvolume/plugins/csi.vue +18 -16
  73. package/edit/persistentvolume/plugins/fc.vue +13 -14
  74. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  75. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  76. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  77. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  78. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  79. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  80. package/edit/persistentvolume/plugins/local.vue +1 -3
  81. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  82. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  83. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  84. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  85. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  86. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  87. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  88. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  89. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  90. package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -0
  91. package/edit/secret/index.vue +1 -1
  92. package/edit/service.vue +1 -0
  93. package/edit/serviceaccount.vue +1 -0
  94. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  95. package/edit/workload/index.vue +2 -1
  96. package/edit/workload/mixins/workload.js +1 -1
  97. package/initialize/App.vue +4 -4
  98. package/initialize/install-plugins.js +17 -2
  99. package/machine-config/components/EC2Networking.vue +5 -2
  100. package/machine-config/components/__tests__/EC2Networking.test.ts +24 -0
  101. package/mixins/__tests__/brand.spec.ts +2 -2
  102. package/mixins/__tests__/chart.test.ts +21 -0
  103. package/mixins/brand.js +1 -7
  104. package/mixins/chart.js +7 -1
  105. package/mixins/create-edit-view/index.js +5 -0
  106. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
  107. package/models/management.cattle.io.cluster.js +21 -3
  108. package/models/provisioning.cattle.io.cluster.js +21 -9
  109. package/package.json +5 -4
  110. package/pages/auth/login.vue +1 -3
  111. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  112. package/pages/c/_cluster/apps/charts/chart.vue +33 -15
  113. package/pages/c/_cluster/explorer/index.vue +8 -6
  114. package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
  115. package/pages/c/_cluster/settings/brand.vue +1 -1
  116. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  117. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  118. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  119. package/pages/home.vue +5 -2
  120. package/pkg/dynamic-importer.lib.js +4 -0
  121. package/plugins/dashboard-client-init.js +3 -0
  122. package/plugins/dashboard-store/getters.js +18 -1
  123. package/plugins/dashboard-store/resource-class.js +4 -4
  124. package/plugins/i18n.js +8 -0
  125. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
  126. package/plugins/steve/steve-pagination-utils.ts +39 -20
  127. package/plugins/steve/subscribe.js +17 -9
  128. package/plugins/subscribe-events.ts +4 -2
  129. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
  130. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  131. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  132. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  133. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  134. package/rancher-components/Pill/types.ts +0 -1
  135. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  136. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  137. package/rancher-components/RcIcon/index.ts +1 -0
  138. package/rancher-components/RcIcon/types.ts +160 -0
  139. package/rancher-components/utils/status.test.ts +67 -0
  140. package/rancher-components/utils/status.ts +77 -0
  141. package/scripts/typegen.sh +1 -0
  142. package/store/action-menu.js +8 -0
  143. package/store/auth.js +3 -3
  144. package/store/catalog.js +6 -0
  145. package/store/index.js +36 -17
  146. package/store/prefs.js +4 -5
  147. package/store/type-map.js +3 -3
  148. package/store/wm.ts +4 -4
  149. package/types/shell/index.d.ts +39 -2
  150. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  151. package/types/store/pagination.types.ts +157 -9
  152. package/types/store/subscribe-events.types.ts +8 -1
  153. package/types/store/subscribe.types.ts +1 -0
  154. package/utils/__tests__/provider.test.ts +98 -0
  155. package/utils/__tests__/selector-typed.test.ts +263 -0
  156. package/utils/__tests__/version.test.ts +19 -1
  157. package/utils/back-off.ts +3 -3
  158. package/utils/color.js +1 -1
  159. package/utils/dynamic-content/__tests__/info.test.ts +21 -9
  160. package/utils/dynamic-content/info.ts +44 -2
  161. package/utils/favicon.js +4 -4
  162. package/utils/pagination-wrapper.ts +12 -8
  163. package/utils/provider.ts +14 -0
  164. package/utils/selector-typed.ts +6 -2
  165. package/utils/version.js +15 -0
  166. package/plugins/nuxt-client-init.js +0 -3
@@ -0,0 +1,51 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import RcIcon from './RcIcon.vue';
3
+
4
+ describe('rcIcon.vue', () => {
5
+ it('renders with the correct type class and size classes', () => {
6
+ const wrapper = shallowMount(RcIcon, {
7
+ props: {
8
+ size: 'medium',
9
+ type: 'search',
10
+ },
11
+ });
12
+
13
+ expect(wrapper.classes()).toContain('icon-search');
14
+ expect(wrapper.classes()).toContain('medium');
15
+ });
16
+
17
+ it('sets aria-hidden to true by default', () => {
18
+ const wrapper = shallowMount(RcIcon, {
19
+ props: {
20
+ size: 'medium',
21
+ type: 'search',
22
+ },
23
+ });
24
+
25
+ expect(wrapper.attributes('aria-hidden')).toBe('true');
26
+ });
27
+
28
+ it('sets aria-hidden to false when explicitly provided', () => {
29
+ const wrapper = shallowMount(RcIcon, {
30
+ props: {
31
+ size: 'medium',
32
+ type: 'search',
33
+ ariaHidden: false,
34
+ },
35
+ });
36
+
37
+ expect(wrapper.attributes('aria-hidden')).toBe('false');
38
+ });
39
+
40
+ it('sets aria-hidden to true when explicitly provided', () => {
41
+ const wrapper = shallowMount(RcIcon, {
42
+ props: {
43
+ size: 'medium',
44
+ type: 'search',
45
+ ariaHidden: true,
46
+ },
47
+ });
48
+
49
+ expect(wrapper.attributes('aria-hidden')).toBe('true');
50
+ });
51
+ });
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import { RcIconProps, RcIconType, RcIconSize } from '@components/RcIcon/types';
3
+ import { computed } from 'vue';
4
+ import { useStatusColors } from '@components/utils/status';
5
+ const props = withDefaults(defineProps<RcIconProps>(), { size: 'small', ariaHidden: true });
6
+ const fontSize = computed(() => {
7
+ return RcIconSize[props.size];
8
+ });
9
+
10
+ const iconClass = computed(() => {
11
+ return RcIconType[props.type];
12
+ });
13
+
14
+ const status = computed(() => {
15
+ if (props.status && props.status !== 'inherit') {
16
+ return props.status;
17
+ }
18
+
19
+ return 'none';
20
+ });
21
+
22
+ const { textColor } = useStatusColors({ status: status.value }, 'outlined');
23
+
24
+ const color = computed(() => {
25
+ if (props.status === 'inherit') {
26
+ return 'inherit';
27
+ }
28
+
29
+ return textColor.value;
30
+ });
31
+ </script>
32
+
33
+ <template>
34
+ <i
35
+ class="rc-icon"
36
+ :class="{[props.size]: true, [iconClass]: true}"
37
+ :aria-hidden="props.ariaHidden"
38
+ />
39
+ </template>
40
+
41
+ <style lang="scss" scoped>
42
+ .rc-icon {
43
+ font-size: v-bind(fontSize);
44
+ color: v-bind(color);
45
+ }
46
+ </style>
@@ -0,0 +1 @@
1
+ export { default as RcIcon } from './RcIcon.vue';
@@ -0,0 +1,160 @@
1
+ import { Status } from '../utils/status';
2
+
3
+ export const RcIconType = {
4
+ actions: 'icon-actions',
5
+ ai: 'icon-ai',
6
+ 'alert-alt': 'icon-alert-alt',
7
+ alert: 'icon-alert',
8
+ anchor: 'icon-anchor',
9
+ apple: 'icon-apple',
10
+ application: 'icon-application',
11
+ apps: 'icon-apps',
12
+ archive: 'icon-archive',
13
+ 'backup-restore': 'icon-backup-restore',
14
+ backup: 'icon-backup',
15
+ 'brush-icon': 'icon-brush-icon',
16
+ 'category-alt': 'icon-category-alt',
17
+ checkmark: 'icon-checkmark',
18
+ 'chevron-beginning': 'icon-chevron-beginning',
19
+ 'chevron-down': 'icon-chevron-down',
20
+ 'chevron-end': 'icon-chevron-end',
21
+ 'chevron-left': 'icon-chevron-left',
22
+ 'chevron-right': 'icon-chevron-right',
23
+ 'chevron-up': 'icon-chevron-up',
24
+ 'circle-plus': 'icon-circle-plus',
25
+ cis: 'icon-cis',
26
+ close: 'icon-close',
27
+ 'cluster-management': 'icon-cluster-management',
28
+ cluster: 'icon-cluster',
29
+ code: 'icon-code',
30
+ comment: 'icon-comment',
31
+ commit: 'icon-commit',
32
+ compass: 'icon-compass',
33
+ 'confirmation-alt': 'icon-confirmation-alt',
34
+ copy: 'icon-copy',
35
+ dashboard: 'icon-dashboard',
36
+ dock: 'icon-dock',
37
+ docker: 'icon-docker',
38
+ document: 'icon-document',
39
+ 'dot-half': 'icon-dot-half',
40
+ 'dot-open': 'icon-dot-open',
41
+ dot: 'icon-dot',
42
+ 'downgrade-alt': 'icon-downgrade-alt',
43
+ download: 'icon-download',
44
+ edit: 'icon-edit',
45
+ elemental: 'icon-elemental',
46
+ endpoints_connected: 'icon-endpoints_connected',
47
+ endpoints_disconnected: 'icon-endpoints_disconnected',
48
+ epinio: 'icon-epinio',
49
+ error: 'icon-error',
50
+ explore: 'icon-explore',
51
+ extension: 'icon-extension',
52
+ 'external-link': 'icon-external-link',
53
+ file: 'icon-file',
54
+ filter_alt: 'icon-filter_alt',
55
+ flask: 'icon-flask',
56
+ fleet: 'icon-fleet',
57
+ folder: 'icon-folder',
58
+ fork: 'icon-fork',
59
+ gatekeeper: 'icon-gatekeeper',
60
+ gear: 'icon-gear',
61
+ gemini: 'icon-gemini',
62
+ git: 'icon-git',
63
+ github: 'icon-github',
64
+ gitlab: 'icon-gitlab',
65
+ globe: 'icon-globe',
66
+ groups: 'icon-groups',
67
+ harvester: 'icon-harvester',
68
+ helm: 'icon-helm',
69
+ hide: 'icon-hide',
70
+ history: 'icon-history',
71
+ home: 'icon-home',
72
+ 'info-circle': 'icon-info-circle',
73
+ info: 'icon-info',
74
+ init_container: 'icon-init_container',
75
+ istio: 'icon-istio',
76
+ keyboard: 'icon-keyboard',
77
+ keyboard_tab: 'icon-keyboard_tab',
78
+ linux: 'icon-linux',
79
+ 'list-flat': 'icon-list-flat',
80
+ 'list-grouped': 'icon-list-grouped',
81
+ lock: 'icon-lock',
82
+ logging: 'icon-logging',
83
+ longhorn: 'icon-longhorn',
84
+ marketplace: 'icon-marketplace',
85
+ menu: 'icon-menu',
86
+ minus: 'icon-minus',
87
+ monitoring: 'icon-monitoring',
88
+ more: 'icon-more',
89
+ namespace: 'icon-namespace',
90
+ notifier: 'icon-notifier',
91
+ 'notify-announcement': 'icon-notify-announcement',
92
+ 'notify-bell': 'icon-notify-bell',
93
+ 'notify-busy': 'icon-notify-busy',
94
+ 'notify-error': 'icon-notify-error',
95
+ 'notify-info': 'icon-notify-info',
96
+ 'notify-tick': 'icon-notify-tick',
97
+ 'notify-warning': 'icon-notify-warning',
98
+ ollama: 'icon-ollama',
99
+ openai: 'icon-openai',
100
+ 'os-management': 'icon-os-management',
101
+ pause: 'icon-pause',
102
+ 'pin-outlined': 'icon-pin-outlined',
103
+ pin: 'icon-pin',
104
+ pipeline: 'icon-pipeline',
105
+ play: 'icon-play',
106
+ plus: 'icon-plus',
107
+ pod_security: 'icon-pod_security',
108
+ print: 'icon-print',
109
+ 'question-mark': 'icon-question-mark',
110
+ 'quick-action': 'icon-quick-action',
111
+ 'rancher-desktop': 'icon-rancher-desktop',
112
+ 'rancher-observability': 'icon-rancher-observability',
113
+ 'refresh-alt': 'icon-refresh-alt',
114
+ refresh: 'icon-refresh',
115
+ 'repository-alt': 'icon-repository-alt',
116
+ repository: 'icon-repository',
117
+ rio: 'icon-rio',
118
+ 'role-binding': 'icon-role-binding',
119
+ search: 'icon-search',
120
+ send: 'icon-send',
121
+ service: 'icon-service',
122
+ show: 'icon-show',
123
+ snapshot: 'icon-snapshot',
124
+ 'sort-down': 'icon-sort-down',
125
+ 'sort-up': 'icon-sort-up',
126
+ sort: 'icon-sort',
127
+ sources: 'icon-sources',
128
+ spinner: 'icon-spinner',
129
+ stackstate: 'icon-stackstate',
130
+ 'star-open': 'icon-star-open',
131
+ star: 'icon-star',
132
+ storage: 'icon-storage',
133
+ 'tag-alt': 'icon-tag-alt',
134
+ terminal: 'icon-terminal',
135
+ 'thinking-process': 'icon-thinking-process',
136
+ trash: 'icon-trash',
137
+ unlock: 'icon-unlock',
138
+ 'upgrade-alt': 'icon-upgrade-alt',
139
+ upload: 'icon-upload',
140
+ 'user-check': 'icon-user-check',
141
+ 'user-xmark': 'icon-user-xmark',
142
+ user: 'icon-user',
143
+ 'version-alt': 'icon-version-alt',
144
+ warning: 'icon-warning',
145
+ windows: 'icon-windows',
146
+ };
147
+
148
+ export const RcIconSize = {
149
+ large: '25px',
150
+ medium: '18px',
151
+ small: '14px',
152
+ none: undefined
153
+ };
154
+
155
+ export interface RcIconProps {
156
+ size: keyof typeof RcIconSize;
157
+ type: keyof typeof RcIconType;
158
+ ariaHidden?: boolean;
159
+ status?: Status | 'inherit';
160
+ }
@@ -0,0 +1,67 @@
1
+
2
+ import { reactive } from 'vue';
3
+ import { wrapIfVar, useStatusColors, Status } from './status';
4
+
5
+ describe('utils: status', () => {
6
+ describe('wrapIfVar', () => {
7
+ it('should wrap a CSS variable', () => {
8
+ const result = wrapIfVar('--rc-info');
9
+
10
+ expect(result).toBe('var(--rc-info)');
11
+ });
12
+
13
+ it('should not wrap a normal color', () => {
14
+ const result = wrapIfVar('red');
15
+
16
+ expect(result).toBe('red');
17
+ });
18
+ });
19
+
20
+ describe('useStatusColors', () => {
21
+ it.each([
22
+ 'info',
23
+ 'success',
24
+ 'warning',
25
+ 'error',
26
+ 'unknown',
27
+ 'none'
28
+ ])('solid: should return the correct colors for status: %p', (status: Status) => {
29
+ const props = reactive({ status });
30
+ const {
31
+ borderColor,
32
+ backgroundColor,
33
+ textColor
34
+ } = useStatusColors(props, 'solid');
35
+
36
+ expect(borderColor.value).toBe(`var(--rc-${ status })`);
37
+ if (status !== 'none') {
38
+ // eslint-disable-next-line jest/no-conditional-expect
39
+ expect(backgroundColor.value).toBe(`var(--rc-${ status })`);
40
+ }
41
+ expect(textColor.value).toBe(`var(--rc-${ status }-secondary)`);
42
+ });
43
+
44
+ it.each([
45
+ 'info',
46
+ 'success',
47
+ 'warning',
48
+ 'error',
49
+ 'unknown',
50
+ 'none'
51
+ ])('outlined: should return the correct colors for status: %p', (status: Status) => {
52
+ const props = reactive({ status });
53
+ const {
54
+ borderColor,
55
+ backgroundColor,
56
+ textColor
57
+ } = useStatusColors(props, 'outlined');
58
+
59
+ expect(borderColor.value).toBe(`var(--rc-${ status }-secondary)`);
60
+ if (status !== 'none') {
61
+ // eslint-disable-next-line jest/no-conditional-expect
62
+ expect(backgroundColor.value).toBe(`var(--rc-${ status }-secondary)`);
63
+ }
64
+ expect(textColor.value).toBe(`var(--rc-${ status })`);
65
+ });
66
+ });
67
+ });
@@ -0,0 +1,77 @@
1
+ import { computed } from 'vue';
2
+
3
+ export const StatusDefinitions = {
4
+ info: {
5
+ primary: '--rc-info',
6
+ secondary: '--rc-info-secondary'
7
+ },
8
+ success: {
9
+ primary: '--rc-success',
10
+ secondary: '--rc-success-secondary'
11
+ },
12
+ warning: {
13
+ primary: '--rc-warning',
14
+ secondary: '--rc-warning-secondary'
15
+ },
16
+ error: {
17
+ primary: '--rc-error',
18
+ secondary: '--rc-error-secondary'
19
+ },
20
+ unknown: {
21
+ primary: '--rc-unknown',
22
+ secondary: '--rc-unknown-secondary'
23
+ },
24
+ none: {
25
+ primary: '--rc-none',
26
+ secondary: '--rc-none-secondary'
27
+ },
28
+ };
29
+
30
+ export type Status = keyof typeof StatusDefinitions;
31
+ export type StatusObject = { status: Status };
32
+ export type Style = 'solid' | 'outlined';
33
+
34
+ export function wrapIfVar(colorVar: string) {
35
+ return colorVar.startsWith('--') ? `var(${ colorVar })` : colorVar;
36
+ }
37
+
38
+ /**
39
+ * A composable to make it easier to use status colors in multiple components
40
+ *
41
+ * @param propsWithStatus The props which contain a `status: Status` property. Ideally I'd prefer to just pass status but doing so either forces the consumer to wrap the values in a Ref or this code is no longer reactive.
42
+ * @param style {@link Style} Will the block of code being using the solid or outlined styling
43
+ * @returns An object containing the relevant style colors
44
+ */
45
+ export function useStatusColors(propsWithStatus: StatusObject, style: Style) {
46
+ const statusColors = computed(() => {
47
+ return StatusDefinitions[propsWithStatus.status];
48
+ });
49
+ const isOutlined = style === 'outlined';
50
+
51
+ const borderColor = computed(() => {
52
+ const colorVar = isOutlined ? statusColors.value.secondary : statusColors.value.primary;
53
+
54
+ return wrapIfVar(colorVar);
55
+ });
56
+
57
+ const backgroundColor = computed(() => {
58
+ if (propsWithStatus.status === 'none') {
59
+ return 'none';
60
+ }
61
+ const colorVar = isOutlined ? statusColors.value.secondary : statusColors.value.primary;
62
+
63
+ return wrapIfVar(colorVar);
64
+ });
65
+
66
+ const textColor = computed(() => {
67
+ const colorVar = isOutlined ? statusColors.value.primary : statusColors.value.secondary;
68
+
69
+ return wrapIfVar(colorVar);
70
+ });
71
+
72
+ return {
73
+ borderColor,
74
+ backgroundColor,
75
+ textColor
76
+ };
77
+ }
@@ -29,6 +29,7 @@ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/prefs.js --declaration --al
29
29
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/plugins.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
30
30
 
31
31
  # # plugins
32
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/plugins/i18n.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/ > /dev/null
32
33
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/plugins/dashboard-store/normalize.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/plugins/dashboard-store/ > /dev/null
33
34
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/plugins/dashboard-store/resource-class.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/plugins/dashboard-store/ > /dev/null
34
35
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/plugins/dashboard-store/classify.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/plugins/dashboard-store/ > /dev/null
@@ -111,6 +111,14 @@ export const mutations = {
111
111
  state.modalData = data;
112
112
  },
113
113
 
114
+ updateModalData(state, data) {
115
+ state.modalData = state.modalData || {};
116
+
117
+ data.forEach(({ key, value }) => {
118
+ state.modalData[key] = value;
119
+ });
120
+ },
121
+
114
122
  clearCallbackData(state) {
115
123
  state.performCallbackData = undefined;
116
124
  },
package/store/auth.js CHANGED
@@ -404,18 +404,18 @@ export const actions = {
404
404
  // Unload plugins - we will load again on login
405
405
  await rootState.$plugin.logout();
406
406
 
407
- let logoutAction = 'logout';
407
+ let logoutAction = '';
408
408
  const data = {};
409
409
 
410
410
  // SLO - Single-sign logout - will logout auth provider from all places where it's logged in
411
411
  if (options.slo) {
412
- logoutAction = 'logoutAll';
412
+ logoutAction = '?logoutAll';
413
413
  data.finalRedirectUrl = returnTo({ isSlo: true }, this);
414
414
  }
415
415
 
416
416
  try {
417
417
  const res = await dispatch('rancher/request', {
418
- url: `/v3/tokens?action=${ logoutAction }`,
418
+ url: `/v1/logout${ logoutAction }`,
419
419
  method: 'post',
420
420
  data,
421
421
  headers: { 'Content-Type': 'application/json' },
package/store/catalog.js CHANGED
@@ -504,11 +504,16 @@ function addChart(ctx, map, chart, repo) {
504
504
 
505
505
  if ( !obj ) {
506
506
  if ( ctx ) { }
507
+
508
+ const primeOnly = chart.annotations?.[CATALOG_ANNOTATIONS.PRIME_ONLY] === 'true';
507
509
  const experimental = !!chart.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL];
508
510
  const windowsIncompatible = !(chart.annotations?.[CATALOG_ANNOTATIONS.PERMITTED_OS] || '').includes('windows');
509
511
  const deploysOnWindows = (chart.annotations?.[CATALOG_ANNOTATIONS.DEPLOYED_OS] || '').includes('windows');
510
512
  const tags = [];
511
513
 
514
+ if (primeOnly) {
515
+ tags.push(ctx.rootGetters['i18n/withFallback']('generic.primeOnly'));
516
+ }
512
517
  if (experimental) {
513
518
  tags.push(ctx.rootGetters['i18n/withFallback']('generic.experimental'));
514
519
  }
@@ -542,6 +547,7 @@ function addChart(ctx, map, chart, repo) {
542
547
  keywords: chart.keywords || [],
543
548
  categories: filterCategories(chart.keywords),
544
549
  deprecated: !!chart.deprecated,
550
+ primeOnly,
545
551
  experimental,
546
552
  hidden: !!chart.annotations?.[CATALOG_ANNOTATIONS.HIDDEN],
547
553
  targetNamespace: chart.annotations?.[CATALOG_ANNOTATIONS.NAMESPACE],
package/store/index.js CHANGED
@@ -263,7 +263,7 @@ export const state = () => {
263
263
  $route: markRaw({}),
264
264
  $plugin: markRaw({}),
265
265
  showWorkspaceSwitcher: true,
266
-
266
+ localCluster: null,
267
267
  };
268
268
  };
269
269
 
@@ -272,10 +272,20 @@ export const getters = {
272
272
  return state.clusterReady === true;
273
273
  },
274
274
 
275
+ /**
276
+ * Cache of the mgmt cluster fetched at start up
277
+ *
278
+ * We cannot rely on the store to cache this as the store may contain a page without the local cluster
279
+ */
280
+ localCluster(state) {
281
+ return state.localCluster;
282
+ },
283
+
275
284
  isMultiCluster(state, getters) {
276
- const clusters = getters['management/all'](MANAGEMENT.CLUSTER);
285
+ const clusterCount = getters['management/all'](COUNT)?.[0]?.counts?.[MANAGEMENT.CLUSTER]?.summary?.count || 0;
286
+ const localCluster = getters['localCluster'];
277
287
 
278
- if (clusters.length === 1 && clusters[0].metadata?.name === 'local') {
288
+ if (clusterCount === 1 && !!localCluster) {
279
289
  return false;
280
290
  } else {
281
291
  return true;
@@ -592,10 +602,9 @@ export const getters = {
592
602
  },
593
603
 
594
604
  isStandaloneHarvester(state, getters) {
595
- const clusters = getters['management/all'](MANAGEMENT.CLUSTER);
596
- const cluster = clusters.find((c) => c.id === 'local') || {};
605
+ const localCluster = getters['localCluster'];
597
606
 
598
- return getters['isSingleProduct'] && cluster.isHarvester && !getters['isRancherInHarvester'];
607
+ return getters['isSingleProduct'] && localCluster?.isHarvester && !getters['isRancherInHarvester'];
599
608
  },
600
609
 
601
610
  showTopLevelMenu(getters) {
@@ -640,9 +649,10 @@ export const mutations = {
640
649
  clearPageActionHandler(state) {
641
650
  state.pageActionHandler = null;
642
651
  },
643
- managementChanged(state, { ready, isRancher }) {
652
+ managementChanged(state, { ready, isRancher, localCluster }) {
644
653
  state.managementReady = ready;
645
654
  state.isRancher = isRancher;
655
+ state.localCluster = localCluster;
646
656
  },
647
657
  clusterReady(state, ready) {
648
658
  state.clusterReady = ready;
@@ -846,11 +856,21 @@ export const actions = {
846
856
 
847
857
  res = await allHash(promises);
848
858
 
859
+ let localCluster = null;
860
+
849
861
  if (!res[MANAGEMENT.SETTING] || !paginateClusters({ rootGetters, state })) {
850
862
  // This introduces a synchronous request, however we need settings to determine if SSP is enabled
851
- // Eventually it will be removed when SSP is always on
852
- res[MANAGEMENT.CLUSTER] = await dispatch('management/findAll', { type: MANAGEMENT.CLUSTER, opt: { watch: false } });
863
+ await dispatch('management/findAll', { type: MANAGEMENT.CLUSTER, opt: { watch: false } });
853
864
  toWatch.push(MANAGEMENT.CLUSTER);
865
+
866
+ localCluster = getters['management/byId'](MANAGEMENT.CLUSTER, 'local');
867
+ } else {
868
+ try {
869
+ localCluster = await dispatch('management/find', {
870
+ type: MANAGEMENT.CLUSTER, id: 'local', opt: { watch: false }
871
+ });
872
+ } catch (e) { // we don't care about errors, specifically 404s
873
+ }
854
874
  }
855
875
 
856
876
  // See comment above. Now that we have feature flags we can watch resources
@@ -858,11 +878,7 @@ export const actions = {
858
878
  dispatch('management/watch', { type });
859
879
  });
860
880
 
861
- const isMultiCluster = getters['isMultiCluster'];
862
-
863
881
  // If the local cluster is a Harvester cluster and 'rancher-manager-support' is true, it means that the embedded Rancher is being used.
864
- const localCluster = res[MANAGEMENT.CLUSTER]?.find((c) => c.id === 'local');
865
-
866
882
  if (localCluster?.isHarvester) {
867
883
  const harvesterSetting = await dispatch('cluster/findAll', { type: HCI.SETTING, opt: { url: `/v1/harvester/${ HCI.SETTING }s` } });
868
884
  const rancherManagerSupport = harvesterSetting.find((setting) => setting.id === 'rancher-manager-support');
@@ -904,6 +920,7 @@ export const actions = {
904
920
  commit('managementChanged', {
905
921
  ready: true,
906
922
  isRancher,
923
+ localCluster
907
924
  });
908
925
 
909
926
  if ( res[FLEET.WORKSPACE] ) {
@@ -914,6 +931,8 @@ export const actions = {
914
931
  });
915
932
  }
916
933
 
934
+ const isMultiCluster = getters['isMultiCluster'];
935
+
917
936
  console.log(`Done loading management; isRancher=${ isRancher }; isMultiCluster=${ isMultiCluster }`); // eslint-disable-line no-console
918
937
  },
919
938
 
@@ -1232,10 +1251,10 @@ export const actions = {
1232
1251
  }
1233
1252
  },
1234
1253
 
1235
- nuxtClientInit({ dispatch, commit, rootState }, nuxt) {
1236
- commit('setRouter', nuxt.app.router);
1237
- commit('setRoute', nuxt.route);
1238
- commit('setPlugin', nuxt.app.$plugin);
1254
+ dashboardClientInit({ dispatch, commit, rootState }, context) {
1255
+ commit('setRouter', context.app.router);
1256
+ commit('setRoute', context.route);
1257
+ commit('setPlugin', context.app.$plugin);
1239
1258
 
1240
1259
  dispatch('management/rehydrateSubscribe');
1241
1260
  dispatch('cluster/rehydrateSubscribe');
package/store/prefs.js CHANGED
@@ -523,15 +523,14 @@ export const actions = {
523
523
  setBrandStyle({ rootState, rootGetters }, dark = false) {
524
524
  if (rootState.managementReady) {
525
525
  try {
526
- const brandSetting = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.BRAND);
526
+ const brandSetting = rootGetters['management/brand'];
527
527
 
528
- if (brandSetting && brandSetting.value && brandSetting.value !== '') {
529
- const brand = brandSetting.value;
530
- const brandMeta = getBrandMeta(brand);
528
+ if (brandSetting !== '') {
529
+ const brandMeta = getBrandMeta(brandSetting);
531
530
  const hasStylesheet = brandMeta.hasStylesheet === 'true';
532
531
 
533
532
  if (hasStylesheet) {
534
- document.body.classList.add(brand);
533
+ document.body.classList.add(brandMeta);
535
534
  } else {
536
535
  // TODO option apply color at runtime
537
536
  }
package/store/type-map.js CHANGED
@@ -1895,7 +1895,7 @@ function ifHave(getters, option) {
1895
1895
  case IF_HAVE.NOT_V1_ISTIO: {
1896
1896
  return !isV1Istio(getters);
1897
1897
  }
1898
- case IF_HAVE.MULTI_CLUSTER: {
1898
+ case IF_HAVE.MULTI_CLUSTER: { // Used by harvester extension
1899
1899
  return getters.isMultiCluster;
1900
1900
  }
1901
1901
  case IF_HAVE.NEUVECTOR_NAMESPACE: {
@@ -1904,10 +1904,10 @@ function ifHave(getters, option) {
1904
1904
  case IF_HAVE.ADMIN: {
1905
1905
  return isAdminUser(getters);
1906
1906
  }
1907
- case IF_HAVE.MCM_DISABLED: {
1907
+ case IF_HAVE.MCM_DISABLED: { // There's a general MCM ff, this is conflating it with a harvester concept
1908
1908
  return !getters['isRancherInHarvester'];
1909
1909
  }
1910
- case IF_HAVE.NOT_STANDALONE_HARVESTER: {
1910
+ case IF_HAVE.NOT_STANDALONE_HARVESTER: { // Not used by harvester extension...
1911
1911
  return !getters['isStandaloneHarvester'];
1912
1912
  }
1913
1913
  default:
package/store/wm.ts CHANGED
@@ -80,11 +80,11 @@ export const mutations = {
80
80
  addTab(state: State, tab: Tab) {
81
81
  const existing = state.tabs.find((x) => x.id === tab.id);
82
82
 
83
- if (!existing) {
84
- if (tab.position === undefined) {
85
- tab.position = (window.localStorage.getItem(STORAGE_KEY['pin']) || BOTTOM) as Position;
86
- }
83
+ if (tab.position === undefined || tab.position as string === 'undefined') {
84
+ tab.position = (window.localStorage.getItem(STORAGE_KEY['pin']) || BOTTOM) as Position;
85
+ }
87
86
 
87
+ if (!existing) {
88
88
  if (state.lockedPositions.includes(BOTTOM)) {
89
89
  tab.position = BOTTOM;
90
90
  }