@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.4

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 (172) hide show
  1. package/assets/styles/base/_basic.scss +7 -8
  2. package/assets/styles/global/_button.scss +10 -0
  3. package/assets/styles/global/_form.scss +2 -1
  4. package/assets/styles/global/_tooltip.scss +2 -2
  5. package/assets/styles/themes/_dark.scss +15 -3
  6. package/assets/styles/themes/_light.scss +7 -2
  7. package/assets/styles/vendor/vue-select.scss +4 -0
  8. package/assets/translations/en-us.yaml +66 -9
  9. package/assets/translations/zh-hans.yaml +2 -3
  10. package/components/AppModal.vue +50 -0
  11. package/components/BannerGraphic.vue +0 -42
  12. package/components/ButtonMultiAction.vue +1 -1
  13. package/components/Carousel.vue +88 -74
  14. package/components/CommunityLinks.vue +6 -1
  15. package/components/CopyToClipboardText.vue +3 -0
  16. package/components/Dialog.vue +20 -1
  17. package/components/GrowlManager.vue +9 -2
  18. package/components/LocaleSelector.vue +8 -1
  19. package/components/PaginatedResourceTable.vue +4 -7
  20. package/components/ProgressBarMulti.vue +14 -0
  21. package/components/PromptChangePassword.vue +3 -0
  22. package/components/Questions/Reference.vue +57 -28
  23. package/components/ResourceDetail/Masthead.vue +1 -1
  24. package/components/SelectIconGrid.vue +12 -1
  25. package/components/SideNav.vue +12 -38
  26. package/components/SortableTable/index.vue +1 -0
  27. package/components/Tabbed/index.vue +9 -1
  28. package/components/YamlEditor.vue +1 -0
  29. package/components/__tests__/Carousel.test.ts +56 -27
  30. package/components/auth/Principal.vue +5 -3
  31. package/components/fleet/FleetClusters.vue +82 -1
  32. package/components/fleet/FleetRepos.vue +13 -30
  33. package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
  34. package/components/form/ChangePassword.vue +2 -0
  35. package/components/form/ColorInput.vue +24 -1
  36. package/components/form/FileSelector.vue +2 -0
  37. package/components/form/KeyValue.vue +230 -160
  38. package/components/form/LabeledSelect.vue +2 -2
  39. package/components/form/PlusMinus.vue +14 -2
  40. package/components/form/ResourceLabeledSelect.vue +13 -53
  41. package/components/form/ResourceSelector.vue +1 -0
  42. package/components/form/ResourceTabs/index.vue +79 -36
  43. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
  44. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
  45. package/components/form/SSHKnownHosts/index.vue +101 -0
  46. package/components/form/SecretSelector.vue +2 -2
  47. package/components/form/Select.vue +1 -1
  48. package/components/form/SelectOrCreateAuthSecret.vue +43 -11
  49. package/components/form/__tests__/KeyValue.test.ts +1 -1
  50. package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
  51. package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
  52. package/components/formatter/FleetSummaryGraph.vue +6 -7
  53. package/components/formatter/WorkloadHealthScale.vue +7 -0
  54. package/components/nav/Group.vue +30 -4
  55. package/components/nav/Header.vue +82 -114
  56. package/components/nav/HeaderPageActionMenu.vue +27 -131
  57. package/components/nav/NamespaceFilter.vue +1 -1
  58. package/components/nav/Type.vue +15 -0
  59. package/composables/focusTrap.ts +68 -0
  60. package/config/home-links.js +21 -13
  61. package/config/labels-annotations.js +2 -0
  62. package/config/page-actions.js +1 -0
  63. package/config/pagination-table-headers.js +15 -1
  64. package/config/product/explorer.js +7 -17
  65. package/config/table-headers.js +6 -0
  66. package/config/version.js +5 -1
  67. package/core/plugin.ts +41 -1
  68. package/core/plugins.js +125 -72
  69. package/core/types-provisioning.ts +91 -2
  70. package/core/types.ts +55 -0
  71. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
  72. package/detail/catalog.cattle.io.app.vue +1 -1
  73. package/detail/fleet.cattle.io.cluster.vue +3 -3
  74. package/detail/namespace.vue +13 -19
  75. package/detail/networking.k8s.io.ingress.vue +13 -53
  76. package/detail/provisioning.cattle.io.cluster.vue +12 -1
  77. package/detail/secret.vue +25 -0
  78. package/detail/workload/index.vue +3 -3
  79. package/dialog/AddCustomBadgeDialog.vue +5 -1
  80. package/edit/auth/ldap/__tests__/config.test.ts +18 -0
  81. package/edit/auth/ldap/config.vue +24 -0
  82. package/edit/auth/saml.vue +8 -6
  83. package/edit/fleet.cattle.io.gitrepo.vue +34 -23
  84. package/edit/logging-flow/index.vue +4 -19
  85. package/edit/networking.k8s.io.ingress/index.vue +18 -65
  86. package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
  87. package/edit/provisioning.cattle.io.cluster/index.vue +27 -8
  88. package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
  89. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
  90. package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
  91. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
  92. package/edit/secret/index.vue +1 -1
  93. package/edit/secret/ssh.vue +21 -3
  94. package/edit/service.vue +1 -2
  95. package/list/networking.k8s.io.ingress.vue +1 -1
  96. package/list/node.vue +15 -8
  97. package/list/persistentvolume.vue +12 -4
  98. package/list/provisioning.cattle.io.cluster.vue +1 -0
  99. package/list/service.vue +1 -1
  100. package/list/workload.vue +4 -0
  101. package/mixins/chart.js +4 -1
  102. package/models/catalog.cattle.io.app.js +3 -1
  103. package/models/catalog.cattle.io.clusterrepo.js +56 -7
  104. package/models/fleet.cattle.io.bundle.js +0 -11
  105. package/models/fleet.cattle.io.cluster.js +17 -1
  106. package/models/fleet.cattle.io.gitrepo.js +88 -52
  107. package/models/provisioning.cattle.io.cluster.js +36 -1
  108. package/models/secret.js +5 -0
  109. package/models/service.js +1 -0
  110. package/models/workload.js +19 -1
  111. package/package.json +5 -4
  112. package/pages/account/index.vue +4 -0
  113. package/pages/c/_cluster/apps/charts/index.vue +4 -0
  114. package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
  115. package/pages/c/_cluster/explorer/index.vue +13 -6
  116. package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
  117. package/pages/c/_cluster/fleet/index.vue +75 -89
  118. package/pages/c/_cluster/settings/links.vue +2 -2
  119. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
  120. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
  121. package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
  122. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
  123. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
  124. package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
  125. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
  126. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
  127. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
  128. package/pages/c/_cluster/uiplugins/index.vue +50 -12
  129. package/pages/diagnostic.vue +17 -15
  130. package/pages/home.vue +32 -6
  131. package/plugins/clean-html.js +50 -0
  132. package/plugins/dashboard-store/resource-class.js +4 -0
  133. package/plugins/plugin.js +54 -49
  134. package/plugins/steve/mutations.js +1 -1
  135. package/plugins/steve/steve-class.js +8 -0
  136. package/plugins/steve/steve-pagination-utils.ts +3 -1
  137. package/rancher-components/Accordion/Accordion.vue +4 -4
  138. package/rancher-components/BadgeState/BadgeState.vue +7 -0
  139. package/rancher-components/Card/Card.vue +12 -0
  140. package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
  141. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  142. package/rancher-components/Form/LabeledInput/LabeledInput.vue +19 -1
  143. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
  144. package/rancher-components/RcButton/RcButton.vue +90 -0
  145. package/rancher-components/RcButton/index.ts +2 -0
  146. package/rancher-components/RcButton/types.ts +17 -0
  147. package/rancher-components/RcDropdown/RcDropdown.vue +122 -0
  148. package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
  149. package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
  150. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
  151. package/rancher-components/RcDropdown/index.ts +4 -0
  152. package/rancher-components/RcDropdown/types.ts +22 -0
  153. package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
  154. package/rancher-components/RcDropdown/useDropdownContext.ts +110 -0
  155. package/scripts/test-plugins-build.sh +2 -0
  156. package/scripts/typegen.sh +2 -0
  157. package/store/catalog.js +1 -1
  158. package/tsconfig.json +2 -1
  159. package/types/components/paginatedResourceTable.ts +25 -0
  160. package/types/components/resourceLabeledSelect.ts +48 -0
  161. package/types/resources/fleet.d.ts +17 -0
  162. package/types/shell/index.d.ts +61 -0
  163. package/utils/auth.js +5 -1
  164. package/utils/cluster.js +106 -0
  165. package/utils/fleet.ts +35 -3
  166. package/utils/ingress.ts +64 -0
  167. package/utils/uiplugins.ts +56 -44
  168. package/utils/validators/cron-schedule.js +7 -2
  169. package/utils/validators/formRules/__tests__/index.test.ts +53 -17
  170. package/utils/validators/formRules/index.ts +20 -5
  171. package/vue.config.js +1 -1
  172. package/components/RelatedWorkloadsTable.vue +0 -50
