@rancher/shell 3.0.0-rc.9 → 3.0.1-rc.1

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 (130) hide show
  1. package/assets/brand/harvester/favicon.png +0 -0
  2. package/assets/brand/harvester/metadata.json +3 -0
  3. package/assets/images/pl/harvester.svg +1 -0
  4. package/assets/translations/en-us.yaml +37 -15
  5. package/assets/translations/zh-hans.yaml +2 -5
  6. package/components/BrandImage.vue +5 -1
  7. package/components/CopyToClipboardText.vue +2 -0
  8. package/components/CruResourceFooter.vue +1 -0
  9. package/components/DetailTop.vue +1 -1
  10. package/components/EmberPage.vue +0 -8
  11. package/components/ExplorerMembers.vue +5 -1
  12. package/components/ExplorerProjectsNamespaces.vue +39 -15
  13. package/components/HardwareResourceGauge.vue +12 -2
  14. package/components/InputOrDisplay.vue +6 -2
  15. package/components/LandingPagePreference.vue +2 -2
  16. package/components/MessageLink.vue +1 -1
  17. package/components/ResourceDetail/Masthead.vue +22 -1
  18. package/components/ResourceDetail/index.vue +2 -8
  19. package/components/ResourceTable.vue +40 -7
  20. package/components/ResourceYaml.vue +1 -1
  21. package/components/SideNav.vue +1 -1
  22. package/components/SortableTable/actions.js +1 -1
  23. package/components/SortableTable/index.vue +17 -1
  24. package/components/SortableTable/selection.js +1 -1
  25. package/components/SortableTable/sorting.js +11 -3
  26. package/components/TableDataUserIcon.vue +1 -1
  27. package/components/fleet/FleetClusters.vue +0 -3
  28. package/components/fleet/FleetRepos.vue +0 -7
  29. package/components/form/ArrayList.vue +5 -1
  30. package/components/form/ArrayListSelect.vue +5 -1
  31. package/components/form/HookOption.vue +31 -29
  32. package/components/form/KeyValue.vue +1 -1
  33. package/components/form/LabeledSelect.vue +26 -7
  34. package/components/form/LifecycleHooks.vue +2 -2
  35. package/components/form/Password.vue +7 -1
  36. package/components/form/UnitInput.vue +10 -1
  37. package/components/form/__tests__/UnitInput.test.ts +1 -0
  38. package/components/formatter/ClusterProvider.vue +3 -3
  39. package/components/formatter/ImagePercentageBar.vue +1 -1
  40. package/components/formatter/SecretData.vue +1 -1
  41. package/components/formatter/Si.vue +5 -1
  42. package/components/formatter/Translate.vue +1 -1
  43. package/components/nav/Header.vue +38 -17
  44. package/components/nav/NamespaceFilter.vue +5 -8
  45. package/components/nav/TopLevelMenu.vue +11 -51
  46. package/components/nav/WorkspaceSwitcher.vue +0 -1
  47. package/config/labels-annotations.js +2 -0
  48. package/config/private-label.js +2 -1
  49. package/config/router/routes.js +2 -26
  50. package/config/settings.ts +5 -0
  51. package/config/table-headers.js +15 -0
  52. package/config/types.js +3 -0
  53. package/config/version.js +2 -0
  54. package/detail/catalog.cattle.io.app.vue +17 -4
  55. package/detail/fleet.cattle.io.bundle.vue +5 -68
  56. package/detail/fleet.cattle.io.cluster.vue +11 -9
  57. package/detail/fleet.cattle.io.gitrepo.vue +3 -2
  58. package/directives/clean-tooltip.js +4 -4
  59. package/edit/cis.cattle.io.clusterscan.vue +4 -3
  60. package/edit/fleet.cattle.io.gitrepo.vue +11 -8
  61. package/edit/logging-flow/Match.vue +75 -42
  62. package/edit/logging-flow/index.vue +89 -10
  63. package/edit/logging.banzaicloud.io.output/index.vue +2 -2
  64. package/edit/management.cattle.io.project.vue +4 -3
  65. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +5 -5
  66. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -1
  67. package/edit/namespace.vue +1 -1
  68. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +26 -0
  69. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +63 -149
  70. package/edit/provisioning.cattle.io.cluster/index.vue +2 -1
  71. package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -4
  72. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +7 -2
  73. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +108 -35
  74. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +1 -1
  75. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +1 -1
  76. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryMirrors.vue +1 -1
  77. package/edit/workload/mixins/workload.js +1 -1
  78. package/list/harvesterhci.io.management.cluster.vue +244 -0
  79. package/list/namespace.vue +16 -4
  80. package/mixins/browser-tab-visibility.js +1 -1
  81. package/mixins/chart.js +6 -2
  82. package/mixins/metric-poller.js +1 -1
  83. package/mixins/resource-fetch.js +1 -1
  84. package/models/__tests__/management.cattle.io.cluster.test.ts +45 -3
  85. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +0 -86
  86. package/models/catalog.cattle.io.app.js +108 -21
  87. package/models/cloudcredential.js +4 -4
  88. package/models/fleet.cattle.io.bundle.js +3 -1
  89. package/models/fleet.cattle.io.gitrepo.js +51 -63
  90. package/models/k8s.cni.cncf.io.networkattachmentdefinition.js +88 -0
  91. package/models/management.cattle.io.cluster.js +39 -7
  92. package/models/management.cattle.io.project.js +4 -0
  93. package/models/management.cattle.io.setting.js +25 -0
  94. package/models/provisioning.cattle.io.cluster.js +6 -16
  95. package/models/storage.k8s.io.storageclass.js +15 -4
  96. package/models/workload.js +1 -1
  97. package/package.json +5 -5
  98. package/pages/auth/login.vue +3 -2
  99. package/pages/auth/logout.vue +7 -9
  100. package/pages/auth/setup.vue +4 -1
  101. package/pages/c/_cluster/apps/charts/install.vue +11 -3
  102. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  103. package/pages/c/_cluster/explorer/index.vue +1 -2
  104. package/pages/c/_cluster/fleet/index.vue +13 -9
  105. package/pages/c/_cluster/settings/brand.vue +4 -1
  106. package/pages/c/_cluster/uiplugins/index.vue +4 -2
  107. package/pages/diagnostic.vue +1 -0
  108. package/pages/prefs.vue +22 -10
  109. package/plugins/dashboard-store/resource-class.js +11 -3
  110. package/plugins/steve/mutations.js +4 -1
  111. package/plugins/steve/steve-pagination-utils.ts +1 -1
  112. package/plugins/steve/subscribe.js +3 -4
  113. package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -2
  114. package/store/features.js +1 -0
  115. package/store/i18n.js +5 -1
  116. package/store/prefs.js +8 -0
  117. package/types/resources/fleet.d.ts +40 -0
  118. package/types/shell/index.d.ts +442 -396
  119. package/utils/__tests__/object.test.ts +152 -1
  120. package/utils/auth.js +1 -1
  121. package/utils/create-yaml.js +1 -1
  122. package/utils/favicon.js +2 -0
  123. package/utils/fleet.ts +159 -0
  124. package/utils/gc/gc.ts +1 -1
  125. package/utils/object.js +37 -0
  126. package/utils/string.js +9 -0
  127. package/utils/v-sphere.ts +31 -0
  128. package/utils/validators/cron-schedule.js +1 -1
  129. package/utils/validators/formRules/index.ts +2 -2
  130. package/config/product/multi-cluster-apps.js +0 -61
