@rancher/shell 3.0.11 → 3.0.12-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 (219) hide show
  1. package/assets/images/providers/entraid-black.svg +4 -0
  2. package/assets/images/providers/entraid.svg +9 -0
  3. package/assets/images/vendor/entraid.svg +9 -0
  4. package/assets/styles/app.scss +0 -1
  5. package/assets/styles/base/_mixins.scss +31 -0
  6. package/assets/styles/base/_variables.scss +2 -0
  7. package/assets/styles/themes/_modern.scss +6 -5
  8. package/assets/translations/en-us.yaml +24 -21
  9. package/assets/translations/zh-hans.yaml +4 -11
  10. package/chart/__tests__/S3.test.ts +10 -3
  11. package/components/CountBox.vue +20 -0
  12. package/components/CreateDriver.vue +0 -12
  13. package/components/DetailText.vue +12 -3
  14. package/components/EmptyProductPage.vue +76 -0
  15. package/components/Resource/Detail/CopyToClipboard.vue +1 -2
  16. package/components/Resource/Detail/Metadata/KeyValueRow.vue +9 -3
  17. package/components/Resource/Detail/TitleBar/__tests__/__snapshots__/index.test.ts.snap +31 -0
  18. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +45 -1
  19. package/components/Resource/Detail/TitleBar/index.vue +1 -1
  20. package/components/Resource/Detail/ViewOptions/__tests__/__snapshots__/index.test.ts.snap +9 -0
  21. package/components/Resource/Detail/ViewOptions/__tests__/index.test.ts +62 -0
  22. package/components/Resource/Detail/ViewOptions/index.vue +2 -1
  23. package/components/ResourceList/Masthead.vue +25 -2
  24. package/components/SelectIconGrid.vue +5 -0
  25. package/components/SideNav.vue +13 -0
  26. package/components/__tests__/CountBox.test.ts +72 -0
  27. package/components/__tests__/DetailText.test.ts +113 -0
  28. package/components/__tests__/PromptModal.test.ts +2 -0
  29. package/components/fleet/FleetClusterTargets/index.vue +18 -1
  30. package/components/fleet/FleetClusters.vue +1 -0
  31. package/components/fleet/__tests__/FleetClusters.test.ts +71 -0
  32. package/components/form/InputWithSelect.vue +18 -10
  33. package/components/form/KeyValue.vue +17 -1
  34. package/components/form/LabeledSelect.vue +82 -24
  35. package/components/form/NodeScheduling.vue +17 -3
  36. package/components/form/PrivateRegistry.vue +69 -0
  37. package/components/form/Select.vue +73 -56
  38. package/components/form/ServiceNameSelect.vue +13 -11
  39. package/components/form/__tests__/KeyValue.test.ts +66 -0
  40. package/components/form/__tests__/NodeScheduling.test.ts +9 -0
  41. package/components/form/__tests__/PrivateRegistry.test.ts +133 -0
  42. package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
  43. package/components/formatter/WorkloadHealthScale.vue +3 -1
  44. package/components/nav/Group.vue +33 -9
  45. package/components/nav/Header.vue +56 -10
  46. package/components/nav/NotificationCenter/Notification.vue +4 -1
  47. package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
  48. package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
  49. package/components/nav/TopLevelMenu.vue +15 -1
  50. package/components/nav/Type.vue +8 -7
  51. package/components/nav/WindowManager/index.vue +2 -1
  52. package/components/nav/WorkspaceSwitcher.vue +13 -0
  53. package/components/nav/__tests__/Group.test.ts +67 -0
  54. package/components/nav/__tests__/Header.test.ts +235 -0
  55. package/components/nav/__tests__/Type.test.ts +20 -3
  56. package/components/templates/default.vue +34 -4
  57. package/components/templates/home.vue +12 -25
  58. package/components/templates/plain.vue +13 -26
  59. package/composables/useLabeledFormElement.ts +10 -2
  60. package/composables/useLabeledSelect.ts +60 -0
  61. package/composables/useUserRetentionValidation.ts +1 -49
  62. package/config/cookies.js +0 -1
  63. package/config/labels-annotations.js +1 -0
  64. package/config/pagination-table-headers.js +8 -1
  65. package/config/product/apps.js +2 -1
  66. package/config/product/auth.js +1 -0
  67. package/config/product/backup.js +1 -0
  68. package/config/product/compliance.js +1 -1
  69. package/config/product/explorer.js +25 -6
  70. package/config/product/fleet.js +1 -0
  71. package/config/product/gatekeeper.js +1 -0
  72. package/config/product/istio.js +1 -0
  73. package/config/product/logging.js +1 -0
  74. package/config/product/longhorn.js +2 -1
  75. package/config/product/manager.js +1 -0
  76. package/config/product/monitoring.js +1 -0
  77. package/config/product/navlinks.js +1 -0
  78. package/config/product/neuvector.js +2 -1
  79. package/config/product/settings.js +1 -0
  80. package/config/product/uiplugins.js +1 -0
  81. package/config/query-params.js +1 -0
  82. package/config/router/routes.js +0 -8
  83. package/core/__tests__/plugin-products-helpers.test.ts +454 -0
  84. package/core/__tests__/plugin-products.test.ts +3810 -0
  85. package/core/extension-manager-impl.js +30 -1
  86. package/core/plugin-products-base.ts +392 -0
  87. package/core/plugin-products-extending.ts +44 -0
  88. package/core/plugin-products-helpers.ts +263 -0
  89. package/core/plugin-products-top-level.ts +66 -0
  90. package/core/plugin-products-type-guards.ts +33 -0
  91. package/core/plugin-products.ts +50 -0
  92. package/core/plugin-types.ts +237 -0
  93. package/core/plugin.ts +45 -10
  94. package/core/productDebugger.js +48 -0
  95. package/core/types.ts +97 -11
  96. package/detail/__tests__/__snapshots__/fleet.cattle.io.bundle.test.ts.snap +52 -0
  97. package/detail/__tests__/fleet.cattle.io.bundle.test.ts +171 -0
  98. package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
  99. package/detail/fleet.cattle.io.bundle.vue +21 -34
  100. package/detail/management.cattle.io.fleetworkspace.vue +49 -0
  101. package/dialog/ExtensionCatalogInstallDialog.vue +1 -1
  102. package/dialog/InstallExtensionDialog.vue +6 -27
  103. package/dialog/UninstallExistingExtensionDialog.vue +141 -0
  104. package/dialog/UninstallExtensionDialog.vue +4 -26
  105. package/dialog/__tests__/UninstallExistingExtensionDialog.test.ts +114 -0
  106. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -0
  107. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
  108. package/edit/__tests__/kontainerDriver.test.ts +0 -13
  109. package/edit/__tests__/nodeDriver.test.ts +5 -11
  110. package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
  111. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  112. package/edit/auth/__tests__/oidc.test.ts +54 -0
  113. package/edit/auth/azuread.vue +1 -1
  114. package/edit/auth/oidc.vue +8 -0
  115. package/edit/kontainerDriver.vue +1 -2
  116. package/edit/nodeDriver.vue +0 -2
  117. package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
  118. package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
  119. package/edit/provisioning.cattle.io.cluster/__tests__/Ingress.test.ts +176 -0
  120. package/edit/provisioning.cattle.io.cluster/index.vue +70 -99
  121. package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -1
  122. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +6 -0
  123. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +7 -2
  124. package/initialize/App.vue +29 -2
  125. package/initialize/install-plugins.js +0 -2
  126. package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
  127. package/list/catalog.cattle.io.app.vue +25 -5
  128. package/list/management.cattle.io.feature.vue +1 -1
  129. package/list/management.cattle.io.fleetworkspace.vue +8 -0
  130. package/list/provisioning.cattle.io.cluster.vue +0 -1
  131. package/list/workload.vue +11 -4
  132. package/machine-config/amazonec2.vue +1 -0
  133. package/mixins/chart.js +40 -9
  134. package/mixins/resource-fetch.js +12 -3
  135. package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
  136. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
  137. package/models/__tests__/chart.test.ts +99 -6
  138. package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
  139. package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
  140. package/models/catalog.cattle.io.app.js +21 -17
  141. package/models/catalog.cattle.io.clusterrepo.js +39 -11
  142. package/models/chart.js +33 -19
  143. package/models/fleet-application.js +1 -1
  144. package/models/fleet.cattle.io.bundle.js +1 -1
  145. package/models/kontainerdriver.js +11 -0
  146. package/models/management.cattle.io.authconfig.js +5 -1
  147. package/models/management.cattle.io.cluster.js +0 -53
  148. package/models/management.cattle.io.feature.js +3 -3
  149. package/models/management.cattle.io.kontainerdriver.js +1 -26
  150. package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
  151. package/models/nodedriver.js +7 -0
  152. package/models/pod.js +18 -0
  153. package/models/workload.js +20 -2
  154. package/package.json +13 -13
  155. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +0 -1
  156. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +189 -0
  157. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
  158. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
  159. package/pages/c/_cluster/apps/charts/chart.vue +217 -33
  160. package/pages/c/_cluster/apps/charts/index.vue +2 -2
  161. package/pages/c/_cluster/apps/charts/install.vue +8 -3
  162. package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
  163. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
  164. package/pages/c/_cluster/settings/brand.vue +4 -4
  165. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +39 -2
  166. package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
  167. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +246 -23
  168. package/pages/c/_cluster/uiplugins/index.vue +166 -62
  169. package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -0
  170. package/plugins/dashboard-store/actions.js +3 -2
  171. package/plugins/dashboard-store/resource-class.js +62 -6
  172. package/plugins/plugin.js +16 -0
  173. package/plugins/steve/steve-pagination-utils.ts +7 -0
  174. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +205 -1
  175. package/rancher-components/Form/LabeledInput/LabeledInput.vue +82 -4
  176. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
  177. package/scripts/test-plugins-build.sh +5 -2
  178. package/scripts/typegen.sh +13 -1
  179. package/server/server-middleware.js +2 -2
  180. package/static/humans.txt +1 -0
  181. package/static/robots.txt +34 -0
  182. package/static/welcome-cow.svg +18 -0
  183. package/store/__tests__/catalog.test.ts +161 -11
  184. package/store/__tests__/type-map.test.ts +84 -24
  185. package/store/auth.js +0 -3
  186. package/store/catalog.js +60 -8
  187. package/store/type-map.js +42 -3
  188. package/tsconfig.paths.json +1 -0
  189. package/types/resources/pod.ts +18 -0
  190. package/types/shell/index.d.ts +8539 -2938
  191. package/types/store/dashboard-store.types.ts +5 -0
  192. package/types/store/pagination.types.ts +6 -0
  193. package/utils/__tests__/git.test.ts +270 -0
  194. package/utils/__tests__/inactivity.test.ts +316 -0
  195. package/utils/__tests__/object.test.ts +77 -0
  196. package/utils/__tests__/time.test.ts +14 -1
  197. package/utils/__tests__/url.test.ts +246 -0
  198. package/utils/axios.js +1 -4
  199. package/utils/dynamic-importer.js +3 -2
  200. package/utils/object.js +33 -2
  201. package/utils/pagination-utils.ts +1 -1
  202. package/utils/time.ts +5 -0
  203. package/utils/uiplugins.ts +12 -16
  204. package/utils/validators/__tests__/private-registry.test.ts +76 -0
  205. package/utils/validators/private-registry.ts +28 -0
  206. package/vue.config.js +0 -9
  207. package/assets/images/providers/azuread-black.svg +0 -22
  208. package/assets/images/providers/azuread.svg +0 -25
  209. package/assets/images/vendor/azuread.svg +0 -18
  210. package/assets/styles/fonts/_dots.scss +0 -18
  211. package/components/EmberPage.vue +0 -622
  212. package/components/EmberPageView.vue +0 -39
  213. package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
  214. package/mixins/labeled-form-element.ts +0 -225
  215. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
  216. package/pages/c/_cluster/manager/pages/_page.vue +0 -22
  217. package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
  218. package/plugins/ember-cookie.js +0 -17
  219. package/utils/ember-page.js +0 -30
