@rancher/shell 3.0.2-rc.5 → 3.0.2-rc.6

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 (206) hide show
  1. package/assets/images/providers/nutanix.svg +12 -1
  2. package/assets/styles/base/_basic.scss +2 -1
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +2 -0
  5. package/assets/styles/global/_labeled-input.scss +5 -13
  6. package/assets/styles/global/_layout.scss +1 -0
  7. package/assets/styles/global/_select.scss +5 -0
  8. package/assets/styles/themes/_dark.scss +1 -3
  9. package/assets/styles/themes/_light.scss +5 -1
  10. package/assets/translations/en-us.yaml +130 -23
  11. package/assets/translations/zh-hans.yaml +0 -3
  12. package/cloud-credential/azure.vue +1 -1
  13. package/components/ActionMenuShell.vue +105 -0
  14. package/components/AppModal.vue +2 -2
  15. package/components/AsyncButton.vue +2 -0
  16. package/components/ButtonGroup.vue +9 -2
  17. package/components/ClusterBadge.vue +1 -0
  18. package/components/ClusterIconMenu.vue +3 -0
  19. package/components/ClusterProviderIcon.vue +14 -1
  20. package/components/CodeMirror.vue +96 -5
  21. package/components/Collapse.vue +16 -3
  22. package/components/CruResource.vue +9 -0
  23. package/components/CruResourceFooter.vue +1 -1
  24. package/components/ExplorerMembers.vue +2 -1
  25. package/components/Import.vue +14 -1
  26. package/components/LandingPagePreference.vue +4 -2
  27. package/components/PodSecurityAdmission.vue +8 -6
  28. package/components/PromptChangePassword.vue +1 -0
  29. package/components/PromptRemove.vue +23 -21
  30. package/components/ResourceDetail/Masthead.vue +30 -11
  31. package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
  32. package/components/ResourceDetail/index.vue +6 -0
  33. package/components/ResourceTable.vue +6 -1
  34. package/components/ResourceYaml.vue +1 -0
  35. package/components/Setting.vue +115 -0
  36. package/components/SortableTable/THead.vue +2 -0
  37. package/components/SortableTable/index.vue +7 -12
  38. package/components/Tabbed/index.vue +16 -15
  39. package/components/Wizard.vue +108 -104
  40. package/components/YamlEditor.vue +12 -2
  41. package/components/__tests__/Collapse.test.ts +2 -2
  42. package/components/auth/Principal.vue +29 -17
  43. package/components/auth/__tests__/Principal.test.ts +40 -0
  44. package/components/auth/login/ldap.vue +7 -0
  45. package/components/fleet/FleetBundles.vue +1 -1
  46. package/components/fleet/FleetRepos.vue +1 -1
  47. package/components/fleet/FleetResources.vue +0 -2
  48. package/components/fleet/FleetSummary.vue +60 -65
  49. package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
  50. package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
  51. package/components/form/ArrayList.vue +6 -2
  52. package/components/form/ColorInput.vue +1 -0
  53. package/components/form/KeyValue.vue +11 -12
  54. package/components/form/LabeledSelect.vue +15 -3
  55. package/components/form/Labels.vue +8 -1
  56. package/components/form/Members/MembershipEditor.vue +230 -222
  57. package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
  58. package/components/form/Password.vue +3 -0
  59. package/components/form/ProjectMemberEditor.vue +6 -3
  60. package/components/form/ResourceTabs/index.vue +15 -13
  61. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
  62. package/components/form/SchedulingCustomization.vue +85 -0
  63. package/components/form/Select.vue +3 -2
  64. package/components/form/SelectOrCreateAuthSecret.vue +2 -1
  65. package/components/form/UnitInput.vue +1 -2
  66. package/components/form/__tests__/ArrayList.test.ts +9 -6
  67. package/components/form/__tests__/LabeledSelect.test.ts +37 -0
  68. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
  69. package/components/formatter/LiveDate.vue +3 -1
  70. package/components/formatter/ServiceType.vue +12 -4
  71. package/components/formatter/WorkloadHealthScale.vue +2 -1
  72. package/components/nav/Header.vue +35 -2
  73. package/components/nav/HeaderPageActionMenu.vue +11 -40
  74. package/components/nav/Jump.vue +8 -2
  75. package/components/nav/NamespaceFilter.vue +5 -4
  76. package/components/nav/Pinned.vue +1 -1
  77. package/components/nav/TopLevelMenu.helper.ts +5 -5
  78. package/components/nav/WindowManager/ContainerLogs.vue +96 -58
  79. package/components/nav/WindowManager/ContainerShell.vue +99 -18
  80. package/components/nav/WindowManager/index.vue +74 -6
  81. package/components/templates/default.vue +2 -47
  82. package/config/features.js +1 -0
  83. package/config/labels-annotations.js +11 -1
  84. package/config/router/navigation-guards/index.js +2 -1
  85. package/config/router/navigation-guards/record-last-route.js +24 -0
  86. package/config/settings.ts +66 -98
  87. package/config/version.js +1 -1
  88. package/core/types-provisioning.ts +7 -0
  89. package/detail/fleet.cattle.io.bundle.vue +7 -0
  90. package/detail/fleet.cattle.io.cluster.vue +0 -3
  91. package/detail/fleet.cattle.io.gitrepo.vue +8 -15
  92. package/detail/provisioning.cattle.io.cluster.vue +8 -2
  93. package/dialog/DeactivateDriverDialog.vue +5 -5
  94. package/dialog/GitRepoForceUpdateDialog.vue +132 -0
  95. package/directives/strip-html-aria-label.js +19 -0
  96. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
  97. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
  98. package/edit/auth/__tests__/oidc.test.ts +26 -9
  99. package/edit/auth/ldap/__tests__/config.test.ts +40 -0
  100. package/edit/auth/ldap/config.vue +67 -89
  101. package/edit/auth/oidc.vue +15 -1
  102. package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
  103. package/edit/cis.cattle.io.clusterscan.vue +13 -1
  104. package/edit/fleet.cattle.io.gitrepo.vue +198 -72
  105. package/edit/logging-flow/Match.vue +0 -21
  106. package/edit/management.cattle.io.project.vue +1 -1
  107. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
  108. package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
  109. package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
  110. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
  111. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
  112. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
  113. package/edit/provisioning.cattle.io.cluster/index.vue +28 -30
  114. package/edit/provisioning.cattle.io.cluster/rke2.vue +63 -12
  115. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
  116. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
  117. package/edit/resources.cattle.io.backup.vue +150 -15
  118. package/edit/secret/__tests__/ssh.test.ts +79 -0
  119. package/edit/secret/ssh.vue +7 -1
  120. package/edit/workload/Job.vue +2 -2
  121. package/edit/workload/index.vue +3 -1
  122. package/initialize/install-directives.js +2 -0
  123. package/initialize/install-plugins.js +6 -1
  124. package/list/catalog.cattle.io.app.vue +21 -4
  125. package/list/fleet.cattle.io.bundle.vue +1 -1
  126. package/list/management.cattle.io.setting.vue +34 -132
  127. package/list/provisioning.cattle.io.cluster.vue +11 -3
  128. package/machine-config/vmwarevsphere.vue +15 -8
  129. package/mixins/__tests__/auth-config.test.ts +74 -0
  130. package/mixins/__tests__/chart.test.ts +5 -4
  131. package/mixins/__tests__/create-edit-view.test.ts +38 -0
  132. package/mixins/auth-config.js +8 -0
  133. package/mixins/chart.js +2 -2
  134. package/mixins/create-edit-view/impl.js +4 -1
  135. package/mixins/vue-select-overrides.js +10 -0
  136. package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
  137. package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
  138. package/models/__tests__/secret.test.ts +56 -13
  139. package/models/catalog.cattle.io.app.js +112 -37
  140. package/models/cluster.js +11 -0
  141. package/models/fleet.cattle.io.bundle.js +40 -2
  142. package/models/fleet.cattle.io.gitrepo.js +169 -109
  143. package/models/management.cattle.io.fleetworkspace.js +4 -0
  144. package/models/management.cattle.io.kontainerdriver.js +7 -0
  145. package/models/nodedriver.js +4 -1
  146. package/models/provisioning.cattle.io.cluster.js +24 -0
  147. package/models/secret.js +1 -1
  148. package/package.json +4 -4
  149. package/pages/auth/login.vue +4 -2
  150. package/pages/auth/verify.vue +11 -1
  151. package/pages/c/_cluster/apps/charts/index.vue +6 -4
  152. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  153. package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
  154. package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
  155. package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
  156. package/pages/c/_cluster/explorer/index.vue +33 -35
  157. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  158. package/pages/c/_cluster/fleet/index.vue +0 -5
  159. package/pages/c/_cluster/legacy/project/index.vue +1 -1
  160. package/pages/c/_cluster/settings/performance.vue +52 -53
  161. package/pages/c/_cluster/uiplugins/index.vue +19 -22
  162. package/pages/home.vue +17 -12
  163. package/pages/prefs.vue +5 -1
  164. package/plugins/shortkey.js +10 -1
  165. package/plugins/steve/steve-pagination-utils.ts +58 -8
  166. package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
  167. package/promptRemove/management.cattle.io.globalrole.vue +1 -1
  168. package/promptRemove/management.cattle.io.project.vue +2 -8
  169. package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
  170. package/promptRemove/mixin/roleDeletionCheck.js +1 -7
  171. package/promptRemove/pod.vue +7 -28
  172. package/rancher-components/Card/Card.vue +9 -1
  173. package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
  174. package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
  175. package/rancher-components/Form/Radio/RadioButton.vue +18 -3
  176. package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
  177. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
  178. package/rancher-components/RcButton/RcButton.test.ts +97 -0
  179. package/rancher-components/RcButton/RcButton.vue +14 -9
  180. package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
  181. package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -2
  182. package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
  183. package/rancher-components/RcDropdown/index.ts +1 -0
  184. package/rancher-components/RcDropdown/types.ts +27 -0
  185. package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
  186. package/scripts/typegen.sh +1 -0
  187. package/store/__tests__/auth.test.ts +120 -0
  188. package/store/action-menu.js +13 -3
  189. package/store/auth.js +14 -9
  190. package/store/catalog.js +14 -7
  191. package/store/features.js +1 -0
  192. package/store/prefs.js +9 -28
  193. package/store/type-map.utils.ts +4 -0
  194. package/types/resources/settings.d.ts +27 -20
  195. package/types/shell/index.d.ts +18 -2
  196. package/utils/__tests__/array.test.ts +13 -1
  197. package/utils/__tests__/string.test.ts +80 -1
  198. package/utils/array.ts +13 -0
  199. package/utils/auth.js +4 -0
  200. package/utils/cluster.js +1 -1
  201. package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
  202. package/utils/pagination-utils.ts +15 -2
  203. package/utils/string.js +31 -7
  204. package/utils/validators/formRules/__tests__/index.test.ts +27 -0
  205. package/utils/validators/formRules/index.ts +16 -0
  206. package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