@@ -10,7 +10,6 @@ import { compare } from '@shell/utils/version';
10
10
  import { AS, MODE, _VIEW, _YAML } from '@shell/config/query-params';
11
11
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
12
12
  import { CAPI as CAPI_ANNOTATIONS, NODE_ARCHITECTURE } from '@shell/config/labels-annotations';
13
- import capitalize from 'lodash/capitalize';
14
13
 
15
14
  /**
16
15
  * Class representing Cluster resource.
@@ -283,19 +282,7 @@ export default class ProvCluster extends SteveModel {
283
282
  }
284
283
 
285
284
  get isImported() {
286
- // As of Rancher v2.6.7, this returns false for imported K3s clusters,
287
- // in which this.provisioner is `k3s`.
288
-
289
- const isImportedProvisioner = this.provisioner === 'imported';
290
- const isImportedSpecialCases = this.mgmt?.providerForEmberParam === 'import' ||
291
- // when imported cluster is GKE
292
- !!this.mgmt?.spec?.gkeConfig?.imported ||
293
- // or AKS
294
- !!this.mgmt?.spec?.aksConfig?.imported ||
295
- // or EKS
296
- !!this.mgmt?.spec?.eksConfig?.imported;
297
-
298
- return !this.isLocal && (isImportedProvisioner || (!this.isRke2 && !this.mgmt?.machineProvider && isImportedSpecialCases));
285
+ return this.mgmt?.isImported;
299
286
  }
300
287
 
301
288
  get isCustom() {
@@ -331,7 +318,8 @@ export default class ProvCluster extends SteveModel {
331
318
  }
332
319
 
333
320
  get isRke1() {
334
- return !!this.mgmt?.spec?.rancherKubernetesEngineConfig || this.labels['provider.cattle.io'] === 'rke';
321
+ // rancherKubernetesEngineConfig is not defined on imported RKE1 clusters
322
+ return !!this.mgmt?.spec?.rancherKubernetesEngineConfig || this.mgmt?.labels['provider.cattle.io'] === 'rke';
335
323
  }
336
324
 
337
325
  get isHarvester() {
@@ -408,6 +396,8 @@ export default class ProvCluster extends SteveModel {
408
396
  provisioner = 'k3s';
409
397
  } else if ( this.isImportedRke2 ) {
410
398
  provisioner = 'rke2';
399
+ } else if ((this.isImported || this.isLocal) && this.isRke1) {
400
+ provisioner = 'rke';
411
401
  }
412
402
 
413
403
  return this.$rootGetters['i18n/withFallback'](`cluster.provider."${ provisioner }"`, null, ucFirst(provisioner));
@@ -424,7 +414,7 @@ export default class ProvCluster extends SteveModel {
424
414
  if (!node.metadata?.state?.transitioning) {
425
415
  const architecture = node.status?.nodeLabels?.[NODE_ARCHITECTURE];
426
416
 
427
- const key = architecture ? capitalize(architecture) : this.t('cluster.architecture.label.unknown');
417
+ const key = architecture || this.t('cluster.architecture.label.unknown');
428
418
 
429
419
  obj[key] = (obj[key] || 0) + 1;
430
420
  }
@@ -112,16 +112,21 @@ export default class extends SteveModel {
112
112
  return this.patch(data, {}, true, true);
113
113
  }
114
114
 
115
- setDefault() {
116
- const allStorageClasses = this.$rootGetters['cluster/all'](STORAGE_CLASS) || [];
115
+ async setDefault() {
116
+ const inStore = this.$rootGetters['currentProduct'].inStore;
117
+ const allStorageClasses = this.$rootGetters[`${ inStore }/all`](STORAGE_CLASS) || [];
118
+
119
+ for (const storageClass of allStorageClasses) {
120
+ await storageClass.resetDefault();
121
+ }
117
122
 
118
123
  allStorageClasses.forEach((storageClass) => storageClass.resetDefault());
119
124
  this.updateDefault(true);
120
125
  }
121
126
 
122
- resetDefault() {
127
+ async resetDefault() {
123
128
  if (this.isDefault) {
124
- this.updateDefault(false);
129
+ await this.updateDefault(false);
125
130
  }
126
131
  }
127
132
 
@@ -146,4 +151,10 @@ export default class extends SteveModel {
146
151
 
147
152
  return out;
148
153
  }
154
+
155
+ cleanForNew() {
156
+ this.$dispatch(`cleanForNew`, this);
157
+
158
+ delete this?.metadata?.annotations?.[STORAGE.DEFAULT_STORAGE_CLASS];
159
+ }
149
160
  }
@@ -110,7 +110,7 @@ export default class Workload extends WorkloadService {
110
110
  spec.template = {
111
111
  spec: {
112
112
  restartPolicy: this.type === WORKLOAD_TYPES.JOB ? 'Never' : 'Always',
113
- containers: [{ ...defaultContainer }],
113
+ containers: [{ ...structuredClone(defaultContainer) }],
114
114
  initContainers: []
115
115
  }
116
116
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.0-rc.9",
3
+ "version": "3.0.1-rc.1",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -62,8 +62,8 @@
62
62
  "cookie": "0.5.0",
63
63
  "cookie-universal": "2.2.2",
64
64
  "core-js": "3.25.3",
65
- "cron-validator": "1.2.0",
66
- "cronstrue": "1.95.0",
65
+ "cron-validator": "1.3.1",
66
+ "cronstrue": "2.50.0",
67
67
  "cross-env": "6.0.3",
68
68
  "css-loader": "6.7.3",
69
69
  "csv-loader": "3.0.3",
@@ -74,7 +74,7 @@
74
74
  "dagre-d3": "0.6.4",
75
75
  "dayjs": "1.8.29",
76
76
  "diff2html": "3.4.24",
77
- "dompurify": "2.4.5",
77
+ "dompurify": "2.5.4",
78
78
  "element-matches": "^0.1.2",
79
79
  "eslint": "7.32.0",
80
80
  "eslint-config-standard": "16.0.3",
@@ -102,7 +102,7 @@
102
102
  "js-yaml": "4.1.0",
103
103
  "js-yaml-loader": "1.2.2",
104
104
  "jsdiff": "1.1.1",
105
- "jsonpath-plus": "6.0.1",
105
+ "jsonpath-plus": "10.0.0",
106
106
  "jsrsasign": "10.5.25",
107
107
  "jszip": "3.8.0",
108
108
  "lodash": "4.17.21",
@@ -64,7 +64,8 @@ export default {
64
64
  },
65
65
 
66
66
  computed: {
67
- ...mapGetters({ t: 'i18n/t' }),
67
+ ...mapGetters(['isStandaloneHarvester']),
68
+ ...mapGetters({ t: 'i18n/t', hasMultipleLocales: 'i18n/hasMultipleLocales' }),
68
69
 
69
70
  loggedOutSuccessMsg() {
70
71
  if (this.isSlo) {
@@ -497,7 +498,7 @@ export default {
497
498
  </div>
498
499
  </template>
499
500
  <div
500
- v-if="showLocaleSelector"
501
+ v-if="showLocaleSelector && hasMultipleLocales && !isStandaloneHarvester"
501
502
  class="locale-selector"
502
503
  >
503
504
  <LocaleSelector
@@ -1,21 +1,19 @@
1
1
  <script>
2
- import { authProvidersInfo } from '@shell/utils/auth';
2
+ import { configType } from '@shell/models/management.cattle.io.authconfig';
3
3
 
4
4
  export default {
5
5
  async fetch() {
6
- const authInfo = await authProvidersInfo(this.$store);
6
+ const publicAuthProviders = await this.$store.dispatch('auth/getAuthProviders');
7
7
 
8
- if (authInfo.enabled?.length) {
9
- const authProvider = authInfo.enabled[0];
8
+ const samlAuthProvider = publicAuthProviders.find((authProvider) => configType[authProvider.id] === 'saml');
10
9
 
11
- const {
12
- logoutAllSupported, logoutAllEnabled, logoutAllForced, configType
13
- } = authProvider;
10
+ if (!!samlAuthProvider) {
11
+ const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = samlAuthProvider;
14
12
 
15
- if (configType === 'saml' && logoutAllSupported && logoutAllEnabled && logoutAllForced) {
13
+ if (logoutAllSupported && logoutAllEnabled && logoutAllForced) {
16
14
  // SAML - force SLO (logout from all apps)
17
15
  await this.$store.dispatch('auth/logout', {
18
- force: true, slo: true, provider: authProvider
16
+ force: true, slo: true, provider: samlAuthProvider
19
17
  }, { root: true });
20
18
  } else {
21
19
  // simple logout
@@ -141,7 +141,7 @@ export default {
141
141
  type: MANAGEMENT.FEATURE, id: 'multi-cluster-management', opt: { url: `/v1/${ MANAGEMENT.FEATURE }/multi-cluster-management` }
142
142
  });
143
143
 
144
- const mcmEnabled = mcmFeature?.spec?.value || mcmFeature?.status?.default;
144
+ const mcmEnabled = (mcmFeature?.spec?.value || mcmFeature?.status?.default) && productName !== 'Harvester';
145
145
 
146
146
  let serverUrl;
147
147
 
@@ -496,6 +496,7 @@ export default {
496
496
 
497
497
  .span-6 {
498
498
  padding: 0 60px;
499
+ margin: 0;
499
500
  }
500
501
 
501
502
  .landscape {
@@ -503,6 +504,7 @@ export default {
503
504
  margin: 0;
504
505
  object-fit: cover;
505
506
  padding: 0;
507
+ width: 49%;
506
508
  }
507
509
  }
508
510
 
@@ -512,6 +514,7 @@ export default {
512
514
  overflow-y: auto;
513
515
  position: relative;
514
516
  height: 100vh;
517
+ width: 51%;
515
518
 
516
519
  & > div:first-of-type {
517
520
  flex:3;
@@ -294,8 +294,9 @@ export default {
294
294
  */