@@ -1,4 +1,6 @@
1
- import { mount } from '@vue/test-utils';
1
+ import { defineComponent, nextTick } from 'vue';
2
+ import { mount, flushPromises } from '@vue/test-utils';
3
+ import { useForm } from 'vee-validate';
2
4
  import { LabeledInput } from './index';
3
5
 
4
6
  describe('component: LabeledInput', () => {
@@ -105,4 +107,206 @@ describe('component: LabeledInput', () => {
105
107
  expect(mainInput.attributes('aria-label')).toBeUndefined();
106
108
  expect(wrapper.find('label').text()).toBe(label);
107
109
  });
110
+
111
+ describe('vee-validate integration', () => {
112
+ const i18nMock = { $store: { getters: { 'i18n/t': jest.fn() } } };
113
+
114
+ it('without name prop: existing rules-based validation message is shown after blur', async() => {
115
+ const errorMessage = 'This field cannot be empty';
116
+ const notEmptyRule = (v: string) => (!v ? errorMessage : undefined);
117
+
118
+ const wrapper = mount(LabeledInput, {
119
+ propsData: {
120
+ rules: [notEmptyRule],
121
+ value: '',
122
+ },
123
+ mocks: i18nMock
124
+ });
125
+
126
+ await wrapper.find('input').trigger('blur');
127
+ await nextTick();
128
+
129
+ expect(wrapper.vm.validationMessage).toBe(errorMessage);
130
+ });
131
+
132
+ it('without name prop: error CSS class is not applied automatically', async() => {
133
+ const notEmptyRule = (v: string) => (!v ? 'Error' : undefined);
134
+
135
+ const wrapper = mount(LabeledInput, {
136
+ propsData: {
137
+ rules: [notEmptyRule],
138
+ value: '',
139
+ },
140
+ mocks: i18nMock
141
+ });
142
+
143
+ await wrapper.find('input').trigger('blur');
144
+ await nextTick();
145
+
146
+ expect(wrapper.find('.labeled-input').classes()).not.toContain('error');
147
+ });
148
+
149
+ it('with name prop: name attribute is set on the input element', () => {
150
+ const wrapper = mount(LabeledInput, {
151
+ propsData: { name: 'myField' },
152
+ mocks: i18nMock
153
+ });
154
+
155
+ expect(wrapper.find('input').attributes('name')).toStrictEqual('myField');
156
+ });
157
+
158
+ it('with name prop: existing rules run through vee-validate and show error message after blur', async() => {
159
+ const errorMessage = 'Field cannot be empty';
160
+ const notEmptyRule = (v: string) => (!v ? errorMessage : undefined);
161
+
162
+ const wrapper = mount(LabeledInput, {
163
+ propsData: {
164
+ name: 'testField',
165
+ rules: [notEmptyRule],
166
+ value: '',
167
+ },
168
+ mocks: i18nMock
169
+ });
170
+
171
+ await wrapper.find('input').trigger('blur');
172
+ await flushPromises();
173
+
174
+ expect(wrapper.vm.validationMessage).toStrictEqual(errorMessage);
175
+ });
176
+
177
+ it('with name prop: no error class when validation passes', async() => {
178
+ const notEmptyRule = (v: string) => (!v ? 'Error' : undefined);
179
+
180
+ const wrapper = mount(LabeledInput, {
181
+ propsData: {
182
+ name: 'testField',
183
+ rules: [notEmptyRule],
184
+ value: 'valid value',
185
+ },
186
+ mocks: i18nMock
187
+ });
188
+
189
+ await wrapper.find('input').trigger('blur');
190
+ await flushPromises();
191
+
192
+ expect(wrapper.find('.labeled-input').classes()).not.toContain('error');
193
+ expect(wrapper.vm.validationMessage).toBeUndefined();
194
+ });
195
+
196
+ it('with name prop: form-level validation schema error is shown when the form validates', async() => {
197
+ const errorMessage = 'Username is required';
198
+ let triggerFormValidation!: () => Promise<unknown>;
199
+
200
+ const TestWrapper = defineComponent({
201
+ components: { LabeledInput },
202
+ setup() {
203
+ const { validate } = useForm({
204
+ validationSchema: { username: (v: string) => (!v ? errorMessage : true) },
205
+ initialValues: { username: '' }
206
+ });
207
+
208
+ triggerFormValidation = validate;
209
+
210
+ return {};
211
+ },
212
+ template: '<LabeledInput name="username" value="" />'
213
+ });
214
+
215
+ const wrapper = mount(TestWrapper, { global: { mocks: { $store: { getters: { 'i18n/t': jest.fn() } } } } });
216
+
217
+ await triggerFormValidation();
218
+ await flushPromises();
219
+
220
+ const labeledInput = wrapper.findComponent(LabeledInput);
221
+
222
+ expect(labeledInput.vm.validationMessage).toStrictEqual(errorMessage);
223
+ });
224
+
225
+ it('without name prop: error clears when a previously invalid value becomes valid', async() => {
226
+ const errorMessage = 'This field cannot be empty';
227
+ const notEmptyRule = (v: string) => (!v ? errorMessage : undefined);
228
+
229
+ const wrapper = mount(LabeledInput, {
230
+ propsData: {
231
+ rules: [notEmptyRule],
232
+ value: '',
233
+ },
234
+ mocks: i18nMock
235
+ });
236
+
237
+ await wrapper.find('input').trigger('blur');
238
+ await nextTick();
239
+
240
+ expect(wrapper.vm.validationMessage).toBe(errorMessage);
241
+
242
+ await wrapper.setProps({ value: 'valid value' });
243
+ await nextTick();
244
+
245
+ expect(wrapper.vm.validationMessage).toBeUndefined();
246
+ });
247
+
248
+ it('with name prop: error clears when a previously invalid value becomes valid', async() => {
249
+ const errorMessage = 'Field cannot be empty';
250
+ const notEmptyRule = (v: string) => (!v ? errorMessage : undefined);
251
+
252
+ const wrapper = mount(LabeledInput, {
253
+ propsData: {
254
+ name: 'testField',
255
+ rules: [notEmptyRule],
256
+ value: '',
257
+ },
258
+ mocks: i18nMock
259
+ });
260
+
261
+ await wrapper.find('input').trigger('blur');
262
+ await flushPromises();
263
+
264
+ expect(wrapper.vm.validationMessage).toStrictEqual(errorMessage);
265
+
266
+ await wrapper.setProps({ value: 'valid value' });
267
+ await flushPromises();
268
+
269
+ expect(wrapper.vm.validationMessage).toBeUndefined();
270
+ });
271
+
272
+ describe('with both name and rules provided', () => {
273
+ it('shows the error message exactly once when invalid (not duplicated across both validation paths)', async() => {
274
+ const errorMessage = 'Field cannot be empty';
275
+ const notEmptyRule = (v: string) => (!v ? errorMessage : undefined);
276
+
277
+ const wrapper = mount(LabeledInput, {
278
+ propsData: {
279
+ name: 'testField',
280
+ rules: [notEmptyRule],
281
+ value: '',
282
+ },
283
+ mocks: i18nMock
284
+ });
285
+
286
+ await wrapper.find('input').trigger('blur');
287
+ await flushPromises();
288
+
289
+ expect(wrapper.vm.validationMessage).toStrictEqual(errorMessage);
290
+ expect(wrapper.vm.validationMessage).not.toContain(`${ errorMessage }, ${ errorMessage }`);
291
+ });
292
+
293
+ it('shows no error when the value satisfies the rules', async() => {
294
+ const notEmptyRule = (v: string) => (!v ? 'Field cannot be empty' : undefined);
295
+
296
+ const wrapper = mount(LabeledInput, {
297
+ propsData: {
298
+ name: 'testField',
299
+ rules: [notEmptyRule],
300
+ value: 'valid value',
301
+ },
302
+ mocks: i18nMock
303
+ });
304
+
305
+ await wrapper.find('input').trigger('blur');
306
+ await flushPromises();
307
+
308
+ expect(wrapper.vm.validationMessage).toBeUndefined();
309
+ });
310
+ });
311
+ });
108
312
  });
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
- import { defineComponent, inject } from 'vue';
2
+ import { defineComponent, inject, computed, watch } from 'vue';
3
+ import { useField } from 'vee-validate';
3
4
  import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow.vue';
