@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.4

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 (172) hide show
  1. package/assets/styles/base/_basic.scss +7 -8
  2. package/assets/styles/global/_button.scss +10 -0
  3. package/assets/styles/global/_form.scss +2 -1
  4. package/assets/styles/global/_tooltip.scss +2 -2
  5. package/assets/styles/themes/_dark.scss +15 -3
  6. package/assets/styles/themes/_light.scss +7 -2
  7. package/assets/styles/vendor/vue-select.scss +4 -0
  8. package/assets/translations/en-us.yaml +66 -9
  9. package/assets/translations/zh-hans.yaml +2 -3
  10. package/components/AppModal.vue +50 -0
  11. package/components/BannerGraphic.vue +0 -42
  12. package/components/ButtonMultiAction.vue +1 -1
  13. package/components/Carousel.vue +88 -74
  14. package/components/CommunityLinks.vue +6 -1
  15. package/components/CopyToClipboardText.vue +3 -0
  16. package/components/Dialog.vue +20 -1
  17. package/components/GrowlManager.vue +9 -2
  18. package/components/LocaleSelector.vue +8 -1
  19. package/components/PaginatedResourceTable.vue +4 -7
  20. package/components/ProgressBarMulti.vue +14 -0
  21. package/components/PromptChangePassword.vue +3 -0
  22. package/components/Questions/Reference.vue +57 -28
  23. package/components/ResourceDetail/Masthead.vue +1 -1
  24. package/components/SelectIconGrid.vue +12 -1
  25. package/components/SideNav.vue +12 -38
  26. package/components/SortableTable/index.vue +1 -0
  27. package/components/Tabbed/index.vue +9 -1
  28. package/components/YamlEditor.vue +1 -0
  29. package/components/__tests__/Carousel.test.ts +56 -27
  30. package/components/auth/Principal.vue +5 -3
  31. package/components/fleet/FleetClusters.vue +82 -1
  32. package/components/fleet/FleetRepos.vue +13 -30
  33. package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
  34. package/components/form/ChangePassword.vue +2 -0
  35. package/components/form/ColorInput.vue +24 -1
  36. package/components/form/FileSelector.vue +2 -0
  37. package/components/form/KeyValue.vue +230 -160
  38. package/components/form/LabeledSelect.vue +2 -2
  39. package/components/form/PlusMinus.vue +14 -2
  40. package/components/form/ResourceLabeledSelect.vue +13 -53
  41. package/components/form/ResourceSelector.vue +1 -0
  42. package/components/form/ResourceTabs/index.vue +79 -36
  43. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
  44. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
  45. package/components/form/SSHKnownHosts/index.vue +101 -0
  46. package/components/form/SecretSelector.vue +2 -2
  47. package/components/form/Select.vue +1 -1
  48. package/components/form/SelectOrCreateAuthSecret.vue +43 -11
  49. package/components/form/__tests__/KeyValue.test.ts +1 -1
  50. package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
  51. package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
  52. package/components/formatter/FleetSummaryGraph.vue +6 -7
  53. package/components/formatter/WorkloadHealthScale.vue +7 -0
  54. package/components/nav/Group.vue +30 -4
  55. package/components/nav/Header.vue +82 -114
  56. package/components/nav/HeaderPageActionMenu.vue +27 -131
  57. package/components/nav/NamespaceFilter.vue +1 -1
  58. package/components/nav/Type.vue +15 -0
  59. package/composables/focusTrap.ts +68 -0
  60. package/config/home-links.js +21 -13
  61. package/config/labels-annotations.js +2 -0
  62. package/config/page-actions.js +1 -0
  63. package/config/pagination-table-headers.js +15 -1
  64. package/config/product/explorer.js +7 -17
  65. package/config/table-headers.js +6 -0
  66. package/config/version.js +5 -1
  67. package/core/plugin.ts +41 -1
  68. package/core/plugins.js +125 -72
  69. package/core/types-provisioning.ts +91 -2
  70. package/core/types.ts +55 -0
  71. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
  72. package/detail/catalog.cattle.io.app.vue +1 -1
  73. package/detail/fleet.cattle.io.cluster.vue +3 -3
  74. package/detail/namespace.vue +13 -19
  75. package/detail/networking.k8s.io.ingress.vue +13 -53
  76. package/detail/provisioning.cattle.io.cluster.vue +12 -1
  77. package/detail/secret.vue +25 -0
  78. package/detail/workload/index.vue +3 -3
  79. package/dialog/AddCustomBadgeDialog.vue +5 -1
  80. package/edit/auth/ldap/__tests__/config.test.ts +18 -0
  81. package/edit/auth/ldap/config.vue +24 -0
  82. package/edit/auth/saml.vue +8 -6
  83. package/edit/fleet.cattle.io.gitrepo.vue +34 -23
  84. package/edit/logging-flow/index.vue +4 -19
  85. package/edit/networking.k8s.io.ingress/index.vue +18 -65
  86. package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
  87. package/edit/provisioning.cattle.io.cluster/index.vue +27 -8
  88. package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
  89. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
  90. package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
  91. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
  92. package/edit/secret/index.vue +1 -1
  93. package/edit/secret/ssh.vue +21 -3
  94. package/edit/service.vue +1 -2
  95. package/list/networking.k8s.io.ingress.vue +1 -1
  96. package/list/node.vue +15 -8
  97. package/list/persistentvolume.vue +12 -4
  98. package/list/provisioning.cattle.io.cluster.vue +1 -0
  99. package/list/service.vue +1 -1
  100. package/list/workload.vue +4 -0
  101. package/mixins/chart.js +4 -1
  102. package/models/catalog.cattle.io.app.js +3 -1
  103. package/models/catalog.cattle.io.clusterrepo.js +56 -7
  104. package/models/fleet.cattle.io.bundle.js +0 -11
  105. package/models/fleet.cattle.io.cluster.js +17 -1
  106. package/models/fleet.cattle.io.gitrepo.js +88 -52
  107. package/models/provisioning.cattle.io.cluster.js +36 -1
  108. package/models/secret.js +5 -0
  109. package/models/service.js +1 -0
  110. package/models/workload.js +19 -1
  111. package/package.json +5 -4
  112. package/pages/account/index.vue +4 -0
  113. package/pages/c/_cluster/apps/charts/index.vue +4 -0
  114. package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
  115. package/pages/c/_cluster/explorer/index.vue +13 -6
  116. package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
  117. package/pages/c/_cluster/fleet/index.vue +75 -89
  118. package/pages/c/_cluster/settings/links.vue +2 -2
  119. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
  120. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
  121. package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
  122. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
  123. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
  124. package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
  125. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
  126. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
  127. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
  128. package/pages/c/_cluster/uiplugins/index.vue +50 -12
  129. package/pages/diagnostic.vue +17 -15
  130. package/pages/home.vue +32 -6
  131. package/plugins/clean-html.js +50 -0
  132. package/plugins/dashboard-store/resource-class.js +4 -0
  133. package/plugins/plugin.js +54 -49
  134. package/plugins/steve/mutations.js +1 -1
  135. package/plugins/steve/steve-class.js +8 -0
  136. package/plugins/steve/steve-pagination-utils.ts +3 -1
  137. package/rancher-components/Accordion/Accordion.vue +4 -4
  138. package/rancher-components/BadgeState/BadgeState.vue +7 -0
  139. package/rancher-components/Card/Card.vue +12 -0
  140. package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
  141. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  142. package/rancher-components/Form/LabeledInput/LabeledInput.vue +19 -1
  143. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
  144. package/rancher-components/RcButton/RcButton.vue +90 -0
  145. package/rancher-components/RcButton/index.ts +2 -0
  146. package/rancher-components/RcButton/types.ts +17 -0
  147. package/rancher-components/RcDropdown/RcDropdown.vue +122 -0
  148. package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
  149. package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
  150. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
  151. package/rancher-components/RcDropdown/index.ts +4 -0
  152. package/rancher-components/RcDropdown/types.ts +22 -0
  153. package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
  154. package/rancher-components/RcDropdown/useDropdownContext.ts +110 -0
  155. package/scripts/test-plugins-build.sh +2 -0
  156. package/scripts/typegen.sh +2 -0
  157. package/store/catalog.js +1 -1
  158. package/tsconfig.json +2 -1
  159. package/types/components/paginatedResourceTable.ts +25 -0
  160. package/types/components/resourceLabeledSelect.ts +48 -0
  161. package/types/resources/fleet.d.ts +17 -0
  162. package/types/shell/index.d.ts +61 -0
  163. package/utils/auth.js +5 -1
  164. package/utils/cluster.js +106 -0
  165. package/utils/fleet.ts +35 -3
  166. package/utils/ingress.ts +64 -0
  167. package/utils/uiplugins.ts +56 -44
  168. package/utils/validators/cron-schedule.js +7 -2
  169. package/utils/validators/formRules/__tests__/index.test.ts +53 -17
  170. package/utils/validators/formRules/index.ts +20 -5
  171. package/vue.config.js +1 -1
  172. package/components/RelatedWorkloadsTable.vue +0 -50