295
295
  userValues = diff(this.loadedVersionValues, this.chartValues);
296
296
  } else if ( this.existing ) {
297
+ await this.existing.fetchValues(); // In theory this has already been called, but do again to be safe
297
298
  /* For an already installed app, use the values from the previous install. */
298
- userValues = clone(this.existing.spec?.values || {});
299
+ userValues = clone(this.existing.values || {});
299
300
  } else {
300
301
  /* For an new app, start empty. */
301
302
  userValues = {};
@@ -1457,6 +1458,7 @@ export default {
1457
1458
  <Banner
1458
1459
  v-if="isNamespaceNew && value.metadata.namespace.length"
1459
1460
  color="info"
1461
+ class="namespace-create-banner"
1460
1462
  >
1461
1463
  <div v-clean-html="t('catalog.install.steps.basics.createNamespace', {namespace: value.metadata.namespace}, true) " />
1462
1464
  </Banner>
@@ -1661,9 +1663,10 @@ export default {
1661
1663
  class="mt-10"
1662
1664
  >
1663
1665
  <UnitInput
1664
- v-model.number="customCmdOpts.timeout"
1666
+ v-model:value="customCmdOpts.timeout"
1665
1667
  :label="t('catalog.install.helm.timeout.label')"
1666
1668
  :suffix="t('catalog.install.helm.timeout.unit', {value: customCmdOpts.timeout})"
1669
+ type="number"
1667
1670
  />
1668
1671
  </div>
1669
1672
  <div
@@ -1672,9 +1675,10 @@ export default {
1672
1675
  >
1673
1676
  <UnitInput
1674
1677
  v-if="existing"
1675
- v-model.number="customCmdOpts.historyMax"
1678
+ v-model:value="customCmdOpts.historyMax"
1676
1679
  :label="t('catalog.install.helm.historyMax.label')"
1677
1680
  :suffix="t('catalog.install.helm.historyMax.unit', {value: customCmdOpts.historyMax})"
1681
+ type="number"
1678
1682
  />
1679
1683
  </div>
1680
1684
  <div
@@ -1852,6 +1856,10 @@ export default {
1852
1856
  .spacer {
1853
1857
  line-height: 2;
1854
1858
  }
1859
+
1860
+ .namespace-create-banner {
1861
+ margin-bottom: 70px;
1862
+ }
1855
1863
  }
1856
1864
  &__values {
1857
1865
  &__controls {
@@ -164,7 +164,7 @@ describe('page: cluster dashboard', () => {
164
164
  ['created', 'glance.created', []],
165
165
  ['architecture', 'mixed', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }, { labels: { [NODE_ARCHITECTURE]: 'intel' } }]],
166
166
  ['architecture', 'mixed', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }, { labels: { } }]],
167
- ['architecture', 'Amd64', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }]],
167
+ ['architecture', 'amd64', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }]],
168
168
  ['architecture', 'unknown', [{ labels: { } }]],