4
5
  import LabeledTooltip from '@components/LabeledTooltip/LabeledTooltip.vue';
5
6
  import { escapeHtml, generateRandomAlphaString } from '@shell/utils/string';
@@ -114,6 +115,15 @@ export default defineComponent({
114
115
  ariaLabel: {
115
116
  type: String,
116
117
  default: ''
118
+ },
119
+
120
+ /**
121
+ * The field name used for vee-validate integration. When provided, the
122
+ * component registers with a parent vee-validate form context
123
+ */
124
+ name: {
125
+ type: String,
126
+ default: null
117
127
  }
118
128
  },
119
129
 
@@ -132,15 +142,72 @@ export default defineComponent({
132
142
 
133
143
  const onInput = inject('onInput', provideProps.onInput);
134
144
 
145
+ // Stable fallback name so useField is always called unconditionally.
146
+ // When no name prop is given the field won't match any form-schema path.
147
+ const standaloneFieldId = `__field__${ generateRandomAlphaString(12) }`;
148
+ const veeFieldName = computed(() => props.name || standaloneFieldId);
149
+
150
+ // Pass existing rules to vee-validate so field-level validation still runs
151
+ const veeValidator = (value: unknown): boolean | string => {
152
+ // Return true when name is absent to avoid duplicating
153
+ // useLabeledFormElement validation
154
+ if (!props.name) {
155
+ return true;
156
+ }
157
+ for (const rule of props.rules as Array<(v: unknown) => string | undefined>) {
158
+ const msg = rule(value);
159
+
160
+ if (msg) {
161
+ return msg;
162
+ }
163
+ }
164
+
165
+ return true;
166
+ };
167
+
168
+ const {
169
+ errorMessage: veeError,
170
+ handleBlur: veeHandleBlur,
171
+ validate: veeValidate,
172
+ value: veeValue,
173
+ } = useField<string | number | Record<string, unknown>>(
174
+ veeFieldName,
175
+ veeValidator,
176
+ {
177
+ initialValue: props.value as string | number,
178
+ validateOnValueUpdate: true,
179
+ }
180
+ );
181
+
182
+ // Keep vee-validate's internal value in sync with the controlled prop value.
183
+ watch(() => props.value, (v) => {
184
+ if (veeValue.value !== v) {
185
+ veeValue.value = v as string | number;
186
+ }
187
+ });
188
+
189
+ const effectiveValidationMessage = computed(() => {
190
+ if (props.name && veeError.value) {
191
+ return veeError.value;
192
+ }
193
+
194
+ return validationMessage.value;
195
+ });
196
+
197
+ const effectiveStatus = computed(() => props.status);
198
+
135
199
  return {
136
200
  focused,
137
201
  onFocusLabeled,
138
202
  onBlurLabeled,
139
203
  onInput,
140
204
  isDisabled,
141
- validationMessage,
205
+ validationMessage: effectiveValidationMessage,
142
206
  requiredField,
143
207
  isCompact,
208
+ veeHandleBlur,
209
+ veeValidate,
210
+ effectiveStatus,
144
211
  };
145
212
  },
146
213
 
@@ -339,6 +406,11 @@ export default defineComponent({
339
406
  onBlur(event: string | FocusEvent): void {
340
407
  this.$emit('blur', event);
341
408
  this.onBlurLabeled();
409
+ // Mark the field as touched in vee-validate without relying on its
410
+ // 'validated-only' guard, then run validation unconditionally so
411
+ // errors surface on the first blur (matching useLabeledFormElement behavior).
412
+ this.veeHandleBlur(event instanceof FocusEvent ? event : undefined, false);
413
+ this.veeValidate();
342
414
  },
343
415
 
344
416
  escapeHtml
@@ -353,7 +425,7 @@ export default defineComponent({
353
425
  focused,
354
426
  [mode]: true,
355
427
  disabled: isDisabled,
356
- [status]: status,
428
+ [effectiveStatus]: effectiveStatus,
357
429
  suffix: hasSuffix,
358
430
  'has-clean-tooltip': hasTooltip,
359
431
  'compact-input': isCompact,
@@ -389,13 +461,14 @@ export default defineComponent({
389
461
  ref="value"
390
462
  v-bind="$attrs"
391
463
  v-stripped-aria-label="!hasLabel && ariaLabel ? ariaLabel : undefined"
464
+ :name="name || undefined"
392
465
  :maxlength="_maxlength"
393
466
  :disabled="isDisabled"
394
467
  :aria-disabled="isDisabled"
395
468
  :value="value || ''"
396
469
  :placeholder="_placeholder"
397
470
  autocapitalize="off"
398
- :class="{ conceal: type === 'multiline-password' }"
471
+ :class="{ 'multiline-password': type === 'multiline-password' }"
399
472
  :aria-describedby="ariaDescribedBy"
400
473
  :aria-required="requiredField"
401
474
  @update:value="onInput"
@@ -410,6 +483,7 @@ export default defineComponent({
410
483
  :role="type === 'number' ? undefined : 'textbox'"
411
484
  :class="{ 'no-label': !hasLabel }"
412
485
  v-bind="$attrs"
486
+ :name="name || undefined"
413
487
  :maxlength="_maxlength"
414
488
  :disabled="isDisabled"
415
489
  :aria-disabled="isDisabled"
@@ -464,6 +538,10 @@ export default defineComponent({
464
538
  </div>
465
539
  </template>
466
540
  <style scoped lang="scss">
541
+ .multiline-password:not(:focus) {
542
+ -webkit-text-security: disc;
543
+ }
544
+
467
545
  .labeled-input.view {
468
546
  input {
469
547
  text-overflow: ellipsis;
@@ -6,7 +6,7 @@ type StateType = boolean | 'true' | 'false' | undefined;
6
6
  export default defineComponent({
7
7
  props: {
8
8
  value: {
9
- type: [Boolean, String, Number],
9
+ type: [Boolean, String, Number, null],
10
10
  default: false
11
11
  },
12
12
 
@@ -236,10 +236,13 @@ function clone_repo_test_extension_build() {
236
236
  # Here we just add the extension that we want to include as a check (all our official extensions should be included here)
237
237
  # Don't forget to add the unit tests exception to clone_repo_test_extension_build function if a new extension has those
238
238
  # TODO: ISSUE #16858 - Reenable the tests as packages migrate to node version 24
239
- # clone_repo_test_extension_build "rancher" "kubewarden-ui" "kubewarden"
239
+ clone_repo_test_extension_build "rancher" "kubewarden-ui" "kubewarden"
240
240
  # clone_repo_test_extension_build "rancher" "elemental-ui" "elemental"
241
241
  clone_repo_test_extension_build "neuvector" "manager-ext" "neuvector-ui-ext"
242
242
  # clone_repo_test_extension_build "StackVista" "rancher-extension-stackstate" "observability"
243
- # clone_repo_test_extension_build "harvester" "harvester-ui-extension" "harvester"
243
+ clone_repo_test_extension_build "harvester" "harvester-ui-extension" "harvester"
244
+ clone_repo_test_extension_build "rancher" "ali-ui" "ali"
245
+ clone_repo_test_extension_build "rancher" "virtual-clusters-ui" "virtual-clusters"
246
+ # clone_repo_test_extension_build "rancher" "rancher-ai-ui" "rancher-ai-ui"
244
247
 
245
248
  echo "All done"
@@ -22,11 +22,13 @@ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/table-headers.js --declara
22
22
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/types.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config > /dev/null
23
23
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/labels-annotations.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config > /dev/null
24
24
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/version.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config > /dev/null
25
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/product/*.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config/product > /dev/null
25
26
 
26
27
  # # store
27
28
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/features.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
28
- ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/prefs.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
29
29
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/plugins.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
30
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/prefs.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
31
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/store-types.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
30
32
 
31
33
  # # plugins
32
34
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/plugins/i18n.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/ > /dev/null
@@ -93,6 +95,16 @@ function processDir() {
93
95
  echo "declare module '${module}' {" >> ${INDEX}
94
96
  cat $entry >> ${INDEX}
95
97
  echo -e "}" >> ${INDEX}
98
+
99
+ # Also generate a module declaration with .js extension for JS source files
100
+ # TypeScript imports use .js extensions for JS files
101
+ if [ "${name}" != "index" ]; then
102
+ local moduleWithJs=${basePkg}/${name}.js
103
+ echo -e "\n// ${moduleWithJs}\n" >> ${INDEX}
104
+ echo "declare module '${moduleWithJs}' {" >> ${INDEX}
105
+ cat $entry >> ${INDEX}
106
+ echo -e "}" >> ${INDEX}
107
+ fi
96
108
  fi
97
109
  fi
98
110
  done
@@ -1,6 +1,6 @@
1
1
  module.exports = function(req, res, next) {
2
- // We do this redirect so that /verify-auth can work with both standalone and
3
- // while dashboard is nested under ember.
2
+ // We do this redirect so that /verify-auth can work with both standalone
3
+ // and hosted configurations.
4
4
  if (req.url.includes('/verify-auth') || req.url.includes('/verify-auth-azure')) {
5
5
  res.writeHead(301, { Location: req.url.replace(/verify-auth(-azure)?/, 'auth/verify') });
6
6
  res.end();
@@ -0,0 +1 @@
1
+ This product was created by the inspirational people at Rancher by SUSE.
@@ -0,0 +1,34 @@
1
+ # ::::::::::::::::::::::::::::::;;;;;;;:::::::::::::::::::;:::::::::::::::::::
2
+ # ::::::::::::::::::::::;+xxxxxxxxxxxxxxxxxxxx+;:::::::::+xxx+::::::::::::::::
3
+ # :::::::::::::::::;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;::::+xxxxxxx+::::::::::::
4
+ # ::::::::::::::+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;+xxxxxxxxxxx+::::::::
5
+ # :::::::::::+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;::;++;:::::
6
+ # :::::::::+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+::::::;+;::::
7
+ # :::::::;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::::;++:++::::
8
+ # ::::::+xxxxxxxxxx++xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+::::;:;xx::::
9
+ # :::::+xxxxxx+;:::::::::;;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+;;;+xxx;:::
10
+ # ::::;xxxxx+:::::::::::::::;+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+;;+xxxxxxxx;:::
11
+ # ::::xxxxx;::::;+xxxxxx++::::;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx++++++++;::::
12
+ # ::::xxxx+::::;xxx+;;;+xxx;::::xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+;;::::::
13
+ # ::::xxxx+::::+xx;:::::;+xx;::::xxxxxxxxxxxxxxxxxxxxxxx;:::;;;;;;;:::::::::::
14
+ # ::::xxxxx;:::+xx+::::::;xxx;::::xxxxxx;:::::::;;+xxxxx;:::::::::::::::::::::
15
+ # ::::;xxxx+;:::;++::::::;xxx;::::;xxxxx+;:::::::::;+xxxx;::::::::::::::::::::
16
+ # :::::+xxxx+;::::::::::;xxxx;:::::;+xxxxxx+;:::::::;+xxxxx+;:::::::::::::::::
17
+ # ::::::;xxxxx++;;:::;;+xxxx;:::::::::::::::::::::::::::::::::::::::::::::::::
18
+ # :::::::;+xxxxxxxxxxxxxxxx;::::::::::::::::::::::::::::::::::::::::::::::::::
19
+ # :::::::::;++xxxxxxxxxx++::::::::::::::::::::::::::::::::::::::::::::::::::::
20
+ # ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
21
+ # ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
22
+ # ::::::::;;;;;::::::::::;;:::::::::;;:::::::::;;;;;::::::::::::;;;;;;;;;:::::
23
+ # :::::+X&&$$$$&$+::::::x&$+:::::::X&X;:::::;X$&$$$$&$x;::::::x&&$$$$$$$$x::::
24
+ # ::::x&$X;::::x$&X:::::x&$+:::::::X&X;::::+$&$;::::+$$X;::::;&$;:::::::::::::
25
+ # :::;$&X;::::::::::::::x&$+:::::::X&X;::::X&$;::::::::::::::+&$::::::::::::::
26
+ # ::::x&&$X;;:::::::::::x&$+:::::::X&X;::::+$&&X+;:::::::::::+&$;:::::::::::::
27
+ # :::::;X$&&&&&&$;::::::x&$+:::::::X&X;::::::x$&&&&&&$+::::::+&&&&&&&&&&+:::::
28
+ # :::::::::::;x$&&$:::::x&$+:::::::X&X;::::::::::::+$&&$+::::+&$::::::::::::::
29
+ # :::::;::::::::X$&;::::+$$x:::::::$&X;:::::;::::::::x$$+::::+&$::::::::::::::
30
+ # :::;$&$X;:::;X$&$:::::;X&$X;:::x$&$+::::;X&$X;:::;x$&$+::::;&$x;;;;;;;;:::::
31
+ # :::::+X&&&&&&&X;::::::::+X$&&&&&$x;:::::::;X$&&&&&&$+:::::::;$&&&&&&&&&x::::
32
+ # :::::::::;;;::::::::::::::::;;:::::::::::::::::;;::::::::::::::::::::::::::;
33
+ User-Agent: *
34
+ Disallow: /
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4
+ viewBox="0 0 305.3 143.2" style="enable-background:new 0 0 305.3 143.2;" xml:space="preserve">
5
+ <style type="text/css">
6
+ .st0{fill:#0876A9;}
7
+ </style>
8
+ <g>
9
+ <path class="st0" d="M305.2,31.5l-3.3-19.9C300.8,5.2,298.3,0,296.4,0c-2,0-3.6,5.3-3.6,11.8v5.2c0,6.5-5.3,11.8-11.8,11.8h-5.2
10
+ c-0.4,0-0.7,0-1.1,0V43c0.4,0,0.7,0,1.1,0h19.5C301.8,43.1,306.2,37.8,305.2,31.5"/>
11
+ <path class="st0" d="M258.3,14.6h-31.7c-0.3,0-0.5,0-0.8,0h-32.5c-0.4,0-0.8,0-1.1,0.1v-3c0-6.5-1.6-11.8-3.6-11.8
12
+ s-4.5,5.2-5.5,11.6l-3.3,19.9c-1.1,6.4,3.4,11.6,9.8,11.6h19.5c2,0,3.9-0.3,5.6-0.9c-0.6,3.3-3.5,5.9-7,5.9h-27.4
13
+ c-4.4,0-7.8-4-7.1-8.4L176,23c0.7-4.4-2.6-8.4-7.1-8.4H32.5c-2.9,0-5.4,1.7-6.5,4.2L0.3,58c-0.4,0.7-0.4,1.5,0.1,2.1l5,5.9
14
+ c0.6,0.7,1.7,0.8,2.5,0.2l17.5-13.8v83.6c0,4,3.2,7.2,7.2,7.2h38.7c4,0,7.2-3.2,7.2-7.2V107c0-4,3.2-7.2,7.2-7.2h96.7
15
+ c4,0,7.2,3.2,7.2,7.2v29.1c0,4,3.2,7.2,7.2,7.2h38.7c4,0,7.2-3.2,7.2-7.2v-31.3h-20.6c-6.5,0-11.8-5.3-11.8-11.8V72.9
16
+ c0-3.8,1.9-7.2,4.7-9.4v24c0,6.5,5.3,11.8,11.8,11.8h31.7c6.5,0,11.8-5.3,11.8-11.8V26.4C270.1,19.9,264.8,14.6,258.3,14.6"/>
17
+ </g>
18
+ </svg>