@@ -603,39 +603,63 @@ export default {
603
603
  </div>
604
604
  <div
605
605
  class="kv-container"
606
+ role="grid"
607
+ :aria-rowcount="rows.length"
608
+ :aria-colcount="extraColumns.length + 2"
606
609
  :style="containerStyle"
607
610
  >
608
611
  <template v-if="rows.length || isView">
609
- <label class="text-label">
610
- {{ _keyLabel }}
611
- <i
612
- v-if="_protip && !isView && addAllowed"
613
- v-clean-tooltip="_protip"
614
- class="icon icon-info"
615
- />
616
- </label>
617
- <label class="text-label">
618
- {{ _valueLabel }}
619
- </label>
620
- <label
621
- v-for="(c, i) in extraColumns"
622
- :key="i"
623
- >
624
- <slot :name="'label:'+c">{{ c }}</slot>
625
- </label>
626
- <slot
627
- v-if="canRemove"
628
- name="remove"
629
- >
630
- <span />
631
- </slot>
612
+ <div class="rowgroup">
613
+ <div class="row">
614
+ <label
615
+ class="text-label"
616
+ role="columnheader"
617
+ >
618
+ {{ _keyLabel }}
619
+ <i
620
+ v-if="_protip && !isView && addAllowed"
621
+ v-clean-tooltip="_protip"
622
+ class="icon icon-info"
623
+ />
624
+ </label>
625
+ <label
626
+ class="text-label"
627
+ role="columnheader"
628
+ >
629
+ {{ _valueLabel }}
630
+ </label>
631
+ <label
632
+ v-for="(c, i) in extraColumns"
633
+ :key="i"
634
+ role="columnheader"
635
+ >
636
+ <slot :name="'label:'+c">{{ c }}</slot>
637
+ </label>
638
+ <slot
639
+ v-if="canRemove"
640
+ name="remove"
641
+ >
642
+ <span />
643
+ </slot>
644
+ </div>
645
+ </div>
632
646
  </template>
633
647
  <template v-if="!rows.length && isView">
634
- <div class="kv-item key text-muted">
635
- &mdash;
636
- </div>
637
- <div class="kv-item key text-muted">
638
- &mdash;
648
+ <div class="rowgroup">
649
+ <div class="row">
650
+ <div
651
+ class="kv-item key text-muted"
652
+ role="gridcell"
653
+ >
654
+ &mdash;
655
+ </div>
656
+ <div
657
+ class="kv-item key text-muted"
658
+ role="gridcell"
659
+ >
660
+ &mdash;
661
+ </div>
662
+ </div>
639
663
  </div>
640
664
  </template>
641
665
  <template
@@ -643,146 +667,172 @@ export default {
643
667
  v-else
644
668
  :key="i"
645
669
  >
646
- <!-- Key -->
647
- <div
648
- class="kv-item key"
649
- >
650
- <slot
651
- name="key"
652
- :row="row"
653
- :mode="mode"
654
- :keyName="keyName"
655
- :valueName="valueName"
656
- :queueUpdate="queueUpdate"
657
- :disabled="disabled"
658
- >
659
- <Select
660
- v-if="keyOptions"
661
- ref="key"
662
- v-model:value="row[keyName]"
663
- :searchable="true"
664
- :disabled="disabled || isProtected(row.key)"
665
- :clearable="false"
666
- :taggable="keyTaggable"
667
- :options="calculateOptions(row[keyName])"
668
- :data-testid="`select-kv-item-key-${i}`"
669
- @update:value="queueUpdate"
670
- />
671
- <input
672
- v-else
673
- ref="key"
674
- v-model="row[keyName]"
675
- :disabled="isView || disabled || !keyEditable || isProtected(row.key)"
676
- :placeholder="_keyPlaceholder"
677
- :data-testid="`input-kv-item-key-${i}`"
678
- @input="queueUpdate"
679
- @paste="onPaste(i, $event)"
670
+ <div class="rowgroup">
671
+ <div class="row">
672
+ <!-- Key -->
673
+ <div
674
+ class="kv-item key"
675
+ role="gridcell"
676
+ :aria-rowindex="i+1"
677
+ :aria-colindex="1"
680
678
  >
681
- </slot>
682
- </div>
683
-
684
- <!-- Value -->
685
- <div
686
- :data-testid="`kv-item-value-${i}`"
687
- class="kv-item value"
688
- >
689
- <slot
690
- name="value"
691
- :row="row"
692
- :mode="mode"
693
- :keyName="keyName"
694
- :valueName="valueName"
695
- :queueUpdate="queueUpdate"
696
- >
697
- <div v-if="!row.supported">
698
- {{ t('detailText.unsupported', null, true) }}
699
- </div>
700
- <div v-else-if="row.binary">
701
- {{ binaryTextSize(row.value) }}
679
+ <slot
680
+ name="key"
681
+ :row="row"
682
+ :mode="mode"
683
+ :keyName="keyName"
684
+ :valueName="valueName"
685
+ :queueUpdate="queueUpdate"
686
+ :disabled="disabled"
687
+ >
688
+ <Select
689
+ v-if="keyOptions"
690
+ ref="key"
691
+ v-model:value="row[keyName]"
692
+ :searchable="true"
693
+ :disabled="disabled || isProtected(row.key)"
694
+ :clearable="false"
695
+ :taggable="keyTaggable"
696
+ :options="calculateOptions(row[keyName])"
697
+ :data-testid="`select-kv-item-key-${i}`"
698
+ :aria-label="t('generic.ariaLabel.key', {index: i})"
699
+ @update:value="queueUpdate"
700
+ />
701
+ <input
702
+ v-else
703
+ ref="key"
704
+ v-model="row[keyName]"
705
+ :disabled="isView || disabled || !keyEditable || isProtected(row.key)"
706
+ :placeholder="_keyPlaceholder"
707
+ :data-testid="`input-kv-item-key-${i}`"
708
+ :aria-label="t('generic.ariaLabel.key', {index: i})"
709
+ @input="queueUpdate"
710
+ @paste="onPaste(i, $event)"
711
+ >
712
+ </slot>
702
713
  </div>
714
+
715
+ <!-- Value -->
703
716
  <div
704
- v-else
705
- class="value-container"
706
- :class="{ 'upload-button': parseValueFromFile }"
717
+ :data-testid="`kv-item-value-${i}`"
718
+ class="kv-item value"
719
+ role="gridcell"
720
+ :aria-rowindex="i+1"
721
+ :aria-colindex="2"
707
722
  >
708
- <CodeMirror
709
- v-if="valueMarkdownMultiline"
710
- ref="cm"
711
- data-testid="code-mirror-multiline-field"
712
- :class="{['focus']: codeMirrorFocus[i]}"
713
- :value="row[valueName]"
714
- :as-text-area="true"
715
- :mode="mode"
716
- @onInput="onInputMarkdownMultiline(i, $event)"
717
- @onFocus="onFocusMarkdownMultiline(i, $event)"
718
- />
719
- <TextAreaAutoGrow
720
- v-else-if="valueMultiline && row[valueName] !== undefined"
721
- v-model:value="row[valueName]"
722
- data-testid="value-multiline"
723
- :class="{'conceal': valueConcealed}"
724
- :disabled="disabled || isProtected(row.key)"
723
+ <slot
724
+ name="value"
725
+ :row="row"
725
726
  :mode="mode"
726
- :placeholder="_valuePlaceholder"
727
- :min-height="40"
728
- :spellcheck="false"
729
- @update:value="queueUpdate"
730
- />
731
- <input
732
- v-else
733
- v-model="row[valueName]"
734
- :disabled="isView || disabled || isProtected(row.key)"
735
- :type="valueConcealed ? 'password' : 'text'"
736
- :placeholder="_valuePlaceholder"
737
- autocorrect="off"
738
- autocapitalize="off"
739
- spellcheck="false"
740
- :data-testid="`input-kv-item-value-${i}`"
741
- @input="queueUpdate"
727
+ :keyName="keyName"
728
+ :valueName="valueName"
729
+ :queueUpdate="queueUpdate"
742
730
  >
743
- <FileSelector
744
- v-if="parseValueFromFile && readAllowed && !isView && isValueFieldEmpty(row[valueName])"
745
- class="btn btn-sm role-secondary file-selector"
746
- :label="t('generic.upload')"
747
- :include-file-name="true"
748
- @selected="onValueFileSelected(i, $event)"
731
+ <div v-if="!row.supported">
732
+ {{ t('detailText.unsupported', null, true) }}
733
+ </div>
734
+ <div v-else-if="row.binary">
735
+ {{ binaryTextSize(row.value) }}
736
+ </div>
737
+ <div
738
+ v-else
739
+ class="value-container"
740
+ :class="{ 'upload-button': parseValueFromFile }"
741
+ >
742
+ <CodeMirror
743
+ v-if="valueMarkdownMultiline"
744
+ ref="cm"
745
+ data-testid="code-mirror-multiline-field"
746
+ :class="{['focus']: codeMirrorFocus[i]}"
747
+ :value="row[valueName]"
748
+ :as-text-area="true"
749
+ :mode="mode"
750
+ :options="{
751
+ screenReaderLabel: t('generic.ariaLabel.value', { index: i })
752
+ }"
753
+ @onInput="onInputMarkdownMultiline(i, $event)"
754
+ @onFocus="onFocusMarkdownMultiline(i, $event)"
755
+ />
756
+ <TextAreaAutoGrow
757
+ v-else-if="valueMultiline && row[valueName] !== undefined"
758
+ v-model:value="row[valueName]"
759
+ data-testid="value-multiline"
760
+ :class="{'conceal': valueConcealed}"
761
+ :disabled="disabled || isProtected(row.key)"
762
+ :mode="mode"
763
+ :placeholder="_valuePlaceholder"
764
+ :min-height="40"
765
+ :spellcheck="false"
766
+ :aria-label="t('generic.ariaLabel.value', {index: i})"
767
+ @update:value="queueUpdate"
768
+ />
769
+ <input
770
+ v-else
771
+ v-model="row[valueName]"
772
+ :disabled="isView || disabled || isProtected(row.key)"
773
+ :type="valueConcealed ? 'password' : 'text'"
774
+ :placeholder="_valuePlaceholder"
775
+ autocorrect="off"
776
+ autocapitalize="off"
777
+ spellcheck="false"
778
+ :data-testid="`input-kv-item-value-${i}`"
779
+ :aria-label="t('generic.ariaLabel.value', {index: i})"
780
+ @input="queueUpdate"
781
+ >
782
+ <FileSelector
783
+ v-if="parseValueFromFile && readAllowed && !isView && isValueFieldEmpty(row[valueName])"
784
+ class="btn btn-sm role-secondary file-selector"
785
+ :label="t('generic.upload')"
786
+ :include-file-name="true"
787
+ :aria-label="t('generic.ariaLabel.value', {index: i})"
788
+ @selected="onValueFileSelected(i, $event)"
789
+ />
790
+ </div>
791
+ </slot>
792
+ </div>
793
+ <div
794
+ v-for="(c, j) in extraColumns"
795
+ :key="`${i}-${j}`"
796
+ class="kv-item extra"
797
+ role="gridcell"
798
+ :aria-rowindex="i+1"
799
+ :aria-colindex="j+3"
800
+ >
801
+ <slot
802
+ :name="'col:' + c"
803
+ :row="row"
804
+ :queue-update="queueUpdate"
805
+ :i="i"
749
806
  />
750
807
  </div>
751
- </slot>
752
- </div>
753
- <div
754
- v-for="(c, j) in extraColumns"
755
- :key="`${i}-${j}`"
756
- class="kv-item extra"
757
- >
758
- <slot
759
- :name="'col:' + c"
760
- :row="row"
761
- :queue-update="queueUpdate"
762
- :i="i"
763
- />
764
- </div>
765
- <div
766
- v-if="canRemove"
767
- :key="i"
768
- class="kv-item remove"
769
- :data-testid="`remove-column-${i}`"
770
- >
771
- <slot
772
- name="removeButton"
773
- :remove="remove"
774
- :row="row"
775
- :i="i"
776
- >
777
- <button
778
- type="button"
779
- :disabled="isView || isProtected(row.key) || disabled"
780
- class="btn role-link"
781
- @click="remove(i)"
808
+ <div
809
+ v-if="canRemove"
810
+ :key="i"
811
+ class="kv-item remove"
812
+ role="gridcell"
813
+ :aria-rowindex="i+1"
814
+ :aria-colindex="extraColumns.length+3"
815
+ :data-testid="`remove-column-${i}`"
782
816
  >
783
- {{ removeLabel || t('generic.remove') }}
784
- </button>
785
- </slot>
817
+ <slot
818
+ name="removeButton"
819
+ :remove="remove"
820
+ :row="row"
821
+ :i="i"
822
+ >
823
+ <button
824
+ type="button"
825
+ role="button"
826
+ :disabled="isView || isProtected(row.key) || disabled"
827
+ :aria-label="removeLabel || t('generic.remove')"
828
+ class="btn role-link"
829
+ @click="remove(i)"
830
+ >
831
+ {{ removeLabel || t('generic.remove') }}
832
+ </button>
833
+ </slot>
834
+ </div>
835
+ </div>
786
836
  </div>
787
837
  </template>
788
838
  </div>
@@ -797,9 +847,11 @@ export default {
797
847
  <button
798
848
  v-if="addAllowed"
799
849
  type="button"
850
+ role="button"
800
851
  class="btn role-tertiary add"
801
- data-testid="add_link_button"
852
+ data-testid="add_row_item_button"
802
853
  :disabled="loading || disabled || (keyOptions && filteredKeyOptions.length === 0)"
854
+ :aria-label="_addLabel"
803
855
  @click="add()"
804
856
  >
805
857
  <i
@@ -861,6 +913,24 @@ export default {
861
913
  }
862
914
  }
863
915
  }