@@ -1,7 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed } from 'vue';
3
3
  import { useStore } from 'vuex';
4
- import { useClickOutside } from '@shell/composables/useClickOutside';
4
+ import {
5
+ RcDropdown,
6
+ RcDropdownItem,
7
+ RcDropdownSeparator,
8
+ RcDropdownTrigger
9
+ } from '@components/RcDropdown';
5
10
 
6
11
  const isPageActionMenuOpen = ref(false);
7
12
 
@@ -15,141 +20,32 @@ const pageAction = (action: string) => {
15
20
  store.dispatch('handlePageAction', action);
16
21
  showPageActionsMenu(false);
17
22
  };
18
-
19
- const target = ref(null);
20
-
21
- useClickOutside(target, () => showPageActionsMenu(false));
22
-
23
- const handleBlurEvent = (event: KeyboardEvent) => {
24
- if (event.key === 'Tab') {
25
- showPageActionsMenu(false);
26
- }
27
- };
28
23
  </script>
29
24
 
30
25
  <template>
31
- <v-dropdown
32
- class="actions"
33
- :triggers="[]"
34
- :shown="isPageActionMenuOpen"
35
- :autoHide="false"
36
- :flip="false"
37
- :placement="'bottom-end'"
38
- :distance="-6"
39
- :container="'.page-actions'"
40
- >
41
- <i
26
+ <rc-dropdown :aria-label="t('nav.actionMenu.label')">
27
+ <rc-dropdown-trigger
28
+ tertiary
42
29
  data-testid="page-actions-menu"
