@rancher/shell 3.0.4 → 3.0.5-rc.2

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 (270) hide show
  1. package/assets/images/providers/sks.svg +1 -0
  2. package/assets/styles/base/_basic.scss +6 -0
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +1 -0
  5. package/assets/styles/global/_button.scss +1 -0
  6. package/assets/translations/en-us.yaml +65 -15
  7. package/assets/translations/zh-hans.yaml +4 -3
  8. package/chart/monitoring/index.vue +3 -1
  9. package/cloud-credential/aws.vue +2 -0
  10. package/components/ActionDropdownShell.vue +71 -0
  11. package/components/AppModal.vue +18 -4
  12. package/components/AsyncButton.vue +24 -7
  13. package/components/BannerGraphic.vue +1 -0
  14. package/components/CommunityLinks.vue +4 -59
  15. package/components/CopyToClipboardText.vue +2 -1
  16. package/components/CruResource.vue +6 -1
  17. package/components/DetailText.vue +5 -0
  18. package/components/ExplorerMembers.vue +1 -1
  19. package/components/ExplorerProjectsNamespaces.vue +68 -18
  20. package/components/GlobalRoleBindings.vue +5 -1
  21. package/components/GrowlManager.vue +1 -0
  22. package/components/LandingPagePreference.vue +7 -3
  23. package/components/LocaleSelector.vue +39 -95
  24. package/components/ModalManager.vue +55 -0
  25. package/components/ModalWithCard.vue +1 -0
  26. package/components/PromptModal.vue +47 -8
  27. package/components/PromptRemove.vue +1 -0
  28. package/components/PromptRestore.vue +1 -0
  29. package/components/ResourceCancelModal.vue +1 -0
  30. package/components/ResourceDetail/Masthead.vue +38 -12
  31. package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
  32. package/components/ResourceDetail/index.vue +47 -12
  33. package/components/ResourceTable.vue +54 -19
  34. package/components/SideNav.vue +5 -1
  35. package/components/SlideInPanelManager.vue +126 -0
  36. package/components/SortableTable/THead.vue +5 -2
  37. package/components/SortableTable/actions.js +1 -1
  38. package/components/SortableTable/index.vue +64 -51
  39. package/components/SortableTable/paging.js +16 -19
  40. package/components/SortableTable/selection.js +0 -11
  41. package/components/Wizard.vue +2 -2
  42. package/components/__tests__/AsyncButton.test.ts +2 -2
  43. package/components/__tests__/ModalManager.spec.ts +176 -0
  44. package/components/__tests__/PromptModal.test.ts +148 -0
  45. package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
  46. package/components/auth/AuthBanner.vue +13 -11
  47. package/components/auth/Principal.vue +1 -0
  48. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  49. package/components/auth/login/ldap.vue +1 -1
  50. package/components/fleet/FleetResources.vue +21 -6
  51. package/components/form/ArrayList.vue +76 -60
  52. package/components/form/BannerSettings.vue +17 -2
  53. package/components/form/ColorInput.vue +35 -6
  54. package/components/form/Command.vue +6 -15
  55. package/components/form/EnvVars.vue +16 -8
  56. package/components/form/HealthCheck.vue +3 -3
  57. package/components/form/HookOption.vue +11 -16
  58. package/components/form/LabeledSelect.vue +18 -22
  59. package/components/form/LifecycleHooks.vue +3 -3
  60. package/components/form/MatchExpressions.vue +14 -8
  61. package/components/form/NameNsDescription.vue +128 -104
  62. package/components/form/Networking.vue +20 -12
  63. package/components/form/NodeAffinity.vue +31 -23
  64. package/components/form/NodeScheduling.vue +13 -3
  65. package/components/form/NotificationSettings.vue +15 -1
  66. package/components/form/Password.vue +1 -0
  67. package/components/form/PodAffinity.vue +43 -43
  68. package/components/form/Probe.vue +68 -66
  69. package/components/form/ResourceQuota/Project.vue +5 -1
  70. package/components/form/ResourceSelector.vue +7 -9
  71. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +16 -24
  72. package/components/form/SSHKnownHosts/index.vue +30 -13
  73. package/components/form/Security.vue +54 -56
  74. package/components/form/Select.vue +32 -21
  75. package/components/form/ShellInput.vue +5 -1
  76. package/components/form/Tolerations.vue +5 -1
  77. package/components/form/ValueFromResource.vue +134 -121
  78. package/components/form/WorkloadPorts.vue +18 -18
  79. package/components/form/__tests__/ArrayList.test.ts +5 -2
  80. package/components/form/__tests__/ColorInput.test.ts +35 -0
  81. package/components/form/__tests__/LabeledSelect.test.ts +40 -0
  82. package/components/form/__tests__/MatchExpressions.test.ts +12 -12
  83. package/components/form/__tests__/NameNsDescription.test.ts +115 -14
  84. package/components/form/__tests__/Probe.test.ts +12 -8
  85. package/components/form/__tests__/SSHKnownHosts.test.ts +22 -2
  86. package/components/form/__tests__/Select.test.ts +37 -0
  87. package/components/formatter/InternalExternalIP.vue +2 -0
  88. package/components/formatter/SecretData.vue +20 -7
  89. package/components/nav/Group.vue +27 -5
  90. package/components/nav/Header.vue +17 -43
  91. package/components/nav/NamespaceFilter.vue +134 -86
  92. package/components/nav/TopLevelMenu.vue +4 -5
  93. package/components/nav/Type.vue +12 -1
  94. package/components/nav/WindowManager/ContainerLogs.vue +87 -61
  95. package/components/nav/WindowManager/ContainerLogsActions.vue +76 -0
  96. package/components/templates/blank.vue +4 -1
  97. package/components/templates/default.vue +8 -3
  98. package/components/templates/home.vue +10 -1
  99. package/components/templates/plain.vue +10 -4
  100. package/composables/focusTrap.ts +12 -4
  101. package/composables/useRuntimeFlag.ts +29 -0
  102. package/config/router/routes.js +20 -13
  103. package/config/store.js +4 -0
  104. package/config/uiplugins.js +5 -1
  105. package/core/types.ts +12 -6
  106. package/detail/catalog.cattle.io.app.vue +6 -1
  107. package/detail/fleet.cattle.io.bundle.vue +70 -6
  108. package/detail/fleet.cattle.io.gitrepo.vue +1 -1
  109. package/detail/namespace.vue +0 -3
  110. package/detail/node.vue +17 -13
  111. package/detail/provisioning.cattle.io.cluster.vue +72 -6
  112. package/dialog/AddCustomBadgeDialog.vue +1 -1
  113. package/{pages/c/_cluster/uiplugins/AddExtensionRepos.vue → dialog/AddExtensionReposDialog.vue} +72 -42
  114. package/{components/AssignTo.vue → dialog/AssignToDialog.vue} +71 -80
  115. package/dialog/ChangePasswordDialog.vue +106 -0
  116. package/dialog/DeactivateDriverDialog.vue +1 -0
  117. package/{pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue → dialog/DeveloperLoadExtensionDialog.vue} +74 -71
  118. package/dialog/DisableAuthProviderDialog.vue +101 -0
  119. package/dialog/DrainNode.vue +1 -1
  120. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue → dialog/ExtensionCatalogInstallDialog.vue} +100 -88
  121. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue → dialog/ExtensionCatalogUninstallDialog.vue} +69 -57
  122. package/dialog/FeatureFlagListDialog.vue +288 -0
  123. package/dialog/ForceMachineRemoveDialog.vue +5 -2
  124. package/{components/Import.vue → dialog/ImportDialog.vue} +0 -5
  125. package/{pages/c/_cluster/uiplugins/InstallDialog.vue → dialog/InstallExtensionDialog.vue} +124 -106
  126. package/{components/form/SSHKnownHosts → dialog}/KnownHostsEditDialog.vue +52 -59
  127. package/dialog/MoveNamespaceDialog.vue +157 -0
  128. package/dialog/ScalePoolDownDialog.vue +1 -1
  129. package/{components/nav/Jump.vue → dialog/SearchDialog.vue} +34 -14
  130. package/{pages/c/_cluster/uiplugins/UninstallDialog.vue → dialog/UninstallExtensionDialog.vue} +67 -58
  131. package/dialog/WechatDialog.vue +57 -0
  132. package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +16 -3
  133. package/edit/auth/__tests__/oidc.test.ts +152 -109
  134. package/edit/auth/azuread.vue +2 -1
  135. package/edit/auth/github.vue +1 -1
  136. package/edit/auth/googleoauth.vue +5 -1
  137. package/edit/auth/ldap/index.vue +1 -1
  138. package/edit/auth/oidc.vue +38 -5
  139. package/edit/auth/saml.vue +1 -1
  140. package/edit/cloudcredential.vue +24 -9
  141. package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +40 -9
  142. package/edit/management.cattle.io.user.vue +28 -3
  143. package/edit/namespace.vue +1 -4
  144. package/edit/networking.k8s.io.ingress/IngressClass.vue +7 -3
  145. package/edit/networking.k8s.io.ingress/__tests__/IngressClass.test.ts +58 -0
  146. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +14 -2
  147. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +4 -1
  148. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +26 -9
  149. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +8 -8
  150. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +26 -12
  151. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +66 -0
  152. package/edit/provisioning.cattle.io.cluster/__tests__/utils/rke2-test-data.ts +58 -0
  153. package/edit/provisioning.cattle.io.cluster/rke2.vue +49 -41
  154. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +6 -1
  155. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +5 -3
  156. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +33 -2
  157. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +2 -2
  158. package/edit/token.vue +2 -0
  159. package/edit/workload/index.vue +1 -0
  160. package/edit/workload/mixins/workload.js +0 -2
  161. package/initialize/install-plugins.js +2 -1
  162. package/list/harvesterhci.io.management.cluster.vue +4 -1
  163. package/list/management.cattle.io.feature.vue +4 -287
  164. package/list/provisioning.cattle.io.cluster.vue +20 -12
  165. package/machine-config/azure.vue +16 -4
  166. package/mixins/vue-select-overrides.js +0 -4
  167. package/models/__tests__/namespace.test.ts +25 -1
  168. package/models/cloudcredential.js +5 -0
  169. package/models/fleet.cattle.io.cluster.js +8 -2
  170. package/models/fleet.cattle.io.gitrepo.js +8 -34
  171. package/models/kontainerdriver.js +6 -3
  172. package/models/management.cattle.io.feature.js +7 -1
  173. package/models/management.cattle.io.node.js +3 -3
  174. package/models/namespace.js +11 -6
  175. package/models/nodedriver.js +6 -3
  176. package/models/workload.js +4 -1
  177. package/package.json +3 -3
  178. package/pages/about.vue +13 -3
  179. package/pages/account/index.vue +16 -6
  180. package/pages/auth/login.vue +18 -7
  181. package/pages/auth/logout.vue +4 -1
  182. package/pages/auth/setup.vue +2 -0
  183. package/pages/auth/verify.vue +13 -8
  184. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  185. package/pages/c/_cluster/apps/charts/install.vue +26 -26
  186. package/pages/c/_cluster/auth/config/index.vue +10 -12
  187. package/pages/c/_cluster/explorer/EventsTable.vue +38 -33
  188. package/pages/c/_cluster/explorer/index.vue +17 -15
  189. package/pages/c/_cluster/istio/index.vue +2 -2
  190. package/pages/c/_cluster/longhorn/index.vue +1 -1
  191. package/pages/c/_cluster/monitoring/index.vue +1 -1
  192. package/pages/c/_cluster/monitoring/monitor/_namespace/_id.vue +4 -2
  193. package/pages/c/_cluster/monitoring/monitor/create.vue +4 -2
  194. package/pages/c/_cluster/monitoring/route-receiver/_id.vue +4 -2
  195. package/pages/c/_cluster/monitoring/route-receiver/create.vue +5 -2
  196. package/pages/c/_cluster/neuvector/index.vue +1 -1
  197. package/pages/c/_cluster/settings/banners.vue +4 -3
  198. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +8 -10
  199. package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +4 -7
  200. package/pages/c/_cluster/uiplugins/index.vue +98 -55
  201. package/pages/diagnostic.vue +59 -11
  202. package/pages/fail-whale.vue +14 -8
  203. package/pages/home.vue +24 -18
  204. package/pages/prefs.vue +7 -6
  205. package/pages/support/index.vue +4 -1
  206. package/plugins/internal-api/index.ts +37 -0
  207. package/plugins/internal-api/shared/base-api.ts +13 -0
  208. package/plugins/internal-api/shell/shell.api.ts +108 -0
  209. package/plugins/steve/actions.js +0 -12
  210. package/public/index.html +1 -0
  211. package/rancher-components/Card/Card.vue +1 -1
  212. package/rancher-components/Form/Checkbox/Checkbox.test.ts +59 -1
  213. package/rancher-components/Form/Checkbox/Checkbox.vue +27 -3
  214. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +47 -0
  215. package/rancher-components/Form/LabeledInput/LabeledInput.vue +20 -2
  216. package/rancher-components/Form/Radio/RadioButton.test.ts +36 -1
  217. package/rancher-components/Form/Radio/RadioButton.vue +20 -4
  218. package/rancher-components/Form/Radio/RadioGroup.test.ts +60 -0
  219. package/rancher-components/Form/Radio/RadioGroup.vue +52 -10
  220. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
  221. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +5 -0
  222. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +10 -1
  223. package/rancher-components/RcButton/RcButton.vue +2 -1
  224. package/rancher-components/RcButton/types.ts +1 -0
  225. package/rancher-components/RcDropdown/RcDropdown.vue +18 -6
  226. package/rancher-components/RcDropdown/RcDropdownItem.vue +3 -56
  227. package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +68 -0
  228. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +92 -0
  229. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -0
  230. package/rancher-components/RcDropdown/index.ts +2 -0
  231. package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
  232. package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
  233. package/rancher-components/RcDropdown/useDropdownItem.ts +63 -0
  234. package/scripts/extension/bundle +20 -0
  235. package/scripts/extension/helm/charts/ui-plugin-server/templates/cr.yaml +2 -1
  236. package/scripts/extension/helm/charts/ui-plugin-server/values.yaml +2 -0
  237. package/scripts/extension/helmpatch +44 -31
  238. package/scripts/extension/publish +12 -12
  239. package/scripts/typegen.sh +2 -4
  240. package/server/har-file.js +25 -3
  241. package/store/action-menu.js +26 -56
  242. package/store/features.js +2 -1
  243. package/store/index.js +5 -0
  244. package/store/modal.ts +71 -0
  245. package/store/slideInPanel.ts +47 -0
  246. package/store/type-map.js +12 -1
  247. package/store/type-map.utils.ts +4 -4
  248. package/types/global-vue.d.ts +5 -0
  249. package/types/internal-api/shell/growl.d.ts +25 -0
  250. package/types/internal-api/shell/modal.d.ts +77 -0
  251. package/types/internal-api/shell/slideIn.d.ts +15 -0
  252. package/types/resources/fleet.d.ts +0 -14
  253. package/types/shell/index.d.ts +43 -24
  254. package/types/vue-shim.d.ts +4 -1
  255. package/utils/__mocks__/tabbable.js +13 -0
  256. package/utils/__tests__/object.test.ts +38 -4
  257. package/utils/cluster.js +35 -0
  258. package/utils/fleet.ts +15 -73
  259. package/utils/object.js +48 -5
  260. package/utils/validators/formRules/__tests__/index.test.ts +10 -1
  261. package/utils/validators/formRules/index.ts +27 -3
  262. package/utils/validators/machine-pool.ts +20 -0
  263. package/components/DisableAuthProviderModal.vue +0 -114
  264. package/components/MoveModal.vue +0 -166
  265. package/components/PromptChangePassword.vue +0 -123
  266. package/components/fleet/FleetBundleResources.vue +0 -86
  267. package/components/formatter/ExtensionCache.vue +0 -74
  268. package/components/formatter/Port.vue +0 -24
  269. package/components/formatter/SecretType.vue +0 -41
  270. package/types/vue-shim.d +0 -20
