@rancher/shell 0.3.16 → 0.3.18

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 (174) hide show
  1. package/assets/images/wechat-qr-code.jpg +0 -0
  2. package/assets/translations/en-us.yaml +75 -16
  3. package/assets/translations/zh-hans.yaml +151 -15
  4. package/chart/__tests__/S3.test.ts +50 -0
  5. package/chart/rancher-backup/S3.vue +21 -0
  6. package/chart/rancher-backup/index.vue +4 -0
  7. package/components/AsyncButton.vue +1 -1
  8. package/components/CommunityLinks.vue +1 -0
  9. package/components/FileDiff.vue +92 -85
  10. package/components/Inactivity.vue +10 -0
  11. package/components/LazyImage.vue +2 -2
  12. package/components/PromptRestore.vue +7 -5
  13. package/components/ResourceDetail/Masthead.vue +1 -1
  14. package/components/ResourceDetail/index.vue +8 -14
  15. package/components/ResourceList/index.vue +1 -1
  16. package/components/ResourceTable.vue +50 -2
  17. package/components/YamlEditor.vue +1 -0
  18. package/components/__tests__/PromptRestore.test.ts +72 -0
  19. package/components/auth/AzureWarning.vue +1 -1
  20. package/components/auth/RoleDetailEdit.vue +1 -0
  21. package/components/fleet/FleetResources.vue +3 -64
  22. package/components/form/FileImageSelector.vue +9 -0
  23. package/components/form/FileSelector.vue +2 -1
  24. package/components/form/MatchExpressions.vue +1 -3
  25. package/components/form/NameNsDescription.vue +28 -12
  26. package/components/form/NodeAffinity.vue +2 -2
  27. package/components/form/PodAffinity.vue +2 -2
  28. package/components/form/ResourceTabs/index.vue +8 -2
  29. package/components/form/Select.vue +16 -0
  30. package/components/form/__tests__/FileImageSelector.test.ts +42 -0
  31. package/components/form/__tests__/FileSelector.test.ts +76 -0
  32. package/components/form/__tests__/NodeAffinity.test.ts +38 -0
  33. package/components/form/__tests__/PodAffinity.test.ts +46 -0
  34. package/components/formatter/ClusterLink.vue +8 -4
  35. package/components/formatter/ClusterProvider.vue +3 -1
  36. package/components/formatter/ImageName.vue +23 -0
  37. package/components/formatter/PodImages.vue +7 -1
  38. package/components/formatter/__tests__/ClusterLink.test.ts +101 -0
  39. package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
  40. package/components/nav/Header.vue +2 -2
  41. package/components/nav/WindowManager/ContainerShell.vue +60 -36
  42. package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
  43. package/config/__test__/home-links.test.ts +62 -0
  44. package/config/home-links.js +15 -3
  45. package/config/labels-annotations.js +7 -2
  46. package/config/persistentVolume.ts +108 -0
  47. package/config/product/manager.js +5 -1
  48. package/config/router.js +0 -4
  49. package/config/settings.ts +4 -0
  50. package/config/table-headers.js +6 -5
  51. package/config/types.js +2 -0
  52. package/config/uiplugins.js +50 -5
  53. package/core/plugin-helpers.js +39 -15
  54. package/core/plugin.ts +9 -0
  55. package/core/plugins.js +1 -1
  56. package/core/types-provisioning.ts +253 -0
  57. package/core/types.ts +21 -3
  58. package/detail/autoscaling.horizontalpodautoscaler/index.vue +50 -1
  59. package/detail/fleet.cattle.io.gitrepo.vue +10 -2
  60. package/detail/node.vue +6 -6
  61. package/detail/pod.vue +38 -9
  62. package/detail/provisioning.cattle.io.cluster.vue +46 -7
  63. package/detail/workload/index.vue +49 -18
  64. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +62 -0
  65. package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
  66. package/edit/auth/github.vue +1 -0
  67. package/edit/autoscaling.horizontalpodautoscaler/hpa-scaling-rule.vue +130 -0
  68. package/edit/autoscaling.horizontalpodautoscaler/index.vue +79 -0
  69. package/edit/fleet.cattle.io.clustergroup.vue +14 -3
  70. package/edit/fleet.cattle.io.gitrepo.vue +18 -1
  71. package/edit/namespace.vue +9 -1
  72. package/edit/networking.k8s.io.ingress/RulePath.vue +0 -2
  73. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
  74. package/edit/persistentvolume/index.vue +2 -1
  75. package/edit/persistentvolume/plugins/csi.vue +3 -1
  76. package/edit/persistentvolume/plugins/longhorn.vue +12 -12
  77. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -30
  78. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
  79. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +79 -1
  80. package/edit/provisioning.cattle.io.cluster/index.vue +53 -1
  81. package/edit/provisioning.cattle.io.cluster/rke2.vue +335 -151
  82. package/edit/storage.k8s.io.storageclass/index.vue +1 -2
  83. package/edit/ui.cattle.io.navlink.vue +213 -186
  84. package/initialize/App.js +3 -13
  85. package/initialize/layouts.ts +26 -0
  86. package/layouts/default.vue +1 -1
  87. package/list/group.principal.vue +1 -1
  88. package/list/provisioning.cattle.io.cluster.vue +8 -1
  89. package/middleware/authenticated.js +101 -5
  90. package/mixins/brand.js +39 -3
  91. package/mixins/child-hook.js +2 -2
  92. package/mixins/create-edit-view/impl.js +4 -4
  93. package/models/chart.js +1 -1
  94. package/models/fleet.cattle.io.cluster.js +33 -4
  95. package/models/fleet.cattle.io.gitrepo.js +113 -38
  96. package/models/management.cattle.io.kontainerdriver.js +14 -0
  97. package/models/persistentvolume.js +2 -111
  98. package/models/pod.js +30 -0
  99. package/models/provisioning.cattle.io.cluster.js +9 -1
  100. package/models/rke.cattle.io.etcdsnapshot.js +10 -7
  101. package/package.json +2 -2
  102. package/pages/about.vue +8 -2
  103. package/pages/auth/login.vue +1 -1
  104. package/pages/auth/logout.vue +11 -3
  105. package/pages/c/_cluster/apps/charts/index.vue +5 -2
  106. package/pages/c/_cluster/apps/charts/install.vue +5 -0
  107. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  108. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  109. package/pages/c/_cluster/explorer/index.vue +2 -11
  110. package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
  111. package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
  112. package/pages/c/_cluster/settings/brand.vue +11 -8
  113. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +177 -0
  114. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +19 -3
  115. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +90 -21
  116. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +107 -37
  117. package/pages/c/_cluster/uiplugins/index.vue +160 -44
  118. package/pages/docs/_doc.vue +9 -3
  119. package/pages/home.vue +6 -6
  120. package/pages/support/index.vue +10 -4
  121. package/pkg/auto-import.js +1 -1
  122. package/plugins/clean-tooltip-directive.js +1 -1
  123. package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
  124. package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
  125. package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
  126. package/plugins/dashboard-store/actions.js +1 -1
  127. package/plugins/dashboard-store/resource-class.js +39 -2
  128. package/plugins/plugin.js +9 -1
  129. package/plugins/steve/__tests__/getters.spec.ts +93 -0
  130. package/plugins/steve/getters.js +21 -1
  131. package/plugins/steve/subscribe.js +1 -3
  132. package/rancher-components/BadgeState/BadgeState.vue +5 -1
  133. package/rancher-components/Banner/Banner.test.ts +51 -1
  134. package/rancher-components/Banner/Banner.vue +134 -53
  135. package/rancher-components/Card/Card.test.ts +37 -0
  136. package/rancher-components/Card/Card.vue +24 -7
  137. package/rancher-components/Form/Checkbox/Checkbox.test.ts +20 -29
  138. package/rancher-components/Form/Checkbox/Checkbox.vue +45 -20
  139. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +2 -8
  140. package/rancher-components/Form/LabeledInput/LabeledInput.vue +22 -10
  141. package/rancher-components/Form/Radio/RadioButton.test.ts +31 -0
  142. package/rancher-components/Form/Radio/RadioButton.vue +30 -13
  143. package/rancher-components/Form/Radio/RadioGroup.vue +26 -7
  144. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -6
  145. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +25 -38
  146. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +23 -11
  147. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +19 -5
  148. package/rancher-components/StringList/StringList.test.ts +453 -49
  149. package/rancher-components/StringList/StringList.vue +44 -26
  150. package/scripts/extension/publish +2 -2
  151. package/scripts/typegen.sh +11 -2
  152. package/server/server-middleware.js +4 -12
  153. package/store/index.js +14 -3
  154. package/store/prefs.js +0 -3
  155. package/store/store-types.js +2 -0
  156. package/store/type-map.js +17 -29
  157. package/types/api.d.ts +1 -0
  158. package/types/fleet.d.ts +1 -0
  159. package/types/shell/index.d.ts +931 -85
  160. package/types/userPreferences.d.ts +1 -1
  161. package/utils/__mocks__/socket.js +21 -0
  162. package/utils/grafana.js +23 -11
  163. package/utils/kube.js +9 -0
  164. package/utils/object.js +27 -0
  165. package/utils/selector.js +2 -1
  166. package/utils/settings.ts +2 -2
  167. package/utils/validators/formRules/index.ts +3 -3
  168. package/vue.config.js +3 -2
  169. package/components/.DS_Store +0 -0
  170. package/components/__tests__/.DS_Store +0 -0
  171. package/creators/pkg/package-lock.json +0 -37
  172. package/pages/safeMode.vue +0 -17
  173. package/plugins/steve/urloptions.js +0 -47
  174. package/yarn-error.log +0 -196
