@rancher/shell 3.0.4 → 3.0.5-rc.2

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 (270) hide show
  1. package/assets/images/providers/sks.svg +1 -0
  2. package/assets/styles/base/_basic.scss +6 -0
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +1 -0
  5. package/assets/styles/global/_button.scss +1 -0
  6. package/assets/translations/en-us.yaml +65 -15
  7. package/assets/translations/zh-hans.yaml +4 -3
  8. package/chart/monitoring/index.vue +3 -1
  9. package/cloud-credential/aws.vue +2 -0
  10. package/components/ActionDropdownShell.vue +71 -0
  11. package/components/AppModal.vue +18 -4
  12. package/components/AsyncButton.vue +24 -7
  13. package/components/BannerGraphic.vue +1 -0
  14. package/components/CommunityLinks.vue +4 -59
  15. package/components/CopyToClipboardText.vue +2 -1
  16. package/components/CruResource.vue +6 -1
  17. package/components/DetailText.vue +5 -0
  18. package/components/ExplorerMembers.vue +1 -1
  19. package/components/ExplorerProjectsNamespaces.vue +68 -18
  20. package/components/GlobalRoleBindings.vue +5 -1
  21. package/components/GrowlManager.vue +1 -0
  22. package/components/LandingPagePreference.vue +7 -3
  23. package/components/LocaleSelector.vue +39 -95
  24. package/components/ModalManager.vue +55 -0
  25. package/components/ModalWithCard.vue +1 -0
  26. package/components/PromptModal.vue +47 -8
  27. package/components/PromptRemove.vue +1 -0
  28. package/components/PromptRestore.vue +1 -0
  29. package/components/ResourceCancelModal.vue +1 -0
  30. package/components/ResourceDetail/Masthead.vue +38 -12
  31. package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
  32. package/components/ResourceDetail/index.vue +47 -12
  33. package/components/ResourceTable.vue +54 -19
  34. package/components/SideNav.vue +5 -1
  35. package/components/SlideInPanelManager.vue +126 -0
  36. package/components/SortableTable/THead.vue +5 -2
  37. package/components/SortableTable/actions.js +1 -1
  38. package/components/SortableTable/index.vue +64 -51
  39. package/components/SortableTable/paging.js +16 -19
  40. package/components/SortableTable/selection.js +0 -11
  41. package/components/Wizard.vue +2 -2
  42. package/components/__tests__/AsyncButton.test.ts +2 -2
  43. package/components/__tests__/ModalManager.spec.ts +176 -0
  44. package/components/__tests__/PromptModal.test.ts +148 -0
  45. package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
  46. package/components/auth/AuthBanner.vue +13 -11
  47. package/components/auth/Principal.vue +1 -0
  48. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  49. package/components/auth/login/ldap.vue +1 -1
  50. package/components/fleet/FleetResources.vue +21 -6
  51. package/components/form/ArrayList.vue +76 -60
  52. package/components/form/BannerSettings.vue +17 -2
  53. package/components/form/ColorInput.vue +35 -6
  54. package/components/form/Command.vue +6 -15
  55. package/components/form/EnvVars.vue +16 -8
  56. package/components/form/HealthCheck.vue +3 -3
  57. package/components/form/HookOption.vue +11 -16
  58. package/components/form/LabeledSelect.vue +18 -22
  59. package/components/form/LifecycleHooks.vue +3 -3
  60. package/components/form/MatchExpressions.vue +14 -8
  61. package/components/form/NameNsDescription.vue +128 -104
  62. package/components/form/Networking.vue +20 -12
  63. package/components/form/NodeAffinity.vue +31 -23
  64. package/components/form/NodeScheduling.vue +13 -3
  65. package/components/form/NotificationSettings.vue +15 -1
  66. package/components/form/Password.vue +1 -0
  67. package/components/form/PodAffinity.vue +43 -43
  68. package/components/form/Probe.vue +68 -66
  69. package/components/form/ResourceQuota/Project.vue +5 -1
  70. package/components/form/ResourceSelector.vue +7 -9
  71. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +16 -24
  72. package/components/form/SSHKnownHosts/index.vue +30 -13
  73. package/components/form/Security.vue +54 -56
  74. package/components/form/Select.vue +32 -21
  75. package/components/form/ShellInput.vue +5 -1
  76. package/components/form/Tolerations.vue +5 -1
  77. package/components/form/ValueFromResource.vue +134 -121
  78. package/components/form/WorkloadPorts.vue +18 -18
  79. package/components/form/__tests__/ArrayList.test.ts +5 -2
  80. package/components/form/__tests__/ColorInput.test.ts +35 -0
  81. package/components/form/__tests__/LabeledSelect.test.ts +40 -0
  82. package/components/form/__tests__/MatchExpressions.test.ts +12 -12
  83. package/components/form/__tests__/NameNsDescription.test.ts +115 -14
  84. package/components/form/__tests__/Probe.test.ts +12 -8
  85. package/components/form/__tests__/SSHKnownHosts.test.ts +22 -2
  86. package/components/form/__tests__/Select.test.ts +37 -0
  87. package/components/formatter/InternalExternalIP.vue +2 -0
  88. package/components/formatter/SecretData.vue +20 -7
  89. package/components/nav/Group.vue +27 -5
  90. package/components/nav/Header.vue +17 -43
  91. package/components/nav/NamespaceFilter.vue +134 -86
  92. package/components/nav/TopLevelMenu.vue +4 -5
  93. package/components/nav/Type.vue +12 -1
  94. package/components/nav/WindowManager/ContainerLogs.vue +87 -61
  95. package/components/nav/WindowManager/ContainerLogsActions.vue +76 -0
  96. package/components/templates/blank.vue +4 -1
  97. package/components/templates/default.vue +8 -3
  98. package/components/templates/home.vue +10 -1
  99. package/components/templates/plain.vue +10 -4
  100. package/composables/focusTrap.ts +12 -4
  101. package/composables/useRuntimeFlag.ts +29 -0
  102. package/config/router/routes.js +20 -13
  103. package/config/store.js +4 -0
  104. package/config/uiplugins.js +5 -1
  105. package/core/types.ts +12 -6
  106. package/detail/catalog.cattle.io.app.vue +6 -1
  107. package/detail/fleet.cattle.io.bundle.vue +70 -6
  108. package/detail/fleet.cattle.io.gitrepo.vue +1 -1
  109. package/detail/namespace.vue +0 -3
  110. package/detail/node.vue +17 -13
  111. package/detail/provisioning.cattle.io.cluster.vue +72 -6
  112. package/dialog/AddCustomBadgeDialog.vue +1 -1
  113. package/{pages/c/_cluster/uiplugins/AddExtensionRepos.vue → dialog/AddExtensionReposDialog.vue} +72 -42
  114. package/{components/AssignTo.vue → dialog/AssignToDialog.vue} +71 -80
  115. package/dialog/ChangePasswordDialog.vue +106 -0
  116. package/dialog/DeactivateDriverDialog.vue +1 -0
  117. package/{pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue → dialog/DeveloperLoadExtensionDialog.vue} +74 -71
  118. package/dialog/DisableAuthProviderDialog.vue +101 -0
  119. package/dialog/DrainNode.vue +1 -1
  120. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue → dialog/ExtensionCatalogInstallDialog.vue} +100 -88
  121. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue → dialog/ExtensionCatalogUninstallDialog.vue} +69 -57
  122. package/dialog/FeatureFlagListDialog.vue +288 -0
  123. package/dialog/ForceMachineRemoveDialog.vue +5 -2
  124. package/{components/Import.vue → dialog/ImportDialog.vue} +0 -5
  125. package/{pages/c/_cluster/uiplugins/InstallDialog.vue → dialog/InstallExtensionDialog.vue} +124 -106
  126. package/{components/form/SSHKnownHosts → dialog}/KnownHostsEditDialog.vue +52 -59
  127. package/dialog/MoveNamespaceDialog.vue +157 -0
  128. package/dialog/ScalePoolDownDialog.vue +1 -1
  129. package/{components/nav/Jump.vue → dialog/SearchDialog.vue} +34 -14
  130. package/{pages/c/_cluster/uiplugins/UninstallDialog.vue → dialog/UninstallExtensionDialog.vue} +67 -58
  131. package/dialog/WechatDialog.vue +57 -0
  132. package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +16 -3
  133. package/edit/auth/__tests__/oidc.test.ts +152 -109
  134. package/edit/auth/azuread.vue +2 -1
  135. package/edit/auth/github.vue +1 -1
  136. package/edit/auth/googleoauth.vue +5 -1
  137. package/edit/auth/ldap/index.vue +1 -1
  138. package/edit/auth/oidc.vue +38 -5
  139. package/edit/auth/saml.vue +1 -1
  140. package/edit/cloudcredential.vue +24 -9
  141. package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +40 -9
  142. package/edit/management.cattle.io.user.vue +28 -3
  143. package/edit/namespace.vue +1 -4
  144. package/edit/networking.k8s.io.ingress/IngressClass.vue +7 -3
  145. package/edit/networking.k8s.io.ingress/__tests__/IngressClass.test.ts +58 -0
  146. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +14 -2
  147. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +4 -1
  148. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +26 -9
  149. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +8 -8
  150. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +26 -12
  151. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +66 -0
  152. package/edit/provisioning.cattle.io.cluster/__tests__/utils/rke2-test-data.ts +58 -0
  153. package/edit/provisioning.cattle.io.cluster/rke2.vue +49 -41
  154. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +6 -1
  155. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +5 -3
  156. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +33 -2
  157. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +2 -2
  158. package/edit/token.vue +2 -0
  159. package/edit/workload/index.vue +1 -0
  160. package/edit/workload/mixins/workload.js +0 -2
  161. package/initialize/install-plugins.js +2 -1
  162. package/list/harvesterhci.io.management.cluster.vue +4 -1
  163. package/list/management.cattle.io.feature.vue +4 -287
  164. package/list/provisioning.cattle.io.cluster.vue +20 -12
  165. package/machine-config/azure.vue +16 -4
  166. package/mixins/vue-select-overrides.js +0 -4
  167. package/models/__tests__/namespace.test.ts +25 -1
  168. package/models/cloudcredential.js +5 -0
  169. package/models/fleet.cattle.io.cluster.js +8 -2
  170. package/models/fleet.cattle.io.gitrepo.js +8 -34
  171. package/models/kontainerdriver.js +6 -3
  172. package/models/management.cattle.io.feature.js +7 -1
  173. package/models/management.cattle.io.node.js +3 -3
  174. package/models/namespace.js +11 -6
  175. package/models/nodedriver.js +6 -3
  176. package/models/workload.js +4 -1
  177. package/package.json +3 -3
  178. package/pages/about.vue +13 -3
  179. package/pages/account/index.vue +16 -6
  180. package/pages/auth/login.vue +18 -7
  181. package/pages/auth/logout.vue +4 -1
  182. package/pages/auth/setup.vue +2 -0
  183. package/pages/auth/verify.vue +13 -8
  184. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  185. package/pages/c/_cluster/apps/charts/install.vue +26 -26
  186. package/pages/c/_cluster/auth/config/index.vue +10 -12
  187. package/pages/c/_cluster/explorer/EventsTable.vue +38 -33
  188. package/pages/c/_cluster/explorer/index.vue +17 -15
  189. package/pages/c/_cluster/istio/index.vue +2 -2
  190. package/pages/c/_cluster/longhorn/index.vue +1 -1
  191. package/pages/c/_cluster/monitoring/index.vue +1 -1
  192. package/pages/c/_cluster/monitoring/monitor/_namespace/_id.vue +4 -2
  193. package/pages/c/_cluster/monitoring/monitor/create.vue +4 -2
  194. package/pages/c/_cluster/monitoring/route-receiver/_id.vue +4 -2
  195. package/pages/c/_cluster/monitoring/route-receiver/create.vue +5 -2
  196. package/pages/c/_cluster/neuvector/index.vue +1 -1
  197. package/pages/c/_cluster/settings/banners.vue +4 -3
  198. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +8 -10
  199. package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +4 -7
  200. package/pages/c/_cluster/uiplugins/index.vue +98 -55
  201. package/pages/diagnostic.vue +59 -11
  202. package/pages/fail-whale.vue +14 -8
  203. package/pages/home.vue +24 -18
  204. package/pages/prefs.vue +7 -6
  205. package/pages/support/index.vue +4 -1
  206. package/plugins/internal-api/index.ts +37 -0
  207. package/plugins/internal-api/shared/base-api.ts +13 -0
  208. package/plugins/internal-api/shell/shell.api.ts +108 -0
  209. package/plugins/steve/actions.js +0 -12
  210. package/public/index.html +1 -0
  211. package/rancher-components/Card/Card.vue +1 -1
  212. package/rancher-components/Form/Checkbox/Checkbox.test.ts +59 -1
  213. package/rancher-components/Form/Checkbox/Checkbox.vue +27 -3
  214. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +47 -0
  215. package/rancher-components/Form/LabeledInput/LabeledInput.vue +20 -2
  216. package/rancher-components/Form/Radio/RadioButton.test.ts +36 -1
  217. package/rancher-components/Form/Radio/RadioButton.vue +20 -4
  218. package/rancher-components/Form/Radio/RadioGroup.test.ts +60 -0
  219. package/rancher-components/Form/Radio/RadioGroup.vue +52 -10
  220. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
  221. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +5 -0
  222. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +10 -1
  223. package/rancher-components/RcButton/RcButton.vue +2 -1
  224. package/rancher-components/RcButton/types.ts +1 -0
  225. package/rancher-components/RcDropdown/RcDropdown.vue +18 -6
  226. package/rancher-components/RcDropdown/RcDropdownItem.vue +3 -56
  227. package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +68 -0
  228. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +92 -0
  229. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -0
  230. package/rancher-components/RcDropdown/index.ts +2 -0
  231. package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
  232. package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
  233. package/rancher-components/RcDropdown/useDropdownItem.ts +63 -0
  234. package/scripts/extension/bundle +20 -0
  235. package/scripts/extension/helm/charts/ui-plugin-server/templates/cr.yaml +2 -1
  236. package/scripts/extension/helm/charts/ui-plugin-server/values.yaml +2 -0
  237. package/scripts/extension/helmpatch +44 -31
  238. package/scripts/extension/publish +12 -12
  239. package/scripts/typegen.sh +2 -4
  240. package/server/har-file.js +25 -3
  241. package/store/action-menu.js +26 -56
  242. package/store/features.js +2 -1
  243. package/store/index.js +5 -0
  244. package/store/modal.ts +71 -0
  245. package/store/slideInPanel.ts +47 -0
  246. package/store/type-map.js +12 -1
  247. package/store/type-map.utils.ts +4 -4
  248. package/types/global-vue.d.ts +5 -0
  249. package/types/internal-api/shell/growl.d.ts +25 -0
  250. package/types/internal-api/shell/modal.d.ts +77 -0
  251. package/types/internal-api/shell/slideIn.d.ts +15 -0
  252. package/types/resources/fleet.d.ts +0 -14
  253. package/types/shell/index.d.ts +43 -24
  254. package/types/vue-shim.d.ts +4 -1
  255. package/utils/__mocks__/tabbable.js +13 -0
  256. package/utils/__tests__/object.test.ts +38 -4
  257. package/utils/cluster.js +35 -0
  258. package/utils/fleet.ts +15 -73
  259. package/utils/object.js +48 -5
  260. package/utils/validators/formRules/__tests__/index.test.ts +10 -1
  261. package/utils/validators/formRules/index.ts +27 -3
  262. package/utils/validators/machine-pool.ts +20 -0
  263. package/components/DisableAuthProviderModal.vue +0 -114
  264. package/components/MoveModal.vue +0 -166
  265. package/components/PromptChangePassword.vue +0 -123
  266. package/components/fleet/FleetBundleResources.vue +0 -86
  267. package/components/formatter/ExtensionCache.vue +0 -74
  268. package/components/formatter/Port.vue +0 -24
  269. package/components/formatter/SecretType.vue +0 -41
  270. package/types/vue-shim.d +0 -20