916
+
917
+ .rowgroup {
918
+ display: grid;
919
+ grid-column-start: 1;
920
+ grid-column-end: span end;
921
+ grid-template-columns: subgrid;
922
+ }
923
+
924
+ .row {
925
+ &::before {
926
+ display: none;
927
+ }
928
+ display: grid;
929
+ grid-column-start: 1;
930
+ grid-column-end: span end;
931
+ grid-template-columns: subgrid;
932
+ }
933
+
864
934
  .remove {
865
935
  text-align: center;
866
936
  BUTTON {
@@ -291,7 +291,7 @@ export default {
291
291
  ]"
292
292
  :tabindex="isView || disabled ? -1 : 0"
293
293
  @click="focusSearch"
294
- @keyup.enter.space.down="focusSearch"
294
+ @keydown.enter.space.down="focusSearch"
295
295
  >
296
296
  <div
297
297
  :class="{ 'labeled-container': true, raised, empty, [mode]: true }"
@@ -396,7 +396,7 @@ export default {
396
396
 
397
397
  <template #list-footer>
398
398
  <div
399
- v-if="canPaginate && totalResults"
399
+ v-if="canPaginate && totalResults && pages > 1"
400
400
  class="pagination-slot"
401
401
  >
402
402
  <div class="load-more">
@@ -54,11 +54,17 @@ export default {
54
54
  <button
55
55
  v-clean-tooltip="minusTooltip"
56
56
  :disabled="disabled || !canMinus"
57
+ :aria-disabled="disabled || !canMinus"
57
58
  type="button"
59
+ role="button"
60
+ :aria-label="t('workload.plus')"
58
61
  class="btn btn-sm role-secondary"
59
62
  @click="$emit('minus')"
60
63
  >
61
- <i class="icon icon-sm icon-minus" />
64
+ <i
65
+ class="icon icon-sm icon-minus"
66
+ :alt="t('workload.plus')"
67
+ />
62
68
  </button>
63
69
  <div class="value">
64
70
  {{ value }}
@@ -66,11 +72,17 @@ export default {
66
72
  <button
67
73
  v-clean-tooltip="plusTooltip"
68
74
  :disabled="disabled || !canPlus"
75
+ :aria-disabled="disabled || !canPlus"
69
76
  type="button"
77
+ role="button"
78
+ :aria-label="t('workload.minus')"
70
79
  class="btn btn-sm role-secondary"
71
80
  @click="$emit('plus')"
72
81
  >
73
- <i class="icon icon-sm icon-plus" />
82
+ <i
83
+ class="icon icon-sm icon-plus"
84
+ :alt="t('workload.minus')"
85
+ />
74
86
  </button>
75
87
  </div>
76
88
  </template>
@@ -3,53 +3,8 @@ import { PropType, defineComponent } from 'vue';
3
3
  import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
4
4
  import { PaginationParamFilter } from '@shell/types/store/pagination.types';
5
5
  import { labelSelectPaginationFunction, LabelSelectPaginationFunctionOptions } from '@shell/components/form/labeled-select-utils/labeled-select.utils';
6
- import { LabelSelectPaginateFn, LabelSelectPaginateFnOptions, LabelSelectPaginateFnResponse } from '@shell/types/components/labeledSelect';
7
-
8
- type PaginateTypeOverridesFn = (opts: LabelSelectPaginationFunctionOptions) => LabelSelectPaginationFunctionOptions;
9
-
10
- interface SharedSettings {
11
- /**
12
- * Provide specific LabelSelect options for this mode (paginated / not paginated)
13
- */
14
- labelSelectOptions?: { [key: string]: any },
15
- /**
16
- * Map the resources shown in LabelSelect
17
- */
18
- mapResult?: (resources: any[]) => any[]
19
- }
20
-
21
- /**
22
- * Settings to use when the LabelSelect is paginating
23
- */
24
- export interface ResourceLabeledSelectPaginateSettings extends SharedSettings {
25
- /**
26
- * Override the convience function which fetches a page of results
27
- */
28
- overrideRequest?: LabelSelectPaginateFn,
29
- /**
30
- * Override the default settings used in the convenience function to fetch a page of results
31
- */
32
- requestSettings?: PaginateTypeOverridesFn,
33
- }
34
-
35
- /**
36
- * Settings to use when the LabelSelect is fetching all resources (not paginating)
37
- */
38
- export type ResourceLabeledSelectSettings = SharedSettings
39
-
40
- /**
41
- * Force a specific mode
42
- */
43
- export enum RESOURCE_LABEL_SELECT_MODE {
44
- /**
45
- * Fetch all resources
46
- */
47
- ALL_RESOURCES = 'ALL', // eslint-disable-line no-unused-vars
48
- /**
49
- * Determine if all resources are fetched given system settings
50
- */
51
- DYNAMIC = 'DYNAMIC', // eslint-disable-line no-unused-vars
52
- }
6
+ import { LabelSelectPaginateFnOptions, LabelSelectPaginateFnResponse } from '@shell/types/components/labeledSelect';
7
+ import { RESOURCE_LABEL_SELECT_MODE, ResourceLabeledSelectPaginateSettings, ResourceLabeledSelectSettings } from '@shell/types/components/resourceLabeledSelect';
53
8
 
54
9
  /**
55
10
  * Convenience wrapper around the LabelSelect component to support pagination
@@ -66,6 +21,8 @@ export default defineComponent({
66
21
 
67
22
  components: { LabeledSelect },
68
23
 
24
+ emits: ['update:value'],
25
+
69
26
  props: {
70
27
  /**
71
28
  * Resource to show
@@ -89,7 +46,7 @@ export default defineComponent({
89
46
  },
90
47
 
91
48
  /**
92
- * Specific settings to use when we're showing all results
49
+ * Specific settings to use when we're showing all results in the drop down
93
50
  */
94
51
  allResourcesSettings: {
95
52
  type: Object as PropType<ResourceLabeledSelectSettings>,
@@ -97,7 +54,7 @@ export default defineComponent({
97
54
  },
98
55
 
99
56
  /**
100
- * Specific settings to use when we're showing paginated results
57
+ * Specific settings to use when we're showing paginated results in the drop down
101
58
  */
102
59
  paginatedResourceSettings: {
103
60
  type: Object as PropType<ResourceLabeledSelectPaginateSettings>,
@@ -120,6 +77,7 @@ export default defineComponent({
120
77
  }
121
78
 
122
79
  if (!this.paginate) {
80
+ // The resource won't be paginated and component expects everything up front
123
81
  await this.$store.dispatch(`${ this.inStore }/findAll`, { type: this.resourceType });
124
82
  }
125
83
  },
@@ -148,13 +106,14 @@ export default defineComponent({
148
106
 
149
107
  const all = this.$store.getters[`${ this.inStore }/all`](this.resourceType);
150
108
 
151
- return this.allResourcesSettings?.mapResult ? this.allResourcesSettings.mapResult(all) : all;
109
+ return this.allResourcesSettings?.updateResources ? this.allResourcesSettings.updateResources(all) : all;
152
110
  }
153
111
  },
154
112
 
155
113
  methods: {
156
114
  /**
157
- * Typeof LabelSelectPaginateFn
115
+ * Make the request to fetch the resource given the state of the label select (filter, page, page size, etc see LabelSelectPaginateFn)
116
+ * opts: Typeof LabelSelectPaginateFn
158
117
  */
159
118
  async paginateType(opts: LabelSelectPaginateFnOptions): Promise<LabelSelectPaginateFnResponse> {
160
119
  if (this.paginatedResourceSettings?.overrideRequest) {
@@ -175,9 +134,9 @@ export default defineComponent({
175
134
  const options = this.paginatedResourceSettings?.requestSettings ? this.paginatedResourceSettings.requestSettings(defaultOptions) : defaultOptions;
176
135
  const res = await labelSelectPaginationFunction(options);
177
136
 
178
- return this.paginatedResourceSettings?.mapResult ? {
137
+ return this.paginatedResourceSettings?.updateResources ? {
179
138
  ...res,
180
- page: this.paginatedResourceSettings.mapResult(res.page)
139
+ page: this.paginatedResourceSettings.updateResources(res.page)
181
140
  } : res;
182
141
  },
183
142
  },
@@ -190,5 +149,6 @@ export default defineComponent({
190
149
  :loading="$fetchState.pending"
191
150
  :options="allOfType"
192
151
  :paginate="paginateType"
152
+ @update:value="$emit('update:value', $event)"
193
153
  />
194
154
  </template>
@@ -36,6 +36,7 @@ export default {
36
36
  },
37
37
 
38
38
  async fetch() {
39
+ // Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
39
40
  const hash = await allHash({ allResources: this.$store.dispatch('cluster/findAll', { type: this.type }) });
40
41
 
41
42
  this.allResources = hash.allResources;