@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
@@ -7,10 +7,10 @@ import CruResource from '@shell/components/CruResource';
7
7
  import { LabeledInput } from '@components/Form/LabeledInput';
8
8
  import { RadioGroup } from '@components/Form/Radio';
9
9
  import FileImageSelector from '@shell/components/form/FileImageSelector';
10
- import NameNsDescription, { normalizeName } from '@shell/components/form/NameNsDescription';
11
- import Tab from '@shell/components/Tabbed/Tab';
12
- import Tabbed from '@shell/components/Tabbed';
13
10
  import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
11
+ import NameNsDescription, { normalizeName } from '@shell/components/form/NameNsDescription';
12
+ import { Banner } from '@components/Banner';
13
+ import FormValidation from '@shell/mixins/form-validation';
14
14
 
15
15
  const LINK_TYPE_URL = 'url';
16
16
  const LINK_TYPE_SERVICE = 'service';
@@ -19,16 +19,15 @@ const LINK_TARGET_BLANK = '_blank';
19
19
  const LINK_TARGET_SELF = '_self';
20
20
 
21
21
  export default {
22
- mixins: [CreateEditView],
22
+ mixins: [CreateEditView, FormValidation],
23
23
  components: {
24
24
  CruResource,
25
25
  LabeledInput,
26
26
  RadioGroup,
27
27
  NameNsDescription,
28
- Tabbed,
29
- Tab,
30
28
  FileImageSelector,
31
- LabeledSelect
29
+ LabeledSelect,
30
+ Banner
32
31
  },
33
32
  data() {
34
33
  return {
@@ -56,12 +55,19 @@ export default {
56
55
  label: this.t('navLink.tabs.link.type.service')
57
56
  }
58
57
  ],
59
- currentLinkType: null,
60
- targetName: null,
61
- currentTarget: LINK_TARGET_BLANK,
62
- protocolsOptions: PROTOCOLS,
63
- services: [],
64
- currentService: null,
58
+ currentLinkType: null,
59
+ targetName: null,
60
+ currentTarget: LINK_TARGET_BLANK,
61
+ protocolsOptions: PROTOCOLS,
62
+ services: [],
63
+ currentService: null,
64
+ imageErrorMessage: '',
65
+ fvFormRuleSets: [
66
+ { path: 'metadata.name', rules: ['nameRequired'] },
67
+ { path: 'spec.toURL', rules: ['urlRequired'] },
68
+ { path: 'spec.toService.namespace', rules: ['serviceNamespaceRequired'] },
69
+ { path: 'spec.toService.scheme', rules: ['serviceSchemeRequired'] }],
70
+
65
71
  };
66
72
  },
67
73
  props: {
@@ -112,6 +118,44 @@ export default {
112
118
  label: id, id, name, namespace
113
119
  }) );
114
120
  },
121
+ imageError() {
122
+ return !!this.imageErrorMessage && !this.value.spec.iconSrc;
123
+ },
124
+ fvExtraRules() {
125
+ const isLinkTypeUrl = this.currentLinkType === LINK_TYPE_URL;
126
+ const isServiceTypeUrl = this.currentLinkType === LINK_TYPE_SERVICE;
127
+
128
+ return {
129
+ nameRequired: () => {
130
+ if (!this.value.metadata.name) {
131
+ return this.getError('navLink.name.label');
132
+ }
133
+ },
134
+
135
+ urlRequired: () => {
136
+ const condition = this.value.spec.toURL;
137
+
138
+ if (isLinkTypeUrl && !condition) {
139
+ return this.getError('navLink.tabs.link.toURL.label');
140
+ }
141
+ },
142
+ serviceNamespaceRequired: () => {
143
+ const condition = this.value.spec.toService.name && this.value.spec.toService.namespace;
144
+
145
+ if (isServiceTypeUrl && !condition) {
146
+ return this.getError('navLink.tabs.link.toService.service.label');
147
+ }
148
+ },
149
+ serviceSchemeRequired: () => {
150
+ const condition = this.value.spec.toService.scheme;
151
+
152
+ if (isServiceTypeUrl && !condition) {
153
+ return this.getError('navLink.tabs.link.toService.scheme.label');
154
+ }
155
+ }
156
+
157
+ };
158
+ }
115
159
  },