43
- class="icon icon-actions"
44
- tabindex="0"
45
- @keydown="handleBlurEvent"
46
- @click="showPageActionsMenu(true)"
47
- @focus.capture="showPageActionsMenu(true)"
48
- />
49
-
50
- <template #popper>
51
- <div
52
- ref="target"
53
- class="user-menu"
30
+ :aria-label="t('nav.actionMenu.button.label')"
31
+ >
32
+ <i class="icon icon-actions" />
33
+ </rc-dropdown-trigger>
34
+ <template #dropdownCollection>
35
+ <template
36
+ v-for="(a) in pageActions"
37
+ :key="a.label"
54
38
  >
55
- <ul
56
- data-testid="page-actions-dropdown"
57
- class="list-unstyled dropdown"
39
+ <rc-dropdown-item
40
+ v-if="!a.separator"
41
+ @click="pageAction(a)"
58
42
  >
59
- <li
60
- v-for="(a) in pageActions"
61
- :key="a.label"
62
- class="user-menu-item"
63
- >
64
- <a
65
- v-if="!a.separator"
66
- @click="pageAction(a)"
67
- >{{ a.labelKey ? t(a.labelKey) : a.label }}</a>
68
- <div
69
- v-else
70
- class="menu-separator"
71
- >
72
- <div class="menu-separator-line" />
73
- </div>
74
- </li>
75
- </ul>
76
- </div>
43
+ {{ a.labelKey ? t(a.labelKey) : a.label }}
44
+ </rc-dropdown-item>
45
+ <rc-dropdown-separator
46
+ v-else
47
+ />
48
+ </template>
77
49
  </template>