@@ -0,0 +1,108 @@
1
+ export const VOLUME_PLUGINS = [
2
+ {
3
+ labelKey: 'persistentVolume.awsElasticBlockStore.label',
4
+ value: 'awsElasticBlockStore',
5
+ supported: true
6
+ },
7
+ {
8
+ labelKey: 'persistentVolume.azureDisk.label',
9
+ value: 'azureDisk',
10
+ supported: true
11
+ },
12
+ {
13
+ labelKey: 'persistentVolume.azureFile.label',
14
+ value: 'azureFile',
15
+ supported: true
16
+ },
17
+ {
18
+ labelKey: 'persistentVolume.cephfs.label',
19
+ value: 'cephfs',
20
+ },
21
+ {
22
+ labelKey: 'persistentVolume.rbd.label',
23
+ value: 'rbd',
24
+ },
25
+ {
26
+ labelKey: 'persistentVolume.csi.label',
27
+ value: 'csi',
28
+ supported: true
29
+ },
30
+ {
31
+ labelKey: 'persistentVolume.fc.label',
32
+ value: 'fc',
33
+ },
34
+ {
35
+ labelKey: 'persistentVolume.flexVolume.label',
36
+ value: 'flexVolume',
37
+ },
38
+ {
39
+ labelKey: 'persistentVolume.flocker.label',
40
+ value: 'flocker',
41
+ },
42
+ {
43
+ labelKey: 'persistentVolume.glusterfs.label',
44
+ value: 'glusterfs',
45
+ },
46
+ {
47
+ labelKey: 'persistentVolume.gcePersistentDisk.label',
48
+ value: 'gcePersistentDisk',
49
+ supported: true
50
+ },
51
+ {
52
+ labelKey: 'persistentVolume.hostPath.label',
53
+ value: 'hostPath',
54
+ supported: true
55
+ },
56
+ {
57
+ labelKey: 'persistentVolume.iscsi.label',
58
+ value: 'iscsi',
59
+ },
60
+ {
61
+ labelKey: 'persistentVolume.local.label',
62
+ value: 'local',
63
+ supported: true
64
+ },
65
+ {
66
+ labelKey: 'persistentVolume.longhorn.label',
67
+ value: 'longhorn',
68
+ supported: true
69
+ },
70
+ {
71
+ labelKey: 'persistentVolume.nfs.label',
72
+ value: 'nfs',
73
+ supported: true
74
+ },
75
+ {
76
+ labelKey: 'persistentVolume.cinder.label',
77
+ value: 'cinder',
78
+ },
79
+ {
80
+ labelKey: 'persistentVolume.photonPersistentDisk.label',
81
+ value: 'photonPersistentDisk',
82
+ },
83
+ {
84
+ labelKey: 'persistentVolume.portworxVolume.label',
85
+ value: 'portworxVolume',
86
+ },
87
+
88
+ {
89
+ labelKey: 'persistentVolume.quobyte.label',
90
+ value: 'quobyte',
91
+ },
92
+
93
+ {
94
+ labelKey: 'persistentVolume.scaleIO.label',
95
+ value: 'scaleIO',
96
+ },
97
+ {
98
+ labelKey: 'persistentVolume.storageos.label',
99
+ value: 'storageos',
100
+ },
101
+ {
102
+ labelKey: 'persistentVolume.vsphereVolume.label',
103
+ value: 'vsphereVolume',
104
+ supported: true
105
+ },
106
+ ];
107
+
108
+ export const LONGHORN_PLUGIN = VOLUME_PLUGINS.find((plugin) => plugin.value === 'longhorn');
@@ -8,7 +8,7 @@ import {
8
8
  } from '@shell/config/types';
