@rancher/shell 3.0.5-rc.6 → 3.0.5-rc.8
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/assets/brand/classic/metadata.json +3 -0
- package/assets/styles/app.scss +1 -0
- package/assets/styles/base/_color.scss +16 -0
- package/assets/styles/base/_helpers.scss +10 -0
- package/assets/styles/base/_variables.scss +18 -12
- package/assets/styles/fonts/_icons.scss +1 -32
- package/assets/styles/global/_layout.scss +1 -1
- package/assets/styles/themes/_dark.scss +262 -258
- package/assets/styles/themes/_light.scss +538 -509
- package/assets/styles/themes/_modern.scss +914 -0
- package/assets/translations/en-us.yaml +110 -29
- package/chart/__tests__/S3.test.ts +2 -1
- package/cloud-credential/generic.vue +18 -10
- package/cloud-credential/harvester.vue +1 -9
- package/components/AdvancedSection.vue +8 -0
- package/components/ChartReadme.vue +17 -7
- package/components/CodeMirror.vue +1 -1
- package/components/Drawer/Chrome.vue +0 -1
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +27 -28
- package/components/Drawer/ResourceDetailDrawer/composables.ts +4 -24
- package/components/Drawer/ResourceDetailDrawer/index.vue +18 -4
- package/components/InstallHelmCharts.vue +656 -0
- package/components/LazyImage.vue +60 -4
- package/components/Loading.vue +1 -1
- package/components/LocaleSelector.vue +7 -2
- package/components/Markdown.vue +4 -0
- package/components/PaginatedResourceTable.vue +46 -1
- package/components/PromptRestore.vue +22 -44
- package/components/Resource/Detail/Masthead/composable.ts +16 -0
- package/components/Resource/Detail/Masthead/index.vue +37 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +10 -2
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +26 -7
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +8 -1
- package/components/Resource/Detail/Metadata/KeyValue.vue +12 -10
- package/components/Resource/Detail/Metadata/Rectangle.vue +3 -1
- package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +10 -17
- package/components/Resource/Detail/Metadata/composables.ts +9 -7
- package/components/Resource/Detail/Metadata/index.vue +17 -2
- package/components/Resource/Detail/Page.vue +35 -21
- package/components/Resource/Detail/SpacedRow.vue +1 -1
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +8 -9
- package/components/Resource/Detail/TitleBar/composables.ts +5 -5
- package/components/Resource/Detail/TitleBar/index.vue +12 -3
- package/components/ResourceDetail/Masthead/legacy.vue +1 -1
- package/components/ResourceDetail/index.vue +569 -72
- package/components/ResourceList/index.vue +1 -0
- package/components/ResourceTable.vue +6 -1
- package/components/ResourceYaml.vue +1 -1
- package/components/RichTranslation.vue +106 -0
- package/components/SlideInPanelManager.vue +13 -10
- package/components/SortableTable/index.vue +5 -5
- package/components/SortableTable/selection.js +0 -1
- package/components/Tabbed/index.vue +35 -4
- package/components/__tests__/LazyImage.spec.ts +121 -0
- package/components/__tests__/PromptRestore.test.ts +1 -65
- package/components/__tests__/RichTranslation.test.ts +115 -0
- package/components/fleet/FleetStatus.vue +4 -0
- package/components/fleet/dashboard/ResourcePanel.vue +2 -1
- package/components/form/ClusterAppearance.vue +5 -0
- package/components/form/FileImageSelector.vue +1 -1
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -0
- package/components/form/Networking.vue +24 -19
- package/components/form/ProjectMemberEditor.vue +1 -1
- package/components/form/ResourceLabeledSelect.vue +22 -8
- package/components/form/ResourceTabs/index.vue +20 -0
- package/components/form/SecretSelector.vue +9 -0
- package/components/form/SelectOrCreateAuthSecret.vue +6 -3
- package/components/form/__tests__/Networking.test.ts +116 -0
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +3 -38
- package/components/formatter/FleetApplicationSource.vue +25 -17
- package/components/formatter/PodImages.vue +1 -1
- package/components/formatter/__tests__/LiveDate.test.ts +10 -2
- package/components/google/AccountAccess.vue +44 -46
- package/components/nav/Favorite.vue +4 -0
- package/components/nav/Group.vue +4 -1
- package/components/nav/NotificationCenter/Notification.vue +1 -27
- package/components/nav/WindowManager/index.vue +3 -3
- package/composables/resources.ts +2 -2
- package/config/labels-annotations.js +3 -2
- package/config/pagination-table-headers.js +8 -1
- package/config/product/explorer.js +27 -2
- package/config/product/manager.js +0 -1
- package/config/query-params.js +10 -0
- package/config/router/routes.js +21 -1
- package/config/system-namespaces.js +1 -1
- package/config/table-headers.js +30 -1
- package/config/types.js +1 -1
- package/config/version.js +1 -1
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +11 -0
- package/detail/__tests__/workload.test.ts +164 -0
- package/detail/configmap.vue +33 -75
- package/detail/projectsecret.vue +11 -0
- package/detail/provisioning.cattle.io.cluster.vue +351 -369
- package/detail/secret.vue +49 -308
- package/detail/workload/index.vue +38 -21
- package/dialog/InstallExtensionDialog.vue +8 -5
- package/dialog/RotateEncryptionKeyDialog.vue +10 -30
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
- package/edit/auth/ldap/__tests__/config.test.ts +14 -0
- package/edit/auth/ldap/config.vue +24 -0
- package/edit/compliance.cattle.io.clusterscan.vue +1 -1
- package/edit/configmap.vue +4 -1
- package/edit/fleet.cattle.io.gitrepo.vue +5 -6
- package/edit/fleet.cattle.io.helmop.vue +78 -56
- package/edit/logging.banzaicloud.io.output/index.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/awsElasticsearch.vue +5 -6
- package/edit/networking.k8s.io.ingress/Certificate.vue +20 -22
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +8 -3
- package/edit/networking.k8s.io.ingress/Rule.vue +2 -5
- package/edit/networking.k8s.io.ingress/RulePath.vue +17 -11
- package/edit/networking.k8s.io.ingress/__tests__/Certificate.test.ts +165 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +11 -10
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -3
- package/edit/networking.k8s.io.networkpolicy/index.vue +17 -17
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +3 -2
- package/edit/provisioning.cattle.io.cluster/rke2.vue +123 -61
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +9 -7
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +22 -13
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +10 -12
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +39 -38
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +41 -19
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +16 -3
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +32 -33
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryMirrors.vue +9 -10
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +16 -9
- package/edit/secret/basic.vue +1 -0
- package/edit/secret/index.vue +126 -15
- package/edit/workload/index.vue +5 -14
- package/list/projectsecret.vue +345 -0
- package/list/provisioning.cattle.io.cluster.vue +1 -69
- package/list/secret.vue +109 -0
- package/machine-config/__tests__/vmwarevsphere.test.ts +5 -7
- package/machine-config/google.vue +9 -1
- package/machine-config/vmwarevsphere.vue +7 -17
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/chart.js +0 -2
- package/mixins/create-edit-view/impl.js +10 -1
- package/mixins/resource-fetch-api-pagination.js +11 -12
- package/mixins/resource-fetch.js +3 -1
- package/models/__tests__/chart.test.ts +111 -80
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
- package/models/__tests__/node.test.ts +7 -63
- package/models/catalog.cattle.io.app.js +1 -1
- package/models/catalog.cattle.io.operation.js +1 -1
- package/models/chart.js +36 -20
- package/models/cloudcredential.js +2 -163
- package/models/cluster/node.js +7 -7
- package/models/cluster.x-k8s.io.machine.js +3 -3
- package/models/cluster.x-k8s.io.machinedeployment.js +11 -2
- package/models/compliance.cattle.io.clusterscan.js +2 -2
- package/models/configmap.js +4 -0
- package/models/constraints.gatekeeper.sh.constraint.js +1 -1
- package/models/fleet-application.js +0 -17
- package/models/fleet.cattle.io.cluster.js +2 -2
- package/models/fleet.cattle.io.gitrepo.js +15 -1
- package/models/fleet.cattle.io.helmop.js +26 -22
- package/models/management.cattle.io.setting.js +4 -0
- package/models/persistentvolumeclaim.js +1 -1
- package/models/pod.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +39 -67
- package/models/rke.cattle.io.etcdsnapshot.js +1 -1
- package/models/secret.js +161 -2
- package/models/storage.k8s.io.storageclass.js +2 -2
- package/models/workload.js +3 -3
- package/package.json +11 -10
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +1 -0
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +4 -1
- package/pages/c/_cluster/apps/charts/__tests__/AppChartCardFooter.spec.js +41 -0
- package/pages/c/_cluster/apps/charts/chart.vue +422 -174
- package/pages/c/_cluster/apps/charts/index.vue +46 -35
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/projectsecret.vue +24 -0
- package/pages/c/_cluster/fleet/__tests__/index.test.ts +608 -314
- package/pages/c/_cluster/fleet/index.vue +103 -45
- package/pages/c/_cluster/manager/cloudCredential/index.vue +2 -59
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +10 -3
- package/pages/c/_cluster/uiplugins/index.vue +36 -25
- package/plugins/dashboard-store/__tests__/normalize.test.ts +223 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +191 -0
- package/plugins/dashboard-store/__tests__/utils/normalize-usecases.ts +1526 -0
- package/plugins/dashboard-store/actions.js +42 -22
- package/plugins/dashboard-store/normalize.js +29 -17
- package/plugins/dashboard-store/resource-class.js +83 -17
- package/plugins/steve/__tests__/getters.test.ts +1 -1
- package/plugins/steve/__tests__/subscribe.spec.ts +259 -1
- package/plugins/steve/getters.js +8 -2
- package/plugins/steve/resourceWatcher.js +10 -3
- package/plugins/steve/steve-pagination-utils.ts +14 -3
- package/plugins/steve/subscribe.js +192 -19
- package/plugins/steve/worker/web-worker.advanced.js +2 -0
- package/rancher-components/Card/Card.vue +0 -18
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.test.ts +15 -0
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +65 -0
- package/rancher-components/Pill/RcStatusBadge/index.ts +2 -0
- package/rancher-components/Pill/RcStatusBadge/types.ts +5 -0
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.test.ts +33 -0
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +75 -0
- package/rancher-components/Pill/RcStatusIndicator/index.ts +2 -0
- package/rancher-components/Pill/RcStatusIndicator/types.ts +7 -0
- package/rancher-components/Pill/types.ts +2 -0
- package/rancher-components/RcButton/RcButton.vue +1 -1
- package/rancher-components/RcDropdown/RcDropdown.test.ts +98 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +5 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +7 -1
- package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +2 -1
- package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +2 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +21 -0
- package/rancher-components/RcDropdown/useDropdownItem.ts +30 -1
- package/rancher-components/RcItemCard/RcItemCard.test.ts +20 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +40 -6
- package/store/__tests__/catalog.test.ts +93 -1
- package/store/aws.js +19 -8
- package/store/catalog.js +8 -3
- package/types/kube/kube-api.ts +12 -0
- package/types/resources/settings.d.ts +1 -1
- package/types/shell/index.d.ts +643 -585
- package/types/store/pagination.types.ts +16 -6
- package/types/uiplugins.ts +73 -0
- package/utils/__tests__/back-off.test.ts +354 -0
- package/utils/__tests__/create-yaml.test.ts +235 -0
- package/utils/__tests__/kontainer.test.ts +19 -0
- package/utils/__tests__/uiplugins.test.ts +84 -0
- package/utils/back-off.ts +176 -0
- package/utils/create-yaml.js +103 -9
- package/utils/dynamic-importer.js +8 -0
- package/utils/kontainer.ts +3 -5
- package/utils/pagination-utils.ts +18 -0
- package/utils/style.ts +3 -0
- package/utils/uiplugins.ts +29 -2
- package/utils/validators/__tests__/setting.test.js +92 -0
- package/utils/validators/formRules/__tests__/index.test.ts +88 -7
- package/utils/validators/formRules/index.ts +83 -8
- package/utils/validators/setting.js +17 -0
- package/cloud-credential/__tests__/harvester.test.ts +0 -18
- package/components/ResourceDetail/__tests__/index.test.ts +0 -135
- package/components/ResourceDetail/legacy.vue +0 -562
- package/components/formatter/CloudCredExpired.vue +0 -69
- package/models/etcdbackup.js +0 -45
- package/pages/explorer/resource/detail/configmap.vue +0 -42
- package/pages/explorer/resource/detail/secret.vue +0 -50
- package/utils/aws.js +0 -0
|
@@ -4,304 +4,79 @@ import { FLEET } from '@shell/config/types';
|
|
|
4
4
|
|
|
5
5
|
const fleetWorkspaces = [
|
|
6
6
|
{
|
|
7
|
-
id:
|
|
8
|
-
type:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
creationTimestamp: '2025-03-24T08:55:59Z',
|
|
14
|
-
fields: [
|
|
15
|
-
'fleet-local',
|
|
16
|
-
'44d'
|
|
17
|
-
],
|
|
18
|
-
generation: 1,
|
|
19
|
-
name: 'fleet-local',
|
|
20
|
-
ownerReferences: [
|
|
21
|
-
{
|
|
22
|
-
apiVersion: 'v1',
|
|
23
|
-
kind: 'Namespace',
|
|
24
|
-
name: 'fleet-local',
|
|
25
|
-
uid: '481ca51a-a855-4342-8932-a8753b5ff1ff'
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
relationships: [
|
|
29
|
-
{
|
|
30
|
-
fromId: 'fleet-local',
|
|
31
|
-
fromType: 'namespace',
|
|
32
|
-
rel: 'owner',
|
|
33
|
-
state: 'active'
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
resourceVersion: '1362',
|
|
37
|
-
state: {
|
|
38
|
-
error: false,
|
|
39
|
-
message: 'Resource is current',
|
|
40
|
-
name: 'active',
|
|
41
|
-
transitioning: false
|
|
42
|
-
},
|
|
43
|
-
uid: 'c117994d-5d21-4ac5-97be-15f25c5e8801'
|
|
44
|
-
},
|
|
45
|
-
status: {},
|
|
46
|
-
repos: [{ name: 'lots-a' }],
|
|
47
|
-
helmOps: [{ name: 'lots-b' }]
|
|
7
|
+
id: 'fleet-local',
|
|
8
|
+
type: 'management.cattle.io.fleetworkspace',
|
|
9
|
+
kind: 'FleetWorkspace',
|
|
10
|
+
metadata: { name: 'fleet-local' },
|
|
11
|
+
repos: [{ name: 'lots-a' }],
|
|
12
|
+
helmOps: [{ name: 'lots-b' }]
|
|
48
13
|
},
|
|
49
14
|
{
|
|
50
|
-
id:
|
|
51
|
-
type:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
creationTimestamp: '2025-03-24T08:55:59Z',
|
|
57
|
-
fields: [
|
|
58
|
-
'fleet-default',
|
|
59
|
-
'44d'
|
|
60
|
-
],
|
|
61
|
-
generation: 1,
|
|
62
|
-
name: 'fleet-default',
|
|
63
|
-
ownerReferences: [
|
|
64
|
-
{
|
|
65
|
-
apiVersion: 'v1',
|
|
66
|
-
kind: 'Namespace',
|
|
67
|
-
name: 'fleet-default',
|
|
68
|
-
uid: '481ca51a-a855-4342-8932-a8753b5ff1ff'
|
|
69
|
-
}
|
|
70
|
-
],
|
|
71
|
-
relationships: [
|
|
72
|
-
{
|
|
73
|
-
fromId: 'fleet-default',
|
|
74
|
-
fromType: 'namespace',
|
|
75
|
-
rel: 'owner',
|
|
76
|
-
state: 'active'
|
|
77
|
-
}
|
|
78
|
-
],
|
|
79
|
-
resourceVersion: '1362',
|
|
80
|
-
state: {
|
|
81
|
-
error: false,
|
|
82
|
-
message: 'Resource is current',
|
|
83
|
-
name: 'active',
|
|
84
|
-
transitioning: false
|
|
85
|
-
},
|
|
86
|
-
uid: 'c117994d-5d21-4ac5-97be-15f25c5e8801'
|
|
87
|
-
},
|
|
88
|
-
status: {},
|
|
89
|
-
repos: [{ name: 'lots-c' }],
|
|
90
|
-
helmOps: [{ name: 'lots-d' }]
|
|
15
|
+
id: 'fleet-default',
|
|
16
|
+
type: 'management.cattle.io.fleetworkspace',
|
|
17
|
+
kind: 'FleetWorkspace',
|
|
18
|
+
metadata: { name: 'fleet-default' },
|
|
19
|
+
repos: [{ name: 'lots-c' }],
|
|
20
|
+
helmOps: [{ name: 'lots-d' }]
|
|
91
21
|
}
|
|
92
22
|
];
|
|
93
23
|
|
|
94
24
|
const gitRepos = [
|
|
95
25
|
{
|
|
96
|
-
id:
|
|
97
|
-
type:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
annotations: {},
|
|
103
|
-
creationTimestamp: '2025-03-24T09:09:56Z',
|
|
104
|
-
fields: [
|
|
105
|
-
'lots-a',
|
|
106
|
-
'https://github.com/git-repo',
|
|
107
|
-
'420bf95e3d5ac89a7801deb0bc1206a5abc54b45',
|
|
108
|
-
'17/20',
|
|
109
|
-
'Modified(2) [Cluster fleet-default/fleet-1; configmap.v1 lots-a/test-config-eight missing'
|
|
110
|
-
],
|
|
111
|
-
finalizers: [
|
|
112
|
-
'fleet.cattle.io/gitrepo-finalizer'
|
|
113
|
-
],
|
|
114
|
-
generation: 1,
|
|
115
|
-
name: 'lots-a',
|
|
116
|
-
namespace: 'fleet-default',
|
|
117
|
-
resourceVersion: '22615976',
|
|
118
|
-
state: {
|
|
119
|
-
error: false,
|
|
120
|
-
message: '',
|
|
121
|
-
name: 'modified',
|
|
122
|
-
transitioning: false
|
|
123
|
-
},
|
|
124
|
-
uid: 'd70cd36b-9cb9-4913-b0ec-0e3a2d7b92fd'
|
|
125
|
-
},
|
|
126
|
-
spec: {
|
|
127
|
-
branch: 'main',
|
|
128
|
-
paths: [
|
|
129
|
-
'scale'
|
|
130
|
-
],
|
|
131
|
-
repo: 'https://github.com/git-repo',
|
|
132
|
-
targetNamespace: 'lots-a',
|
|
133
|
-
targets: [
|
|
134
|
-
{ clusterSelector: {} }
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
|
-
status: {
|
|
138
|
-
commit: '420bf95e3d5ac89a7801deb0bc1206a5abc54b45',
|
|
139
|
-
conditions: [
|
|
140
|
-
{
|
|
141
|
-
error: true,
|
|
142
|
-
lastUpdateTime: '2025-05-04T16:33:15Z',
|
|
143
|
-
message: 'Modified(2) [Cluster fleet-default/fleet-1]; configmap.v1 lots-a/test-config-eight missing',
|
|
144
|
-
status: 'False',
|
|
145
|
-
transitioning: true,
|
|
146
|
-
type: 'Ready'
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
error: false,
|
|
150
|
-
lastUpdateTime: '2025-05-07T09:39:08Z',
|
|
151
|
-
status: 'True',
|
|
152
|
-
transitioning: false,
|
|
153
|
-
type: 'GitPolling'
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
error: false,
|
|
157
|
-
lastUpdateTime: '2025-03-24T09:09:57Z',
|
|
158
|
-
status: 'False',
|
|
159
|
-
transitioning: false,
|
|
160
|
-
type: 'Reconciling'
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
error: false,
|
|
164
|
-
lastUpdateTime: '2025-03-24T09:09:57Z',
|
|
165
|
-
status: 'False',
|
|
166
|
-
transitioning: false,
|
|
167
|
-
type: 'Stalled'
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
error: false,
|
|
171
|
-
lastUpdateTime: '2025-03-24T09:09:57Z',
|
|
172
|
-
status: 'True',
|
|
173
|
-
transitioning: false,
|
|
174
|
-
type: 'Accepted'
|
|
175
|
-
}
|
|
176
|
-
],
|
|
177
|
-
desiredReadyClusters: 2,
|
|
178
|
-
display: {
|
|
179
|
-
readyBundleDeployments: '1/2',
|
|
180
|
-
state: 'Modified'
|
|
181
|
-
},
|
|
182
|
-
gitJobStatus: 'Current',
|
|
183
|
-
lastPollingTriggered: '2025-05-07T13:34:43Z',
|
|
184
|
-
observedGeneration: 1,
|
|
185
|
-
perClusterResourceCounts: {
|
|
186
|
-
'fleet-default/fleet-1': {
|
|
187
|
-
desiredReady: 2,
|
|
188
|
-
missing: 1,
|
|
189
|
-
modified: 0,
|
|
190
|
-
notReady: 0,
|
|
191
|
-
orphaned: 0,
|
|
192
|
-
ready: 1,
|
|
193
|
-
unknown: 0,
|
|
194
|
-
waitApplied: 0
|
|
195
|
-
},
|
|
196
|
-
'fleet-default/fleet-2': {
|
|
197
|
-
desiredReady: 2,
|
|
198
|
-
missing: 1,
|
|
199
|
-
modified: 0,
|
|
200
|
-
notReady: 0,
|
|
201
|
-
orphaned: 0,
|
|
202
|
-
ready: 1,
|
|
203
|
-
unknown: 0,
|
|
204
|
-
waitApplied: 0
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
readyClusters: 0,
|
|
208
|
-
resourceCounts: {
|
|
209
|
-
desiredReady: 2,
|
|
210
|
-
missing: 1,
|
|
211
|
-
modified: 0,
|
|
212
|
-
notReady: 0,
|
|
213
|
-
orphaned: 0,
|
|
214
|
-
ready: 1,
|
|
215
|
-
unknown: 0,
|
|
216
|
-
waitApplied: 0
|
|
217
|
-
},
|
|
218
|
-
resources: [
|
|
219
|
-
{
|
|
220
|
-
apiVersion: 'v1',
|
|
221
|
-
id: 'lots-a/test-config-eight',
|
|
222
|
-
kind: 'ConfigMap',
|
|
223
|
-
name: 'test-config-eight',
|
|
224
|
-
namespace: 'lots-a',
|
|
225
|
-
perClusterState: {
|
|
226
|
-
missing: [
|
|
227
|
-
'fleet-default/fleet-1'
|
|
228
|
-
]
|
|
229
|
-
},
|
|
230
|
-
state: 'Missing',
|
|
231
|
-
type: 'configmap'
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
apiVersion: 'v1',
|
|
235
|
-
id: 'lots-a/test-config-five',
|
|
236
|
-
kind: 'ConfigMap',
|
|
237
|
-
name: 'test-config-five',
|
|
238
|
-
namespace: 'lots-a',
|
|
239
|
-
perClusterState: {
|
|
240
|
-
missing: [
|
|
241
|
-
'fleet-default/fleet-1'
|
|
242
|
-
],
|
|
243
|
-
ready: [
|
|
244
|
-
'fleet-default/fleet-2'
|
|
245
|
-
]
|
|
246
|
-
},
|
|
247
|
-
state: 'Missing',
|
|
248
|
-
type: 'configmap'
|
|
249
|
-
}
|
|
250
|
-
],
|
|
251
|
-
summary: {
|
|
252
|
-
desiredReady: 2,
|
|
253
|
-
modified: 1,
|
|
254
|
-
nonReadyResources: [
|
|
255
|
-
{
|
|
256
|
-
bundleState: 'Modified',
|
|
257
|
-
modifiedStatus: [
|
|
258
|
-
{
|
|
259
|
-
apiVersion: 'v1',
|
|
260
|
-
kind: 'ConfigMap',
|
|
261
|
-
missing: true,
|
|
262
|
-
name: 'test-config-five',
|
|
263
|
-
namespace: 'lots-a'
|
|
264
|
-
}
|
|
265
|
-
],
|
|
266
|
-
name: 'lots-a-scale-lotsofbundles-five'
|
|
267
|
-
}
|
|
268
|
-
],
|
|
269
|
-
ready: 1
|
|
270
|
-
}
|
|
271
|
-
}
|
|
26
|
+
id: 'fleet-default/lots-a',
|
|
27
|
+
type: FLEET.GIT_REPO,
|
|
28
|
+
metadata: { namespace: 'fleet-local' },
|
|
29
|
+
nameDisplay: 'lots-a',
|
|
30
|
+
stateDisplay: 'Active',
|
|
31
|
+
stateSort: 'Active'
|
|
272
32
|
}
|
|
273
33
|
];
|
|
274
34
|
|
|
275
|
-
const
|
|
35
|
+
const helmOps = [
|
|
36
|
+
{
|
|
37
|
+
id: 'helm-op-1',
|
|
38
|
+
type: FLEET.HELM_OP,
|
|
39
|
+
metadata: { namespace: 'fleet-local' },
|
|
40
|
+
nameDisplay: 'helm-op-1',
|
|
41
|
+
stateDisplay: 'Active',
|
|
42
|
+
stateSort: 'Active'
|
|
43
|
+
}
|
|
44
|
+
];
|
|
276
45
|
|
|
277
46
|
const requiredSetup = (computed = {}, dataProps = {}) => {
|
|
278
47
|
return {
|
|
279
48
|
global: {
|
|
280
|
-
|
|
281
|
-
mocks: {
|
|
49
|
+
mocks: {
|
|
282
50
|
$store: {
|
|
283
51
|
getters: {
|
|
284
|
-
currentProduct:
|
|
285
|
-
'management/schemaFor':
|
|
286
|
-
'rancher/byId':
|
|
287
|
-
'i18n/t':
|
|
288
|
-
t:
|
|
52
|
+
currentProduct: { inStore: 'cluster' },
|
|
53
|
+
'management/schemaFor': jest.fn(),
|
|
54
|
+
'rancher/byId': jest.fn(),
|
|
55
|
+
'i18n/t': (text: string) => text,
|
|
56
|
+
t: (text: string) => text,
|
|
57
|
+
'slideInPanel/isOpen': false,
|
|
58
|
+
'slideInPanel/isClosing': false,
|
|
289
59
|
},
|
|
290
|
-
dispatch: jest.fn()
|
|
60
|
+
dispatch: jest.fn(),
|
|
61
|
+
commit: jest.fn(),
|
|
291
62
|
},
|
|
292
|
-
$fetchState: {},
|
|
63
|
+
$fetchState: { pending: false },
|
|
64
|
+
$router: { push: jest.fn() },
|
|
65
|
+
$shell: { slideInPanel: jest.fn() },
|
|
66
|
+
t: (key: string) => key,
|
|
67
|
+
},
|
|
68
|
+
stubs: {
|
|
69
|
+
'router-link': RouterLinkStub, ButtonGroup: true, Checkbox: true, RcButton: true, ResourcePanel: true, FleetApplications: true, ResourceCard: true, ResourceDetails: true, EmptyDashboard: true
|
|
293
70
|
},
|
|
294
|
-
stubs: { 'router-link': RouterLinkStub },
|
|
295
71
|
directives: { 'trim-whitespace': (id: any) => id },
|
|
296
72
|
},
|
|
297
73
|
computed: {
|
|
298
74
|
...Dashboard.computed,
|
|
299
75
|
allNamespaces: () => [],
|
|
300
|
-
workspaces: () => [],
|
|
301
76
|
...computed
|
|
302
77
|
},
|
|
303
78
|
data: () => ({
|
|
304
|
-
presetVersion: '',
|
|
79
|
+
presetVersion: '1.2.3',
|
|
305
80
|
permissions: {},
|
|
306
81
|
FLEET,
|
|
307
82
|
[FLEET.GIT_REPO]: [],
|
|
@@ -311,7 +86,6 @@ const requiredSetup = (computed = {}, dataProps = {}) => {
|
|
|
311
86
|
fleetWorkspaces: [],
|
|
312
87
|
viewModeOptions: [
|
|
313
88
|
{
|
|
314
|
-
// tooltipKey: 'fleet.dashboard.viewMode.table',
|
|
315
89
|
icon: 'icon-list-flat',
|
|
316
90
|
value: 'flat',
|
|
317
91
|
disabled: true
|
|
@@ -322,7 +96,7 @@ const requiredSetup = (computed = {}, dataProps = {}) => {
|
|
|
322
96
|
value: 'cards',
|
|
323
97
|
},
|
|
324
98
|
],
|
|
325
|
-
viewMode:
|
|
99
|
+
viewMode: 'cards',
|
|
326
100
|
isWorkspaceCollapsed: {},
|
|
327
101
|
isStateCollapsed: {},
|
|
328
102
|
typeFilter: {},
|
|
@@ -334,35 +108,47 @@ const requiredSetup = (computed = {}, dataProps = {}) => {
|
|
|
334
108
|
};
|
|
335
109
|
|
|
336
110
|
describe('component: FleetDashboard', () => {
|
|
337
|
-
it('no workspaces', () => {
|
|
111
|
+
it('should render NoWorkspaces component when no workspaces are available and user has no permissions', async() => {
|
|
338
112
|
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
339
113
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
expect(workspaceCards.exists()).toBeFalsy();
|
|
345
|
-
expect(noWorkspaces.exists()).toBeTruthy();
|
|
346
|
-
expect(noResources.exists()).toBeFalsy();
|
|
114
|
+
await wrapper.vm.$nextTick();
|
|
115
|
+
expect(wrapper.findComponent({ name: 'Loading' }).exists()).toBe(false);
|
|
116
|
+
expect(wrapper.findComponent({ name: 'NoWorkspaces' }).exists()).toBe(true);
|
|
117
|
+
expect(wrapper.findComponent({ name: 'EmptyDashboard' }).exists()).toBe(false);
|
|
347
118
|
});
|
|
348
119
|
|
|
349
|
-
it('no
|
|
120
|
+
it('should render EmptyDashboard component when workspaces exist but no gitRepos or helmOps', async() => {
|
|
350
121
|
const wrapper = mount(Dashboard, {
|
|
351
122
|
...requiredSetup(
|
|
352
123
|
{ workspaces: () => fleetWorkspaces },
|
|
353
124
|
),
|
|
354
125
|
});
|
|
355
126
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
127
|
+
await wrapper.vm.$nextTick();
|
|
128
|
+
expect(wrapper.findComponent({ name: 'Loading' }).exists()).toBe(false);
|
|
129
|
+
expect(wrapper.findComponent({ name: 'NoWorkspaces' }).exists()).toBe(false);
|
|
130
|
+
expect(wrapper.findComponent({ name: 'EmptyDashboard' }).exists()).toBe(true);
|
|
131
|
+
});
|
|
359
132
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
133
|
+
it('should render the dashboard when workspaces and resources exist', async() => {
|
|
134
|
+
const wrapper = mount(Dashboard, {
|
|
135
|
+
...requiredSetup(
|
|
136
|
+
{ workspaces: () => fleetWorkspaces },
|
|
137
|
+
{
|
|
138
|
+
[FLEET.GIT_REPO]: gitRepos,
|
|
139
|
+
[FLEET.HELM_OP]: helmOps,
|
|
140
|
+
}
|
|
141
|
+
),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await wrapper.vm.$nextTick();
|
|
145
|
+
expect(wrapper.find('.dashboard').exists()).toBe(true);
|
|
146
|
+
expect(wrapper.findComponent({ name: 'Loading' }).exists()).toBe(false);
|
|
147
|
+
expect(wrapper.findComponent({ name: 'NoWorkspaces' }).exists()).toBe(false);
|
|
148
|
+
expect(wrapper.findComponent({ name: 'EmptyDashboard' }).exists()).toBe(false);
|
|
363
149
|
});
|
|
364
150
|
|
|
365
|
-
it('
|
|
151
|
+
it('should render workspace cards', () => {
|
|
366
152
|
const wrapper = mount(Dashboard, {
|
|
367
153
|
...requiredSetup(
|
|
368
154
|
{ workspaces: () => fleetWorkspaces },
|
|
@@ -384,7 +170,7 @@ describe('component: FleetDashboard', () => {
|
|
|
384
170
|
['fleet-default', 'expanded', true],
|
|
385
171
|
['fleet-local', 'collapsed', false],
|
|
386
172
|
['fleet-default', 'collapsed', false],
|
|
387
|
-
])('%p workspace card
|
|
173
|
+
])('should %p workspace card be %p', async(workspace, _, collapsed) => {
|
|
388
174
|
const wrapper = mount(Dashboard, {
|
|
389
175
|
...requiredSetup(
|
|
390
176
|
{ workspaces: () => fleetWorkspaces },
|
|
@@ -399,28 +185,536 @@ describe('component: FleetDashboard', () => {
|
|
|
399
185
|
expect(expandedPanel.exists()).toBe(!collapsed);
|
|
400
186
|
});
|
|
401
187
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
188
|
+
it('should workspaces return fleetWorkspaces if available', async() => {
|
|
189
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
190
|
+
|
|
191
|
+
wrapper.setData({ fleetWorkspaces });
|
|
192
|
+
|
|
193
|
+
await wrapper.vm.$nextTick();
|
|
194
|
+
expect(wrapper.vm.workspaces).toStrictEqual(fleetWorkspaces);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should allCardsExpanded be true if all workspaces are expanded', async() => {
|
|
198
|
+
const wrapper = mount(Dashboard, {
|
|
199
|
+
...requiredSetup(
|
|
200
|
+
{ workspaces: () => fleetWorkspaces },
|
|
201
|
+
{
|
|
202
|
+
isWorkspaceCollapsed: {
|
|
203
|
+
'fleet-local': false,
|
|
204
|
+
'fleet-default': false
|
|
205
|
+
},
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
await wrapper.vm.$nextTick();
|
|
211
|
+
expect(wrapper.vm.allCardsExpanded).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should allCardsExpanded return false if any workspace is collapsed', async() => {
|
|
215
|
+
const wrapper = mount(Dashboard, {
|
|
216
|
+
...requiredSetup(
|
|
217
|
+
{ workspaces: () => fleetWorkspaces },
|
|
218
|
+
{
|
|
219
|
+
isWorkspaceCollapsed: {
|
|
220
|
+
'fleet-local': true,
|
|
221
|
+
'fleet-default': false
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
await wrapper.vm.$nextTick();
|
|
228
|
+
expect(wrapper.vm.allCardsExpanded).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should selectStates toggle state filter and expands the workspace/state', async() => {
|
|
232
|
+
const workspaceId = 'fleet-local';
|
|
233
|
+
const stateDisplay = 'Modified';
|
|
234
|
+
|
|
235
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
236
|
+
|
|
237
|
+
wrapper.setData({
|
|
238
|
+
stateFilter: { [workspaceId]: {} },
|
|
239
|
+
isWorkspaceCollapsed: { [workspaceId]: true },
|
|
240
|
+
isStateCollapsed: { [workspaceId]: { [stateDisplay]: true } }
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
await wrapper.vm.selectStates(workspaceId, stateDisplay);
|
|
244
|
+
|
|
245
|
+
await wrapper.vm.$nextTick();
|
|
246
|
+
|
|
247
|
+
// Should set stateFilter for Modified to true
|
|
248
|
+
expect((wrapper.vm.stateFilter as any)[workspaceId][stateDisplay]).toBe(true);
|
|
249
|
+
// Workspace should remain expanded
|
|
250
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[workspaceId]).toBe(false);
|
|
251
|
+
// All states should be expanded
|
|
252
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][stateDisplay]).toBe(false);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should selectType toggle type filter and expands all states', async() => {
|
|
256
|
+
const workspaceId = 'fleet-local';
|
|
257
|
+
const stateDisplay = 'Modified';
|
|
258
|
+
const type = FLEET.GIT_REPO;
|
|
259
|
+
|
|
260
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
261
|
+
|
|
262
|
+
wrapper.setData({ isStateCollapsed: { [workspaceId]: { [stateDisplay]: true } } });
|
|
263
|
+
|
|
264
|
+
await wrapper.vm.selectType(workspaceId, type, false);
|
|
265
|
+
await wrapper.vm.$nextTick();
|
|
266
|
+
|
|
267
|
+
expect((wrapper.vm.typeFilter as any)[workspaceId][type]).toBe(false);
|
|
268
|
+
|
|
269
|
+
// Should expand all states for that workspace
|
|
270
|
+
Object.keys((wrapper.vm.isStateCollapsed as any)[workspaceId]).forEach((state) => {
|
|
271
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][state]).toBe(false);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should toggleCard toggle the collapse state of a workspace card', async() => {
|
|
276
|
+
const workspaceId = 'fleet-local';
|
|
277
|
+
|
|
278
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
279
|
+
|
|
280
|
+
await wrapper.vm.toggleCard(workspaceId);
|
|
281
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[workspaceId]).toBe(true);
|
|
282
|
+
|
|
283
|
+
await wrapper.vm.toggleCard(workspaceId);
|
|
284
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[workspaceId]).toBe(false);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should toggleCardAll expand or collapses all workspace cards', async() => {
|
|
288
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
289
|
+
|
|
290
|
+
const ws1 = fleetWorkspaces[0].id;
|
|
291
|
+
const ws2 = fleetWorkspaces[1].id;
|
|
292
|
+
|
|
293
|
+
wrapper.vm.isWorkspaceCollapsed = {
|
|
294
|
+
[ws1]: true,
|
|
295
|
+
[ws2]: false,
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
await wrapper.vm.$nextTick();
|
|
299
|
+
|
|
300
|
+
// Collapse all
|
|
301
|
+
await wrapper.vm.toggleCardAll('collapse');
|
|
302
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws1]).toBe(true);
|
|
303
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws2]).toBe(true);
|
|
304
|
+
|
|
305
|
+
// Expand all
|
|
306
|
+
await wrapper.vm.toggleCardAll('expand');
|
|
307
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws1]).toBe(false);
|
|
308
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws2]).toBe(false);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should toggleState toggle the collapse state of a state panel', async() => {
|
|
312
|
+
const workspaceId = 'fleet-local';
|
|
313
|
+
const stateDisplay = 'Modified';
|
|
314
|
+
|
|
315
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
316
|
+
|
|
317
|
+
wrapper.setData({ isStateCollapsed: { [workspaceId]: { [stateDisplay]: true } } });
|
|
318
|
+
|
|
319
|
+
await wrapper.vm.toggleState(workspaceId, stateDisplay);
|
|
320
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][stateDisplay]).toBe(false);
|
|
321
|
+
|
|
322
|
+
await wrapper.vm.toggleState(workspaceId, stateDisplay);
|
|
323
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][stateDisplay]).toBe(true);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should toggleStateAll expand or collapse all state panels for a workspace', async() => {
|
|
327
|
+
const workspaceId = 'fleet-local';
|
|
328
|
+
|
|
329
|
+
const state1 = 'Modified';
|
|
330
|
+
const state2 = 'Error';
|
|
331
|
+
|
|
332
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
333
|
+
|
|
334
|
+
wrapper.setData({ isStateCollapsed: { [workspaceId]: { [state1]: true } } });
|
|
335
|
+
|
|
336
|
+
(wrapper.vm.isStateCollapsed as any)[workspaceId] = {
|
|
337
|
+
[state1]: true,
|
|
338
|
+
[state2]: false,
|
|
339
|
+
};
|
|
340
|
+
await wrapper.vm.$nextTick();
|
|
341
|
+
|
|
342
|
+
// Collapse all states for the workspace
|
|
343
|
+
await wrapper.vm.toggleStateAll(workspaceId, 'collapse');
|
|
344
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][state1]).toBe(true);
|
|
345
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][state2]).toBe(true);
|
|
346
|
+
|
|
347
|
+
// Expand all states for the workspace
|
|
348
|
+
await wrapper.vm.toggleStateAll(workspaceId, 'expand');
|
|
349
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][state1]).toBe(false);
|
|
350
|
+
expect((wrapper.vm.isStateCollapsed as any)[workspaceId][state2]).toBe(false);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('should loadMore increment cardsCount for a specific state', async() => {
|
|
354
|
+
const workspaceId = 'fleet-local';
|
|
355
|
+
const stateDisplay = 'Modified';
|
|
356
|
+
|
|
357
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
358
|
+
|
|
359
|
+
wrapper.vm.CARDS_MIN = 5;
|
|
360
|
+
wrapper.vm.CARDS_SIZE = 5;
|
|
361
|
+
|
|
362
|
+
expect((wrapper.vm.cardsCount as any)[workspaceId]).toBeUndefined();
|
|
363
|
+
|
|
364
|
+
await wrapper.vm.loadMore(workspaceId, stateDisplay);
|
|
365
|
+
expect((wrapper.vm.cardsCount as any)[workspaceId][stateDisplay]).toBe(wrapper.vm.CARDS_MIN + wrapper.vm.CARDS_SIZE);
|
|
366
|
+
|
|
367
|
+
await wrapper.vm.loadMore(workspaceId, stateDisplay);
|
|
368
|
+
expect((wrapper.vm.cardsCount as any)[workspaceId][stateDisplay]).toBe(wrapper.vm.CARDS_MIN + (2 * wrapper.vm.CARDS_SIZE));
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('should loadLess decrement cardsCount for a specific state, not going below CARDS_MIN', async() => {
|
|
372
|
+
const workspaceId = 'fleet-local';
|
|
373
|
+
const stateDisplay = 'Modified';
|
|
374
|
+
|
|
375
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
376
|
+
|
|
377
|
+
wrapper.vm.CARDS_MIN = 5;
|
|
378
|
+
wrapper.vm.CARDS_SIZE = 5;
|
|
379
|
+
|
|
380
|
+
(wrapper.vm.cardsCount as any)[workspaceId] = { [stateDisplay]: wrapper.vm.CARDS_MIN + (2 * wrapper.vm.CARDS_SIZE) }; // Start with enough to decrement
|
|
381
|
+
await wrapper.vm.$nextTick();
|
|
382
|
+
|
|
383
|
+
await wrapper.vm.loadLess(workspaceId, stateDisplay);
|
|
384
|
+
expect((wrapper.vm.cardsCount as any)[workspaceId][stateDisplay]).toBe(wrapper.vm.CARDS_MIN + wrapper.vm.CARDS_SIZE);
|
|
385
|
+
|
|
386
|
+
await wrapper.vm.loadLess(workspaceId, stateDisplay);
|
|
387
|
+
expect((wrapper.vm.cardsCount as any)[workspaceId][stateDisplay]).toBe(wrapper.vm.CARDS_MIN);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it('should _resourceStates groups resources by stateDisplay and sorts them', () => {
|
|
391
|
+
const resources = [
|
|
392
|
+
{
|
|
393
|
+
id: 'a', type: FLEET.GIT_REPO, metadata: { namespace: 'ns' }, nameDisplay: 'git-a', stateDisplay: 'Pending', stateSort: 'Pending'
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
id: 'b', type: FLEET.GIT_REPO, metadata: { namespace: 'ns' }, nameDisplay: 'git-b', stateDisplay: 'Active', stateSort: 'Active'
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
id: 'c', type: FLEET.GIT_REPO, metadata: { namespace: 'ns' }, nameDisplay: 'git-c', stateDisplay: 'Active', stateSort: 'Active'
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
id: 'd', type: FLEET.HELM_OP, metadata: { namespace: 'ns' }, nameDisplay: 'helm-d', stateDisplay: 'Error', stateSort: 'Error'
|
|
403
|
+
},
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
407
|
+
|
|
408
|
+
const result = wrapper.vm._resourceStates(resources);
|
|
409
|
+
|
|
410
|
+
// Expect sorting by stateSort
|
|
411
|
+
expect(result.map((s) => s.stateDisplay)).toStrictEqual(['Active', 'Error', 'Pending']);
|
|
412
|
+
expect(result[0].resources).toHaveLength(2); // Active
|
|
413
|
+
expect(result[1].resources).toHaveLength(1); // Error
|
|
414
|
+
expect(result[2].resources).toHaveLength(1); // Pending
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('should _filterResources filters by type, state, and search filters', async() => {
|
|
418
|
+
const workspaceId = 'fleet-local';
|
|
419
|
+
|
|
420
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
421
|
+
|
|
422
|
+
wrapper.setData({ typeFilter: { [workspaceId]: { [FLEET.GIT_REPO]: false, [FLEET.HELM_OP]: true } } });
|
|
423
|
+
|
|
424
|
+
wrapper.vm.applicationStates[workspaceId] = [
|
|
425
|
+
{
|
|
426
|
+
stateDisplay: 'Active', statePanel: { id: 'active' }, resources: []
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
stateDisplay: 'Modified', statePanel: { id: 'modified' }, resources: []
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
stateDisplay: 'Error', statePanel: { id: 'error' }, resources: []
|
|
433
|
+
}
|
|
434
|
+
];
|
|
435
|
+
|
|
436
|
+
const activeState = {
|
|
437
|
+
stateDisplay: 'Active',
|
|
438
|
+
statePanel: { id: 'active' },
|
|
439
|
+
resources: [
|
|
440
|
+
{
|
|
441
|
+
id: 'git-1', type: FLEET.GIT_REPO, namespace: workspaceId, nameDisplay: 'git-1', stateDisplay: 'Active', stateSort: 'Active'
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
id: 'helm-1', type: FLEET.HELM_OP, namespace: workspaceId, nameDisplay: 'helm-1', stateDisplay: 'Active', stateSort: 'Active'
|
|
445
|
+
},
|
|
446
|
+
]
|
|
447
|
+
};
|
|
448
|
+
const modifiedState = {
|
|
449
|
+
stateDisplay: 'Modified',
|
|
450
|
+
statePanel: { id: 'modified' },
|
|
451
|
+
resources: [
|
|
452
|
+
{
|
|
453
|
+
id: 'git-2', type: FLEET.GIT_REPO, namespace: workspaceId, nameDisplay: 'git-2', stateDisplay: 'Modified', stateSort: 'Modified'
|
|
454
|
+
},
|
|
455
|
+
]
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
let filtered = wrapper.vm._filterResources(activeState);
|
|
459
|
+
|
|
460
|
+
expect(filtered).toHaveLength(1); // Only GitRepos
|
|
461
|
+
|
|
462
|
+
// Test type filter
|
|
463
|
+
(wrapper.vm.typeFilter as any)[workspaceId][FLEET.GIT_REPO] = false;
|
|
464
|
+
(wrapper.vm.typeFilter as any)[workspaceId][FLEET.HELM_OP] = true;
|
|
465
|
+
filtered = wrapper.vm._filterResources(activeState);
|
|
466
|
+
expect(filtered).toHaveLength(1); // Only helm-1
|
|
467
|
+
|
|
468
|
+
// Test state filter
|
|
469
|
+
(wrapper.vm.typeFilter as any)[workspaceId][FLEET.GIT_REPO] = true;
|
|
470
|
+
(wrapper.vm.typeFilter as any)[workspaceId][FLEET.HELM_OP] = true;
|
|
471
|
+
(wrapper.vm.stateFilter as any)[workspaceId] = { active: true }; // Only show 'Active'
|
|
472
|
+
filtered = wrapper.vm._filterResources(modifiedState);
|
|
473
|
+
expect(filtered).toHaveLength(0);
|
|
474
|
+
|
|
475
|
+
// Test search filter
|
|
476
|
+
(wrapper.vm.stateFilter as any)[workspaceId] = {}; // Clear state filter
|
|
477
|
+
(wrapper.vm.searchFilter as any)[workspaceId] = 'git-1';
|
|
478
|
+
filtered = wrapper.vm._filterResources(activeState);
|
|
479
|
+
expect(filtered).toHaveLength(1); // Only git-1
|
|
480
|
+
expect(filtered[0].id).toBe('git-1');
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it('should _groupByWorkspace correctly group resources by workspace ID', () => {
|
|
484
|
+
const workspaces = [
|
|
485
|
+
{
|
|
486
|
+
id: 'test-ws1', data: 'foo', repos: [], helmOps: []
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
id: 'test-ws2', data: 'bar', repos: [], helmOps: []
|
|
490
|
+
}
|
|
491
|
+
];
|
|
492
|
+
|
|
493
|
+
const wrapper = mount(Dashboard, { ...requiredSetup({ workspaces: () => workspaces }) });
|
|
494
|
+
|
|
495
|
+
const callback = (ws: any) => ws.data.toUpperCase();
|
|
496
|
+
const result = wrapper.vm._groupByWorkspace(callback);
|
|
497
|
+
|
|
498
|
+
expect(result).toStrictEqual({
|
|
499
|
+
'test-ws1': 'FOO',
|
|
500
|
+
'test-ws2': 'BAR'
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should _stateExistsInWorkspace correctly identify if a state exists in a workspace', () => {
|
|
505
|
+
const workspaceId = 'fleet-local';
|
|
506
|
+
|
|
507
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
508
|
+
|
|
509
|
+
wrapper.vm.applicationStates[workspaceId] = [
|
|
510
|
+
{ stateDisplay: 'Active', statePanel: { id: 'active' } },
|
|
511
|
+
{ stateDisplay: 'Modified', statePanel: { id: 'modified' } }
|
|
512
|
+
];
|
|
513
|
+
|
|
514
|
+
expect(wrapper.vm._stateExistsInWorkspace(workspaceId, 'active')).toBe(true);
|
|
515
|
+
expect(wrapper.vm._stateExistsInWorkspace(workspaceId, 'non-existent')).toBe(false);
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
it('should _decodeStateFilter correctly filter based on stateFilter', () => {
|
|
519
|
+
const workspaceId = 'fleet-local';
|
|
520
|
+
|
|
521
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
522
|
+
|
|
523
|
+
wrapper.vm.applicationStates[workspaceId] = [
|
|
524
|
+
{ stateDisplay: 'Active', statePanel: { id: 'active' } },
|
|
525
|
+
{ stateDisplay: 'Modified', statePanel: { id: 'modified' } }
|
|
526
|
+
];
|
|
527
|
+
|
|
528
|
+
(wrapper.vm.stateFilter as any)[workspaceId] = {};
|
|
529
|
+
expect(wrapper.vm._decodeStateFilter(workspaceId, { statePanel: { id: 'active' } })).toBe(true);
|
|
530
|
+
|
|
531
|
+
(wrapper.vm.stateFilter as any)[workspaceId] = { active: true };
|
|
532
|
+
expect(wrapper.vm._decodeStateFilter(workspaceId, { statePanel: { id: 'active' } })).toBe(true);
|
|
533
|
+
expect(wrapper.vm._decodeStateFilter(workspaceId, { statePanel: { id: 'modified' } })).toBe(false);
|
|
534
|
+
|
|
535
|
+
(wrapper.vm.stateFilter as any)[workspaceId] = { nonExistent: true };
|
|
536
|
+
expect(wrapper.vm._decodeStateFilter(workspaceId, { statePanel: { id: 'active' } })).toBe(true);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
it('should _decodeTypeFilter correctly filter based on typeFilter', () => {
|
|
540
|
+
const workspaceId = 'fleet-local';
|
|
541
|
+
|
|
542
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
543
|
+
|
|
544
|
+
wrapper.vm.typeFilter = {};
|
|
545
|
+
expect(wrapper.vm._decodeTypeFilter(workspaceId, FLEET.GIT_REPO)).toBe(true);
|
|
546
|
+
|
|
547
|
+
(wrapper.vm.typeFilter as any)[workspaceId] = { [FLEET.GIT_REPO]: true };
|
|
548
|
+
expect(wrapper.vm._decodeTypeFilter(workspaceId, FLEET.GIT_REPO)).toBe(true);
|
|
549
|
+
|
|
550
|
+
expect(wrapper.vm._decodeTypeFilter(workspaceId, FLEET.HELM_OP)).toBe(false);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it('should _decodeSearchFilter correctly filter based on searchFilter', () => {
|
|
554
|
+
const workspaceId = 'fleet-local';
|
|
555
|
+
|
|
556
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
557
|
+
|
|
558
|
+
// No search filter set (returns true)
|
|
559
|
+
wrapper.vm.searchFilter = {};
|
|
560
|
+
expect(wrapper.vm._decodeSearchFilter(workspaceId, 'my-app')).toBe(true);
|
|
561
|
+
|
|
562
|
+
// Search filter set, name matches (returns true)
|
|
563
|
+
(wrapper.vm.searchFilter as any)[workspaceId] = 'my';
|
|
564
|
+
expect(wrapper.vm._decodeSearchFilter(workspaceId, 'my-app')).toBe(true);
|
|
565
|
+
|
|
566
|
+
// Search filter set, name does not match (returns false)
|
|
567
|
+
expect(wrapper.vm._decodeSearchFilter(workspaceId, 'other-app')).toBe(false);
|
|
568
|
+
|
|
569
|
+
// View mode is not CARDS (returns true)
|
|
570
|
+
wrapper.vm.viewMode = 'flat';
|
|
571
|
+
expect(wrapper.vm._decodeSearchFilter(workspaceId, 'my-app')).toBe(true);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it('should _cleanStateFilter remove non-existent states from stateFilter', () => {
|
|
575
|
+
const workspaceId = 'fleet-local';
|
|
576
|
+
|
|
577
|
+
const wrapper = mount(Dashboard, { ...requiredSetup() });
|
|
578
|
+
|
|
579
|
+
wrapper.vm.applicationStates[workspaceId] = [
|
|
580
|
+
{ stateDisplay: 'Active', statePanel: { id: 'active' } },
|
|
581
|
+
];
|
|
582
|
+
(wrapper.vm.stateFilter as any)[workspaceId] = {
|
|
583
|
+
active: true,
|
|
584
|
+
nonExistent: true
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
wrapper.vm._cleanStateFilter(workspaceId);
|
|
588
|
+
|
|
589
|
+
expect((wrapper.vm.stateFilter as any)[workspaceId]).toStrictEqual({ active: true });
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it('should toggle workspace card collapse state when expand button is clicked', async() => {
|
|
593
|
+
const workspaceId = 'fleet-local';
|
|
594
|
+
|
|
595
|
+
const wrapper = mount(Dashboard, {
|
|
596
|
+
...requiredSetup(
|
|
597
|
+
{ workspaces: () => fleetWorkspaces },
|
|
598
|
+
{
|
|
599
|
+
[FLEET.GIT_REPO]: gitRepos,
|
|
600
|
+
[FLEET.HELM_OP]: helmOps,
|
|
601
|
+
isWorkspaceCollapsed: {
|
|
602
|
+
'fleet-local': false,
|
|
603
|
+
'fleet-default': true
|
|
604
|
+
},
|
|
605
|
+
isStateCollapsed: {
|
|
606
|
+
'fleet-local': {
|
|
607
|
+
Active: true, Modified: true, Error: true
|
|
608
|
+
},
|
|
609
|
+
'fleet-default': { Active: true }
|
|
610
|
+
},
|
|
611
|
+
typeFilter: {
|
|
612
|
+
'fleet-local': {
|
|
613
|
+
[FLEET.GIT_REPO]: true,
|
|
614
|
+
[FLEET.HELM_OP]: true,
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
stateFilter: {},
|
|
618
|
+
searchFilter: {},
|
|
619
|
+
}
|
|
620
|
+
),
|
|
621
|
+
stubs: ['Loading', 'NoWorkspaces', 'EmptyDashboard', 'RouterLinkStub'],
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
const expandButton = wrapper.find(`[data-testid="workspace-expand-btn-${ workspaceId }"]`);
|
|
625
|
+
|
|
626
|
+
await expandButton.trigger('click');
|
|
627
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[workspaceId]).toBe(true);
|
|
628
|
+
|
|
629
|
+
await expandButton.trigger('click');
|
|
630
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[workspaceId]).toBe(false);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
it('should toggle all workspace cards collapse state when "Expand All" / "Collapse All" is clicked', async() => {
|
|
634
|
+
const wrapper = mount(Dashboard, {
|
|
635
|
+
...requiredSetup(
|
|
636
|
+
{ workspaces: () => fleetWorkspaces },
|
|
637
|
+
{
|
|
638
|
+
[FLEET.GIT_REPO]: gitRepos,
|
|
639
|
+
[FLEET.HELM_OP]: helmOps,
|
|
640
|
+
isWorkspaceCollapsed: {
|
|
641
|
+
'fleet-local': false,
|
|
642
|
+
'fleet-default': true
|
|
643
|
+
},
|
|
644
|
+
isStateCollapsed: {
|
|
645
|
+
'fleet-local': {
|
|
646
|
+
Active: true, Modified: true, Error: true
|
|
647
|
+
},
|
|
648
|
+
'fleet-default': { Active: true }
|
|
649
|
+
},
|
|
650
|
+
typeFilter: {
|
|
651
|
+
'fleet-local': {
|
|
652
|
+
[FLEET.GIT_REPO]: true,
|
|
653
|
+
[FLEET.HELM_OP]: true,
|
|
654
|
+
},
|
|
655
|
+
},
|
|
656
|
+
stateFilter: {},
|
|
657
|
+
searchFilter: {},
|
|
658
|
+
}
|
|
659
|
+
),
|
|
660
|
+
stubs: ['Loading', 'NoWorkspaces', 'EmptyDashboard', 'RouterLinkStub'],
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
const ws1 = fleetWorkspaces[0].id;
|
|
664
|
+
const ws2 = fleetWorkspaces[1].id;
|
|
665
|
+
|
|
666
|
+
(wrapper.vm.isWorkspaceCollapsed as any)[ws1] = true;
|
|
667
|
+
(wrapper.vm.isWorkspaceCollapsed as any)[ws2] = true;
|
|
668
|
+
await wrapper.vm.$nextTick();
|
|
669
|
+
|
|
670
|
+
const expandAllButton = wrapper.find('[data-testid="fleet-dashboard-expand-all"]');
|
|
671
|
+
|
|
672
|
+
// Click to Expand All
|
|
673
|
+
expect(wrapper.vm.allCardsExpanded).toBe(false);
|
|
674
|
+
|
|
675
|
+
await expandAllButton.trigger('click');
|
|
676
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws1]).toBe(false);
|
|
677
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws2]).toBe(false);
|
|
678
|
+
expect(wrapper.vm.allCardsExpanded).toBe(true);
|
|
679
|
+
|
|
680
|
+
// Click to Collapse All
|
|
681
|
+
await expandAllButton.trigger('click');
|
|
682
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws1]).toBe(true);
|
|
683
|
+
expect((wrapper.vm.isWorkspaceCollapsed as any)[ws2]).toBe(true);
|
|
684
|
+
expect(wrapper.vm.allCardsExpanded).toBe(false);
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('should update view mode when ButtonGroup value changes', async() => {
|
|
688
|
+
const wrapper = mount(Dashboard, {
|
|
689
|
+
...requiredSetup(
|
|
690
|
+
{ workspaces: () => fleetWorkspaces },
|
|
691
|
+
{ [FLEET.GIT_REPO]: gitRepos }
|
|
692
|
+
),
|
|
693
|
+
stubs: ['Loading', 'NoWorkspaces', 'EmptyDashboard', 'RouterLinkStub'],
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
const buttonGroup = wrapper.findComponent({ name: 'ButtonGroup' });
|
|
697
|
+
|
|
698
|
+
expect(wrapper.vm.viewMode).toBe('flat');
|
|
699
|
+
|
|
700
|
+
await buttonGroup.vm.$emit('update:value', 'cards');
|
|
701
|
+
expect(wrapper.vm.viewMode).toBe('cards');
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it('should search filter be visible only if viewMode is cards', async() => {
|
|
705
|
+
const wrapper = mount(Dashboard, {
|
|
706
|
+
...requiredSetup(
|
|
707
|
+
{ workspaces: () => fleetWorkspaces },
|
|
708
|
+
{ [FLEET.GIT_REPO]: gitRepos }
|
|
709
|
+
),
|
|
710
|
+
stubs: ['Loading', 'NoWorkspaces', 'EmptyDashboard', 'RouterLinkStub'],
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
wrapper.vm.viewMode = 'cards';
|
|
714
|
+
await wrapper.vm.$nextTick();
|
|
715
|
+
|
|
716
|
+
const searchInput = wrapper.find('[data-testid="fleet-dashboard-search-input-fleet-local"]');
|
|
717
|
+
|
|
718
|
+
expect(searchInput.exists()).toBe(true);
|
|
719
|
+
});
|
|
426
720
|
});
|