@@ -1,6 +1,5 @@
1
1
  <script>
2
2
  import SimpleBox from '@shell/components/SimpleBox';
3
- import AppModal from '@shell/components/AppModal.vue';
4
3
  import Closeable from '@shell/mixins/closeable';
5
4
  import { MANAGEMENT } from '@shell/config/types';
6
5
  import { SETTING } from '@shell/config/settings';
@@ -9,11 +8,11 @@ import { isRancherPrime } from '@shell/config/version';
9
8
  import { fetchLinks } from '@shell/config/home-links';
10
9
  import { processLink } from '@shell/plugins/clean-html';
11
10
 
12
- // i18n-ignore footer.wechat.title, footer.wechat.modalText, footer.wechat.modalText2
11
+ // i18n-ignore footer.wechat.title
13
12
  export default {
14
13
  name: 'CommunityLinks',
15
14
 
16
- components: { SimpleBox, AppModal },
15
+ components: { SimpleBox },
17
16
 
18
17
  props: {
19
18
  linkOptions: {
@@ -87,10 +86,7 @@ export default {
87
86
  },
88
87
  methods: {
89
88
  show() {
90
- this.showWeChatModal = true;
91
- },
92
- close() {
93
- this.showWeChatModal = false;
89
+ this.$store.dispatch('management/promptModal', { component: 'WechatDialog' });
94
90
  }
95
91
  },
96
92
  };
@@ -140,38 +136,12 @@ export default {
140
136
  :aria-label="t('footer.wechat.title')"
141
137
  role="link"
142
138
  @click="show"
143
- @keyup.enter="show"
139
+ @keydown.enter="show"
144
140
  >
145
141
  {{ t('footer.wechat.title') }}
146
142
  </a>
147
143
  </div>
148
144
  </SimpleBox>
149
- <app-modal
150
- v-if="showWeChatModal"
151
- name="wechat-modal"
152
- height="auto"
153
- :width="640"
154
- @close="close"
155
- >
156
- <div class="wechat-modal">
157
- <h1>{{ t('footer.wechat.modalText') }}</h1>
158
- <h1>{{ t('footer.wechat.modalText2') }}</h1>
159
- <div class="qr-img" />
160
- <div>
161
- <button
162
- class="btn role-primary"
163
- tabindex="0"
164
- :aria-label="t('generic.close')"
165
- role="button"
166
- @click="close"
167
- @keyup.enter="close"
168
- @keyup.space="close"
169
- >
170
- {{ t('generic.close') }}
171
- </button>
172
- </div>
173
- </div>
174
- </app-modal>
175
145
  </div>
176
146
  </template>
177
147
 
@@ -188,29 +158,4 @@ export default {
188
158
  .support-link:not(:last-child) {
189
159
  margin-bottom: 15px;
190
160
  }
191
-
192
- .wechat-modal {
193
- margin: 60px;
194
- display: flex;
195
- flex-direction: column;
196
- align-items: center;
197
- }
198
-
199
- .link {
200
- cursor: pointer;
201
- }
202
-
203
- .btn {
204
- margin: 20px auto 0;
205
- }
206
-
207
- .qr-img {
208
- background-image: url('../assets/images/wechat-qr-code.jpg');
209
- background-repeat: no-repeat;
210
- background-size: cover;
211
- background-position: center center;
212
- height: 128px;
213
- width: 128px;
214
- margin: 15px auto 10px;
215
- }
216
161
  </style>
@@ -49,9 +49,10 @@ export default {
49
49
  v-if="text"
50
50
  class="copy-to-clipboard-text"
51
51
  role="button"
52
- :aria-label="t('generic.copyToClipboard')"
53
52
  :class="{ 'copied': copied, 'plain': plain}"
54
53
  href="#"
54
+ :aria-label="t('generic.copyToClipboard')"
55
+ v-bind="$attrs"
55
56
  @click="clicked"
56
57
  @keyup.space="clicked"
57
58
  >
@@ -544,7 +544,10 @@ export default {
544
544
  class="flex-right"
545
545
  >{{ t('generic.moreInfo') }} <i class="icon icon-external-link" /></a>
546
546
  </div>
547
- <hr v-if="subtype.description">
547
+ <hr
548
+ v-if="subtype.description"
549
+ role="none"
550
+ >
548
551
  <div
549
552
  v-if="subtype.description"
550
553
  class="description"
@@ -906,6 +909,8 @@ form.create-resource-container .cru {
906
909
  position: sticky;
907
910
  bottom: 0;
908
911
  background-color: var(--header-bg);
912
+ height: $footer-height;
913
+ box-sizing: border-box;
909
914
 
910
915
  // Overrides outlet padding
911
916
  margin-left: -$space-m;
@@ -58,6 +58,10 @@ export default {
58
58
  },
59
59
 
60
60
  computed: {
61
+ itemLabel() {
62
+ return this.labelKey ? this.t(this.labelKey) : this.label ? this.label : this.t('labels.annotations.singular');
63
+ },
64
+
61
65
  isBinary() {
62
66
  if ( this.binary === null ) {
63
67
  return typeof this.value === 'string' && !asciiLike(this.value);
@@ -186,6 +190,7 @@ export default {
186
190
  :text="value"
187
191
  class="role-tertiary"
188
192
  action-color=""
193
+ :aria-label="t('detailText.copyAriaLabel', {item: itemLabel })"
189
194
  />
190
195
  </div>
191
196
  </template>
@@ -63,7 +63,7 @@ export default {
63
63
  }
64
64
 
65
65
  if (projectRoleTemplateBindingSchema) {
66
- this.$store.dispatch('rancher/findAll', { type: NORMAN.PROJECT_ROLE_TEMPLATE_BINDING }, { root: true })
66
+ this.$store.dispatch('rancher/findAll', { type: NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, opt: { force: true } }, { root: true })
67
67
  .then((bindings) => {
68
68
  this['projectRoleTemplateBindings'] = bindings;
69
69
  this.loadingProjectBindings = false;
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { mapGetters } from 'vuex';
2
+ import { mapGetters, useStore } from 'vuex';
3
3
  import ResourceTable, { defaultTableSortGenerationFn } from '@shell/components/ResourceTable';
4
4
  import { STATE, AGE, NAME, NS_SNAPSHOT_QUOTA } from '@shell/config/table-headers';
5
5
  import { uniq } from '@shell/utils/array';
@@ -9,22 +9,23 @@ import { PanelLocation, ExtensionPoint } from '@shell/core/types';
9
9
  import ExtensionPanel from '@shell/components/ExtensionPanel';
10
10
  import Masthead from '@shell/components/ResourceList/Masthead';
11
11
  import { mapPref, GROUP_RESOURCES, ALL_NAMESPACES, DEV } from '@shell/store/prefs';
12
- import MoveModal from '@shell/components/MoveModal';
13
12
  import ButtonMultiAction from '@shell/components/ButtonMultiAction.vue';
14
-
13
+ import { escapeHtml } from '@shell/utils/string';
15
14
  import { NAMESPACE_FILTER_ALL_ORPHANS } from '@shell/utils/namespace-filter';
16
15
  import ResourceFetch from '@shell/mixins/resource-fetch';
17
16
  import DOMPurify from 'dompurify';
18
17
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
18
+ import ActionMenu from '@shell/components/ActionMenuShell.vue';
19
+ import { useRuntimeFlag } from '@shell/composables/useRuntimeFlag';
19
20
 
20
21
  export default {
21
22
  name: 'ListProjectNamespace',
22
23
  components: {
23
24
  ExtensionPanel,
24
25
  Masthead,
25
- MoveModal,
26
26
  ResourceTable,
27
27
  ButtonMultiAction,
28
+ ActionMenu,
28
29
  },
29
30
  mixins: [ResourceFetch],
30
31
 
@@ -58,6 +59,13 @@ export default {
58
59
  this.projects = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PROJECT, opt: { force: true } });
59
60
  },
60
61
 
62
+ setup() {
63
+ const store = useStore();
64
+ const { featureDropdownMenu } = useRuntimeFlag(store);
65
+
66
+ return { featureDropdownMenu };
67
+ },
68
+
61
69
  data() {
62
70
  return {
63
71
  loadResources: [NAMESPACE],
@@ -79,9 +87,20 @@ export default {
79
87
  }
80
88
  };
81
89
  },
82
-
90
+ watch: {
91
+ actionCb: {
92
+ handler(neu) {
93
+ if (neu?.moveNamespaceCb) {
94
+ this.clearSelection();
95
+ this.$store.dispatch('action-menu/clearCallbackData');
96
+ }
97
+ },
98
+ immediate: true
99
+ }
100
+ },
83
101
  computed: {
84
102
  ...mapGetters(['currentCluster', 'currentProduct']),
103
+ ...mapGetters({ actionCb: 'action-menu/performCallbackData' }),
85
104
  namespaces() {
86
105
  const inStore = this.$store.getters['currentStore'](NAMESPACE);
87
106
 
@@ -155,7 +174,7 @@ export default {
155
174
  rowsWithFakeNamespaces() {
156
175
  const fakeRows = this.projectsWithoutNamespaces.map((project) => {
157
176
  return {
158
- groupByLabel: `${ ('resourceTable.groupLabel.notInAProject') }-${ project.id }`,
177
+ groupById: `${ ('resourceTable.groupLabel.notInAProject') }-${ project.id }`,
159
178
  isFake: true,
160
179
  mainRowKey: project.id,
161
180
  nameDisplay: project.spec?.displayName, // Enable filtering by the project name
@@ -166,8 +185,8 @@ export default {
166
185
 
167
186
  if (this.showMockNotInProjectGroup) {
168
187
  fakeRows.push( {
169
- groupByLabel: this.t('resourceTable.groupLabel.notInAProject'), // Same as the groupByLabel for the namespace model
170
- mainRowKey: 'fake-empty',
188
+ groupById: this.t('resourceTable.groupLabel.notInAProject'),
189
+ mainRowKey: 'fake-empty',
171
190
  });
172
191
  }
173
192
 
@@ -273,6 +292,9 @@ export default {
273
292
  },
274
293
  showCreateNsButton() {
275
294
  return this.groupPreference !== 'namespace';
295
+ },
296
+ projectGroupBy() {
297
+ return this.groupPreference === 'none' ? null : 'groupById';
276
298
  }
277
299
  },
278
300
  methods: {
@@ -336,6 +358,10 @@ export default {
336
358
  return location;
337
359
  },
338
360
 
361
+ getProjectActions(group) {
362
+ return group.rows[0].project;
363
+ },
364
+
339
365
  showProjectAction(event, group) {
340
366
  const project = group.rows[0].project;
341
367
 
@@ -359,7 +385,13 @@ export default {
359
385
  );
360
386
  }
361
387
 
362
- return row.groupByLabel;
388
+ if ( row.groupById === this.notInProjectKey) {
389
+ return this.t('resourceTable.groupLabel.notInAProject');
390
+ }
391
+
392
+ const project = row.project?.nameDisplay || row.project?.id || '';
393
+
394
+ return this.t('resourceTable.groupLabel.project', { name: escapeHtml(project) }, true);
363
395
  },
364
396
 
365
397
  projectDescription(group) {
@@ -431,6 +463,7 @@ export default {
431
463
  :schema="schema"
432
464
  :headers="headers"
433
465
  :rows="filteredRows"
466
+ :group-by="projectGroupBy"
434
467
  :groupable="true"
435
468
  :sort-generation-fn="sortGenerationFn"
436
469
  :loading="loading"
@@ -457,7 +490,7 @@ export default {
457
490
  {{ projectDescription(group.group) }}
458
491
  </div>
459
492
  </div>
460
- <div class="right">
493
+ <div class="right mr-10">
461
494
  <router-link
462
495
  v-if="isNamespaceCreatable && (canSeeProjectlessNamespaces || group.group.key !== notInProjectKey)"
463
496
  class="create-namespace btn btn-sm role-secondary mr-5"
@@ -465,13 +498,26 @@ export default {
465
498
  >
466
499
  {{ t('projectNamespaces.createNamespace') }}
467
500
  </router-link>
468
- <ButtonMultiAction
469
- class="project-action mr-10"
470
- :borderless="true"
471
- :aria-label="t('projectNamespaces.tableActionsLabel', { resource: projectResource(group.group) })"
472
- :invisible="!showProjectActionButton(group.group)"
473
- @click="showProjectAction($event, group.group)"
474
- />
501
+ <template v-if="featureDropdownMenu">
502
+ <ActionMenu
503
+ v-if="showProjectActionButton(group.group)"
504
+ :resource="getProjectActions(group.group)"
505
+ :button-aria-label="t('projectNamespaces.tableActionsLabel', { resource: projectResource(group.group) })"
506
+ />
507
+ <div
508
+ v-else
509
+ class="invisible"
510
+ />
511
+ </template>
512
+ <template v-else>
513
+ <ButtonMultiAction
514
+ class="project-action"
515
+ :borderless="true"
516
+ :aria-label="t('projectNamespaces.tableActionsLabel', { resource: projectResource(group.group) })"
517
+ :invisible="!showProjectActionButton(group.group)"
518
+ @click="showProjectAction($event, group.group)"
519
+ />
520
+ </template>
475
521
  </div>
476
522
  </div>
477
523
  </template>
@@ -532,10 +578,14 @@ export default {
532
578
  </tr>
533
579
  </template>
534
580
  </ResourceTable>
535
- <MoveModal @moving="clearSelection" />
536
581
  </div>
537
582
  </template>
538
583
  <style lang="scss" scoped>
584
+ .invisible {
585
+ display: inline-block;
586
+ min-width: 28px;
587
+ }
588
+
539
589
  .project-namespaces {
540
590
  & :deep() {
541
591
  .project-namespaces-table table {
@@ -49,6 +49,10 @@ export default {
49
49
  userId: {
50
50
  type: String,
51
51
  default: ''
52
+ },
53
+ watchOverride: {
54
+ type: Boolean,
55
+ default: true,
52
56
  }
53
57
  },
54
58
  async fetch() {
@@ -138,7 +142,7 @@ export default {
138
142
  this.update();
139
143
  },
140
144
  userId(userId, oldUserId) {
141
- if (userId === oldUserId) {
145
+ if (userId === oldUserId || this.watchOverride === true) {
142
146
  return;
143
147
  }
144
148
  this.update();
@@ -107,6 +107,7 @@ export default {
107
107
  @click="close(growl)"
108
108
  />
109
109
  <div
110
+ v-if="growl.title"
110
111
  :id="`growl-title-${ growl.id }`"
111
112
  class="growl-text-title"
112
113
  >
@@ -103,20 +103,24 @@ export default {
103
103
 
104
104
  <template>
105
105
  <div>
106
- <p class="set-landing-leadin">
107
- {{ t('landing.landingPrefs.body') }}
108
- </p>
109
106
  <RadioGroup
110
107
  id="login-route"
111
108
  :value="afterLoginRoute"
112
109
  name="login-route"
113
110
  :options="routeRadioOptions"
111
+ :aria-label="`${t('prefs.landing.label')} - ${ t('landing.landingPrefs.body')}`"
114
112
  @update:value="updateLoginRoute"
115
113
  >
114
+ <template #label>
115
+ <p class="set-landing-leadin">
116
+ {{ t('landing.landingPrefs.body') }}
117
+ </p>
118
+ </template>
116
119
  <template #2="{option}">
117
120
  <div class="custom-page">
118
121
  <RadioButton
119
122
  :label="option.label"
123
+ :radio-option-id="option.radioOptionId"
120
124
  :val="false"
121
125
  :value="afterLoginRoute=== 'home' || afterLoginRoute === 'last-visited'"
122
126
  :v-bind="$attrs"
@@ -1,11 +1,17 @@
1
1
  <script>
2
2
  import { mapGetters } from 'vuex';
3
3
  import Select from '@shell/components/form/Select.vue';
4
+ import { RcDropdown, RcDropdownTrigger, RcDropdownItem } from '@components/RcDropdown';
4
5
 
5
6
  export default {
6
- name: 'LocalSelector',
7
+ name: 'LocaleSelector',
7
8
 
8
- components: { Select },
9
+ components: {
10
+ Select,
11
+ RcDropdown,
12
+ RcDropdownItem,
13
+ RcDropdownTrigger,
14
+ },
9
15
 
10
16
  props: {
11
17
  mode: {
@@ -65,71 +71,37 @@ export default {
65
71
  <template>
66
72
  <div>
67
73
  <div v-if="mode === 'login'">
68
- <div
69
- v-if="showLocale"
70
- role="menu"
71
- :aria-label="t('locale.menu')"
72
- class="locale-login-container"
73
- tabindex="0"
74
- @click="openLocaleSelector"
75
- @blur.capture="closeLocaleSelector"
76
- @keyup.enter="openLocaleSelector"
77
- @keyup.space="openLocaleSelector"
78
- >
79
- <v-dropdown
80
- popperClass="localeSelector"
81
- :shown="isLocaleSelectorOpen"
82
- placement="top"
83
- distance="8"
84
- skidding="12"
85
- :triggers="[]"
86
- :autoHide="false"
87
- :flip="false"
88
- :container="false"
89
- @focus.capture="openLocaleSelector"
74
+ <rc-dropdown v-if="showLocale">
75
+ <rc-dropdown-trigger
76
+ data-testid="locale-selector"
77
+ link
78
+ class="baseline"
79
+ :aria-label="t('locale.menu')"
90
80
  >
91
- <a
92
- data-testid="locale-selector"
93
- class="locale-chooser"
81
+ {{ selectedLocaleLabel }}
82
+ <template
83
+ v-if="showIcon"
84
+ #after
94
85
  >
95
- {{ selectedLocaleLabel }}
96
- <i
97
- v-if="showIcon"
98
- class="icon icon-fw icon-sort-down"
99
- />
100
- </a>
101
- <template #popper>
102
- <ul
103
- class="list-unstyled dropdown"
104
- style="margin: -1px;"
105
- >
106
- <li
107
- v-if="showNone"
108
- v-t="'locale.none'"
109
- class="hand"
110
- tabindex="0"
111
- role="menuitem"
112
- @click.stop="switchLocale('none')"
113
- @keyup.enter.stop="switchLocale('none')"
114
- @keyup.space.stop="switchLocale('none')"
115
- />
116
- <li
117
- v-for="(label, name) in availableLocales"
118
- :key="name"
119
- tabindex="0"
120
- role="menuitem"
121
- class="hand"
122
- :lang="name"
123
- @click.stop="switchLocale(name)"
124
- @keyup.enter.stop="switchLocale(name)"
125
- @keyup.space.stop="switchLocale(name)"
126
- >
127
- {{ label }}
128
- </li>
129
- </ul>
86
+ <i class="icon icon-fw icon-sort-down" />
130
87
  </template>
131
- </v-dropdown>
132
- </div>
88
+ </rc-dropdown-trigger>
89
+ <template #dropdownCollection>
90
+ <rc-dropdown-item
91
+ v-if="showNone"
92
+ v-t="'locale.none'"
93
+ @click="switchLocale('none')"
94
+ />
95
+ <rc-dropdown-item
96
+ v-for="(label, name) in availableLocales"
97
+ :key="name"
98
+ :lang="name"
99
+ @click.stop="switchLocale(name)"
100
+ >
101
+ {{ label }}
102
+ </rc-dropdown-item>
103
+ </template>
104
+ </rc-dropdown>
133
105
  </div>
134
106
  <div v-else>
135
107
  <Select
@@ -142,36 +114,8 @@ export default {
142
114
  </div>
143
115
  </template>
144
116
 
145
- <style lang="scss" scoped>
146
- .advanced {
147
- user-select: none;
148
- padding: 0 5px;
149
- line-height: 40px;
150
- font-size: 15px;
151
- font-weight: 500;
152
- }
153
- .content {
154
- background: var(--nav-active);
155
- padding: 10px;
156
- margin-top: 6px;
157
- border-radius: 4px;
158
- }
159
-
160
- .hand:focus-visible {
161
- @include focus-outline;
162
- outline-offset: 4px;
163
- }
164
-
165
- .locale-chooser {
166
- cursor: pointer;
167
-
168
- &:hover {
169
- text-decoration: none;
117
+ <style lang="scss">
118
+ .baseline {
119
+ align-items: baseline;
170
120
  }
171
- }
172
-
173
- .locale-login-container:focus-visible {
174
- @include focus-outline;
175
- outline-offset: 2px;
176
- }
177
121
  </style>
@@ -0,0 +1,55 @@
1
+ <script lang="ts" setup>
2
+ import { computed, ref } from 'vue';
3
+ import { useStore } from 'vuex';
4
+
5
+ import AppModal from '@shell/components/AppModal.vue';
6
+
7
+ const store = useStore();
8
+
9
+ const isOpen = computed(() => store.getters['modal/isOpen']);
10
+ const component = computed(() => store.getters['modal/component']);
11
+ const componentProps = computed(() => store.getters['modal/componentProps']);
12
+ const resources = computed(() => store.getters['modal/resources']);
13
+ const closeOnClickOutside = computed(() => store.getters['modal/closeOnClickOutside']);
14
+ const modalWidth = computed(() => store.getters['modal/modalWidth']);
15
+ // const modalSticky = computed(() => store.getters['modal/modalSticky']); // TODO: Implement sticky modals
16
+
17
+ const backgroundClosing = ref<Function | null>(null);
18
+
19
+ function close() {
20
+ if (!isOpen.value) return;
21
+
22
+ if (backgroundClosing.value) {
23
+ backgroundClosing.value();
24
+ }
25
+
26
+ store.commit('modal/closeModal');
27
+ }
28
+
29
+ function registerBackgroundClosing(fn: Function) {
30
+ backgroundClosing.value = fn;
31
+ }
32
+ </script>
33
+
34
+ <template>
35
+ <Teleport to="#modals">
36
+ <app-modal
37
+ v-if="isOpen && component"
38
+ :click-to-close="closeOnClickOutside"
39
+ :width="modalWidth"
40
+ :style="{ '--prompt-modal-width': modalWidth }"
41
+ :trigger-focus-trap="true"
42
+ tabindex="0"
43
+ @close="close"
44
+ >
45
+ <component
46
+ :is="component"
47
+ v-bind="componentProps || {}"
48
+ data-testid="modal-manager-component"
49
+ :resources="resources"
50
+ :register-background-closing="registerBackgroundClosing"
51
+ @close="close"
52
+ />
53
+ </app-modal>
54
+ </Teleport>
55
+ </template>
@@ -65,6 +65,7 @@ export default {
65
65
  v-bind="$attrs"
66
66
  class="modal"
67
67
  data-testid="mvc__card"
68
+ :trigger-focus-trap="true"
68
69
  @close="$emit('finish', $event)"
69
70
  >
70
71
  <Card