169
169
  ['architecture', 'glance.architecture', [{ metadata: { state: { transitioning: true } } }]],
170
170
  ])('should show %p label %p', (label, text, nodes) => {
@@ -47,7 +47,6 @@ import Certificates from '@shell/components/Certificates';
47
47
  import { NAME as EXPLORER } from '@shell/config/product/explorer';
48
48
  import TabTitle from '@shell/components/TabTitle';
49
49
  import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
50
- import capitalize from 'lodash/capitalize';
51
50
 
52
51
  export const RESOURCES = [NAMESPACE, INGRESS, PV, WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET, WORKLOAD_TYPES.JOB, WORKLOAD_TYPES.DAEMON_SET, SERVICE];
53
52
 
@@ -232,7 +231,7 @@ export default {
232
231
  if (!node.metadata?.state?.transitioning) {
233
232
  const architecture = node.labels?.[NODE_ARCHITECTURE];
234
233
 
235
- const key = architecture ? capitalize(architecture) : this.t('cluster.architecture.label.unknown');
234
+ const key = architecture || this.t('cluster.architecture.label.unknown');
236
235
 
237
236
  obj[key] = (obj[key] || 0) + 1;
238
237
  }
@@ -12,6 +12,7 @@ import { WORKSPACE_ANNOTATION } from '@shell/config/labels-annotations';
12
12
  import { filterBy } from '@shell/utils/array';
13
13
  import FleetNoWorkspaces from '@shell/components/fleet/FleetNoWorkspaces.vue';
14
14
  import { NAME } from '@shell/config/product/fleet';
15
+ import { xOfy } from '@shell/utils/string';
15
16
 
16
17
  export default {
17
18
  name: 'FleetDashboard',
@@ -39,6 +40,7 @@ export default {
39
40
  allBundles: {
40
41
  inStoreType: 'management',
41
42
  type: FLEET.BUNDLE,
43
+ opt: { excludeFields: ['metadata.managedFields', 'spec.resources'] },
42
44
  },
43
45
  gitRepos: {
44
46
  inStoreType: 'management',
@@ -175,7 +177,12 @@ export default {
175
177
  }
176
178
 
177
179
  if (area === 'clusters') {
178
- group = row.targetClusters;
180
+ if (row.clusterInfo?.ready === row.clusterInfo?.total && row.clusterInfo?.ready) {
181
+ return {
182
+ badgeClass: STATES[STATES_ENUM.ACTIVE].color,
183
+ icon: STATES[STATES_ENUM.ACTIVE].compoundIcon
184
+ };
185
+ }
179
186
  } else if (area === 'bundles') {
180
187
  group = row.bundles;
181
188
  } else if (area === 'resources') {
@@ -223,7 +230,7 @@ export default {
223
230
  }
224
231
 
225
232
  if (area === 'clusters') {
226
- group = row.targetClusters;
233
+ group = '';
227
234
  } else if (area === 'bundles') {
228
235
  group = row.bundles;
229
236
  } else if (area === 'resources') {
@@ -262,11 +269,11 @@ export default {
262
269
  }
263
270
 
264
271
  if (area === 'clusters') {
265
- value = `${ row.targetClustersReady?.length || '0' }/${ row.targetClusters?.length || '?' }`;
272
+ return `${ row.clusterInfo.ready }/${ row.clusterInfo.total }`;
266
273
  } else if (area === 'bundles') {
267
- value = `${ row.bundlesReady?.length || '0' }/${ row.bundles?.length || '?' }`;
274
+ value = xOfy(row.bundlesReady?.length, row.bundles?.length);
268
275
  } else if (area === 'resources') {
269
- value = `${ row.status?.resourceCounts?.ready || '0' }/${ row.status?.resourceCounts?.desiredReady || '?' }`;
276
+ value = xOfy(row.status?.resourceCounts?.ready, row.status?.resourceCounts?.desiredReady);
270
277
  }
271
278
 
272
279
  return value;
@@ -294,7 +301,7 @@ export default {
294
301
  </script>
295
302
 
296
303
  <template>
297
- <div class="fleet-dashboard">
304
+ <div>
298
305
  <Loading v-if="$fetchState.pending" />
299
306
  <!-- no git repos -->
300
307
  <FleetNoWorkspaces
@@ -444,9 +451,6 @@ export default {
444
451
  </template>
445
452
 
446
453
  <style lang="scss" scoped>
447
- .fleet-dashboard {
448
- min-height: 100vh;
449
- }
450
454
  .fleet-empty-dashboard {
451
455
  flex: 1;
452
456
  display: flex;
@@ -141,6 +141,9 @@ export default {
141
141
  const schema = this.$store.getters[`management/schemaFor`](MANAGEMENT.SETTING);
142
142
 
143
143
  return schema?.resourceMethods?.includes('PUT') ? _EDIT : _VIEW;
144
+ },
145
+ customLinkColor() {
146
+ return { color: this.uiLinkColor };
144
147
  }
145
148
  },
146
149
 
@@ -564,7 +567,7 @@ export default {
564
567
  component-testid="link"
565
568
  />
566
569
  <span class="col link-example">
567
- <a>
570
+ <a :style="customLinkColor">
568
571
  {{ t('branding.linkColor.example') }}
569
572
  </a>
570
573
  </span>
@@ -154,7 +154,8 @@ export default {
154
154
  },
155
155
 
156
156
  showAddReposBanner() {
157
- const hasExtensionReposBannerSetting = this.addExtensionReposBannerSetting?.value === 'true';
157
+ // because of https://github.com/rancher/rancher/pull/45894 we need to consider other start values
158
+ const hasExtensionReposBannerSetting = this.addExtensionReposBannerSetting?.value === 'true' || this.addExtensionReposBannerSetting?.value === '' || this.addExtensionReposBannerSetting?.value === undefined;
158
159
  const uiPluginsRepoNotFound = isRancherPrime() && !this.repos?.find((r) => r.urlDisplay === UI_PLUGINS_REPOS.OFFICIAL.URL);
159
160
  const uiPluginsPartnersRepoNotFound = !this.repos?.find((r) => r.urlDisplay === UI_PLUGINS_REPOS.PARTNERS.URL);
160
161
 
@@ -615,7 +616,8 @@ export default {
615
616
  },
616
617
 
617
618
  updateAddReposSetting() {
618
- if (this.addExtensionReposBannerSetting?.value === 'true') {
619
+ // because of https://github.com/rancher/rancher/pull/45894 we need to consider other start values
620
+ if (this.addExtensionReposBannerSetting?.value === 'true' || this.addExtensionReposBannerSetting?.value === '' || this.addExtensionReposBannerSetting?.value === undefined) {
619
621
  this.addExtensionReposBannerSetting.value = 'false';
620
622
  this.addExtensionReposBannerSetting.save();
621
623
  }
@@ -215,6 +215,7 @@ export default {
215
215
  'linode',
216
216
  'targetRoute', // contains circular references, isn't useful (added later to store)
217
217
  '$router', // also contains a circular reference to $store, not useful for diagnostics
218
+ '$route', // also contains a circular reference to $store, not useful for diagnostics
218
219
  ];
219
220
 
220
221
  const clearListsKeys = [
package/pages/prefs.vue CHANGED
@@ -40,6 +40,11 @@ export default {
40
40
  scalingDownPrompt: mapPref(SCALE_POOL_PROMPT),
41
41
 
42
42
  ...mapGetters(['isSingleProduct']),
43
+ ...mapGetters({ hasMultipleLocales: 'i18n/hasMultipleLocales' }),
44
+
45
+ isHarvester() {
46
+ return this.isSingleProduct?.productName === 'harvester';
47
+ },
43
48
 
44
49
  theme: {
45
50
  get() {
@@ -182,7 +187,10 @@ export default {
182
187
  </h1>
183
188
 
184
189
  <!-- Language -->
185
- <div class="mt-10 mb-10">
190
+ <div
191
+ v-if="hasMultipleLocales && !isHarvester"
192
+ class="mt-10 mb-10"
193
+ >
186
194
  <h4 v-t="'prefs.language'" />
187
195
  <div class="row">
188
196
  <div class="col span-4">
@@ -194,7 +202,6 @@ export default {
194
202
  </div>
195
203
  <!-- Theme -->
196
204
  <div class="mt-10 mb-10">
197
- <hr>
198
205
  <h4 v-t="'prefs.theme.label'" />
199
206
  <ButtonGroup
200
207
  v-model:value="theme"
@@ -262,7 +269,10 @@ export default {
262
269
  </div>
263
270
  </div>
264
271
  <!-- Confirmation setting -->
265
- <div class="col adv-features mt-10 mb-10">
272
+ <div
273
+ v-if="!isSingleProduct"
274
+ class="col adv-features mt-10 mb-10"
275
+ >
266
276
  <hr>
267
277
  <h4 v-t="'prefs.confirmationSetting.title'" />
268
278
  <Checkbox
@@ -282,13 +292,15 @@ export default {
282
292
  :label="t('prefs.advFeatures.viewInApi', {}, true)"
283
293
  class="mt-10"
284
294
  />
285
- <br>
286
- <Checkbox
287
- v-model:value="allNamespaces"
288
- data-testid="prefs__allNamespaces"
289
- :label="t('prefs.advFeatures.allNamespaces', {}, true)"
290
- class="mt-20"
291
- />
295
+ <template v-if="!isHarvester">
296
+ <br>
297
+ <Checkbox
298
+ v-model:value="allNamespaces"
299
+ data-testid="prefs__allNamespaces"
300
+ :label="t('prefs.advFeatures.allNamespaces', {}, true)"
301
+ class="mt-20"
302
+ />
303
+ </template>
292
304
  <br>
293
305
  <Checkbox
294
306
  v-model:value="themeShortcut"
@@ -9,7 +9,7 @@ import {
9
9
  AS,
10
10
  MODE
11
11
  } from '@shell/config/query-params';
12
- import { VIEW_IN_API } from '@shell/store/prefs';
12
+ import { VIEW_IN_API, DEV } from '@shell/store/prefs';
13
13
  import { addObject, addObjects, findBy, removeAt } from '@shell/utils/array';
14
14
  import CustomValidators from '@shell/utils/custom-validators';
15
15
  import { downloadFile, generateZip } from '@shell/utils/download';
@@ -84,6 +84,7 @@ export const STATES_ENUM = {
84
84
  DISCONNECTED: 'disconnected',
85
85
  DRAINED: 'drained',
86
86
  DRAINING: 'draining',
87
+ ENABLED: 'enabled',
87
88
  ERR_APPLIED: 'errapplied',
88
89
  ERROR: 'error',
89
90
  ERRORING: 'erroring',
@@ -232,6 +233,9 @@ export const STATES = {
232
233
  [STATES_ENUM.DRAINING]: {
233
234
  color: 'warning', icon: 'tag', label: 'Draining', compoundIcon: 'warning'
234
235
  },
236
+ [STATES_ENUM.ENABLED]: {
237
+ color: 'success', icon: 'dot-open', label: 'Enabled', compoundIcon: 'checkmark'
238
+ },
235
239
  [STATES_ENUM.ERR_APPLIED]: {
236
240
  color: 'error', icon: 'error', label: 'Error Applied', compoundIcon: 'error'
237
241
  },
@@ -997,7 +1001,11 @@ export default class Resource {
997
1001
  }
998
1002
 
999
1003
  get canViewInApi() {
1000
- return this.hasLink('self') && this.$rootGetters['prefs/get'](VIEW_IN_API);
1004
+ try {
1005
+ return this.hasLink('self') && this.$rootGetters['prefs/get'](VIEW_IN_API);
1006
+ } catch {
1007
+ return this.hasLink('self') && this.$rootGetters['prefs/get'](DEV);
1008
+ }
1001
1009
  }
1002
1010
 
1003
1011
  get canYaml() {
@@ -1055,7 +1063,7 @@ export default class Resource {
1055
1063
 
1056
1064
  async doActionGrowl(actionName, body, opt = {}) {
1057
1065
  try {
1058
- await this.$dispatch('resourceAction', {
1066
+ return await this.$dispatch('resourceAction', {
1059
1067
  resource: this,
1060
1068
  actionName,
1061
1069
  body,
@@ -13,6 +13,7 @@ import {
13
13
  import { perfLoadAll } from '@shell/plugins/steve/performanceTesting';
14
14
  import { classify } from '@shell/plugins/dashboard-store/classify';
15
15
  import SteveSchema from '@shell/models/steve-schema';
16
+ import { deepToRaw } from '@shell/utils/object';
16
17
 
17
18
  function registerNamespace(state, namespace) {
18
19
  let cache = state.podsByNamespace[namespace];
@@ -145,7 +146,9 @@ export default {
145
146
 
146
147
  if (worker) {
147
148
  // Store raw json objects, not the proxies
148
- worker.postMessage({ loadSchemas: data });
149
+ const rawData = deepToRaw(data);
150
+
151
+ worker.postMessage({ loadSchemas: rawData });
149
152
  }
150
153
  }
151
154
  },
@@ -6,7 +6,7 @@ import { uniq } from '@shell/utils/array';
6
6
  import {
7
7
  CONFIG_MAP, MANAGEMENT, NAMESPACE, NODE, POD
8
8
  } from '@shell/config/types';
9
- import { Schema } from 'plugins/steve/schema';
9
+ import { Schema } from '@shell/plugins/steve/schema';
10
10
 
11
11
  class NamespaceProjectFilters {
12
12
  /**
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { addObject, clear, removeObject } from '@shell/utils/array';
11
- import { get } from '@shell/utils/object';
11
+ import { get, deepToRaw } from '@shell/utils/object';
12
12
  import { SCHEMA, MANAGEMENT } from '@shell/config/types';
13
13
  import { SETTING } from '@shell/config/settings';
14
14
  import { CSRF } from '@shell/config/cookies';
@@ -35,7 +35,6 @@ import { WORKER_MODES } from './worker';
35
35
  import acceptOrRejectSocketMessage from './accept-or-reject-socket-message';
36
36
  import { BLANK_CLUSTER, STORE } from '@shell/store/store-types.js';
37
37
  import paginationUtils from '@shell/utils/pagination-utils';
38
- import _ from 'lodash';
39
38
 
40
39
  // minimum length of time a disconnect notification is shown
41
40
  const MINIMUM_TIME_NOTIFIED = 3000;
@@ -179,9 +178,9 @@ export async function createWorker(store, ctx) {
179
178
 
180
179
  while (workerQueues[storeName]?.length) {
181
180
  const message = workerQueues[storeName].shift();
181
+ const safeMessage = deepToRaw(message);
182
182
 
183
- // TODO: 11541: Web Worker communication fails due to Proxy objects in messages
184
- store.$workers[storeName].postMessage(_.cloneDeep(message));
183
+ store.$workers[storeName].postMessage(safeMessage);
185
184
  }
186
185
  }
187
186
 
@@ -177,11 +177,16 @@ export default defineComponent({
177
177
  if (this.type !== 'cron' || !this.value) {
178
178
  return;
179
179
  }
180
- if (typeof this.value === 'string' && !isValidCron(this.value)) {
180
+ // refer https://github.com/GuillaumeRochat/cron-validator#readme
181
+ if (!isValidCron(this.value as string, {
182
+ alias: true,
183
+ allowBlankDay: true,
184
+ allowSevenAsSunday: true,
185
+ })) {
181
186
  return this.t('generic.invalidCron');
182
187
  }
183
188
  try {
184
- const hint = cronstrue.toString(this.value || '');
189
+ const hint = cronstrue.toString(this.value as string || '', { verbose: true });
185
190
 
186
191
  return hint;
187
192
  } catch (e) {
package/store/features.js CHANGED
@@ -35,6 +35,7 @@ export const HARVESTER_CONTAINER = create('harvester-baremetal-container-workloa
35
35
  export const FLEET_WORKSPACE_BACK = create('provisioningv2-fleet-workspace-back-population', false);
36
36
  export const STEVE_CACHE = create('ui-sql-cache', false);
37
37
  export const UIEXTENSION = create('uiextension', true);
38
+ export const PROVISIONING_PRE_BOOTSTRAP = create('provisioningprebootstrap', false);
38
39
 
39
40
  // Not currently used.. no point defining ones we don't use
40
41
  // export const EMBEDDED_CLUSTER_API = create('embedded-cluster-api', true);
package/store/i18n.js CHANGED
@@ -58,6 +58,10 @@ export const getters = {
58
58
  return out;
59
59
  },
60
60
 
61
+ hasMultipleLocales(state) {
62
+ return state.available.length > 1;
63
+ },
64
+
61
65
  t: (state) => (key, args, language) => {
62
66
  if (state.selected === NONE && !language) {
63
67
  return `%${ key }%`;
@@ -333,7 +337,7 @@ export const actions = {
333
337
 
334
338
  commit('setSelected', locale);
335
339
 
336
- // Ony update the preference if the locale changed
340
+ // Only update the preference if the locale changed
337
341
  if (currentLocale !== locale) {
338
342
  dispatch('prefs/set', {
339
343
  key: 'locale',