@rancher/shell 3.0.8 → 3.0.9-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.
- package/apis/intf/modal.ts +38 -0
- package/apis/intf/slide-in.ts +3 -1
- package/apis/shell/__tests__/slide-in.test.ts +36 -0
- package/apis/shell/slide-in.ts +5 -1
- package/assets/styles/base/_color.scss +1 -0
- package/assets/styles/base/_typography.scss +14 -5
- package/assets/styles/themes/_light.scss +1 -1
- package/assets/styles/themes/_modern.scss +1 -1
- package/assets/translations/en-us.yaml +94 -33
- package/assets/translations/zh-hans.yaml +0 -2
- package/components/ActionMenuShell.vue +4 -4
- package/components/CodeMirror.vue +4 -3
- package/components/DetailText.vue +54 -7
- package/components/Drawer/Chrome.vue +11 -4
- package/components/Drawer/DrawerCard.vue +19 -0
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +3 -11
- package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +2 -2
- package/components/Drawer/ResourceDetailDrawer/index.vue +3 -20
- package/components/Drawer/types.ts +1 -0
- package/components/DynamicContent/DynamicContentCloseButton.vue +2 -2
- package/components/LocaleSelector.vue +1 -1
- package/components/Markdown.vue +1 -1
- package/components/PopoverCard.vue +3 -3
- package/components/Resource/Detail/Card/ExtrasCard.vue +39 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +142 -0
- package/components/Resource/Detail/Card/StateCard/composables.ts +41 -11
- package/components/Resource/Detail/Card/StateCard/index.vue +3 -9
- package/components/Resource/Detail/Card/StateCard/types.ts +6 -0
- package/components/Resource/Detail/Card/{PodsCard → StatusCard}/index.vue +11 -10
- package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +24 -25
- package/components/Resource/Detail/Cards.vue +27 -0
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +70 -0
- package/components/Resource/Detail/Masthead/index.vue +5 -0
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +4 -2
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -2
- package/components/Resource/Detail/ResourceRow.types.ts +14 -0
- package/components/Resource/Detail/ResourceRow.vue +23 -35
- package/components/Resource/Detail/StatusRow.vue +5 -2
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +38 -7
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +106 -2
- package/components/Resource/Detail/TitleBar/composables.ts +2 -1
- package/components/Resource/Detail/TitleBar/index.vue +41 -6
- package/components/ResourceDetail/Masthead/__tests__/index.test.ts +49 -1
- package/components/ResourceDetail/Masthead/__tests__/latest.test.ts +85 -0
- package/components/ResourceDetail/Masthead/index.vue +1 -0
- package/components/ResourceDetail/Masthead/latest.vue +8 -1
- package/components/ResourceDetail/Masthead/legacy.vue +1 -1
- package/components/Setting.vue +1 -1
- package/components/SortableTable/index.vue +25 -0
- package/components/SortableTable/selection.js +25 -12
- package/components/SortableTable/sorting.js +1 -1
- package/components/Tabbed/Tab.vue +1 -0
- package/components/Tabbed/index.vue +29 -6
- package/components/Window/ContainerShell.vue +10 -13
- package/components/fleet/FleetClusterTargets/TargetsList.vue +47 -29
- package/components/fleet/FleetClusterTargets/index.vue +82 -29
- package/components/fleet/FleetClusters.vue +26 -12
- package/components/fleet/FleetGitRepoPaths.vue +2 -2
- package/components/fleet/FleetResources.vue +14 -0
- package/components/fleet/FleetValuesFrom.vue +2 -2
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +531 -0
- package/components/fleet/__tests__/FleetClusters.test.ts +576 -0
- package/components/fleet/dashboard/ResourceDetails.vue +96 -123
- package/components/form/Conditions.vue +1 -15
- package/components/form/HookOption.vue +5 -0
- package/components/form/LabeledSelect.vue +1 -1
- package/components/form/LifecycleHooks.vue +2 -6
- package/components/form/ResourceLabeledSelect.vue +12 -1
- package/components/form/SeccompProfile.vue +113 -0
- package/components/form/Security.vue +244 -133
- package/components/form/__tests__/LabeledSelect.test.ts +1 -1
- package/components/form/__tests__/SeccompProfile.test.js +124 -0
- package/components/form/__tests__/Security.test.ts +125 -37
- package/components/formatter/Autoscaler.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +4 -1
- package/components/nav/Group.vue +5 -0
- package/components/nav/Header.vue +3 -3
- package/components/nav/HeaderPageActionMenu.vue +1 -1
- package/components/nav/NamespaceFilter.vue +6 -6
- package/components/nav/NotificationCenter/index.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +41 -16
- package/components/nav/TopLevelMenu.vue +45 -25
- package/components/nav/WorkspaceSwitcher.vue +1 -1
- package/components/nav/__tests__/TopLevelMenu.helper.test.ts +277 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +160 -4
- package/components/templates/default.vue +0 -3
- package/components/templates/home.vue +0 -3
- package/components/templates/plain.vue +0 -3
- package/composables/useClickOutside.ts +1 -1
- package/config/product/explorer.js +1 -2
- package/config/types.js +41 -8
- package/detail/__tests__/workload.test.ts +8 -16
- package/detail/catalog.cattle.io.app.vue +6 -0
- package/detail/fleet.cattle.io.cluster.vue +6 -0
- package/detail/workload/index.vue +7 -109
- package/edit/__tests__/projectsecret.test.ts +42 -0
- package/edit/auth/__tests__/oidc.test.ts +50 -0
- package/edit/auth/oidc.vue +68 -44
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +140 -59
- package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +41 -5
- package/edit/projectsecret.vue +29 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +89 -200
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +58 -17
- package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +3 -63
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +82 -14
- package/edit/workload/__tests__/index.test.ts +122 -85
- package/edit/workload/index.vue +48 -29
- package/edit/workload/mixins/workload.js +85 -32
- package/list/catalog.cattle.io.clusterrepo.vue +1 -1
- package/list/projectsecret.vue +2 -2
- package/machine-config/__tests__/vmwarevsphere.test.ts +64 -0
- package/machine-config/amazonec2.vue +2 -2
- package/machine-config/vmwarevsphere.vue +58 -4
- package/mixins/__tests__/brand.spec.ts +18 -13
- package/mixins/__tests__/chart.test.ts +63 -0
- package/mixins/chart.js +56 -51
- package/models/__tests__/catalog.cattle.io.app.test.ts +33 -0
- package/models/__tests__/workload.test.ts +333 -0
- package/models/catalog.cattle.io.app.js +8 -0
- package/models/pod.js +14 -0
- package/models/secret.js +1 -1
- package/models/workload.js +93 -27
- package/package.json +4 -4
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +91 -0
- package/pages/c/_cluster/apps/charts/install.vue +4 -4
- package/pages/c/_cluster/explorer/EventsTable.vue +2 -2
- package/pages/c/_cluster/fleet/index.vue +18 -12
- package/pages/c/_cluster/manager/hostedprovider/index.vue +1 -19
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
- package/pages/c/_cluster/uiplugins/index.vue +1 -1
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +234 -0
- package/plugins/dashboard-store/actions.js +9 -8
- package/plugins/dashboard-store/resource-class.js +97 -1
- package/plugins/steve/__tests__/revision.test.ts +84 -0
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +30 -0
- package/plugins/steve/__tests__/subscribe.spec.ts +134 -0
- package/plugins/steve/mutations.js +9 -0
- package/plugins/steve/revision.ts +26 -0
- package/plugins/steve/steve-pagination-utils.ts +6 -5
- package/plugins/steve/subscribe.js +211 -51
- package/plugins/subscribe-events.ts +2 -2
- package/rancher-components/Form/Checkbox/Checkbox.vue +13 -0
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -1
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +3 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -1
- package/rancher-components/Pill/RcTag/RcTag.vue +1 -1
- package/rancher-components/Pill/index.ts +4 -0
- package/rancher-components/RcButton/RcButton.test.ts +53 -9
- package/rancher-components/RcButton/RcButton.vue +217 -25
- package/rancher-components/RcButton/types.ts +27 -1
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +4 -4
- package/rancher-components/RcDropdown/types.ts +3 -3
- package/rancher-components/RcIcon/RcIcon.test.ts +42 -0
- package/rancher-components/RcIcon/RcIcon.vue +9 -6
- package/rancher-components/RcIcon/types.ts +13 -9
- package/rancher-components/utils/status.test.ts +10 -15
- package/rancher-components/utils/status.ts +5 -6
- package/store/aws.js +18 -12
- package/store/index.js +4 -8
- package/store/type-map.utils.ts +1 -1
- package/types/kube/kube-api.ts +29 -3
- package/types/rancher/steve.api.ts +40 -0
- package/types/shell/index.d.ts +99 -0
- package/types/store/dashboard-store.types.ts +29 -7
- package/types/store/pagination.types.ts +1 -0
- package/types/store/subscribe-events.types.ts +1 -0
- package/utils/__tests__/azure.test.ts +56 -0
- package/utils/__tests__/back-off.test.ts +364 -245
- package/utils/__tests__/error.test.ts +44 -0
- package/utils/__tests__/fleet.test.ts +8 -1
- package/utils/__tests__/pagination-wrapper.test.ts +167 -0
- package/utils/__tests__/version.test.ts +55 -1
- package/utils/azure.js +12 -0
- package/utils/back-off.ts +302 -69
- package/utils/cspAdaptor.ts +32 -14
- package/utils/dynamic-content/__tests__/index.test.ts +1 -1
- package/utils/dynamic-content/__tests__/new-release.test.ts +48 -7
- package/utils/dynamic-content/__tests__/support-notice.test.ts +1 -4
- package/utils/dynamic-content/index.ts +1 -6
- package/utils/dynamic-content/new-release.ts +5 -3
- package/utils/dynamic-content/types.d.ts +0 -1
- package/utils/error.js +9 -0
- package/utils/fleet.ts +2 -2
- package/utils/inactivity.ts +2 -3
- package/utils/pagination-wrapper.ts +101 -17
- package/utils/validators/formRules/index.ts +3 -0
- package/utils/version.js +38 -0
- package/components/auth/AzureWarning.vue +0 -77
- /package/components/Resource/Detail/{Card/PodsCard/Bubble.vue → Bubble.vue} +0 -0
- /package/components/Resource/Detail/Card/{PodsCard → StatusCard}/composable.ts +0 -0
|
@@ -25,6 +25,14 @@ export default {
|
|
|
25
25
|
useQueryParamsForSimpleFiltering: {
|
|
26
26
|
type: Boolean,
|
|
27
27
|
default: false
|
|
28
|
+
},
|
|
29
|
+
removeSubRows: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: false,
|
|
32
|
+
},
|
|
33
|
+
ignoreFilter: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false,
|
|
28
36
|
}
|
|
29
37
|
},
|
|
30
38
|
|
|
@@ -99,9 +107,9 @@ export default {
|
|
|
99
107
|
:schema="schema"
|
|
100
108
|
:headers="headers"
|
|
101
109
|
:rows="rows"
|
|
102
|
-
:sub-rows="true"
|
|
103
110
|
:loading="loading"
|
|
104
111
|
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
112
|
+
:ignore-filter="ignoreFilter"
|
|
105
113
|
key-field="_key"
|
|
106
114
|
>
|
|
107
115
|
<template #cell:workspace="{row}">
|
|
@@ -151,18 +159,22 @@ export default {
|
|
|
151
159
|
>{{ row.bundleInfo.total }}</span>
|
|
152
160
|
</template>
|
|
153
161
|
|
|
154
|
-
<template
|
|
162
|
+
<template
|
|
163
|
+
v-if="!removeSubRows"
|
|
164
|
+
#additional-sub-row="{fullColspan, row, onRowMouseEnter, onRowMouseLeave, showSubRow}"
|
|
165
|
+
>
|
|
155
166
|
<tr
|
|
156
|
-
class="labels-row sub-row"
|
|
167
|
+
class="labels-row additional-sub-row"
|
|
168
|
+
:class="{ 'has-sub-row': showSubRow}"
|
|
157
169
|
@mouseenter="onRowMouseEnter"
|
|
158
170
|
@mouseleave="onRowMouseLeave"
|
|
159
171
|
>
|
|
160
|
-
<template v-if="row.customLabels.length">
|
|
172
|
+
<template v-if="row.customLabels && row.customLabels.length">
|
|
161
173
|
<td> </td>
|
|
162
174
|
<td> </td>
|
|
163
175
|
<td :colspan="fullColspan-2">
|
|
164
176
|
<span
|
|
165
|
-
v-if="row.customLabels.length"
|
|
177
|
+
v-if="row.customLabels && row.customLabels.length"
|
|
166
178
|
class="mt-5"
|
|
167
179
|
> {{ t('fleet.cluster.labels') }}:
|
|
168
180
|
<span
|
|
@@ -184,7 +196,7 @@ export default {
|
|
|
184
196
|
</Tag>
|
|
185
197
|
</span>
|
|
186
198
|
<a
|
|
187
|
-
v-if="row.customLabels.length > 7"
|
|
199
|
+
v-if="row.customLabels && row.customLabels.length > 7"
|
|
188
200
|
href="#"
|
|
189
201
|
@click.prevent="toggleCustomLabels(row)"
|
|
190
202
|
>
|
|
@@ -193,14 +205,16 @@ export default {
|
|
|
193
205
|
</span>
|
|
194
206
|
</td>
|
|
195
207
|
</template>
|
|
196
|
-
<td
|
|
197
|
-
v-else
|
|
198
|
-
:colspan="fullColspan"
|
|
199
|
-
>
|
|
200
|
-
|
|
201
|
-
</td>
|
|
202
208
|
</tr>
|
|
203
209
|
</template>
|
|
210
|
+
<template
|
|
211
|
+
v-else
|
|
212
|
+
#sub-row
|
|
213
|
+
>
|
|
214
|
+
<tr
|
|
215
|
+
class="sub-row"
|
|
216
|
+
/>
|
|
217
|
+
</template>
|
|
204
218
|
</ResourceTable>
|
|
205
219
|
</template>
|
|
206
220
|
|
|
@@ -35,6 +35,19 @@ export default {
|
|
|
35
35
|
},
|
|
36
36
|
|
|
37
37
|
computed: {
|
|
38
|
+
groupOptions() {
|
|
39
|
+
return [{
|
|
40
|
+
tooltipKey: 'resourceTable.groupBy.none',
|
|
41
|
+
icon: 'icon-list-flat',
|
|
42
|
+
value: 'none',
|
|
43
|
+
}, {
|
|
44
|
+
tooltipKey: 'resourceTable.groupBy.cluster',
|
|
45
|
+
hideColumn: 'provider',
|
|
46
|
+
icon: 'icon-folder',
|
|
47
|
+
value: 'clusterId',
|
|
48
|
+
field: 'clusterId',
|
|
49
|
+
}];
|
|
50
|
+
},
|
|
38
51
|
computedResources() {
|
|
39
52
|
const resources = (this.rows || []).map((r) => ({
|
|
40
53
|
tableKey: r.key,
|
|
@@ -107,6 +120,7 @@ export default {
|
|
|
107
120
|
:table-actions="false"
|
|
108
121
|
:row-actions="false"
|
|
109
122
|
:search="search"
|
|
123
|
+
:group-options="groupOptions"
|
|
110
124
|
key-field="tableKey"
|
|
111
125
|
default-sort-by="state"
|
|
112
126
|
>
|
|
@@ -1221,4 +1221,535 @@ describe('component: FleetClusterTargets', () => {
|
|
|
1221
1221
|
});
|
|
1222
1222
|
});
|
|
1223
1223
|
});
|
|
1224
|
+
|
|
1225
|
+
describe('clusterGroup Functionality Tests', () => {
|
|
1226
|
+
describe('clusterGroup Data Management', () => {
|
|
1227
|
+
it('should initialize with empty selectedClusterGroups', () => {
|
|
1228
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1229
|
+
props: {
|
|
1230
|
+
targets: [],
|
|
1231
|
+
namespace: 'fleet-default',
|
|
1232
|
+
mode: _EDIT
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual([]);
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
it('should populate allClusterGroups from store data', async() => {
|
|
1240
|
+
const mockClusterGroups = [
|
|
1241
|
+
{
|
|
1242
|
+
metadata: { namespace: 'fleet-default', name: 'production-group' },
|
|
1243
|
+
nameDisplay: 'Production Group'
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
metadata: { namespace: 'fleet-default', name: 'staging-group' },
|
|
1247
|
+
nameDisplay: 'Staging Group'
|
|
1248
|
+
}
|
|
1249
|
+
];
|
|
1250
|
+
|
|
1251
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1252
|
+
props: {
|
|
1253
|
+
targets: [],
|
|
1254
|
+
namespace: 'fleet-default',
|
|
1255
|
+
mode: _EDIT
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
wrapper.setData({ allClusterGroups: mockClusterGroups });
|
|
1260
|
+
await flushPromises();
|
|
1261
|
+
|
|
1262
|
+
expect(wrapper.vm.allClusterGroups).toStrictEqual(mockClusterGroups);
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
it('should filter clusterGroupsOptions by namespace', () => {
|
|
1266
|
+
const mockClusterGroups = [
|
|
1267
|
+
{
|
|
1268
|
+
metadata: { namespace: 'fleet-default', name: 'group-1' },
|
|
1269
|
+
nameDisplay: 'Group 1'
|
|
1270
|
+
},
|
|
1271
|
+
{
|
|
1272
|
+
metadata: { namespace: 'other-namespace', name: 'group-2' },
|
|
1273
|
+
nameDisplay: 'Group 2'
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
metadata: { namespace: 'fleet-default', name: 'group-3' },
|
|
1277
|
+
nameDisplay: 'Group 3'
|
|
1278
|
+
}
|
|
1279
|
+
];
|
|
1280
|
+
|
|
1281
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1282
|
+
props: {
|
|
1283
|
+
targets: [],
|
|
1284
|
+
namespace: 'fleet-default',
|
|
1285
|
+
mode: _EDIT
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1289
|
+
wrapper.setData({ allClusterGroups: mockClusterGroups });
|
|
1290
|
+
|
|
1291
|
+
const filteredOptions = wrapper.vm.clusterGroupsOptions;
|
|
1292
|
+
|
|
1293
|
+
expect(filteredOptions).toHaveLength(2);
|
|
1294
|
+
expect(filteredOptions).toStrictEqual([
|
|
1295
|
+
{ label: 'Group 1', value: 'group-1' },
|
|
1296
|
+
{ label: 'Group 3', value: 'group-3' }
|
|
1297
|
+
]);
|
|
1298
|
+
});
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
describe('clusterGroup Selection Methods', () => {
|
|
1302
|
+
it('should update selectedClusterGroups when selectClusterGroups is called', async() => {
|
|
1303
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1304
|
+
props: {
|
|
1305
|
+
targets: [],
|
|
1306
|
+
namespace: 'fleet-default',
|
|
1307
|
+
mode: _EDIT
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
const updateSpy = jest.spyOn(wrapper.vm, 'update');
|
|
1312
|
+
|
|
1313
|
+
wrapper.vm.selectClusterGroups(['group-1', 'group-2']);
|
|
1314
|
+
await flushPromises();
|
|
1315
|
+
|
|
1316
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['group-1', 'group-2']);
|
|
1317
|
+
expect(updateSpy).toHaveBeenCalledWith();
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
it('should emit update:value when selectClusterGroups is called', async() => {
|
|
1321
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1322
|
+
props: {
|
|
1323
|
+
targets: [],
|
|
1324
|
+
namespace: 'fleet-default',
|
|
1325
|
+
mode: _EDIT
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
|
|
1329
|
+
wrapper.vm.selectClusterGroups(['test-group']);
|
|
1330
|
+
await flushPromises();
|
|
1331
|
+
|
|
1332
|
+
expect(wrapper.emitted('update:value')).toBeDefined();
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
it('should handle empty array in selectClusterGroups', async() => {
|
|
1336
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1337
|
+
props: {
|
|
1338
|
+
targets: [],
|
|
1339
|
+
namespace: 'fleet-default',
|
|
1340
|
+
mode: _EDIT
|
|
1341
|
+
}
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
// First set some groups
|
|
1345
|
+
wrapper.vm.selectClusterGroups(['group-1', 'group-2']);
|
|
1346
|
+
await flushPromises();
|
|
1347
|
+
|
|
1348
|
+
// Then clear them
|
|
1349
|
+
wrapper.vm.selectClusterGroups([]);
|
|
1350
|
+
await flushPromises();
|
|
1351
|
+
|
|
1352
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual([]);
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
it('should replace existing selectedClusterGroups on new selection', async() => {
|
|
1356
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1357
|
+
props: {
|
|
1358
|
+
targets: [],
|
|
1359
|
+
namespace: 'fleet-default',
|
|
1360
|
+
mode: _EDIT
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
// Initial selection
|
|
1365
|
+
wrapper.vm.selectClusterGroups(['group-1', 'group-2']);
|
|
1366
|
+
await flushPromises();
|
|
1367
|
+
|
|
1368
|
+
// Replace with new selection
|
|
1369
|
+
wrapper.vm.selectClusterGroups(['group-3', 'group-4', 'group-5']);
|
|
1370
|
+
await flushPromises();
|
|
1371
|
+
|
|
1372
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['group-3', 'group-4', 'group-5']);
|
|
1373
|
+
});
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
describe('clusterGroup Target Processing', () => {
|
|
1377
|
+
it('should parse existing targets with clusterGroup in fromTargets', () => {
|
|
1378
|
+
const targets = [
|
|
1379
|
+
{ clusterGroup: 'production-group' },
|
|
1380
|
+
{ clusterGroup: 'staging-group' },
|
|
1381
|
+
{ clusterName: 'specific-cluster' }
|
|
1382
|
+
];
|
|
1383
|
+
|
|
1384
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1385
|
+
props: {
|
|
1386
|
+
targets,
|
|
1387
|
+
namespace: 'fleet-default',
|
|
1388
|
+
mode: _EDIT
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['production-group', 'staging-group']);
|
|
1393
|
+
expect(wrapper.vm.selectedClusters).toStrictEqual(['specific-cluster']);
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
it('should include clusterGroups in normalizeTargets output', () => {
|
|
1397
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1398
|
+
props: {
|
|
1399
|
+
targets: [],
|
|
1400
|
+
namespace: 'fleet-default',
|
|
1401
|
+
mode: _EDIT
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
|
|
1405
|
+
const result = wrapper.vm.normalizeTargets(
|
|
1406
|
+
['cluster-1'],
|
|
1407
|
+
[{ matchLabels: { env: 'prod' } }],
|
|
1408
|
+
['group-1', 'group-2']
|
|
1409
|
+
);
|
|
1410
|
+
|
|
1411
|
+
expect(result).toStrictEqual([
|
|
1412
|
+
{ clusterName: 'cluster-1' },
|
|
1413
|
+
{ clusterSelector: { matchLabels: { env: 'prod' } } },
|
|
1414
|
+
{ clusterGroup: 'group-1' },
|
|
1415
|
+
{ clusterGroup: 'group-2' }
|
|
1416
|
+
]);
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1419
|
+
it('should handle only clusterGroups in normalizeTargets', () => {
|
|
1420
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1421
|
+
props: {
|
|
1422
|
+
targets: [],
|
|
1423
|
+
namespace: 'fleet-default',
|
|
1424
|
+
mode: _EDIT
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
const result = wrapper.vm.normalizeTargets([], [], ['group-1', 'group-2']);
|
|
1429
|
+
|
|
1430
|
+
expect(result).toStrictEqual([
|
|
1431
|
+
{ clusterGroup: 'group-1' },
|
|
1432
|
+
{ clusterGroup: 'group-2' }
|
|
1433
|
+
]);
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
it('should return undefined when normalizeTargets has no inputs', () => {
|
|
1437
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1438
|
+
props: {
|
|
1439
|
+
targets: [],
|
|
1440
|
+
namespace: 'fleet-default',
|
|
1441
|
+
mode: _EDIT
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
|
|
1445
|
+
const result = wrapper.vm.normalizeTargets([], [], []);
|
|
1446
|
+
|
|
1447
|
+
expect(result).toBeUndefined();
|
|
1448
|
+
});
|
|
1449
|
+
|
|
1450
|
+
it('should include clusterGroups in toTargets when targetMode is clusters', () => {
|
|
1451
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1452
|
+
props: {
|
|
1453
|
+
targets: [],
|
|
1454
|
+
namespace: 'fleet-default',
|
|
1455
|
+
mode: _EDIT
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
wrapper.setData({
|
|
1460
|
+
targetMode: 'clusters',
|
|
1461
|
+
selectedClusters: ['cluster-1'],
|
|
1462
|
+
clusterSelectors: [],
|
|
1463
|
+
selectedClusterGroups: ['group-1', 'group-2']
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
const result = wrapper.vm.toTargets();
|
|
1467
|
+
|
|
1468
|
+
expect(result).toStrictEqual([
|
|
1469
|
+
{ clusterName: 'cluster-1' },
|
|
1470
|
+
{ clusterGroup: 'group-1' },
|
|
1471
|
+
{ clusterGroup: 'group-2' }
|
|
1472
|
+
]);
|
|
1473
|
+
});
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
describe('clusterGroup Integration with Target Modes', () => {
|
|
1477
|
+
it('should handle clusterGroup targets and set appropriate targetMode', () => {
|
|
1478
|
+
const targets = [
|
|
1479
|
+
{ clusterGroup: 'test-group' }
|
|
1480
|
+
];
|
|
1481
|
+
|
|
1482
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1483
|
+
props: {
|
|
1484
|
+
targets,
|
|
1485
|
+
namespace: 'fleet-default',
|
|
1486
|
+
mode: _EDIT
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
// ClusterGroup targets should be parsed correctly
|
|
1491
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['test-group']);
|
|
1492
|
+
});
|
|
1493
|
+
});
|
|
1494
|
+
|
|
1495
|
+
it('should handle mixed targets with clusterGroup, clusterName, and clusterSelector', () => {
|
|
1496
|
+
const targets = [
|
|
1497
|
+
{ clusterName: 'specific-cluster' },
|
|
1498
|
+
{ clusterGroup: 'production-group' },
|
|
1499
|
+
{ clusterSelector: { matchLabels: { env: 'staging' } } },
|
|
1500
|
+
{ clusterGroup: 'development-group' }
|
|
1501
|
+
];
|
|
1502
|
+
|
|
1503
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1504
|
+
props: {
|
|
1505
|
+
targets,
|
|
1506
|
+
namespace: 'fleet-default',
|
|
1507
|
+
mode: _EDIT
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
|
|
1511
|
+
expect(wrapper.vm.selectedClusters).toStrictEqual(['specific-cluster']);
|
|
1512
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['production-group', 'development-group']);
|
|
1513
|
+
expect(wrapper.vm.clusterSelectors).toHaveLength(1);
|
|
1514
|
+
expect(wrapper.vm.clusterSelectors[0].matchLabels).toStrictEqual({ env: 'staging' });
|
|
1515
|
+
});
|
|
1516
|
+
|
|
1517
|
+
it('should reset selectedClusterGroups when reset method is called', () => {
|
|
1518
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1519
|
+
props: {
|
|
1520
|
+
targets: [],
|
|
1521
|
+
namespace: 'fleet-default',
|
|
1522
|
+
mode: _EDIT
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
|
|
1526
|
+
// Set some cluster groups
|
|
1527
|
+
wrapper.setData({
|
|
1528
|
+
targetMode: 'clusters',
|
|
1529
|
+
selectedClusterGroups: ['group-1', 'group-2'],
|
|
1530
|
+
selectedClusters: ['cluster-1'],
|
|
1531
|
+
clusterSelectors: [{ key: 1 }]
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
// Call reset
|
|
1535
|
+
wrapper.vm.reset();
|
|
1536
|
+
|
|
1537
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual([]);
|
|
1538
|
+
expect(wrapper.vm.targetMode).toBe('all');
|
|
1539
|
+
expect(wrapper.vm.selectedClusters).toStrictEqual([]);
|
|
1540
|
+
expect(wrapper.vm.clusterSelectors).toStrictEqual([]);
|
|
1541
|
+
});
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
describe('clusterGroup Event Handling and Updates', () => {
|
|
1545
|
+
it('should emit correct targets when both clusters and clusterGroups are selected', async() => {
|
|
1546
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1547
|
+
props: {
|
|
1548
|
+
targets: [],
|
|
1549
|
+
namespace: 'fleet-default',
|
|
1550
|
+
mode: _CREATE
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
// Set target mode and selections
|
|
1555
|
+
wrapper.setData({ targetMode: 'clusters' });
|
|
1556
|
+
wrapper.vm.selectClusters(['cluster-1', 'cluster-2']);
|
|
1557
|
+
await flushPromises();
|
|
1558
|
+
|
|
1559
|
+
wrapper.vm.selectClusterGroups(['group-1']);
|
|
1560
|
+
await flushPromises();
|
|
1561
|
+
|
|
1562
|
+
const emittedValues = wrapper.emitted('update:value');
|
|
1563
|
+
const lastEmitted = emittedValues?.[emittedValues.length - 1][0];
|
|
1564
|
+
|
|
1565
|
+
expect(lastEmitted).toStrictEqual([
|
|
1566
|
+
{ clusterName: 'cluster-1' },
|
|
1567
|
+
{ clusterName: 'cluster-2' },
|
|
1568
|
+
{ clusterGroup: 'group-1' }
|
|
1569
|
+
]);
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
it('should handle clusterGroup selection in CREATE mode with proper event emission', async() => {
|
|
1573
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1574
|
+
props: {
|
|
1575
|
+
targets: [],
|
|
1576
|
+
namespace: 'fleet-default',
|
|
1577
|
+
mode: _CREATE
|
|
1578
|
+
}
|
|
1579
|
+
});
|
|
1580
|
+
|
|
1581
|
+
wrapper.setData({ targetMode: 'clusters' });
|
|
1582
|
+
wrapper.vm.selectClusterGroups(['create-group-1', 'create-group-2']);
|
|
1583
|
+
await flushPromises();
|
|
1584
|
+
|
|
1585
|
+
const emittedValues = wrapper.emitted('update:value');
|
|
1586
|
+
|
|
1587
|
+
expect(emittedValues).toBeDefined();
|
|
1588
|
+
|
|
1589
|
+
const lastEmitted = emittedValues?.[emittedValues.length - 1][0];
|
|
1590
|
+
|
|
1591
|
+
expect(lastEmitted).toStrictEqual([
|
|
1592
|
+
{ clusterGroup: 'create-group-1' },
|
|
1593
|
+
{ clusterGroup: 'create-group-2' }
|
|
1594
|
+
]);
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
it('should update component state correctly when clusterGroups prop changes', async() => {
|
|
1598
|
+
const initialTargets = [{ clusterGroup: 'initial-group' }];
|
|
1599
|
+
|
|
1600
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1601
|
+
props: {
|
|
1602
|
+
targets: initialTargets,
|
|
1603
|
+
namespace: 'fleet-default',
|
|
1604
|
+
mode: _EDIT
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
|
|
1608
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['initial-group']);
|
|
1609
|
+
|
|
1610
|
+
// Update props
|
|
1611
|
+
const newTargets = [
|
|
1612
|
+
{ clusterGroup: 'new-group-1' },
|
|
1613
|
+
{ clusterGroup: 'new-group-2' }
|
|
1614
|
+
];
|
|
1615
|
+
|
|
1616
|
+
await wrapper.setProps({ targets: newTargets });
|
|
1617
|
+
|
|
1618
|
+
// Reset and then parse new targets to simulate component update
|
|
1619
|
+
wrapper.vm.reset();
|
|
1620
|
+
wrapper.vm.fromTargets();
|
|
1621
|
+
|
|
1622
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['new-group-1', 'new-group-2']);
|
|
1623
|
+
});
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1626
|
+
describe('clusterGroup Edge Cases and Error Handling', () => {
|
|
1627
|
+
it('should handle undefined clusterGroup in targets gracefully', () => {
|
|
1628
|
+
const targets = [
|
|
1629
|
+
{ clusterGroup: undefined },
|
|
1630
|
+
{ clusterGroup: 'valid-group' },
|
|
1631
|
+
{ clusterName: 'cluster-1' }
|
|
1632
|
+
];
|
|
1633
|
+
|
|
1634
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1635
|
+
props: {
|
|
1636
|
+
targets: targets as any,
|
|
1637
|
+
namespace: 'fleet-default',
|
|
1638
|
+
mode: _EDIT
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['valid-group']);
|
|
1643
|
+
});
|
|
1644
|
+
|
|
1645
|
+
it('should handle empty string clusterGroup in targets', () => {
|
|
1646
|
+
const targets = [
|
|
1647
|
+
{ clusterGroup: '' },
|
|
1648
|
+
{ clusterGroup: 'valid-group' }
|
|
1649
|
+
];
|
|
1650
|
+
|
|
1651
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1652
|
+
props: {
|
|
1653
|
+
targets: targets as any,
|
|
1654
|
+
namespace: 'fleet-default',
|
|
1655
|
+
mode: _EDIT
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
|
|
1659
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['valid-group']);
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
it('should handle empty allClusterGroups data', () => {
|
|
1663
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1664
|
+
props: {
|
|
1665
|
+
targets: [],
|
|
1666
|
+
namespace: 'fleet-default',
|
|
1667
|
+
mode: _EDIT
|
|
1668
|
+
}
|
|
1669
|
+
});
|
|
1670
|
+
|
|
1671
|
+
wrapper.setData({ allClusterGroups: [] });
|
|
1672
|
+
|
|
1673
|
+
expect(() => wrapper.vm.clusterGroupsOptions).not.toThrow();
|
|
1674
|
+
expect(wrapper.vm.clusterGroupsOptions).toStrictEqual([]);
|
|
1675
|
+
});
|
|
1676
|
+
|
|
1677
|
+
it('should handle clusterGroups with missing nameDisplay', () => {
|
|
1678
|
+
const mockClusterGroups = [
|
|
1679
|
+
{
|
|
1680
|
+
metadata: { namespace: 'fleet-default', name: 'group-1' }
|
|
1681
|
+
// Missing nameDisplay
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
metadata: { namespace: 'fleet-default', name: 'group-2' },
|
|
1685
|
+
nameDisplay: 'Group 2'
|
|
1686
|
+
}
|
|
1687
|
+
];
|
|
1688
|
+
|
|
1689
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1690
|
+
props: {
|
|
1691
|
+
targets: [],
|
|
1692
|
+
namespace: 'fleet-default',
|
|
1693
|
+
mode: _EDIT
|
|
1694
|
+
}
|
|
1695
|
+
});
|
|
1696
|
+
|
|
1697
|
+
wrapper.setData({ allClusterGroups: mockClusterGroups });
|
|
1698
|
+
|
|
1699
|
+
const options = wrapper.vm.clusterGroupsOptions;
|
|
1700
|
+
|
|
1701
|
+
expect(options).toStrictEqual([
|
|
1702
|
+
{ label: undefined, value: 'group-1' },
|
|
1703
|
+
{ label: 'Group 2', value: 'group-2' }
|
|
1704
|
+
]);
|
|
1705
|
+
});
|
|
1706
|
+
});
|
|
1707
|
+
|
|
1708
|
+
describe('clusterGroup Component Lifecycle', () => {
|
|
1709
|
+
it('should preserve clusterGroup selections during component updates', async() => {
|
|
1710
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1711
|
+
props: {
|
|
1712
|
+
targets: [],
|
|
1713
|
+
namespace: 'fleet-default',
|
|
1714
|
+
mode: _EDIT
|
|
1715
|
+
}
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
// Set initial selection
|
|
1719
|
+
wrapper.vm.selectClusterGroups(['persistent-group']);
|
|
1720
|
+
await flushPromises();
|
|
1721
|
+
|
|
1722
|
+
// Trigger component update by changing namespace
|
|
1723
|
+
await wrapper.setProps({ namespace: 'different-namespace' });
|
|
1724
|
+
await flushPromises();
|
|
1725
|
+
|
|
1726
|
+
// In EDIT mode, selections should be preserved unless explicitly reset
|
|
1727
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual(['persistent-group']);
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
it('should clear clusterGroup selections on namespace change in CREATE mode', async() => {
|
|
1731
|
+
const wrapper = mount(FleetClusterTargets, {
|
|
1732
|
+
props: {
|
|
1733
|
+
targets: [],
|
|
1734
|
+
namespace: 'fleet-default',
|
|
1735
|
+
mode: _CREATE
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
// Set initial selection
|
|
1740
|
+
wrapper.vm.selectClusterGroups(['temp-group']);
|
|
1741
|
+
await flushPromises();
|
|
1742
|
+
|
|
1743
|
+
// Mock the reset method call that happens on namespace change in CREATE mode
|
|
1744
|
+
const resetSpy = jest.spyOn(wrapper.vm, 'reset');
|
|
1745
|
+
|
|
1746
|
+
await wrapper.setProps({ namespace: 'different-namespace' });
|
|
1747
|
+
|
|
1748
|
+
// Manually trigger reset to simulate the watcher behavior
|
|
1749
|
+
wrapper.vm.reset();
|
|
1750
|
+
|
|
1751
|
+
expect(resetSpy).toHaveBeenCalledWith();
|
|
1752
|
+
expect(wrapper.vm.selectedClusterGroups).toStrictEqual([]);
|
|
1753
|
+
});
|
|
1754
|
+
});
|
|
1224
1755
|
});
|