9
9
  import { MULTI_CLUSTER } from '@shell/store/features';
10
10
  import { DSL } from '@shell/store/type-map';
11
- import { BLANK_CLUSTER } from '@shell/store';
11
+ import { BLANK_CLUSTER } from '@shell/store/store-types.js';
12
12
 
13
13
  export const NAME = 'manager';
14
14
 
@@ -38,6 +38,10 @@ export function init(store) {
38
38
  resource: CAPI.RANCHER_CLUSTER
39
39
  }
40
40
  },
41
+ typeStoreMap: {
42
+ [NORMAN.CLOUD_CREDENTIAL]: 'rancher',
43
+ cloudCredential: 'rancher',
44
+ }
41
45
  });
42
46
 
43
47
  virtualType({
package/config/router.js CHANGED
@@ -48,10 +48,6 @@ export const routerOptions = {
48
48
  path: '/prefs',
49
49
  component: () => interopDefault(import('../pages/prefs.vue' /* webpackChunkName: "pages/prefs" */)),
50
50
  name: 'prefs'
51
- }, {
52
- path: '/safeMode',
53
- component: () => interopDefault(import('../pages/safeMode.vue' /* webpackChunkName: "pages/safeMode" */)),
54
- name: 'safeMode'
55
51
  }, {
56
52
  path: '/support',
57
53
  component: () => interopDefault(import('../pages/support/index.vue' /* webpackChunkName: "pages/support/index" */)),
@@ -89,6 +89,10 @@ export const SETTING = {
89
89
  */
90
90
  CLUSTER_AGENT_DEFAULT_AFFINITY: 'cluster-agent-default-affinity',
91
91
  FLEET_AGENT_DEFAULT_AFFINITY: 'fleet-agent-default-affinity',
92
+ /**
93
+ * manage rancher repositories in extensions (official, partners repos)
94
+ */
95
+ ADD_EXTENSION_REPOS_BANNER_DISPLAY: 'display-add-extension-repos-banner'
92
96
  };
93
97
 
94
98
  // These are the settings that are allowed to be edited via the UI
@@ -264,11 +264,12 @@ export const DURATION = {
264
264
  formatter: 'LiveDuration',
265
265
  };
266
266
 
267
- export const IMAGE = {
268
- name: 'image',
269
- labelKey: 'tableHeaders.image',
270
- value: 'image',
271
- sort: ['image', 'nameSort'],
267
+ export const IMAGE_NAME = {
268
+ name: 'image',
269
+ labelKey: 'tableHeaders.image',
270
+ value: 'image',
271
+ sort: ['image', 'nameSort'],
272
+ formatter: 'ImageName',
272
273
  };
273
274
 
274
275
  export const POD_IMAGES = {
package/config/types.js CHANGED
@@ -151,6 +151,8 @@ export const LONGHORN = {
151
151
  VOLUMES: 'longhorn.io.volume',
152
152
  };
153
153
 
154
+ export const LONGHORN_DRIVER = 'driver.longhorn.io';
155
+
154
156
  export const SNAPSHOT = 'rke.cattle.io.etcdsnapshot';
155
157
 
156
158
  // --------------------------------------
@@ -29,8 +29,21 @@ export const UI_PLUGINS_REPO_NAME = 'rancher-ui-plugins';
29
29
  export const UI_PLUGINS_REPO_URL = 'https://github.com/rancher/ui-plugin-charts';
30
30
  export const UI_PLUGINS_REPO_BRANCH = 'main';
31
31
 
32
+ // Info for the Helm Chart Repo for Partner Extensions
33
+ export const UI_PLUGINS_PARTNERS_REPO_NAME = 'partner-extensions';
34
+
35
+ export const UI_PLUGINS_PARTNERS_REPO_URL = 'https://github.com/rancher/partner-extensions';
36
+ export const UI_PLUGINS_PARTNERS_REPO_BRANCH = 'main';
37
+
38
+ // Info for the Helm Chart Repo for Community Extensions
39
+ export const UI_PLUGINS_COMMUNITY_REPO_NAME = 'community-extensions';
40
+
41
+ export const UI_PLUGINS_COMMUNITY_REPO_URL = 'https://github.com/rancher/community-extensions';
42
+ export const UI_PLUGINS_COMMUNITY_REPO_BRANCH = 'main';
43
+
32
44
  // Chart annotations
33
45
  export const UI_PLUGIN_CHART_ANNOTATIONS = {
46
+ KUBE_VERSION: 'catalog.cattle.io/kube-version',
34
47
  RANCHER_VERSION: 'catalog.cattle.io/rancher-version',
35
48
  EXTENSIONS_VERSION: 'catalog.cattle.io/ui-extensions-version',
36
49
  UI_VERSION: 'catalog.cattle.io/ui-version',
@@ -121,16 +134,18 @@ export function shouldNotLoadPlugin(plugin, rancherVersion, loadedPlugins) {
121
134
  }
122
135
 
123
136
  // Can a chart version be used for this Rancher (based on the annotations on the chart)?
124
- export function isSupportedChartVersion(chartVersion, rancherVersion) {
137
+ export function isSupportedChartVersion(versionsData) {
138
+ const { version, rancherVersion, kubeVersion } = versionsData;
139
+
125
140
  // Plugin specified a required extension API version
126
- const requiredAPI = chartVersion.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
141
+ const requiredAPI = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
127
142
 
128
143
  if (requiredAPI && !semver.satisfies(UI_PLUGIN_API_VERSION, requiredAPI)) {
129
144
  return false;
130
145
  }
131
146
 
132
147
  // Host application
133
- const requiredHost = chartVersion.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST];
148
+ const requiredHost = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST];
134
149
 
135
150
  if (requiredHost && requiredHost !== UI_PLUGIN_HOST_APP) {
136
151
  return false;
@@ -138,24 +153,37 @@ export function isSupportedChartVersion(chartVersion, rancherVersion) {
138
153
 
139
154
  // Rancher version
140
155
  if (rancherVersion) {
141
- const requiredRancherVersion = chartVersion.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.RANCHER_VERSION];
156
+ const requiredRancherVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.RANCHER_VERSION];
142
157
 
143
158
  if (requiredRancherVersion && !semver.satisfies(rancherVersion, requiredRancherVersion)) {
144
159
  return false;
145
160
  }
146
161
  }
147
162
 
163
+ // Kube version
164
+ if (kubeVersion) {
165
+ const requiredKubeVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
166
+
167
+ if (requiredKubeVersion && !semver.satisfies(kubeVersion, requiredKubeVersion)) {
168
+ return false;
169
+ }
170
+ }
171
+
148
172
  return true;
149
173
  }
150
174
 
151
- export function isChartVersionAvailableForInstall(version, rancherVersion, returnObj = false) {
175
+ export function isChartVersionAvailableForInstall(versionsData, returnObj = false) {
176
+ const { version, rancherVersion, kubeVersion } = versionsData;
177
+
152
178
  const parsedRancherVersion = rancherVersion.split('-')?.[0];
153
179
  const regexHashString = new RegExp('^[A-Za-z0-9]{9}$');
154
180
  const isRancherVersionHashString = regexHashString.test(rancherVersion);
155
181
  const requiredUiVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.UI_VERSION];
182
+ const requiredKubeVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
156
183
  const versionObj = { ...version };
157
184
 
158
185
  versionObj.isCompatibleWithUi = true;
186
+ versionObj.isCompatibleWithKubeVersion = true;
159
187
 
160
188
  // if it's a head version of Rancher, then we skip the validation and enable them all
161
189
  if (!isRancherVersionHashString && requiredUiVersion && !semver.satisfies(parsedRancherVersion, requiredUiVersion)) {
@@ -164,6 +192,23 @@ export function isChartVersionAvailableForInstall(version, rancherVersion, retur
164
192
  }
165
193
  versionObj.isCompatibleWithUi = false;
166
194
  versionObj.requiredUiVersion = requiredUiVersion;
195
+
196
+ if (returnObj) {
197
+ return versionObj;
198
+ }
199
+ }
200
+
201
+ // check kube version
202
+ if (kubeVersion && requiredKubeVersion && !semver.satisfies(kubeVersion, requiredKubeVersion)) {
203
+ if (!returnObj) {
204
+ return false;
205
+ }
206
+ versionObj.isCompatibleWithKubeVersion = false;
207
+ versionObj.requiredKubeVersion = requiredKubeVersion;
208
+
209
+ if (returnObj) {
210
+ return versionObj;
211
+ }
167
212
  }
168
213
 
169
214
  if (returnObj) {
@@ -1,8 +1,11 @@
1
1
  import { ActionLocation, CardLocation, ExtensionPoint } from '@shell/core/types';
2
2
  import { isMac } from '@shell/utils/platform';
3
3
  import { ucFirst, randomStr } from '@shell/utils/string';
4
- import { _EDIT, _CONFIG, _DETAIL, _LIST } from '@shell/config/query-params';
4
+ import {
5
+ _EDIT, _CONFIG, _DETAIL, _LIST, _CREATE
6
+ } from '@shell/config/query-params';
5
7
  import { getProductFromRoute } from '@shell/middleware/authenticated';
8
+ import { isEqual } from '@shell/utils/object';
6
9
 
7
10
  function checkRouteProduct({ name, params, query }, locationConfigParam) {
8
11
  const product = getProductFromRoute({
@@ -20,21 +23,24 @@ function checkRouteProduct({ name, params, query }, locationConfigParam) {
20
23
  }
21
24
 
22
25
  function checkRouteMode({ name, query }, locationConfigParam) {
23
- if (locationConfigParam === _EDIT && query.mode && query.mode === _EDIT) {
26
+ if (locationConfigParam === _EDIT && query.mode && query.mode === _EDIT && !query.as) {
24
27
  return true;
25
28
  } else if (locationConfigParam === _CONFIG && query.as && query.as === _CONFIG) {
26
29
  return true;
27
- } else if (locationConfigParam === _DETAIL && name.includes('-id')) {
30
+ } else if (locationConfigParam === _DETAIL && !query.as && name.includes('-id') && (!query.mode || query?.mode !== _EDIT)) {
28
31
  return true;
29
32
  // alias to target all list views
30
33
  } else if (locationConfigParam === _LIST && !name.includes('-id') && name.includes('-resource')) {
31
34
  return true;
35
+ // alias to target create views
36
+ } else if (locationConfigParam === _CREATE && name.endsWith('-create')) {
37
+ return true;
32
38
  }
33
39
 
34
40
  return false;
35
41
  }
36
42
 
37
- function checkExtensionRouteBinding($route, locationConfig) {
43
+ function checkExtensionRouteBinding($route, locationConfig, context) {
38
44
  // if no configuration is passed, consider it as global
39
45
  if (!Object.keys(locationConfig).length) {
40
46
  return true;
@@ -43,23 +49,31 @@ function checkExtensionRouteBinding($route, locationConfig) {
43
49
  const { params } = $route;
44
50
 
45
51
  // "params" to be checked based on the locationConfig
52
+ // This has become overloaded with mode and context
46
53
  const paramsToCheck = [
47
54
  'product',
48
55
  'resource',
49
56
  'namespace',
50
57
  'cluster',
51
58
  'id',
52
- 'mode'
59
+ 'mode',
60
+ 'path',
61
+ // url query params
62
+ 'queryParam',
63
+ // Custom context specific params provided by the extension, not to be confused with location params
64
+ 'context',
53
65
  ];
54
66
 
55
- let res = false;
67
+ let res = true;
56
68
 
57
69
  for (let i = 0; i < paramsToCheck.length; i++) {
58
70
  const param = paramsToCheck[i];
59
71
 
60
72
  if (locationConfig[param]) {
61
- for (let x = 0; x < locationConfig[param].length; x++) {
62
- const locationConfigParam = locationConfig[param][x];
73
+ const asArray = Array.isArray(locationConfig[param]) ? locationConfig[param] : [locationConfig[param]];
74
+
75
+ for (let x = 0; x < asArray.length; x++) {
76
+ const locationConfigParam = asArray[x];
63
77
 
64
78
  if (locationConfigParam) {
65
79
  // handle "product" in a separate way...
@@ -68,6 +82,21 @@ function checkExtensionRouteBinding($route, locationConfig) {
68
82
  // also handle "mode" in a separate way because it mainly depends on query params
69
83
  } else if (param === 'mode') {
70
84
  res = checkRouteMode($route, locationConfigParam);
85
+ } else if (param === 'context') {
86
+ // Need all keys and values to match
87
+ res = isEqual(locationConfigParam, context);
88
+ // evaluate queryParam in route
89
+ } else if (param === 'queryParam') {
90
+ res = isEqual(locationConfigParam, $route.query);
91
+ // evaluate path in route
92
+ } else if (param === 'path' && locationConfigParam.urlPath) {
93
+ if (locationConfigParam.endsWith) {
94
+ res = $route.path.endsWith(locationConfigParam.urlPath);
95
+ } else if (!Object.keys(locationConfigParam).includes('exact') || locationConfigParam.exact) {
96
+ res = locationConfigParam.urlPath === $route.path;
97
+ } else {
98
+ res = $route.path.includes(locationConfigParam.urlPath);
99
+ }
71
100
  } else if (locationConfigParam === params[param]) {
72
101
  res = true;
73
102
  } else {
@@ -91,7 +120,7 @@ function checkExtensionRouteBinding($route, locationConfig) {
91
120
  return res;
92
121
  }
93
122
 
94
- export function getApplicableExtensionEnhancements(pluginCtx, actionType, uiArea, currRoute, translationCtx = pluginCtx) {
123
+ export function getApplicableExtensionEnhancements(pluginCtx, actionType, uiArea, currRoute, translationCtx = pluginCtx, context) {
95
124
  const extensionEnhancements = [];
96
125
 
97
126
  // gate it so that we prevent errors on older versions of dashboard
@@ -99,7 +128,7 @@ export function getApplicableExtensionEnhancements(pluginCtx, actionType, uiArea
99
128
  const actions = pluginCtx.$plugin.getUIConfig(actionType, uiArea);
100
129
 
101
130
  actions.forEach((action, i) => {
102
- if (checkExtensionRouteBinding(currRoute, action.locationConfig)) {
131
+ if (checkExtensionRouteBinding(currRoute, action.locationConfig, context || {})) {
103
132
  // ADD CARD PLUGIN UI ENHANCEMENT
104
133
  if (actionType === ExtensionPoint.CARD) {
105
134
  // intercept to apply translation
@@ -116,11 +145,6 @@ export function getApplicableExtensionEnhancements(pluginCtx, actionType, uiArea
116
145
  actions[i].label = translationCtx.t(action.labelKey);
117
146
  }
118
147
 
119
- // sets the enabled flag to true if omitted on the config
120
- if (!Object.keys(action).includes('enabled')) {
121
- actions[i].enabled = true;
122
- }
123
-
124
148
  // bulkable flag
125
149
  actions[i].bulkable = actions[i].multiple || actions[i].bulkable;
126
150
 
package/core/plugin.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  PluginRouteConfig, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
16
16
  } from './types';
17
17
  import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
18
+ import { registerLayout } from '@shell/initialize/layouts';
18
19
 
19
20
  export type ProductFunction = (plugin: IPlugin, store: any) => void;
20
21
 
@@ -267,6 +268,14 @@ export class Plugin implements IPlugin {
267
268
  }
268
269
 
269
270
  this.l10n[name].push(fn);
271
+ } else if (type === 'layouts') {
272
+ fn().then((component: any) => {
273
+ if (component.default) {
274
+ registerLayout(name, component.default);
275
+ } else {
276
+ console.error(`Failed to load layout ${ name } because the file didn't export a default component.`); // eslint-disable-line no-console
277
+ }
278
+ });
270
279
  } else {
271
280
  if (!this.types[type]) {
272
281
  this.types[type] = {};
package/core/plugins.js CHANGED
@@ -182,7 +182,7 @@ export default function({
182
182
  console.error('Error removing plugin', e); // eslint-disable-line no-console
183
183
  }
184
184
 
185
- delete plugins[plugin.name];
185
+ delete plugins[plugin.id];
186
186
  }
187
187
  },
188
188