@@ -154,7 +154,9 @@ export default {
154
154
  },
155
155
 
156
156
  canNext() {
157
- return (this.activeStepIndex < this.visibleSteps.length - 1) && this.activeStep.ready;
157
+ const activeStep = this.visibleSteps[this.activeStepIndex];
158
+
159
+ return (this.activeStepIndex < this.visibleSteps.length - 1) && activeStep.ready;
158
160
  },
159
161
 
160
162
  readySteps() {
@@ -277,124 +279,126 @@ export default {
277
279
  class="outer-container"
278
280
  :class="{'hide': !stepsLoaded}"
279
281
  >
280
- <div class="header">
281
- <div class="title">
282
- <div
283
- v-if="showBanner"
284
- class="top choice-banner"
285
- >
286
- <slot
287
- v-if="!!bannerImage || !!bannerTitle"
288
- name="bannerTitle"
282
+ <div>
283
+ <div class="header">
284
+ <div class="title">
285
+ <div
286
+ v-if="showBanner"
287
+ class="top choice-banner"
289
288
  >
290
- <div
291
- v-show="initialTitle || activeStepIndex > 0"
292
- class="title"
289
+ <slot
290
+ v-if="!!bannerImage || !!bannerTitle"
291
+ name="bannerTitle"
293
292
  >
294
- <!-- Logo -->
295
- <slot name="bannerTitleImage">
296
- <div
297
- v-if="bannerImage"
298
- class="round-image"
299
- >
300
- <LazyImage
301
- :src="bannerImage"
302
- class="logo"
303
- />
293
+ <div
294
+ v-show="initialTitle || activeStepIndex > 0"
295
+ class="title"
296
+ >
297
+ <!-- Logo -->
298
+ <slot name="bannerTitleImage">
299
+ <div
300
+ v-if="bannerImage"
301
+ class="round-image"
302
+ >
303
+ <LazyImage
304
+ :src="bannerImage"
305
+ class="logo"
306
+ />
307
+ </div>
308
+ </slot>
309
+ <!-- Title with subtext -->
310
+ <div class="subtitle">
311
+ <h2 v-if="bannerTitle">
312
+ {{ bannerTitle }}
313
+ </h2>
314
+ <span
315
+ v-if="bannerTitleSubtext"
316
+ class="subtext"
317
+ >{{ bannerTitleSubtext }}</span>
304
318
  </div>
305
- </slot>
306
- <!-- Title with subtext -->
307
- <div class="subtitle">
308
- <h2 v-if="bannerTitle">
309
- {{ bannerTitle }}
310
- </h2>
319
+ </div>
320
+ </slot>
321
+ <!-- Step number with subtext -->
322
+ <div
323
+ v-if="activeStep && showSteps"
324
+ class="subtitle"
325
+ >
326
+ <h2>{{ !!headerMode ? t(`wizard.${headerMode}`) : t(`asyncButton.${finishMode}.action`) }}: {{ t('wizard.step', {number:activeStepIndex+1}) }}</h2>
327
+ <slot name="bannerSubtext">
311
328
  <span
312
- v-if="bannerTitleSubtext"
329
+ v-if="activeStep.subtext !== null"
313
330
  class="subtext"
314
- >{{ bannerTitleSubtext }}</span>
315
- </div>
331
+ >{{ activeStep.subtext || activeStep.label }}</span>
332
+ </slot>
316
333
  </div>
317
- </slot>
318
- <!-- Step number with subtext -->
319
- <div
320
- v-if="activeStep && showSteps"
321
- class="subtitle"
322
- >
323
- <h2>{{ !!headerMode ? t(`wizard.${headerMode}`) : t(`asyncButton.${finishMode}.action`) }}: {{ t('wizard.step', {number:activeStepIndex+1}) }}</h2>
324
- <slot name="bannerSubtext">
325
- <span
326
- v-if="activeStep.subtext !== null"
327
- class="subtext"
328
- >{{ activeStep.subtext || activeStep.label }}</span>
329
- </slot>
330
334
  </div>
331
- </div>
332
- <div class="step-sequence">
333
- <ul
334
- v-if="showSteps"
335
- class="steps"
336
- tabindex="0"
337
- @keyup.right.stop="selectNext(1)"
338
- @keyup.left.stop="selectNext(-1)"
339
- >
340
- <template
341
- v-for="(step, idx ) in visibleSteps"
342
- :key="idx"
335
+ <div class="step-sequence">
336
+ <ul
337
+ v-if="showSteps"
338
+ class="steps"
339
+ tabindex="0"
340
+ @keyup.right.stop="selectNext(1)"
341
+ @keyup.left.stop="selectNext(-1)"
343
342
  >
344
- <li
345
-
346
- :id="step.name"
347
- :class="{step: true, active: step.name === activeStep.name, disabled: !isAvailable(step)}"
348
- role="presentation"
343
+ <template
344
+ v-for="(step, idx ) in visibleSteps"
345
+ :key="idx"
349
346
  >
350
- <span
351
- :aria-controls="'step' + idx+1"
352
- :aria-selected="step.name === activeStep.name"
353
- role="tab"
354
- class="controls"
355
- @click.prevent="goToStep(idx+1, true)"
347
+ <li
348
+
349
+ :id="step.name"
350
+ :class="{step: true, active: step.name === activeStep.name, disabled: !isAvailable(step)}"
351
+ role="presentation"
356
352
  >
357
353
  <span
358
- class="icon icon-lg"
359
- :class="{'icon-dot': step.name === activeStep.name, 'icon-dot-open':step.name !== activeStep.name}"
360
- />
361
- <span>
362
- {{ step.label }}
354
+ :aria-controls="'step' + idx+1"
355
+ :aria-selected="step.name === activeStep.name"
356
+ role="tab"
357
+ class="controls"
358
+ @click.prevent="goToStep(idx+1, true)"
359
+ >
360
+ <span
361
+ class="icon icon-lg"
362
+ :class="{'icon-dot': step.name === activeStep.name, 'icon-dot-open':step.name !== activeStep.name}"
363
+ />
364
+ <span>
365
+ {{ step.label }}
366
+ </span>
363
367
  </span>
364
- </span>
365
- </li>
366
- <div
367
- v-if="idx!==visibleSteps.length-1"
368
- :key="step.name"
369
- class="divider"
370
- />
371
- </template>
372
- </ul>
368
+ </li>
369
+ <div
370
+ v-if="idx!==visibleSteps.length-1"
371
+ :key="step.name"
372
+ class="divider"
373
+ />
374
+ </template>
375
+ </ul>
376
+ </div>
373
377
  </div>
374
378
  </div>
375
- </div>
376
- <slot
377
- class="step-container"
378
- name="stepContainer"
379
- :activeStep="activeStep"
380
- >
381
- <template
382
- v-for="(step, i) in steps"
383
- :key="i"
379
+ <slot
380
+ class="step-container"
381
+ name="stepContainer"
382
+ :activeStep="activeStep"
384
383
  >
385
- <div
386
- v-if="step.name === activeStep.name || step.hidden"
387
- :key="step.name"
388
- class="step-container__step"
389
- :class="{'hide': step.name !== activeStep.name && step.hidden}"
384
+ <template
385
+ v-for="(step, i) in steps"
386
+ :key="i"
390
387
  >
391
- <slot
392
- :step="step"
393
- :name="step.name"
394
- />
395
- </div>
396
- </template>
397
- </slot>
388
+ <div
389
+ v-if="step.name === activeStep.name || step.hidden"
390
+ :key="step.name"
391
+ class="step-container__step"
392
+ :class="{'hide': step.name !== activeStep.name && step.hidden}"
393
+ >
394
+ <slot
395
+ :step="step"
396
+ :name="step.name"
397
+ />
398
+ </div>
399
+ </template>
400
+ </slot>
401
+ </div>
398
402
  <slot
399
403
  name="controlsContainer"
400
404
  :showPrevious="showPrevious"
@@ -491,7 +495,7 @@ $spacer: 10px;
491
495
  flex-direction: column;
492
496
  flex: 1;
493
497
  padding: 0;
494
- justify-content: flex-start;
498
+ justify-content: space-between;
495
499
  }
496
500
 
497
501
  .header {
@@ -28,6 +28,11 @@ export default {
28
28
  }
29
29
  },
30
30
 
31
+ mode: {
32
+ type: String,
33
+ default: '',
34
+ },
35
+
31
36
  asObject: {
32
37
  type: Boolean,
33
38
  default: false,
@@ -213,17 +218,21 @@ export default {
213
218
  class="btn-group btn-sm diff-mode"
214
219
  >
215
220
  <button
221
+ role="button"
222
+ :aria-label="t('generic.unified')"
216
223
  type="button"
217
224
  class="btn btn-sm bg-default"
218
225
  :class="{'active': diffMode !== 'split'}"
219
226
  @click="diffMode='unified'"
220
- >Unified</button>
227
+ >{{ t('generic.unified') }}</button>
221
228
  <button
229
+ role="button"
230
+ :aria-label="t('generic.split')"
222
231
  type="button"
223
232
  class="btn btn-sm bg-default"
224
233
  :class="{'active': diffMode === 'split'}"
225
234
  @click="diffMode='split'"
226
- >Split</button>
235
+ >{{ t('generic.split') }}</button>
227
236
  </span>
228
237
  </div>
229
238
  <CodeMirror
@@ -234,6 +243,7 @@ export default {
234
243
  :options="codeMirrorOptions"
235
244
  :showKeyMapBox="true"
236
245
  :data-testid="componentTestid + '-code-mirror'"
246
+ :mode="mode"
237
247
  @onInput="onInput"
238
248
  @onReady="onReady"
239
249
  @onChanges="onChanges"
@@ -21,13 +21,13 @@ describe('component: Collapse.vue', () => {
21
21
  describe('collapsed', () => {
22
22
  const wrapper = mount(Collapse, { props: { open: true } });
23
23
 
24
- it('is collapse', () => {
24
+ it('is collapsed', () => {
25
25
  const content = wrapper.find(`[data-testid="collapse-content"]`);
26
26
 
27
27
  expect(content.element).toBeDefined();
28
28
  });
29
29
 
30
- it('icon should is chevron down', () => {
30
+ it('icon is chevron down', () => {
31
31
  const icon = wrapper.find(`[data-testid="collapse-icon-down"]`);
32
32
 
33
33
  expect(icon.element).toBeDefined();
@@ -20,23 +20,7 @@ export default {
20
20
  },
21
21
 
22
22
  async fetch() {
23
- this.principal = this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, this.value);
24
-
25
- if ( this.principal ) {
26
- return;
27
- }
28
-
29
- const principalId = escape(this.value).replace(/\//g, '%2F');
30
-
31
- try {
32
- this.principal = await this.$store.dispatch('rancher/find', {
33
- type: NORMAN.PRINCIPAL,
34
- id: this.value,
35
- opt: { url: `/v3/principals/${ principalId }` }
36
- });
37
- } catch (e) {
38
- console.error('Failed to fetch principal', this.value, principalId); // eslint-disable-line no-console
39
- }
23
+ this.loadData();
40
24
  },
41
25
 
42
26
  data() {
@@ -51,6 +35,34 @@ export default {
51
35
  return p.name && p.loginName && p.name.trim().toLowerCase() !== p.loginName.trim().toLowerCase();
52
36
  }
53
37
  },
38
+
39
+ methods: {
40
+ async loadData() {
41
+ this.principal = this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, this.value);
42
+
43
+ if ( this.principal ) {
44
+ return;
45
+ }
46
+
47
+ const principalId = escape(this.value).replace(/\//g, '%2F');
48
+
49
+ try {
50
+ this.principal = await this.$store.dispatch('rancher/find', {
51
+ type: NORMAN.PRINCIPAL,
52
+ id: this.value,
53
+ opt: { url: `/v3/principals/${ principalId }` }
54
+ });
55
+ } catch (e) {
56
+ console.error('Failed to fetch principal', this.value, principalId); // eslint-disable-line no-console
57
+ }
58
+ }
59
+ },
60
+
61
+ watch: {
62
+ value() {
63
+ this.loadData();
64
+ }
65
+ },
54
66
  };
55
67
  </script>
56
68
 
@@ -0,0 +1,40 @@
1
+ import { mount, type VueWrapper } from '@vue/test-utils';
2
+ import Principal from '@shell/components/auth/Principal.vue';
3
+
4
+ describe('component: Principal', () => {
5
+ it('should render the component', () => {
6
+ const wrapper = mount(Principal, {
7
+ props: { value: 'whatever' },
8
+ global: { mocks: { $fetchState: { pending: false } } },
9
+ });
10
+
11
+ expect(wrapper.exists()).toBe(true);
12
+ });
13
+
14
+ it('should update principal displayed properties on value change', async() => {
15
+ const wrapper: VueWrapper<any, any> = mount(Principal, {
16
+ props: { value: 'whatever' },
17
+ global: {
18
+ mocks: {
19
+ $fetchState: { pending: false },
20
+ $store: {
21
+ getters: {
22
+ 'rancher/byId': (_: any, id: 'first' | 'second') => {
23
+ const options = {
24
+ first: { name: 'first name' },
25
+ second: { name: 'second name' }
26
+ };
27
+
28
+ return options[id];
29
+ }
30
+ }
31
+ },
32
+ },
33
+ },
34
+ });
35
+
36
+ await wrapper.setProps({ value: 'second' });
37
+
38
+ expect(wrapper.vm.principal.name).toStrictEqual('second name');
39
+ });
40
+ });
@@ -2,6 +2,7 @@
2
2
  import { LabeledInput } from '@components/Form/LabeledInput';
3
3
  import AsyncButton from '@shell/components/AsyncButton';
4
4
  import Login from '@shell/mixins/login';
5
+ import loadPlugins from '@shell/plugins/plugin';
5
6
 
6
7
  export default {
7
8
  emits: ['error', 'showInputs'],
@@ -32,6 +33,12 @@ export default {
32
33
  }
33
34
  });
34
35
 
36
+ await loadPlugins({
37
+ app: this.$store.app,
38
+ store: this.$store,
39
+ $plugin: this.$store.$plugin
40
+ });
41
+
35
42
  buttonCb(true);
36
43
  this.$router.replace('/');
37
44
  } catch (err) {
@@ -126,7 +126,7 @@ export default {
126
126
  v-if="displayWarning(row)"
127
127
  class="text-warning"
128
128
  >
129
- {{ row.status.summary.ready }}/{{ row.status.summary.desiredReady }}</span>
129
+ {{ row.status.summary.ready || 0 }}/{{ row.status.summary.desiredReady }}</span>
130
130
  <span v-else-if="row.status && row.status.summary">{{ row.status.summary.desiredReady }}</span>
131
131
  <span v-else>-</span>
132
132
  </template>
@@ -120,7 +120,7 @@ export default {
120
120
  <template #cell:repo="{ row }">
121
121
  <Link
122
122
  :row="row"
123
- :value="row.spec.repo"
123
+ :value="row.spec.repo || ''"
124
124
  label-key="repoDisplay"
125
125
  before-icon-key="repoIcon"
126
126
  url-key="spec.repo"
@@ -1,6 +1,5 @@
1
1
  <script>
2
2
  import SortableTable from '@shell/components/SortableTable';
3
- import { AGE } from '@shell/config/table-headers';
4
3
 
5
4
  export default {
6
5
  name: 'FleetResources',
@@ -65,7 +64,6 @@ export default {
65
64
  sort: 'namespace',
66
65
  label: 'Namespace',
67
66
  },
68
- { ...AGE }
69
67
  ];
70
68
  },
71
69
  }
@@ -2,57 +2,47 @@
2
2
  import { STATES, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
3
3
  import FleetStatus from '@shell/components/fleet/FleetStatus';
4
4
 
5
- const getResourceDefaultState = (labelGetter, stateKey) => {
6
- return {
7
- ready: {
5
+ const getResourcesDefaultState = (labelGetter, stateKey) => {
6
+ return [
7
+ STATES_ENUM.READY,
8
+ STATES_ENUM.NOT_READY,
9
+ STATES_ENUM.WAIT_APPLIED,
10
+ STATES_ENUM.MODIFIED,
11
+ STATES_ENUM.MISSING,
12
+ STATES_ENUM.ORPHANED,
13
+ STATES_ENUM.UNKNOWN,
14
+ ].reduce((acc, state) => {
15
+ acc[state] = {
8
16
  count: 0,
9
- color: STATES[STATES_ENUM.READY].color,
10
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.READY }`, null, STATES[STATES_ENUM.READY].label ),
11
- status: STATES_ENUM.READY
12
- },
13
- info: {
14
- count: 0,
15
- color: STATES[STATES_ENUM.INFO].color,
16
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.INFO }`, null, STATES[STATES_ENUM.INFO].label ),
17
- status: STATES_ENUM.INFO
18
- },
19
- warning: {
20
- count: 0,
21
- color: STATES[STATES_ENUM.WARNING].color,
22
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.WARNING }`, null, STATES[STATES_ENUM.WARNING].label ),
23
- status: STATES_ENUM.WARNING
24
- },
25
- notready: {
26
- count: 0,
27
- color: STATES[STATES_ENUM.NOT_READY].color,
28
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.NOT_READY }`, null, STATES[STATES_ENUM.NOT_READY].label ),
29
- status: STATES_ENUM.NOT_READY
30
- },
31
- error: {
32
- count: 0,
33
- color: STATES[STATES_ENUM.ERROR].color,
34
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.ERROR }`, null, STATES[STATES_ENUM.ERROR].label ),
35
- status: STATES_ENUM.ERROR
36
- },
37
- errapplied: {
38
- count: 0,
39
- color: STATES[STATES_ENUM.ERR_APPLIED].color,
40
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.ERR_APPLIED }`, null, STATES[STATES_ENUM.ERR_APPLIED].label ),
41
- status: STATES_ENUM.ERR_APPLIED,
42
- },
43
- waitapplied: {
44
- count: 0,
45
- color: STATES[STATES_ENUM.WAIT_APPLIED].color,
46
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.WAIT_APPLIED }`, null, STATES[STATES_ENUM.WAIT_APPLIED].label ),
47
- status: STATES_ENUM.WAIT_APPLIED
48
- },
49
- unknown: {
17
+ color: STATES[state].color,
18
+ label: labelGetter(`${ stateKey }.${ state }`, null, STATES[state].label ),
19
+ status: state
20
+ };
21
+
22
+ return acc;
23
+ }, {});
24
+ };
25
+
26
+ const getBundlesDefaultState = (labelGetter, stateKey) => {
27
+ return [
28
+ STATES_ENUM.READY,
29
+ STATES_ENUM.INFO,
30
+ STATES_ENUM.WARNING,
31
+ STATES_ENUM.NOT_READY,
32
+ STATES_ENUM.ERROR,
33
+ STATES_ENUM.ERR_APPLIED,
34
+ STATES_ENUM.WAIT_APPLIED,
35
+ STATES_ENUM.UNKNOWN,
36
+ ].reduce((acc, state) => {
37
+ acc[state] = {
50
38
  count: 0,
51
- color: STATES[STATES_ENUM.UNKNOWN].color,
52
- label: labelGetter(`${ stateKey }.${ STATES_ENUM.UNKNOWN }`, null, STATES[STATES_ENUM.UNKNOWN].label ),
53
- status: STATES_ENUM.UNKNOWN
54
- }
55
- };
39
+ color: STATES[state].color,
40
+ label: labelGetter(`${ stateKey }.${ state }`, null, STATES[state].label ),
41
+ status: state
42
+ };
43
+
44
+ return acc;
45
+ }, {});
56
46
  };
57
47
 
58
48
  export default {
@@ -83,14 +73,18 @@ export default {
83
73
  return this.value.metadata.name;
84
74
  },
85
75
 
76
+ repoNamespace() {
77
+ return this.value.metadata.namespace;
78
+ },
79
+
86
80
  bundleCounts() {
87
- const resources = this.bundles.filter((item) => item.repoName === this.repoName);
81
+ const resources = this.bundles.filter((item) => item.namespace === this.repoNamespace && item.repoName === this.repoName);
88
82
 
89
83
  if (!resources.length) {
90
84
  return [];
91
85
  }
92
86
 
93
- const out = { ...getResourceDefaultState(this.$store.getters['i18n/withFallback'], this.stateKey) };
87
+ const out = { ...getBundlesDefaultState(this.$store.getters['i18n/withFallback'], this.stateKey) };
94
88
 
95
89
  resources.forEach(({ status, metadata }) => {
96
90
  if (!status) {
@@ -99,7 +93,7 @@ export default {
99
93
  return;
100
94
  }
101
95
 
102
- const k = status?.summary.ready > 0 && status?.summary.desiredReady === status.summary.ready;
96
+ const k = status?.summary?.ready > 0 && status?.summary.desiredReady === status?.summary?.ready;
103
97
 
104
98
  if (k) {
105
99
  out.ready.count += 1;
@@ -155,19 +149,20 @@ export default {
155
149
  },
156
150
 
157
151
  resourceCounts() {
158
- const resources = this.value.status.resources || [];
159
- const out = { ...getResourceDefaultState(this.$store.getters['i18n/withFallback'], this.stateKey) };
160
-
161
- resources.forEach(({ state }) => {
162
- const k = state?.toLowerCase();
163
-
164
- if (out[k]) {
165
- out[k].count += 1;
166
-
167
- return;
168
- }
169
- out.unknown.count += 1;
170
- });
152
+ const out = { ...getResourcesDefaultState(this.$store.getters['i18n/withFallback'], this.stateKey) };
153
+ const resourceStatuses = this.value.allResourceStatuses;
154
+
155
+ Object.entries(resourceStatuses.states)
156
+ .filter(([_, count]) => count > 0)
157
+ .forEach(([state, count]) => {
158
+ const k = state?.toLowerCase();
159
+
160
+ if (out[k]) {
161
+ out[k].count += count;
162
+ } else {
163
+ out.unknown.count += count;
164
+ }
165
+ });
171
166
 
172
167
  return Object.values(out).map((item) => {
173
168
  item.value = item.count;
@@ -238,8 +238,12 @@ export default {
238
238
  },
239
239
  zoomFit() {
240
240
  const rootNode = d3.select('.root-node');
241
- const paddingBuffer = 30;
242
241
 
242
+ if (!rootNode?.node()) {
243
+ return;
244
+ }
245
+
246
+ const paddingBuffer = 30;
243
247
  const chartDimentions = rootNode.node().getBoundingClientRect();
244
248
  const chartCoordinates = rootNode.node().getBBox();
245
249
  const parent = rootNode.node().parentElement;