@@ -17,6 +17,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
17
17
  const {
18
18
  dropdownItems,
19
19
  firstDropdownItem,
20
+ lastDropdownItem,
20
21
  dropdownContainer,
21
22
  registerDropdownCollection,
22
23
  } = useDropdownCollection();
@@ -70,7 +71,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
70
71
  /**
71
72
  * Sets focus to the first dropdown item if a keydown event has occurred.
72
73
  */
73
- const setFocus = () => {
74
+ const setFocus = (direction: 'down' | 'up') => {
74
75
  nextTick(() => {
75
76
  if (!didKeydown.value) {
76
77
  dropdownContainer.value?.focus();
@@ -78,7 +79,12 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
78
79
  return;
79
80
  }
80
81
 
81
- firstDropdownItem.value?.focus();
82
+ if (direction === 'down') {
83
+ firstDropdownItem.value?.focus();
84
+ } else if (direction === 'up') {
85
+ lastDropdownItem.value?.focus();
86
+ }
87
+
82
88
  didKeydown.value = false;
83
89
  });
84
90
  };
@@ -95,7 +101,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
95
101
  dropdownItems,
96
102
  close: () => returnFocus(),
97
103
  focusFirstElement: () => {
98
- setFocus();
104
+ setFocus('down');
99
105
  },
100
106
  handleKeydown,
101
107
  });