78
- </v-dropdown>
79
- <div class="page-actions">
80
- <!--Empty container for mounting popper content-->
81
- </div>
50
+ </rc-dropdown>
82
51
  </template>
83
-
84
- <style lang="scss" scoped>
85
- .page-actions :deep(.v-popper__popper) {
86
- .v-popper__wrapper {
87
- .v-popper__arrow-container {
88
- display: none;
89
- }
90
-
91
- .v-popper__inner {
92
- padding: 10px 0 10px 0;
93
- }
94
- }
95
- }
96
-
97
- .icon-actions:focus {
98
- outline: 0;
99
- }
100
-
101
- .user-menu-item {
102
- a, &.no-link > span {
103
- cursor: pointer;
104
- padding: 0px 10px;
105
-
106
- &:hover {
107
- background-color: var(--dropdown-hover-bg);
108
- color: var(--dropdown-hover-text);
109
- text-decoration: none;
110
- }
111
-
112
- // When the menu item is focused, pop the margin and compensate the padding, so that
113
- // the focus border appears within the menu
114
- &:focus {
115
- margin: 0 2px;
116
- padding: 10px 8px;
117
- }
118
- }
119
-
120
- &.no-link > span {
121
- display: flex;
122
- justify-content: space-between;
123
- padding: 10px;
124
- color: var(--link);
125
- }
126
-
127
- div.menu-separator {
128
- cursor: default;
129
- padding: 4px 0;
130
-
131
- .menu-separator-line {
132
- background-color: var(--border);
133
- height: 1px;
134
- }
135
- }
136
- }
137
-
138
- .list-unstyled {
139
- li {
140
- a {
141
- display: flex;
142
- justify-content: space-between;
143
- padding: 10px;
144
- }
145
-
146
- &.user-info {
147
- display: block;
148
- margin-bottom: 10px;
149
- padding: 10px 20px;
150
- border-bottom: solid 1px var(--border);
151
- min-width: 200px;
152
- }
153
- }
154
- }
155
- </style>
@@ -1008,7 +1008,7 @@ export default {
1008
1008
  &.ns-selected:not(:hover) {
1009
1009
  .ns-item {
1010
1010
  > * {
1011
- color: var(--dropdown-hover-bg);
1011
+ color: var(--primary);
1012
1012
  }
1013
1013
  }
1014
1014
 
@@ -118,7 +118,10 @@ export default {
118
118
  {{ type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label) }}
119
119
  </TabTitle>
120
120
  <a
121
+ role="link"
122
+ :aria-label="type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label)"
121
123
  :href="href"
124
+ class="type-link"
122
125
  @click="selectType(); navigate($event);"
123
126
  @mouseenter="setNear(true)"
124
127
  @mouseleave="setNear(false)"
@@ -161,9 +164,11 @@ export default {
161
164
  data-testid="link-type"
162
165
  >
163
166
  <a
167
+ role="link"
164
168
  :href="type.link"
165
169
  :target="type.target"
166
170
  rel="noopener noreferrer nofollow"
171
+ :aria-label="type.label"
167
172
  >
168
173
  <span class="label">{{ type.label }}&nbsp;<i class="icon icon-external-link" /></span>
169
174
  </a>
@@ -178,6 +183,16 @@ export default {
178
183
  margin-right: 4px;
179
184
  }
180
185
 
186
+ .type-link:focus-visible span.label {
187
+ @include focus-outline;
188
+ outline-offset: 2px;
189
+ }
190
+
191
+ .nav-link a:focus-visible .label {
192
+ @include focus-outline;
193
+ outline-offset: 2px;
194
+ }
195
+
181
196
  .child {
182
197
  margin: 0 var(--outline) 0 0;
183
198
 
@@ -0,0 +1,68 @@
1
+ /**
2
+ * focusTrap is a composable based on the "focus-trap" package that allows us to implement focus traps
3
+ * on components for keyboard navigation is a safe and reusable way
4
+ */
5
+ import { watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
6
+ import { createFocusTrap, FocusTrap } from 'focus-trap';
7
+
8
+ export function getFirstFocusableElement(element:any = document):any {
9
+ const focusableElements = element.querySelectorAll(
10
+ 'a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])'
11
+ );
12
+ const filteredFocusableElements:any = [];
13
+
14
+ focusableElements.forEach((el:any) => {
15
+ if (!el.hasAttribute('disabled')) {
16
+ filteredFocusableElements.push(el);
17
+ }
18
+ });
19
+
20
+ return filteredFocusableElements.length ? filteredFocusableElements[0] : document.body;
21
+ }
22
+
23
+ export const DEFAULT_FOCUS_TRAP_OPTS = {
24
+ escapeDeactivates: true,
25
+ allowOutsideClick: true
26
+ };
27
+
28
+ export function useBasicSetupFocusTrap(focusElement: string | HTMLElement, opts:any = DEFAULT_FOCUS_TRAP_OPTS) {
29
+ let focusTrapInstance: FocusTrap;
30
+ let focusEl;
31
+
32
+ onMounted(() => {
33
+ focusEl = typeof focusElement === 'string' ? document.querySelector(focusElement) as HTMLElement : focusElement;
34
+
35
+ focusTrapInstance = createFocusTrap(focusEl, opts);
36
+
37
+ nextTick(() => {
38
+ focusTrapInstance.activate();
39
+ });
40
+ });
41
+
42
+ onBeforeUnmount(() => {
43
+ if (Object.keys(focusTrapInstance).length) {
44
+ focusTrapInstance.deactivate();
45
+ }
46
+ });
47
+ }
48
+
49
+ export function useWatcherBasedSetupFocusTrapWithDestroyIncluded(watchVar:any, focusElement: string | HTMLElement, opts:any = DEFAULT_FOCUS_TRAP_OPTS) {
50
+ let focusTrapInstance: FocusTrap;
51
+ let focusEl;
52
+
53
+ watch(watchVar, (neu) => {
54
+ if (neu) {
55
+ nextTick(() => {
56
+ focusEl = typeof focusElement === 'string' ? document.querySelector(focusElement) as HTMLElement : focusElement;
57
+
58
+ focusTrapInstance = createFocusTrap(focusEl, opts);
59
+
60
+ nextTick(() => {
61
+ focusTrapInstance.activate();
62
+ });
63
+ });
64
+ } else if (!neu && Object.keys(focusTrapInstance).length) {
65
+ focusTrapInstance.deactivate();
66
+ }
67
+ });
68
+ }
@@ -33,9 +33,11 @@ const DEFAULT_LINKS = [
33
33
  },
34
34
  ];
35
35
 
36
- const COLLECTIVE_LINK = {
37
- key: 'suseCollective',
38
- value: 'https://susecollective.suse.com/join/prime',
36
+ const COLLECTIVE_LINK_ID = 'suseCollective';
37
+
38
+ const APP_COLLECTION_LINK = {
39
+ key: 'appCo',
40
+ value: 'https://apps.rancher.io/',
39
41
  enabled: true,
40
42
  };
41
43
 
@@ -55,9 +57,12 @@ const CN_FORUMS_LINK = {
55
57
  // We add a version attribute to the setting so we know what has been migrated and which version of the setting we have
56
58
  export const CUSTOM_LINKS_VERSION = 'v1';
57
59
 
58
- // Version with collective added (Prime)
60
+ // Version with SUSE Collective link added (Prime)
59
61
  export const CUSTOM_LINKS_COLLECTIVE_VERSION = 'v1.1';
60
62
 
63
+ // Version with Application Collective added (Prime)
64
+ export const CUSTOM_LINKS_APP_CO_VERSION = 'v1.2';
65
+
61
66
  // Fetch the settings required for the links, taking into account legacy settings if we have not migrated
62
67
  export async function fetchLinks(store, hasSupport, isSupportPage, t) {
63
68
  let uiLinks = {};
@@ -75,23 +80,26 @@ export async function fetchLinks(store, hasSupport, isSupportPage, t) {
75
80
 
76
81
  // If uiLinks is set and has the correct version, then we are okay, otherwise we need to migrate from the old settings
77
82
  if (uiLinks?.version?.startsWith(CUSTOM_LINKS_VERSION)) {
78
- // v1 > v1.1 migration
79
- if (uiLinks?.version === CUSTOM_LINKS_VERSION) {
80
- uiLinks.version = CUSTOM_LINKS_COLLECTIVE_VERSION;
83
+ // v1 or v1.1 > v1.2 migration
84
+ if (uiLinks?.version === CUSTOM_LINKS_VERSION || uiLinks?.version === CUSTOM_LINKS_COLLECTIVE_VERSION) {
85
+ uiLinks.version = CUSTOM_LINKS_APP_CO_VERSION;
81
86
 
82
87
  // Add collective link so that it is enabled by default
83
- if (!uiLinks.defaults.includes(COLLECTIVE_LINK.key)) {
84
- uiLinks.defaults.push(COLLECTIVE_LINK.key);
88
+ if (!uiLinks.defaults.includes(APP_COLLECTION_LINK.key)) {
89
+ uiLinks.defaults.push(APP_COLLECTION_LINK.key);
85
90
  }
91
+
92
+ // Delete the SUSE Collective link if it is there since it has been removed
93
+ uiLinks.defaults = uiLinks.defaults.filter((link) => link !== COLLECTIVE_LINK_ID);
86
94
  }
87
95
 
88
96
  // Map out the default settings, as we only store keys of the ones to show
89
97
  if (uiLinks.defaults) {
90
98
  const defaults = [...DEFAULT_LINKS];
91
99
 
92
- // Add prime link if necessary
100
+ // Add Prime link if necessary
93
101
  if (isRancherPrime()) {
94
- defaults.push(COLLECTIVE_LINK);
102
+ defaults.push(APP_COLLECTION_LINK);
95
103
  }
96
104
 
97
105
  // Map the link name stored to the default link, if it exists
@@ -115,9 +123,9 @@ export async function fetchLinks(store, hasSupport, isSupportPage, t) {
115
123
  custom: []
116
124
  };
117
125
 
118
- // Add prime link if necessary
126
+ // Add prime link (application collection) if necessary
119
127
  if (isRancherPrime()) {
120
- links.defaults.push(COLLECTIVE_LINK);
128
+ links.defaults.push(APP_COLLECTION_LINK);
121
129
  }
122
130
 
123
131
  // There are two legacy settings:
@@ -112,6 +112,8 @@ export const FLEET = {
112
112
  CLUSTER_DISPLAY_NAME: 'management.cattle.io/cluster-display-name',
113
113
  CLUSTER_NAME: 'management.cattle.io/cluster-name',
114
114
  BUNDLE_ID: 'fleet.cattle.io/bundle-id',
115
+ BUNDLE_NAME: 'fleet.cattle.io/bundle-name',
116
+ BUNDLE_NAMESPACE: 'fleet.cattle.io/bundle-namespace',
115
117
  MANAGED: 'fleet.cattle.io/managed',
116
118
  CLUSTER_NAMESPACE: 'fleet.cattle.io/cluster-namespace',
117
119
  CLUSTER: 'fleet.cattle.io/cluster'
@@ -1,3 +1,4 @@
1
1
  export const RESET_CARDS_ACTION = 'reset-homepage-cards';
2
2
  export const SET_LOGIN_ACTION = 'set-as-login';
3
3
  export const ADD_CUSTOM_NAV_LINK = 'add-custom-nav-link';
4
+ export const SHOW_HIDE_BANNER_ACTION = 'toggle-homepage-banner';
@@ -1,5 +1,7 @@
1
1
  import {
2
- STATE, NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE, OBJECT
2
+ STATE, NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE, OBJECT,
3
+ EVENT_LAST_SEEN_TIME,
4
+ EVENT_TYPE
3
5
  } from '@shell/config/table-headers';
4
6
 
5
7
  // This file contains table headers
@@ -52,6 +54,18 @@ export const STEVE_EVENT_OBJECT = {
52
54
  search: 'involvedObject.kind',
53
55
  };
54
56
 
57
+ export const STEVE_EVENT_LAST_SEEN = {
58
+ ...EVENT_LAST_SEEN_TIME,
59
+ value: 'metadata.fields.0',
60
+ sort: 'metadata.fields.0',
61
+ };
62
+
63
+ export const STEVE_EVENT_TYPE = {
64
+ ...EVENT_TYPE,
65
+ value: '_type',
66
+ sort: '_type',
67
+ };
68
+
55
69
  export const STEVE_LIST_GROUPS = [{
56
70
  tooltipKey: 'resourceTable.groupBy.none',
57
71
  icon: 'icon-list-flat',
@@ -20,12 +20,13 @@ import {
20
20
  STORAGE_CLASS_PROVISIONER, PERSISTENT_VOLUME_SOURCE,
21
21
  HPA_REFERENCE, MIN_REPLICA, MAX_REPLICA, CURRENT_REPLICA,
22
22
  ACCESS_KEY, DESCRIPTION, EXPIRES, EXPIRY_STATE, LAST_USED, SUB_TYPE, AGE_NORMAN, SCOPE_NORMAN, PERSISTENT_VOLUME_CLAIM, RECLAIM_POLICY, PV_REASON, WORKLOAD_HEALTH_SCALE, POD_RESTARTS,
23
- DURATION, MESSAGE, REASON, LAST_SEEN_TIME, EVENT_TYPE, OBJECT, ROLE, ROLES, VERSION, INTERNAL_EXTERNAL_IP, KUBE_NODE_OS, CPU, RAM, SECRET_DATA
23
+ DURATION, MESSAGE, REASON, EVENT_TYPE, OBJECT, ROLE, ROLES, VERSION, INTERNAL_EXTERNAL_IP, KUBE_NODE_OS, CPU, RAM, SECRET_DATA,
24
+ EVENT_LAST_SEEN_TIME
24
25
  } from '@shell/config/table-headers';
25
26
 
26
27
  import { DSL } from '@shell/store/type-map';
27
28
  import {
28
- STEVE_AGE_COL, STEVE_EVENT_OBJECT, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_NAME_COL, STEVE_STATE_COL
29
+ STEVE_AGE_COL, STEVE_EVENT_LAST_SEEN, STEVE_EVENT_OBJECT, STEVE_EVENT_TYPE, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_NAME_COL, STEVE_STATE_COL
29
30
  } from '@shell/config/pagination-table-headers';
30
31
 
31
32
  import { COLUMN_BREAKPOINTS } from '@shell/types/store/type-map';
@@ -321,23 +322,12 @@ export function init(store) {
321
322
  ]
322
323
  );
323
324
 
324
- const eventLastSeenTime = {
325
- ...LAST_SEEN_TIME,
326
- defaultSort: true,
327
- };
328
-
329
325
  headers(EVENT,
330
- [STATE, eventLastSeenTime, EVENT_TYPE, REASON, OBJECT, 'Subobject', 'Source', MESSAGE, 'First Seen', 'Count', NAME_COL, NAMESPACE_COL],
326
+ [STATE, EVENT_LAST_SEEN_TIME, EVENT_TYPE, REASON, OBJECT, 'Subobject', 'Source', MESSAGE, 'First Seen', 'Count', NAME_COL, NAMESPACE_COL],
331
327
  [
332
- STEVE_STATE_COL, {
333
- ...eventLastSeenTime,
334
- value: 'metadata.fields.0',
335
- sort: 'metadata.fields.0',
336
- }, {
337
- ...EVENT_TYPE,
338
- value: '_type',
339
- sort: '_type',
340
- },
328
+ STEVE_STATE_COL,
329
+ STEVE_EVENT_LAST_SEEN,
330
+ STEVE_EVENT_TYPE,
341
331
  REASON,
342
332
  STEVE_EVENT_OBJECT,
343
333
  'Subobject',
@@ -515,6 +515,12 @@ export const LAST_SEEN_TIME = {
515
515
  sort: 'lastTimestamp:desc',
516
516
  tooltip: 'tableHeaders.lastSeenTooltip'
517
517
  };
518
+
519
+ export const EVENT_LAST_SEEN_TIME = {
520
+ ...LAST_SEEN_TIME,
521
+ defaultSort: true,
522
+ };
523
+
518
524
  export const LAST_HEARTBEAT_TIME = {
519
525
  name: 'lastHeartbeatTime',
520
526
  labelKey: 'tableHeaders.lastSeen',
package/config/version.js CHANGED
@@ -1,7 +1,11 @@
1
1
  /**
2
2
  * Store version data retrieved from the backend /rancherversion API
3
3
  */
4
- let _versionData = { RancherPrime: 'false' };
4
+ let _versionData = {
5
+ Version: '',
6
+ RancherPrime: 'false',
7
+ GitCommit: '',
8
+ };
5
9
  let _kubeVersionData = {};
6
10
 
7
11
  export function isRancherPrime() {
package/core/plugin.ts CHANGED
@@ -13,10 +13,19 @@ import {
13
13
  LocationConfig,
14
14
  ExtensionPoint,
15
15
  TabLocation,
16
- PluginRouteRecordRaw, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
16
+ ModelExtensionConstructor,
17
+ PluginRouteRecordRaw, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut,
18
+ ExtensionEnvironment
17
19
  } from './types';
18
20
  import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
19
21
  import { defineAsyncComponent, markRaw, Component } from 'vue';
22
+ import { getVersionData, CURRENT_RANCHER_VERSION } from '@shell/config/version';
23
+
24
+ // Registration IDs used for different extension points in the extensions catalog
25
+ export const EXT_IDS = {
26
+ MODELS: 'models',
27
+ MODEL_EXTENSION: 'model-extension',
28
+ };
20
29
 
21
30
  export type ProductFunction = (plugin: IPlugin, store: any) => void;
22
31
 
@@ -25,6 +34,7 @@ export class Plugin implements IPlugin {
25
34
  public name: string;
26
35
  public types: any = {};
27
36
  public l10n: { [key: string]: Function[] } = {};
37
+ public modelExtensions: { [key: string]: Function[] } = {};
28
38
  public locales: { locale: string, label: string}[] = [];
29
39
  public products: ProductFunction[] = [];
30
40
  public productNames: string[] = [];
@@ -57,6 +67,17 @@ export class Plugin implements IPlugin {
57
67
  });
58
68
  }
59
69
 
70
+ get environment(): ExtensionEnvironment {
71
+ const versionData = getVersionData();
72
+
73
+ return {
74
+ version: versionData.Version,
75
+ commit: versionData.GitCommit,
76
+ isPrime: versionData.RancherPrime === 'true',
77
+ docsVersion: `v${ CURRENT_RANCHER_VERSION }`
78
+ };
79
+ }
80
+
60
81
  get metadata() {
61
82
  return this._metadata;
62
83
  }
@@ -186,6 +207,17 @@ export class Plugin implements IPlugin {
186
207
  this._addUIConfig(ExtensionPoint.CARD, where, when, this._createAsyncComponent(card));
187
208
  }
188
209
 
210
+ /**
211
+ * Adds a model extension
212
+ * @experimental May change or be removed in the future
213
+ *
214
+ * @param type Model type
215
+ * @param clz Class for the model extension (constructor)
216
+ */
217
+ addModelExtension(type: string, clz: ModelExtensionConstructor): void {
218
+ this.register(EXT_IDS.MODEL_EXTENSION, type, clz);
219
+ }
220
+
189
221
  /**
190
222
  * Wraps a component from an extensionConfig with defineAsyncComponent and
191
223
  * markRaw. This prepares the component to be loaded dynamically and prevents
@@ -317,10 +349,18 @@ export class Plugin implements IPlugin {
317
349
  }
318
350
 
319
351
  this.l10n[name].push(fn);
352
+
353
+ // Accumulate model extensions
354
+ } else if (type === EXT_IDS.MODEL_EXTENSION) {
355
+ if (!this.modelExtensions[name]) {
356
+ this.modelExtensions[name] = [];
357
+ }
358
+ this.modelExtensions[name].push(fn);
320
359
  } else {
321
360
  if (!this.types[type]) {
322
361
  this.types[type] = {};
323
362
  }
363
+
324
364
  this.types[type][name] = fn;
325
365
  }
326
366
  }