116
160
  async fetch() {
117
161
  this.services = await this.$store
@@ -214,50 +258,20 @@ export default {
214
258
  getError(label) {
215
259
  return this.$store.getters['i18n/t']('validation.required', { key: this.t(label) });
216
260
  },
217
- /**
218
- * Verify all fields are fulfilled or display footer notification
219
- */
220
- validate() {
221
- const errors = [];
222
-
223
- switch (this.currentLinkType) {
224
- case LINK_TYPE_URL:
225
- if (!this.value.spec.toURL) {
226
- errors.push(this.getError('navLink.tabs.link.toURL.label'));
227
- }
228
- break;
229
-
230
- case LINK_TYPE_SERVICE:
231
- if (!this.value.spec.toService.name || !this.value.spec.toService.namespace) {
232
- errors.push(this.getError(`navLink.tabs.link.toService.service.label`));
233
- }
234
-
235
- if (!this.value.spec.toService.scheme) {
236
- errors.push(this.getError(`navLink.tabs.link.toService.scheme.label`));
237
- }
238
- break;
239
-
240
- // no default
241
- }
242
261
 
243
- if (!this.value.metadata.name) {
244
- errors.push(this.getError('navLink.name.label'));
245
- }
246
-
247
- if (errors.length) {
248
- throw (errors.join('\n'));
249
- }
262
+ setImageError(e) {
263
+ this.imageErrorMessage = e;
250
264
  },
265
+ setIcon(value) {
266
+ this.imageErrorMessage = '';
267
+ this.$emit('update:value.spec.iconSrc ', value);
268
+ }
251
269
  },
252
270
  created() {
253
271
  this.setDefaultValues();
254
272
  this.setUrlType();
255
273
  this.setTargetOption();
256
274
  this.setCurrentService();
257
- // Validate error presence by allowing or resetting submission process
258
- if (this.registerBeforeHook) {
259
- this.registerBeforeHook(this.validate);
260
- }
261
275
  }
262
276
  };
263
277
  </script>
@@ -267,8 +281,10 @@ export default {
267
281
  :can-yaml="!isCreate"
268
282
  :mode="mode"
269
283
  :resource="value"
270
- :errors="errors"
284
+ :errors="fvUnreportedValidationErrors"
271
285
  :cancel-event="true"
286
+ :validation-passed="fvFormIsValid"
287
+ data-testid="Navlink-CRU"
272
288
  @error="e=>errors = e"
273
289
  @finish="save"
274
290
  @cancel="done()"
@@ -284,147 +300,158 @@ export default {
284
300
  name-placeholder="navLink.name.placeholder"
285
301
  description-label="navLink.label.label"
286
302
  description-placeholder="navLink.label.placeholder"
303
+ data-testid="Navlink-name-field"
304
+ :rules="{ name: fvGetAndReportPathRules('metadata.name'), namespace: [], description: [] }"
287
305
  />
288
306
 
289
- <Tabbed
290
- :side-tabs="true"
291
- >
292
- <Tab
293
- name="link"
294
- :label="t('navLink.tabs.link.label')"
295
- >
296
- <div class="row mb-20">
297
- <div class="col span-6">
298
- <RadioGroup
299
- v-model="linkType"
300
- name="type"
301
- :mode="mode"
302
- :options="urlTypeOptions"
303
- />
304
- </div>
305
- </div>
306
-
307
- <template v-if="isURL">
308
- <div class="row mb-20">
309
- <LabeledInput
310
- v-model="value.spec.toURL"
311
- :mode="mode"
312
- :label="t('navLink.tabs.link.toURL.label')"
313
- :required="isURL"
314
- :placeholder="t('navLink.tabs.link.toURL.placeholder')"
315
- />
316
- </div>
317
- </template>
318
- <template v-if="isService">
319
- <div class="row mb-20">
320
- <div class="col span-2">
321
- <LabeledSelect
322
- v-model="value.spec.toService.scheme"
323
- :mode="mode"
324
- :label="t('navLink.tabs.link.toService.scheme.label')"
325
- :required="isService"
326
- :options="protocolsOptions"
327
- :placeholder="t('navLink.tabs.link.toService.scheme.placeholder')"
328
- />
329
- </div>
330
- <div class="col span-5">
331
- <LabeledSelect
332
- v-model="currentService"
333
- :mode="mode"
334
- :label="t('navLink.tabs.link.toService.service.label')"
335
- :options="mappedServices"
336
- :required="isService"
337
- :placeholder="t('navLink.tabs.link.toService.service.placeholder')"
338
- @input="setService"
339
- />
340
- </div>
341
- <div class="col span-2">
342
- <LabeledInput
343
- v-model="value.spec.toService.port"
344
- :mode="mode"
345
- :label="t('navLink.tabs.link.toService.port.label')"
346
- type="number"
347
- :placeholder="t('navLink.tabs.link.toService.port.placeholder')"
348
- />
349
- </div>
350
- <div class="col span-3">
351
- <LabeledInput
352
- v-model="value.spec.toService.path"
353
- :mode="mode"
354
- :label="t('navLink.tabs.link.toService.path.label')"
355
- :placeholder="t('navLink.tabs.link.toService.path.placeholder')"
356
- />
357
- </div>
358
- </div>
359
- </template>
360
- </Tab>
307
+ <div class="spacer" />
308
+ <h2 v-t="'navLink.tabs.link.label'" />
309
+ <div class="row mb-20">
310
+ <div class="col span-6">
311
+ <RadioGroup
312
+ v-model="linkType"
313
+ name="type"
314
+ :mode="mode"
315
+ :options="urlTypeOptions"
316
+ data-testid="Navlink-link-radiogroup"
317
+ />
318
+ </div>
319
+ </div>
361
320
 
362
- <Tab
363
- name="target"
364
- :label="t('navLink.tabs.target.label')"
365
- >
366
- <div class="row mb-20">
367
- <div class="col span-6">
368
- <RadioGroup
369
- v-model="currentTarget"
370
- name="type"
371
- :mode="mode"
372
- :options="targetOptions"
373
- :required="true"
374
- @input="setTargetValue($event)"
375
- />
376
- </div>
377
- <div class="col span-6">
378
- <LabeledInput
379
- v-if="isNamedWindow"
380
- v-model="targetName"
381
- :mode="mode"
382
- :label="t('navLink.tabs.target.namedValue.label')"
383
- @input="setTargetValue($event);"
384
- />
385
- </div>
321
+ <template v-if="isURL">
322
+ <div class="row mb-20">
323
+ <LabeledInput
324
+ v-model="value.spec.toURL"
325
+ :mode="mode"
326
+ :label="t('navLink.tabs.link.toURL.label')"
327
+ :required="isURL"
328
+ :placeholder="t('navLink.tabs.link.toURL.placeholder')"
329
+ :rules="fvGetAndReportPathRules('spec.toURL')"
330
+ data-testid="Navlink-url-field"
331
+ />
332
+ </div>
333
+ </template>
334
+ <template v-if="isService">
335
+ <div class="row mb-20">
336
+ <div class="col span-2">
337
+ <LabeledSelect
338
+ v-model="value.spec.toService.scheme"
339
+ :mode="mode"
340
+ :label="t('navLink.tabs.link.toService.scheme.label')"
341
+ :required="isService"
342
+ :options="protocolsOptions"
343
+ :placeholder="t('navLink.tabs.link.toService.scheme.placeholder')"
344
+ :rules="fvGetAndReportPathRules('spec.toService.scheme')"
345
+ data-testid="Navlink-scheme-field"
346
+ />
386
347
  </div>
387
- </Tab>
388
-
389
- <Tab
390
- name="group"
391
- :label="t('navLink.tabs.group.label')"
392
- >
393
- <div class="row mb-20">
394
- <div class="col span-6">
395
- <LabeledInput
396
- v-model="value.spec.group"
397
- :mode="mode"
398
- :tooltip="t('navLink.tabs.group.group.tooltip')"
399
- :label="t('navLink.tabs.group.group.label')"
400
- />
401
- </div>
402
- <div class="col span-6">
403
- <LabeledInput
404
- v-model="value.spec.sideLabel"
405
- :mode="mode"
406
- :label="t('navLink.tabs.group.sideLabel.label')"
407
- />
408
- </div>
348
+ <div class="col span-5">
349
+ <LabeledSelect
350
+ v-model="currentService"
351
+ :mode="mode"
352
+ :label="t('navLink.tabs.link.toService.service.label')"
353
+ :options="mappedServices"
354
+ :required="isService"
355
+ :placeholder="t('navLink.tabs.link.toService.service.placeholder')"
356
+ :rules="fvGetAndReportPathRules('spec.toService.namespace')"
357
+ data-testid="Navlink-currentService-field"
358
+ @input="setService"
359
+ />
409
360
  </div>
410
-
411
- <div class="row mb-20">
412
- <div class="col span-6">
413
- <LabeledInput
414
- v-model="value.spec.description"
415
- :mode="mode"
416
- :label="t('navLink.tabs.group.description.label')"
417
- />
418
- </div>
419
- <div class="col span-2">
420
- <FileImageSelector
421
- v-model="value.spec.iconSrc"
422
- :mode="mode"
423
- :label="t('navLink.tabs.group.iconSrc.label')"
424
- />
425
- </div>
361
+ <div class="col span-2">
362
+ <LabeledInput
363
+ v-model="value.spec.toService.port"
364
+ :mode="mode"
365
+ :label="t('navLink.tabs.link.toService.port.label')"
366
+ type="number"
367
+ :placeholder="t('navLink.tabs.link.toService.port.placeholder')"
368
+ />
426
369
  </div>
427
- </Tab>
428
- </Tabbed>
370
+ <div class="col span-3">
371
+ <LabeledInput
372
+ v-model="value.spec.toService.path"
373
+ :mode="mode"
374
+ :label="t('navLink.tabs.link.toService.path.label')"
375
+ :placeholder="t('navLink.tabs.link.toService.path.placeholder')"
376
+ />
377
+ </div>
378
+ </div>
379
+ </template>
380
+ <div class="spacer" />
381
+ <h2 v-t="'navLink.tabs.target.label'" />
382
+ <div class="row mb-20">
383
+ <div class="col span-6">
384
+ <RadioGroup
385
+ v-model="currentTarget"
386
+ name="type"
387
+ :mode="mode"
388
+ :options="targetOptions"
389
+ @input="setTargetValue($event)"
390
+ />
391
+ </div>
392
+ <div class="col span-6">
393
+ <LabeledInput
394
+ v-if="isNamedWindow"
395
+ v-model="targetName"
396
+ :mode="mode"
397
+ :label="t('navLink.tabs.target.namedValue.label')"
398
+ @input="setTargetValue($event);"
399
+ />
400
+ </div>
401
+ </div>
402
+ <div class="spacer" />
403
+ <h2 v-t="'navLink.tabs.group.label'" />
404
+
405
+ <div class="row mb-20">
406
+ <div class="col span-6">
407
+ <LabeledInput
408
+ v-model="value.spec.group"
409
+ :mode="mode"
410
+ :tooltip="t('navLink.tabs.group.group.tooltip')"
411
+ :label="t('navLink.tabs.group.group.label')"
412
+ />
413
+ </div>
414
+ <div class="col span-6">
415
+ <LabeledInput
416
+ v-model="value.spec.sideLabel"
417
+ :mode="mode"
418
+ :label="t('navLink.tabs.group.sideLabel.label')"
419
+ />
420
+ </div>
421
+ </div>
422
+
423
+ <div class="row mb-20">
424
+ <div class="col span-6">
425
+ <LabeledInput
426
+ v-model="value.spec.description"
427
+ :mode="mode"
428
+ :label="t('navLink.tabs.group.description.label')"
429
+ />
430
+ </div>
431
+ </div>
432
+
433
+ <h4 v-t="'navLink.tabs.groupImage.label'" />
434
+ <div class="row">
435
+ <label class="text-label">
436
+ {{ t('navLink.tabs.groupImage.iconSrc.tip', {}, true) }}
437
+ </label>
438
+ </div>
439
+ <div class="row">
440
+ <FileImageSelector
441
+ v-model="value.spec.iconSrc"
442
+ :read-as-data-url="true"
443
+ :mode="mode"
444
+ :label="t('navLink.tabs.groupImage.iconSrc.label')"
445
+ accept="image/jpeg,image/png,image/svg+xml"
446
+ @error="setImageError"
447
+ @input="setIcon"
448
+ />
449
+ </div>
450
+ <Banner
451
+ v-if="imageError"
452
+ color="error"
453
+ >
454
+ {{ imageErrorMessage }}
455
+ </Banner>
429
456
  </CruResource>
430
457
  </template>
package/initialize/App.js CHANGED
@@ -1,23 +1,13 @@
1
1
  import Vue from 'vue';
2
2
 
3
- import {
4
- getMatchedComponentsInstances, getChildrenComponentInstancesUsingFetch, promisify, globalHandleError, sanitizeComponent
5
- } from '../utils/nuxt';
3
+ import { getMatchedComponentsInstances, getChildrenComponentInstancesUsingFetch, promisify, globalHandleError } from '../utils/nuxt';
6
4
  import NuxtError from '../layouts/error.vue';
7
5
  import NuxtLoading from '../components/nav/GlobalLoading.vue';
8
6
 
9
7
  import '../assets/styles/app.scss';
8
+ import { getLayouts } from './layouts';
10
9
 
11
- import blank from '../layouts/blank.vue';
12
- import defaultLayout from '../layouts/default.vue';
13
- import home from '../layouts/home.vue';
14
- import plain from '../layouts/plain.vue';
15
- import unauthenticated from '../layouts/unauthenticated.vue';
16
- import standalone from '../layouts/standalone.vue';
17
-
18
- const layouts = {
19
- _blank: sanitizeComponent(blank), _default: sanitizeComponent(defaultLayout), _home: sanitizeComponent(home), _plain: sanitizeComponent(plain), _unauthenticated: sanitizeComponent(unauthenticated), _standalone: sanitizeComponent(standalone)
20
- };
10
+ const layouts = getLayouts();
21
11
 
22
12
  export default {
23
13
  render(h) {
@@ -0,0 +1,26 @@
1
+ import { sanitizeComponent } from '@shell/utils/nuxt';
2
+ import blank from '@shell/layouts/blank.vue';
3
+ import defaultLayout from '@shell/layouts/default.vue';
4
+ import home from '@shell/layouts/home.vue';
5
+ import plain from '@shell/layouts/plain.vue';
6
+ import unauthenticated from '@shell/layouts/unauthenticated.vue';
7
+ import standalone from '@shell/layouts/standalone.vue';
8
+
9
+ export type Component = { [key: string]: any };
10
+ export type Layouts = { [key: string]: Component };
11
+ const layouts: Layouts = { };
12
+
13
+ export function getLayouts(): Layouts {
14
+ return layouts;
15
+ }
16
+
17
+ export function registerLayout(name: string, component: Component): void {
18
+ layouts[`_${ name }`] = sanitizeComponent(component);
19
+ }
20
+
21
+ registerLayout('blank', blank) ;
22
+ registerLayout('default', defaultLayout) ;
23
+ registerLayout('home', home) ;
24
+ registerLayout('plain', plain) ;
25
+ registerLayout('unauthenticated', unauthenticated) ;
26
+ registerLayout('standalone', standalone);
@@ -38,7 +38,7 @@ import PageHeaderActions from '@shell/mixins/page-actions';
38
38
  import BrowserTabVisibility from '@shell/mixins/browser-tab-visibility';
39
39
  import { getClusterFromRoute, getProductFromRoute } from '@shell/middleware/authenticated';
40
40
  import { BOTTOM } from '@shell/utils/position';
41
- import { BLANK_CLUSTER } from '@shell/store';
41
+ import { BLANK_CLUSTER } from '@shell/store/store-types.js';
42
42
 
43
43
  const SET_LOGIN_ACTION = 'set-as-login';
44
44
 
@@ -8,7 +8,7 @@ import { applyProducts } from '@shell/store/type-map';
8
8
  import { NAME } from '@shell/config/product/auth';
9
9
  import { MODE, _EDIT } from '@shell/config/query-params';
10
10
  import { mapState } from 'vuex';
11
- import { BLANK_CLUSTER } from '@shell/store';
11
+ import { BLANK_CLUSTER } from '@shell/store/store-types.js';
12
12
  import { allHash } from '@shell/utils/promise';
13
13
 
14
14
  export default {
@@ -135,6 +135,13 @@ export default {
135
135
  },
136
136
 
137
137
  harvesterEnabled: mapFeature(HARVESTER_FEATURE),
138
+
139
+ nonStandardNamespaces() {
140
+ // Show the namespace grouping option if there's clusters with namespaces other than 'fleet-default' or 'fleet-local'
141
+ // This will be used when there's clusters from extension based provisioners
142
+ // We should re-visit this for scaling reasons
143
+ return this.filteredRows.some((c) => c.metadata.namespace !== 'fleet-local' && c.metadata.namespace !== 'fleet-default');
144
+ }
138
145
  },
139
146
 
140
147
  $loadingResources() {
@@ -182,7 +189,7 @@ export default {
182
189
  <ResourceTable
183
190
  :schema="schema"
184
191
  :rows="filteredRows"
185
- :namespaced="false"
192
+ :namespaced="nonStandardNamespaces"
186
193
  :loading="loading"
187
194
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
188
195
  :data-testid="'cluster-list'"