@@ -0,0 +1,63 @@
1
+ import { inject } from 'vue';
2
+ import { DropdownContext, defaultContext } from './types';
3
+
4
+ export const useDropdownItem = () => {
5
+ const { dropdownItems, close } = inject<DropdownContext>('dropdownContext') || defaultContext;
6
+
7
+ /**
8
+ * Handles keydown events to navigate between dropdown items.
9
+ * @param {KeyboardEvent} e - The keydown event.
10
+ */
11
+ const handleKeydown = (e: KeyboardEvent) => {
12
+ const activeItem = document.activeElement;
13
+
14
+ const activeIndex = dropdownItems.value.indexOf(activeItem || new HTMLElement());
15
+
16
+ if (activeIndex < 0) {
17
+ return;
18
+ }
19
+
20
+ const shouldAdvance = e.key === 'ArrowDown';
21
+
22
+ const newIndex = findNewIndex(shouldAdvance, activeIndex, dropdownItems.value);
23
+
24
+ if (dropdownItems.value[newIndex] instanceof HTMLElement) {
25
+ dropdownItems.value[newIndex].focus();
26
+ }
27
+ };
28
+
29
+ /**
30
+ * Finds the new index for the dropdown item based on the key pressed.
31
+ * @param shouldAdvance - Whether to advance to the next or previous item.
32
+ * @param activeIndex - Current active index.
33
+ * @param itemsArr - Array of dropdown items.
34
+ * @returns The new index.
35
+ */
36
+ const findNewIndex = (shouldAdvance: boolean, activeIndex: number, itemsArr: Element[]) => {
37
+ const newIndex = shouldAdvance ? activeIndex + 1 : activeIndex - 1;
38
+
39
+ if (newIndex > itemsArr.length - 1) {
40
+ return 0;
41
+ }
42
+
43
+ if (newIndex < 0) {
44
+ return itemsArr.length - 1;
45
+ }
46
+
47
+ return newIndex;
48
+ };
49
+
50
+ /**
51
+ * Handles keydown events to activate the dropdown item.
52
+ * @param e - The keydown event.
53
+ */
54
+ const handleActivate = (e: KeyboardEvent) => {
55
+ if (e?.target instanceof HTMLElement) {
56
+ e?.target?.click();
57
+ }
58
+ };
59
+
60
+ return {
61
+ handleKeydown, close, handleActivate
62
+ };
63
+ };
@@ -29,12 +29,32 @@ cp -R ${CHART_TEMPLATE}/* ${TMP}/container/
29
29
  # Copy the plugin assets
30
30
  mkdir -p ${TMP}/container/plugin
31
31
 
32
+ # Copy Helm charts and plugin assets
32
33
  cp -R ${BASE_DIR}/assets/* ${TMP}/container/plugin
33
34
  cp ${BASE_DIR}/package.json ${TMP}/container/plugin
34
35
  cp ${BASE_DIR}/index.yaml ${TMP}/container/
35
36
  cp ${BASE_DIR}/index.yaml ${TMP}/container/plugin
36
37
  rm -f ${TMP}/container/plugin/report.html
37
38
 
39
+ # Add extension .tgz files with proper naming
40
+ echo -e "${CYAN}Copying extension archives...${RESET}"
41
+ for pkg_dir in ${BASE_DIR}/extensions/*/; do
42
+ pkg=$(basename "${pkg_dir}")
43
+ echo -e "Processing package: ${pkg}"
44
+
45
+ # Find all .tgz files in the package directory
46
+ for tgz_path in "${pkg_dir}"*.tgz; do
47
+ if [ -f "${tgz_path}" ]; then
48
+ # Extract version from filename
49
+ version=$(basename "${tgz_path}" .tgz)
50
+ compressed_package_name="${pkg}-${version}.tgz"
51
+
52
+ echo "Copying ${tgz_path} to ${TMP}/container/plugin/${compressed_package_name}"
53
+ cp "${tgz_path}" "${TMP}/container/plugin/${compressed_package_name}"
54
+ fi
55
+ done
56
+ done
57
+
38
58
  # Generate files.txt for each pkg and move pkg files into relative plugin directories
39
59
  for d in ${BASE_DIR}/dist-pkg/*; do
40
60
  pkg=$(basename $d)
@@ -8,7 +8,8 @@ spec:
8
8
  plugin:
9
9
  name: {{ include "extension-server.fullname" . }}
10
10
  version: {{ (semver (default .Chart.AppVersion .Values.plugin.versionOverride)).Original }}
11
- endpoint: http://{{ include "extension-server.fullname" . }}.{{ .Release.Namespace }}.svc
11
+ endpoint: {{ .Values.plugin.endpoint | quote }}
12
+ compressedEndpoint: {{ .Values.plugin.compressedEndpoint | quote }}
12
13
  noCache: {{ .Values.plugin.noCache }}
13
14
  noAuth: {{ .Values.plugin.noAuth }}
14
15
  metadata: {{ include "extension-server.pluginMetadata" . | indent 6 }}
@@ -3,6 +3,8 @@ fullnameOverride: ""
3
3
  plugin:
4
4
  enabled: true
5
5
  versionOverride: ""
6
+ endpoint: ""
7
+ compressedEndpoint: ""
6
8
  noCache: false
7
9
  noAuth: false
8
10
  metadata: {}
@@ -1,15 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Update Chart.yaml and values.yaml files
4
-
5
3
  const fs = require('fs');
6
4
  const path = require('path');
7
5
  const yaml = require('js-yaml');
8
6
 
9
- // TODO: Should already be in the template
10
- // const UI_PLUGIN_ANNOTATION_NAME = 'catalog.cattle.io/ui-component';
11
- // const UI_PLUGIN_ANNOTATION_VALUE = 'plugins';
12
-
13
7
  console.log('Helm file update');
14
8
 
15
9
  if (process.argv.length !== 4) {
@@ -17,12 +11,10 @@ if (process.argv.length !== 4) {
17
11
  process.exit(1);
18
12
  }
19
13
 
20
- const destFolder = process.argv[2];
14
+ const chartFolder = process.argv[2];
21
15
  const pkgFilePath = process.argv[3];
22
16
 
23
17
  const pkgFile = JSON.parse(fs.readFileSync(pkgFilePath, 'utf8'));
24
-
25
- const chartFolder = destFolder;
26
18
  const chartFile = path.join(chartFolder, 'Chart.yaml');
27
19
  const valuesFile = path.join(chartFolder, 'values.yaml');
28
20
 
@@ -32,36 +24,57 @@ if (!fs.existsSync(chartFolder)) {
32
24
  }
33
25
 
34
26
  // --------------------------------------------------------------------------------
35
- // Chart.yaml
27
+ // Chart.yaml updates (annotations)
36
28
  // --------------------------------------------------------------------------------
37
29
  const chart = yaml.load(fs.readFileSync(chartFile, 'utf8'));
38
- let updated = false;
39
-
40
- // Add in annotations to match any rules in the package file
41
- if (pkgFile.rancher && typeof pkgFile.rancher === 'object') {
42
- // See if there are any annotations and merge them in, if there are
43
- if (pkgFile.rancher.annotations) {
44
- chart.annotations = chart.annotations || {};
45
- Object.keys(pkgFile.rancher.annotations).forEach((key) => {
46
- chart.annotations[key] = pkgFile.rancher.annotations[key];
47
- updated = true;
48
- });
49
- }
30
+ let chartUpdated = false;
31
+
32
+ if (pkgFile.rancher?.annotations) {
33
+ chart.annotations = chart.annotations || {};
34
+ Object.entries(pkgFile.rancher.annotations).forEach(([key, value]) => {
35
+ if (chart.annotations[key] !== value) {
36
+ chart.annotations[key] = value;
37
+ chartUpdated = true;
38
+ }
39
+ });
50
40
  }
51
41
 
52
- if (updated) {
53
- // Write out updated file
54
- const str = yaml.dump(chart);
55
-
56
- fs.writeFileSync(chartFile, str, 'utf8');
42
+ if (chartUpdated) {
43
+ fs.writeFileSync(chartFile, yaml.dump(chart), 'utf8');
44
+ console.log('Updated Chart.yaml annotations');
57
45
  }
58
46
 
59
47
  // --------------------------------------------------------------------------------
60
- // values.yaml
48
+ // values.yaml updates (endpoints)
61
49
  // --------------------------------------------------------------------------------
62
-
63
50
  const values = yaml.load(fs.readFileSync(valuesFile, 'utf8'));
64
51
 
65
- const valuesYaml = yaml.dump(values, { quotingType: '"' });
52
+ // Get package metadata from package.json
53
+ const pkgName = pkgFile.name;
54
+ const pkgVersion = pkgFile.version;
55
+ const pkgFullName = `${ pkgName }-${ pkgVersion }`;
56
+
57
+ // Determine build type from environment
58
+ const isGitHubBuild = process.env.GITHUB_BUILD === 'true';
59
+
60
+ // Set endpoints based on build type
61
+ if (isGitHubBuild) {
62
+ const githubSource = process.env.GITHUB_SOURCE;
63
+ const githubBranch = process.env.GITHUB_BRANCH;
64
+
65
+ values.plugin.endpoint = `https://raw.githubusercontent.com/${ githubSource }/${ githubBranch }/extensions/${ pkgName }/${ pkgVersion }`;
66
+ } else {
67
+ const imagePrefix = process.env.IMAGE_PREFIX || '';
68
+ const baseExt = process.env.BASE_EXT;
69
+
70
+ values.plugin.endpoint = `http://${ imagePrefix }${ baseExt }-svc.cattle-ui-plugin-system:8080/plugin/${ pkgFullName }`;
71
+ }
72
+
73
+ // Always set compressedEndpoint as endpoint + .tgz
74
+ values.plugin.compressedEndpoint = `${ values.plugin.endpoint }.tgz`;
66
75
 
67
- fs.writeFileSync(valuesFile, valuesYaml, 'utf8');
76
+ // Write updated values.yaml
77
+ fs.writeFileSync(valuesFile, yaml.dump(values, { quotingType: '"' }), 'utf8');
78
+ console.log('Updated values.yaml endpoints:');
79
+ console.log(`- endpoint: ${ values.plugin.endpoint }`);
80
+ console.log(`- compressedEndpoint: ${ values.plugin.compressedEndpoint }`);
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bash
2
+ # set -eo pipefail comment out for now because of a Harvester issue
2
3
 
3
4
  SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
4
5
  BASE_DIR="$(pwd)"
@@ -330,6 +331,12 @@ if [ "${UPDATE_LATEST_PACAKGES}" = "true" ]; then
330
331
  find plugin -type f | sort > files.txt
331
332
  popd > /dev/null
332
333
 
334
+ # --------------------------------------------------------------------------------
335
+ # Package extensions into tgz for the compressedEndpoint
336
+ # --------------------------------------------------------------------------------
337
+ echo -e "${CYAN}Packaging extension into tgz${RESET}"
338
+ tar -czf ${BASE_DIR}/extensions/${pkg}/${PKG_VERSION}.tgz -C ${BASE_DIR}/extensions/${pkg} ${PKG_VERSION}
339
+
333
340
  # --------------------------------------------------------------------------------
334
341
  # Create the Helm chart
335
342
  # --------------------------------------------------------------------------------
@@ -358,18 +365,11 @@ if [ "${UPDATE_LATEST_PACAKGES}" = "true" ]; then
358
365
  cp ./pkg/${pkg}/README.md ${CHART_FOLDER}/README.md
359
366
  fi
360
367
 
361
- pushd ${CHART_FOLDER}/templates > /dev/null
362
-
363
- if [ "${GITHUB_BUILD}" == "true" ]; then
364
- echo "Patching for GitHub build"
365
- ENDPOINT=https://raw.githubusercontent.com/${GITHUB_SOURCE}/${GITHUB_BRANCH}/extensions/${pkg}/${PKG_VERSION}
366
- else
367
- echo "Patching for container build"
368
- ENDPOINT=http://${IMAGE_PREFIX}${BASE_EXT}-svc.cattle-ui-plugin-system:8080/plugin/${PKG_NAME}
369
- fi
370
- sed -i.bak -e 's@endpoint: .*@endpoint: '"${ENDPOINT}"'@g' cr.yaml
371
- rm *.bak
372
- popd > /dev/null
368
+ export GITHUB_BUILD
369
+ export IMAGE_PREFIX
370
+ export BASE_EXT
371
+ export GITHUB_SOURCE
372
+ export GITHUB_BRANCH
373
373
 
374
374
  # Additional patches
375
375
  ${SCRIPT_DIR}/helmpatch ${CHART_FOLDER} "${BASE_DIR}/pkg/${pkg}/package.json"
@@ -63,10 +63,8 @@ rm -rf ${INDEX}
63
63
  echo "// Auto-generated type definitions for shell" > ${INDEX}
64
64
  echo "// Do not modify this file as changes will get overwritten" >> ${INDEX}
65
65
 
66
- # Copy in the vue shim type definitions
67
- if [ -f "$BASE_DIR/shell/types/vue-shim.d" ]; then
68
- cat "$BASE_DIR/shell/types/vue-shim.d" >> ${INDEX}
69
- fi
66
+ echo "/// <reference types=\"@rancher/shell/types/vue-shim\" />" >> ${INDEX}
67
+ echo "/// <reference types=\"@rancher/shell/types/global-vue\" />" >> ${INDEX}
70
68
 
71
69
  function processDir() {
72
70
  local dir=$1
@@ -1,11 +1,15 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const querystring = require('querystring');
3
4
 
4
5
  // When we receive a request to this URL we will reset the session to replay again from the HAR file
5
6
  // This allows the user to refresh the browser and replay the HAR file again
6
7
  const RESET_URL = '/api/v1/namespaces/cattle-ui-plugin-system/services/http:ui-plugin-operator:80/proxy/index.json';
7
8
 
8
- const EXCLUDES_QS = '?exclude=metadata.managedFields';
9
+ const EXCLUDE_QS = 'exclude';
10
+
11
+ const LEGACY_UI_PLUGIN_INDEX = '/api/v1/namespaces/cattle-ui-plugin-system/services/http:ui-plugin-operator:80/proxy/index.json';
12
+ const NEW_UI_PLUGIN_INDEX = '/v1/uiplugins';
9
13
 
10
14
  /**
11
15
  * Load the network requests/responses from the har file
@@ -113,10 +117,28 @@ function harProxy(responses, folder) {
113
117
  const url = decodeURIComponent(req.originalUrl);
114
118
  let playback = session[req.originalUrl];
115
119
 
120
+ // Handle case where HAR file was created with older UI Extension API that used the operator
121
+ if (!playback && req.originalUrl.includes(NEW_UI_PLUGIN_INDEX)) {
122
+ // Look for new URl for UI plugins
123
+ playback = session[LEGACY_UI_PLUGIN_INDEX];
124
+ }
125
+
116
126
  // If it did not match, try without the metadata excludes query string that was adding in 2.8.0
117
127
  // This might allow HAR captures with Rancher < 2.8.0 to be replayed on >= 2.8.0
118
- if (!playback && req.originalUrl.endsWith(EXCLUDES_QS)) {
119
- playback = session[req.originalUrl.slice(0, -EXCLUDES_QS.length)];
128
+ if (!playback && req.originalUrl.includes('?')) {
129
+ const urlParts = req.originalUrl.split('?');
130
+
131
+ if (urlParts.length > 1) {
132
+ const queryString = urlParts[1];
133
+ const qs = querystring.parse(queryString);
134
+
135
+ delete qs[EXCLUDE_QS];
136
+
137
+ const newQs = querystring.stringify(qs);
138
+ const newUrl = newQs.length ? `${ urlParts[0] }?${ newQs }` : urlParts[0];
139
+
140
+ playback = session[newUrl];
141
+ }
120
142
  }
121
143
 
122
144
  if (playback && playback[req.method] && playback[req.method].length) {
@@ -2,31 +2,26 @@ import { filterBy, isArray } from '@shell/utils/array';
2
2
 
3
3
  export const state = function() {
4
4
  return {
5
- show: false,
6
- resources: [],
7
- elem: null,
8
- event: null,
9
- showPromptMove: false,
10
- showPromptRemove: false,
11
- showPromptRestore: false,
12
- showAssignTo: false,
13
- showPromptUpdate: false,
14
- showModal: false,
15
- toMove: [],
16
- toRemove: [],
17
- toRestore: [],
18
- toAssign: [],
19
- toUpdate: [],
20
- modalData: {},
5
+ show: false,
6
+ resources: [],
7
+ elem: null,
8
+ event: null,
9
+ showPromptRemove: false,
10
+ showPromptRestore: false,
11
+ showModal: false,
12
+ performCallbackData: undefined,
13
+ toRemove: [],
14
+ toRestore: [],
15
+ modalData: {},
21
16
  };
22
17
  };
23
18
 
24
19
  export const getters = {
25
- showing: (state) => state.show,
26
- elem: (state) => state.elem,
27
- event: (state) => state.event,
28
- resources: (state) => state.resources,
29
-
20
+ showing: (state) => state.show,
21
+ elem: (state) => state.elem,
22
+ event: (state) => state.event,
23
+ resources: (state) => state.resources,
24
+ performCallbackData: (state) => state.performCallbackData,
30
25
  optionsArray(state) {
31
26
  let selected = state.resources;
32
27
 
@@ -89,16 +84,6 @@ export const mutations = {
89
84
  state.toRemove = resources;
90
85
  },
91
86
 
92
- togglePromptMove(state, resources) {
93
- if (!resources) {
94
- state.showPromptMove = false;
95
- resources = [];
96
- } else {
97
- state.showPromptMove = !state.showPromptMove;
98
- state.toMove = Array.isArray(resources) ? resources : [resources];
99
- }
100
- },
101
-
102
87
  togglePromptRestore(state, resources) {
103
88
  if (!resources) {
104
89
  state.showPromptRestore = false;
@@ -112,35 +97,13 @@ export const mutations = {
112
97
  state.toRestore = resources;
113
98
  },
114
99
 
115
- toggleAssignTo(state, resources) {
116
- state.showAssignTo = !state.showAssignTo;
117
-
118
- if (!isArray(resources)) {
119
- resources = [resources];
120
- }
121
-
122
- state.toAssign = resources;
123
- },
124
-
125
- togglePromptUpdate(state, resources) {
126
- if (!resources) {
127
- // Clearing the resources also hides the prompt
128
- state.showPromptUpdate = false;
129
- } else {
130
- state.showPromptUpdate = !state.showPromptUpdate;
131
- }
132
-
133
- if (!isArray(resources)) {
134
- resources = [resources];
135
- }
136
-
137
- state.toUpdate = resources;
138
- },
139
-
140
100
  togglePromptModal(state, data) {
141
101
  if (!data) {
142
102
  // Clearing the resources also hides the prompt
143
103
  state.showModal = false;
104
+ } else if (data.performCallback) {
105
+ state.performCallbackData = data;
106
+ state.showModal = false;
144
107
  } else {
145
108
  state.showModal = true;
146
109
  }
@@ -148,6 +111,10 @@ export const mutations = {
148
111
  state.modalData = data;
149
112
  },
150
113
 
114
+ clearCallbackData(state) {
115
+ state.performCallbackData = undefined;
116
+ },
117
+
151
118
  SET_RESOURCE(state, resources) {
152
119
  state.resources = !isArray(resources) ? [resources] : resources;
153
120
  }
@@ -159,6 +126,9 @@ export const actions = {
159
126
  },
160
127
  setResource({ commit }, resource) {
161
128
  commit('SET_RESOURCE', resource);
129
+ },
130
+ clearCallbackData({ commit }) {
131
+ commit('clearCallbackData');
162
132
  }
163
133
  };
164
134
 
package/store/features.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { MANAGEMENT } from '@shell/config/types';
2
+ import { SCHEDULING_CUSTOMIZATION as SCHEDULING_CUSTOMIZATION_FEATURE } from '@shell/config/features';
2
3
 
3
4
  const definitions = {};
4
5
 
@@ -36,7 +37,7 @@ export const FLEET_WORKSPACE_BACK = create('provisioningv2-fleet-workspace-back-
36
37
  export const STEVE_CACHE = create('ui-sql-cache', false);
37
38
  export const UIEXTENSION = create('uiextension', true);
38
39
  export const PROVISIONING_PRE_BOOTSTRAP = create('provisioningprebootstrap', false);
39
- export const SCHEDULING_CUSTOMIZATION = create('cluster-agent-scheduling-customization', false);
40
+ export const SCHEDULING_CUSTOMIZATION = create(SCHEDULING_CUSTOMIZATION_FEATURE, false);
40
41
 
41
42
  // Not currently used.. no point defining ones we don't use
42
43
  // export const EMBEDDED_CLUSTER_API = create('embedded-cluster-api', true);
package/store/index.js CHANGED
@@ -862,6 +862,11 @@ export const actions = {
862
862
  const isRancherInHarvester = (rancherManagerSupport?.value || rancherManagerSupport?.default) === 'true';
863
863
 
864
864
  commit('isRancherInHarvester', isRancherInHarvester);
865
+
866
+ if (getters['isSingleProduct']) {
867
+ console.log('Detect standalone harvester, subscribe Rancher socket'); // eslint-disable-line no-console
868
+ await dispatch('rancher/subscribe');
869
+ }
865
870
  }
866
871
 
867
872
  const pl = res.settings?.find((x) => x.id === 'ui-pl')?.value;
package/store/modal.ts ADDED
@@ -0,0 +1,71 @@
1
+ import { markRaw, Component } from 'vue';
2
+ import { MutationTree, GetterTree, ActionTree } from 'vuex';
3
+
4
+ export interface ModalState {
5
+ isOpen: boolean;
6
+ component: Component | null;
7
+ componentProps: Record<string, any>;
8
+ resources: any[];
9
+ closeOnClickOutside: boolean;
10
+ modalWidth: string;
11
+ modalSticky: boolean;
12
+ }
13
+
14
+ const state = (): ModalState => ({
15
+ isOpen: false,
16
+ component: null,
17
+ componentProps: {},
18
+ resources: [],
19
+ closeOnClickOutside: false,
20
+ modalWidth: '600px',
21
+ modalSticky: false
22
+ });
23
+
24
+ const getters: GetterTree<ModalState, any> = {
25
+ isOpen: (state) => state.isOpen,
26
+ component: (state) => state.component,
27
+ componentProps: (state) => state.componentProps,
28
+ resources: (state) => state.resources,
29
+ closeOnClickOutside: (state) => state.closeOnClickOutside,
30
+ modalWidth: (state) => state.modalWidth,
31
+ modalSticky: (state) => state.modalSticky,
32
+ };
33
+
34
+ const mutations: MutationTree<ModalState> = {
35
+ openModal(state, payload: {
36
+ component: Component;
37
+ componentProps?: Record<string, any>;
38
+ resources?: any[];
39
+ closeOnClickOutside?: boolean;
40
+ modalWidth?: string;
41
+ modalSticky?: boolean;
42
+ }) {
43
+ state.isOpen = true;
44
+ state.component = markRaw(payload.component);
45
+ state.componentProps = payload.componentProps || {};
46
+ state.resources = Array.isArray(payload.resources) ? payload.resources : (payload.resources ? [payload.resources] : []);
47
+ state.closeOnClickOutside = payload.closeOnClickOutside ?? false;
48
+ state.modalWidth = payload.modalWidth || '600px';
49
+ state.modalSticky = payload.modalSticky ?? false;
50
+ },
51
+
52
+ closeModal(state) {
53
+ state.isOpen = false;
54
+ state.component = null;
55
+ state.componentProps = {};
56
+ state.resources = [];
57
+ state.closeOnClickOutside = false;
58
+ state.modalWidth = '600px';
59
+ state.modalSticky = false;
60
+ }
61
+ };
62
+
63
+ const actions: ActionTree<ModalState, any> = {};
64
+
65
+ export default {
66
+ namespaced: true,
67
+ state,
68
+ getters,
69
+ mutations,
70
+ actions
71
+ };
@@ -0,0 +1,47 @@
1
+ import { markRaw, Component } from 'vue';
2
+ import { MutationTree, GetterTree, ActionTree } from 'vuex';
3
+
4
+ export interface SlideInPanelState {
5
+ isOpen: boolean;
6
+ component: Component | null;
7
+ componentProps: Record<string, any>;
8
+ }
9
+
10
+ const state = (): SlideInPanelState => ({
11
+ isOpen: false,
12
+ component: null,
13
+ componentProps: {}
14
+ });
15
+
16
+ const getters: GetterTree<SlideInPanelState, any> = {
17
+ isOpen: (state) => state.isOpen,
18
+ component: (state) => state.component,
19
+ componentProps: (state) => state.componentProps
20
+ };
21
+
22
+ const mutations: MutationTree<SlideInPanelState> = {
23
+ open(state, payload: { component: Component; componentProps?: Record<string, any> }) {
24
+ state.isOpen = true;
25
+ state.component = markRaw(payload.component);
26
+ state.componentProps = payload.componentProps || {};
27
+ },
28
+ close(state) {
29
+ state.isOpen = false;
30
+
31
+ // Delay clearing component/props for 500ms (same as transition duration)
32
+ setTimeout(() => {
33
+ state.component = null;
34
+ state.componentProps = {};
35
+ }, 500);
36
+ }
37
+ };
38
+
39
+ const actions: ActionTree<SlideInPanelState, any> = {};
40
+
41
+ export default {
42
+ namespaced: true,
43
+ state,
44
+ getters,
45
+ mutations,
46
+ actions
47
+ };