@rancher/shell 0.3.0 → 0.3.1
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/styles/global/_button.scss +5 -1
- package/assets/styles/global/_columns.scss +4 -0
- package/assets/styles/global/_layout.scss +1 -2
- package/assets/styles/global/_select.scss +1 -4
- package/assets/styles/themes/_dark.scss +4 -4
- package/assets/styles/themes/_light.scss +4 -3
- package/assets/styles/themes/_suse.scss +1 -1
- package/assets/styles/vendor/vue-select.scss +4 -3
- package/assets/translations/en-us.yaml +669 -73
- package/assets/translations/zh-hans.yaml +547 -165
- package/chart/monitoring/steps/uninstall-v1.vue +2 -2
- package/cloud-credential/azure.vue +23 -0
- package/cloud-credential/harvester.vue +25 -62
- package/cloud-credential/pnap.vue +80 -0
- package/components/.DS_Store +0 -0
- package/components/AdvancedSection.vue +9 -2
- package/components/Alert.vue +2 -2
- package/components/ButtonDropdown.vue +0 -2
- package/components/ButtonGroup.vue +1 -0
- package/components/CollapsibleCard.vue +0 -1
- package/components/CruResource.vue +41 -4
- package/components/DetailTop.vue +58 -3
- package/components/DisableAuthProviderModal.vue +106 -0
- package/{rancher-components/components/Utils/DraggableZone → components}/DraggableZone.vue +0 -0
- package/components/ExplorerMembers.vue +253 -30
- package/components/ExplorerProjectsNamespaces.vue +77 -33
- package/components/GrowlManager.vue +3 -3
- package/components/IconOrSvg.vue +149 -0
- package/components/LogItem.vue +69 -0
- package/components/PodSecurityAdmission.vue +302 -0
- package/components/PromptModal.vue +1 -0
- package/components/ResourceDetail/Masthead.vue +54 -2
- package/components/ResourceDetail/index.vue +12 -5
- package/components/ResourceList/Masthead.vue +11 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +12 -2
- package/components/ResourceList/index.vue +53 -12
- package/components/ResourceList/resource-list.config.js +7 -0
- package/components/ResourceTable.vue +31 -6
- package/components/SimpleBox.vue +1 -1
- package/components/SortableTable/THead.vue +15 -5
- package/components/SortableTable/index.vue +21 -10
- package/components/Tabbed/index.vue +20 -15
- package/components/__tests__/.DS_Store +0 -0
- package/components/__tests__/AsyncButton.test.ts +140 -0
- package/components/__tests__/BackLink.test.ts +33 -0
- package/components/__tests__/ButtonGroup.test.ts +124 -0
- package/components/__tests__/ClusterBadge.test.ts +32 -0
- package/components/__tests__/CollapsibleCard.test.ts +64 -0
- package/components/__tests__/ConsumptionGauge.test.ts +88 -0
- package/components/__tests__/CruResource.test.ts +3 -2
- package/components/__tests__/FixedBanner.test.ts +129 -0
- package/components/__tests__/GrowlManager.test.ts +147 -0
- package/components/__tests__/NamespaceFilter.test.ts +33 -25
- package/components/__tests__/PercentageBar.test.ts +32 -0
- package/components/__tests__/PodSecurityAdmission.test.ts +398 -0
- package/components/auth/AuthBanner.vue +20 -10
- package/components/auth/RoleDetailEdit.vue +26 -17
- package/components/auth/SelectPrincipal.vue +36 -5
- package/components/form/ArrayList.vue +3 -35
- package/components/form/ArrayListGrouped.vue +13 -4
- package/components/form/ArrayListSelect.vue +5 -5
- package/components/form/Error.vue +8 -0
- package/components/form/KeyValue.vue +39 -7
- package/components/form/LabeledSelect.vue +5 -2
- package/components/form/Labels.vue +46 -16
- package/components/form/Members/ClusterPermissionsEditor.vue +17 -17
- package/components/form/Members/MembershipEditor.vue +12 -12
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +1 -1
- package/components/form/Probe.vue +3 -3
- package/components/form/ResourceQuota/Project.vue +6 -6
- package/components/form/ResourceTabs/index.vue +1 -6
- package/components/form/Security.vue +7 -6
- package/components/form/Select.vue +3 -2
- package/components/form/SelectOrCreateAuthSecret.vue +22 -29
- package/components/form/ServicePorts.vue +8 -0
- package/components/form/WorkloadPorts.vue +7 -1
- package/components/form/__tests__/ArrayList.test.ts +74 -0
- package/components/form/__tests__/ArrayListGrouped.test.ts +6 -4
- package/components/formatter/Checked.vue +1 -1
- package/components/formatter/ClusterLink.vue +5 -0
- package/components/formatter/IconIsDefault.vue +2 -2
- package/components/formatter/InternalExternalIP.vue +11 -8
- package/components/formatter/LiveDuration.vue +78 -0
- package/components/formatter/WorkloadHealthScale.vue +5 -3
- package/components/nav/Header.vue +6 -3
- package/components/nav/NamespaceFilter.vue +146 -63
- package/components/nav/TopLevelMenu.vue +22 -19
- package/components/nav/WindowManager/ContainerLogs.vue +83 -126
- package/components/nav/WindowManager/ContainerShell.vue +9 -7
- package/components/nav/WindowManager/Window.vue +2 -0
- package/components/nav/WindowManager/index.vue +10 -0
- package/config/elemental-types.js +9 -0
- package/config/features.js +2 -0
- package/config/home-links.js +4 -1
- package/config/pod-security-admission.ts +82 -0
- package/config/product/apps.js +1 -1
- package/config/product/auth.js +6 -5
- package/config/product/explorer.js +6 -6
- package/config/product/fleet.js +1 -1
- package/config/product/manager.js +6 -2
- package/config/secret.js +0 -1
- package/config/settings.ts +26 -9
- package/config/table-headers.js +22 -11
- package/config/types.js +4 -1
- package/content/docs/zh-hans/getting-started.md +113 -137
- package/content/docs/zh-hans/whats-new.md +8 -46
- package/creators/pkg/package-lock.json +37 -0
- package/creators/pkg/package.json +1 -1
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +35 -9
- package/detail/service.vue +2 -9
- package/detail/workload/index.vue +0 -1
- package/dialog/AddClusterMemberDialog.vue +22 -28
- package/dialog/AddProjectMemberDialog.vue +53 -9
- package/dialog/DiagnosticTimingsDialog.vue +8 -7
- package/dialog/DrainNode.vue +44 -48
- package/dialog/ForceMachineRemoveDialog.vue +5 -7
- package/dialog/GenericPrompt.vue +15 -20
- package/dialog/RollbackWorkloadDialog.vue +15 -46
- package/dialog/RotateCertificatesDialog.vue +5 -7
- package/dialog/RotateEncryptionKeyDialog.vue +5 -9
- package/dialog/SaveAsRKETemplateDialog.vue +5 -13
- package/dialog/ScaleMachineDownDialog.vue +1 -1
- package/dialog/ScalePoolDownDialog.vue +121 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +3 -3
- package/edit/auth/azuread.vue +16 -16
- package/edit/auth/github.vue +8 -0
- package/edit/auth/googleoauth.vue +10 -1
- package/edit/auth/ldap/index.vue +10 -0
- package/edit/auth/oidc.vue +10 -0
- package/edit/auth/saml.vue +10 -0
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
- package/edit/cloudcredential.vue +3 -7
- package/edit/logging-flow/Match.vue +39 -8
- package/edit/logging-flow/index.vue +27 -4
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +107 -0
- package/edit/management.cattle.io.project.vue +8 -1
- package/edit/management.cattle.io.setting.vue +5 -2
- package/edit/management.cattle.io.user.vue +7 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +23 -7
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +2 -2
- package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +14 -6
- package/edit/namespace.vue +18 -4
- package/edit/networking.k8s.io.ingress/Certificate.vue +1 -0
- package/edit/networking.k8s.io.ingress/IngressClass.vue +8 -6
- package/edit/networking.k8s.io.ingress/RulePath.vue +12 -6
- package/edit/networking.k8s.io.ingress/index.vue +8 -6
- package/edit/persistentvolume/index.vue +30 -27
- package/edit/persistentvolume/plugins/cephfs.vue +29 -29
- package/edit/persistentvolume/plugins/csi.vue +102 -62
- package/edit/persistentvolume/plugins/fc.vue +19 -19
- package/edit/persistentvolume/plugins/iscsi.vue +45 -45
- package/edit/persistentvolume/plugins/rbd.vue +39 -39
- package/edit/persistentvolumeclaim.vue +78 -75
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -7
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +10 -1
- package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +87 -27
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -6
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +93 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +29 -6
- package/edit/provisioning.cattle.io.cluster/rke2.vue +440 -152
- package/edit/secret/index.vue +3 -7
- package/edit/service.vue +3 -1
- package/edit/storage.k8s.io.storageclass/index.vue +100 -16
- package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +114 -0
- package/edit/workload/__tests__/index.test.ts +98 -0
- package/edit/workload/index.vue +58 -8
- package/edit/workload/mixins/workload.js +107 -70
- package/edit/workload/storage/ContainerMountPaths.vue +0 -10
- package/edit/workload/storage/emptyDir.vue +88 -0
- package/edit/workload/storage/ephemeralVolume/index.vue +1 -1
- package/edit/workload/storage/index.vue +8 -0
- package/edit/workload/storage/persistentVolumeClaim/index.vue +1 -1
- package/layouts/default.vue +57 -44
- package/list/__tests__/workload.test.ts +5 -2
- package/list/catalog.cattle.io.app.vue +1 -0
- package/list/cis.cattle.io.clusterscan.vue +1 -0
- package/list/fleet.cattle.io.bundle.vue +5 -6
- package/list/fleet.cattle.io.cluster.vue +6 -3
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +5 -6
- package/list/fleet.cattle.io.gitrepo.vue +4 -9
- package/list/helm.cattle.io.projecthelmchart.vue +1 -5
- package/list/logging.banzaicloud.io.clusterflow.vue +4 -1
- package/list/logging.banzaicloud.io.flow.vue +6 -5
- package/list/management.cattle.io.cluster.vue +1 -0
- package/list/management.cattle.io.feature.vue +3 -4
- package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +47 -0
- package/list/management.cattle.io.setting.vue +2 -2
- package/list/management.cattle.io.user.vue +4 -10
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +2 -7
- package/list/node.vue +8 -5
- package/list/persistentvolume.vue +3 -3
- package/list/persistentvolumeclaim.vue +3 -4
- package/list/provisioning.cattle.io.cluster.vue +18 -19
- package/list/service.vue +6 -14
- package/list/workload.vue +43 -38
- package/machine-config/azure.vue +429 -60
- package/machine-config/pnap.vue +288 -0
- package/mixins/auth-config.js +1 -3
- package/mixins/browser-tab-visibility.js +8 -14
- package/mixins/chart.js +1 -1
- package/mixins/create-edit-view/impl.js +4 -0
- package/mixins/create-edit-view/index.js +4 -2
- package/mixins/resource-fetch-namespaced.js +98 -0
- package/mixins/resource-fetch.js +79 -45
- package/mixins/resource-manager.js +1 -23
- package/models/apps.controllerrevision.js +7 -0
- package/models/apps.daemonset.js +18 -0
- package/models/apps.deployment.js +44 -0
- package/models/apps.replicaset.js +7 -0
- package/models/apps.statefulset.js +18 -0
- package/models/batch.job.js +7 -14
- package/models/cluster/node.js +10 -2
- package/models/cluster.x-k8s.io.machine.js +26 -4
- package/models/cluster.x-k8s.io.machinedeployment.js +12 -2
- package/models/event.js +7 -0
- package/models/logging.banzaicloud.io.flow.js +4 -0
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.clusterroletemplatebinding.js +1 -1
- package/models/management.cattle.io.globalrole.js +2 -2
- package/models/management.cattle.io.node.js +37 -2
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +4 -0
- package/models/management.cattle.io.project.js +30 -11
- package/models/management.cattle.io.setting.js +1 -1
- package/models/management.cattle.io.user.js +37 -1
- package/models/namespace.js +42 -5
- package/models/persistentvolume.js +14 -2
- package/models/pod.js +15 -0
- package/models/projectroletemplatebinding.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +61 -10
- package/models/rke-machine.cattle.io.pnapmachinetemplate.js +15 -0
- package/models/service.js +14 -13
- package/models/storage.k8s.io.storageclass.js +33 -18
- package/models/workload.js +38 -7
- package/nuxt.config.js +27 -17
- package/package.json +7 -7
- package/pages/about.vue +14 -2
- package/pages/c/_cluster/apps/charts/index.vue +4 -3
- package/pages/c/_cluster/apps/charts/install.vue +59 -22
- package/pages/c/_cluster/auth/config/_id.vue +6 -0
- package/pages/c/_cluster/auth/config/index.vue +8 -6
- package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
- package/pages/c/_cluster/auth/roles/index.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +12 -6
- package/pages/c/_cluster/longhorn/index.vue +1 -1
- package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +15 -4
- package/pages/c/_cluster/monitoring/index.vue +1 -1
- package/pages/c/_cluster/neuvector/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +48 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +34 -1
- package/pages/c/_cluster/uiplugins/index.vue +28 -2
- package/pages/diagnostic.vue +5 -4
- package/pages/home.vue +105 -30
- package/pages/prefs.vue +23 -12
- package/pages/rio/mesh.vue +1 -1
- package/pkg/dynamic-importer.lib.js +8 -0
- package/pkg/vue.config.js +4 -0
- package/plugins/dashboard-store/__tests__/mutations.spec.js +406 -0
- package/plugins/dashboard-store/actions.js +32 -25
- package/plugins/dashboard-store/getters.js +50 -33
- package/plugins/dashboard-store/mutations.js +134 -28
- package/plugins/dashboard-store/resource-class.js +21 -41
- package/plugins/steve/actions.js +30 -0
- package/plugins/steve/caches/resourceCache.js +60 -0
- package/plugins/steve/getters.js +44 -1
- package/plugins/steve/mutations.js +97 -36
- package/plugins/steve/resourceWatcher.js +277 -0
- package/plugins/steve/schema.utils.js +25 -0
- package/plugins/steve/subscribe.js +288 -115
- package/plugins/steve/worker/index.js +17 -0
- package/plugins/steve/worker/web-worker.advanced.js +302 -0
- package/plugins/steve/{web-worker.steve-sub-worker.js → worker/web-worker.basic.js} +3 -44
- package/rancher-components/Card/Card.vue +3 -3
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -0
- package/rancher-components/StringList/StringList.test.ts +45 -420
- package/rancher-components/StringList/StringList.vue +1 -10
- package/rancher-components/components/Banner/Banner.test.ts +44 -0
- package/rancher-components/components/Banner/Banner.vue +129 -61
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +13 -22
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +8 -6
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +9 -9
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -1
- package/rancher-components/components/StringList/StringList.test.ts +7 -7
- package/rancher-components/components/StringList/StringList.vue +21 -15
- package/scripts/test-plugins-build.sh +8 -0
- package/static/loading-indicator.html +1 -1
- package/store/index.js +54 -3
- package/store/plugins.js +0 -17
- package/store/pnap.js +128 -0
- package/store/prefs.js +4 -2
- package/store/type-map.js +55 -13
- package/types/pod-security-admission.ts +36 -0
- package/types/shell/index.d.ts +496 -396
- package/utils/__tests__/object.test.ts +17 -1
- package/utils/__tests__/pod-security-admission.test.ts +61 -0
- package/utils/async.ts +36 -0
- package/utils/color.js +45 -0
- package/utils/crypto/browserHashUtils.js +18 -0
- package/utils/dynamic-importer.js +8 -0
- package/utils/install-redirect.js +1 -1
- package/utils/object.js +24 -0
- package/utils/pod-security-admission.ts +39 -0
- package/utils/socket.js +61 -24
- package/utils/string.js +2 -0
- package/utils/svg-filter.js +301 -0
- package/utils/time.js +49 -0
- package/utils/validators/cidr.js +4 -0
- package/utils/validators/formRules/__tests__/index.test.ts +23 -3
- package/utils/validators/formRules/index.ts +14 -0
- package/config/product/harvester-manager.js +0 -162
- package/edit/harvesterhci.io.management.cluster.vue +0 -153
- package/list/harvesterhci.io.management.cluster.vue +0 -241
- package/machine-config/harvester.vue +0 -693
- package/models/harvesterhci.io.management.cluster.js +0 -228
- package/pages/c/_cluster/harvesterManager/index.vue +0 -24
- package/rancher-components/Card/Card.test.ts +0 -39
- package/rancher-components/Utils/DraggableZone/DraggableZone.vue +0 -181
- package/rancher-components/Utils/DraggableZone/index.ts +0 -1
- package/rancher-components/components/Utils/DraggableZone/index.ts +0 -1
|
@@ -4,13 +4,18 @@ import Loading from '@shell/components/Loading';
|
|
|
4
4
|
import Masthead from './Masthead';
|
|
5
5
|
import ResourceLoadingIndicator from './ResourceLoadingIndicator';
|
|
6
6
|
import ResourceFetch from '@shell/mixins/resource-fetch';
|
|
7
|
+
import IconMessage from '@shell/components/IconMessage.vue';
|
|
8
|
+
import { ResourceListComponentName } from './resource-list.config';
|
|
7
9
|
|
|
8
10
|
export default {
|
|
11
|
+
name: ResourceListComponentName,
|
|
12
|
+
|
|
9
13
|
components: {
|
|
10
14
|
Loading,
|
|
11
15
|
ResourceTable,
|
|
12
16
|
Masthead,
|
|
13
|
-
ResourceLoadingIndicator
|
|
17
|
+
ResourceLoadingIndicator,
|
|
18
|
+
IconMessage
|
|
14
19
|
},
|
|
15
20
|
mixins: [ResourceFetch],
|
|
16
21
|
|
|
@@ -28,19 +33,16 @@ export default {
|
|
|
28
33
|
default: false
|
|
29
34
|
},
|
|
30
35
|
},
|
|
36
|
+
|
|
31
37
|
async fetch() {
|
|
32
38
|
const store = this.$store;
|
|
33
39
|
const resource = this.resource;
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const inStore = store.getters['currentStore'](resource);
|
|
38
|
-
|
|
39
|
-
const schema = store.getters[`${ inStore }/schemaFor`](resource);
|
|
41
|
+
const schema = this.schema;
|
|
40
42
|
|
|
41
43
|
if ( this.hasListComponent ) {
|
|
42
44
|
// If you provide your own list then call its asyncData
|
|
43
|
-
const importer =
|
|
45
|
+
const importer = this.listComponent;
|
|
44
46
|
const component = (await importer())?.default;
|
|
45
47
|
|
|
46
48
|
if ( component?.typeDisplay ) {
|
|
@@ -49,7 +51,7 @@ export default {
|
|
|
49
51
|
|
|
50
52
|
// If your list page has a fetch then it's responsible for populating rows itself
|
|
51
53
|
if ( component?.fetch ) {
|
|
52
|
-
hasFetch = true;
|
|
54
|
+
this.hasFetch = true;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
// If the custom component supports it, ask it what resources it loads, so we can
|
|
@@ -62,14 +64,17 @@ export default {
|
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
if ( !hasFetch ) {
|
|
67
|
+
if ( !this.hasFetch ) {
|
|
66
68
|
if ( !schema ) {
|
|
67
69
|
store.dispatch('loadingError', new Error(`Type ${ resource } not found, unable to display list`));
|
|
68
70
|
|
|
69
71
|
return;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
// See comment for `namespaceFilterRequired` watcher, skip fetch if we don't have a valid NS
|
|
75
|
+
if (!this.namespaceFilterRequired) {
|
|
76
|
+
await this.$fetchType(resource);
|
|
77
|
+
}
|
|
73
78
|
}
|
|
74
79
|
},
|
|
75
80
|
|
|
@@ -91,6 +96,8 @@ export default {
|
|
|
91
96
|
hasListComponent,
|
|
92
97
|
showMasthead: showMasthead === undefined ? true : showMasthead,
|
|
93
98
|
resource,
|
|
99
|
+
loadResources: [resource], // List of resources that will be loaded, this could be many (`Workloads`)
|
|
100
|
+
hasFetch: false,
|
|
94
101
|
// manual refresh
|
|
95
102
|
manualRefreshInit: false,
|
|
96
103
|
watch: false,
|
|
@@ -98,7 +105,6 @@ export default {
|
|
|
98
105
|
// Provided by fetch later
|
|
99
106
|
customTypeDisplay: null,
|
|
100
107
|
// incremental loading
|
|
101
|
-
loadResources: [resource],
|
|
102
108
|
loadIndeterminate: false,
|
|
103
109
|
// query param for simple filtering
|
|
104
110
|
useQueryParamsForSimpleFiltering: true
|
|
@@ -124,6 +130,23 @@ export default {
|
|
|
124
130
|
}
|
|
125
131
|
},
|
|
126
132
|
|
|
133
|
+
watch: {
|
|
134
|
+
/**
|
|
135
|
+
* When a NS filter is required and the user selects a different one, kick off a new set of API requests
|
|
136
|
+
*
|
|
137
|
+
* ResourceList has two modes
|
|
138
|
+
* 1) ResourceList component handles API request to fetch resources
|
|
139
|
+
* 2) Custom list component handles API request to fetch resources
|
|
140
|
+
*
|
|
141
|
+
* This covers case 1
|
|
142
|
+
*/
|
|
143
|
+
namespaceFilter(neu) {
|
|
144
|
+
if (neu && !this.hasFetch) {
|
|
145
|
+
this.$fetchType(this.resource);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
|
|
127
150
|
created() {
|
|
128
151
|
let listComponent = false;
|
|
129
152
|
|
|
@@ -140,7 +163,20 @@ export default {
|
|
|
140
163
|
</script>
|
|
141
164
|
|
|
142
165
|
<template>
|
|
143
|
-
<
|
|
166
|
+
<IconMessage
|
|
167
|
+
v-if="namespaceFilterRequired"
|
|
168
|
+
:vertical="true"
|
|
169
|
+
:subtle="false"
|
|
170
|
+
icon="icon-filter_alt"
|
|
171
|
+
>
|
|
172
|
+
<template #message>
|
|
173
|
+
<span
|
|
174
|
+
class="filter"
|
|
175
|
+
v-html="t('resourceList.nsFiltering', { resource: $store.getters['type-map/labelFor'](schema, 2) || customTypeDisplay }, true)"
|
|
176
|
+
/>
|
|
177
|
+
</template>
|
|
178
|
+
</IconMessage>
|
|
179
|
+
<div v-else>
|
|
144
180
|
<Masthead
|
|
145
181
|
v-if="showMasthead"
|
|
146
182
|
:type-display="customTypeDisplay"
|
|
@@ -149,6 +185,7 @@ export default {
|
|
|
149
185
|
:show-incremental-loading-indicator="showIncrementalLoadingIndicator"
|
|
150
186
|
:load-resources="loadResources"
|
|
151
187
|
:load-indeterminate="loadIndeterminate"
|
|
188
|
+
:load-namespace="namespaceFilter"
|
|
152
189
|
>
|
|
153
190
|
<template slot="extraActions">
|
|
154
191
|
<slot name="extraActions" />
|
|
@@ -173,6 +210,7 @@ export default {
|
|
|
173
210
|
:adv-filter-hide-labels-as-cols="advFilterHideLabelsAsCols"
|
|
174
211
|
:adv-filter-prevent-filtering-labels="advFilterPreventFilteringLabels"
|
|
175
212
|
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
213
|
+
:force-update-live-and-delayed="forceUpdateLiveAndDelayed"
|
|
176
214
|
/>
|
|
177
215
|
</div>
|
|
178
216
|
</template>
|
|
@@ -185,6 +223,9 @@ export default {
|
|
|
185
223
|
position: relative;
|
|
186
224
|
margin: 0 0 20px 0;
|
|
187
225
|
}
|
|
226
|
+
.filter{
|
|
227
|
+
line-height: 45px;
|
|
228
|
+
}
|
|
188
229
|
.right-action {
|
|
189
230
|
position: absolute;
|
|
190
231
|
top: 10px;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component name of the `ResourceList`
|
|
3
|
+
*
|
|
4
|
+
* This needs to be a in separate file to avoid circular dependency of
|
|
5
|
+
* index.vue --> resource-fetch mixin --> resource-fetch-namespaced mixin --> index.vue
|
|
6
|
+
*/
|
|
7
|
+
export const ResourceListComponentName = 'ResourceList';
|
|
@@ -140,9 +140,30 @@ export default {
|
|
|
140
140
|
useQueryParamsForSimpleFiltering: {
|
|
141
141
|
type: Boolean,
|
|
142
142
|
default: false
|
|
143
|
+
},
|
|
144
|
+
/**
|
|
145
|
+
* Manaul force the update of live and delayed cells. Change this number to kick off the update
|
|
146
|
+
*/
|
|
147
|
+
forceUpdateLiveAndDelayed: {
|
|
148
|
+
type: Number,
|
|
149
|
+
default: 0
|
|
143
150
|
}
|
|
144
151
|
},
|
|
145
152
|
|
|
153
|
+
mounted() {
|
|
154
|
+
/**
|
|
155
|
+
* v-shortkey prevents the event's propagation:
|
|
156
|
+
* https://github.com/fgr-araujo/vue-shortkey/blob/55d802ea305cadcc2ea970b55a3b8b86c7b44c05/src/index.js#L156-L157
|
|
157
|
+
*
|
|
158
|
+
* 'Enter' key press is handled via event listener in order to allow the event propagation
|
|
159
|
+
*/
|
|
160
|
+
window.addEventListener('keyup', this.handleEnterKeyPress);
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
beforeDestroy() {
|
|
164
|
+
window.removeEventListener('keyup', this.handleEnterKeyPress);
|
|
165
|
+
},
|
|
166
|
+
|
|
146
167
|
data() {
|
|
147
168
|
const options = this.$store.getters[`type-map/optionsFor`](this.schema);
|
|
148
169
|
const listGroups = options?.listGroups || [];
|
|
@@ -232,11 +253,16 @@ export default {
|
|
|
232
253
|
return [];
|
|
233
254
|
}
|
|
234
255
|
|
|
256
|
+
const haveAllNamespace = this.$store.getters['haveAllNamespace'];
|
|
257
|
+
|
|
235
258
|
return this.rows.filter((row) => {
|
|
236
259
|
if (this.currentProduct?.hideSystemResources && this.isNamespaced) {
|
|
237
260
|
return !!includedNamespaces[row.metadata.namespace] && !row.isSystemResource;
|
|
238
261
|
} else if (!this.isNamespaced) {
|
|
239
262
|
return true;
|
|
263
|
+
} else if (haveAllNamespace) {
|
|
264
|
+
// `rows` only contains resource from a single namespace
|
|
265
|
+
return true;
|
|
240
266
|
} else {
|
|
241
267
|
return !!includedNamespaces[row.metadata.namespace];
|
|
242
268
|
}
|
|
@@ -375,8 +401,11 @@ export default {
|
|
|
375
401
|
|
|
376
402
|
handleActionButtonClick(event) {
|
|
377
403
|
this.$emit('clickedActionButton', event);
|
|
378
|
-
}
|
|
404
|
+
},
|
|
379
405
|
|
|
406
|
+
handleEnterKeyPress(event) {
|
|
407
|
+
this.keyAction('detail');
|
|
408
|
+
}
|
|
380
409
|
}
|
|
381
410
|
};
|
|
382
411
|
</script>
|
|
@@ -406,6 +435,7 @@ export default {
|
|
|
406
435
|
key-field="_key"
|
|
407
436
|
:sort-generation-fn="safeSortGenerationFn"
|
|
408
437
|
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
438
|
+
:force-update-live-and-delayed="forceUpdateLiveAndDelayed"
|
|
409
439
|
@clickedActionButton="handleActionButtonClick"
|
|
410
440
|
@group-value-change="group = $event"
|
|
411
441
|
v-on="$listeners"
|
|
@@ -447,11 +477,6 @@ export default {
|
|
|
447
477
|
</template>
|
|
448
478
|
|
|
449
479
|
<template #shortkeys>
|
|
450
|
-
<button
|
|
451
|
-
v-shortkey.once="['enter']"
|
|
452
|
-
class="hide detail"
|
|
453
|
-
@shortkey="keyAction('detail')"
|
|
454
|
-
/>
|
|
455
480
|
<button
|
|
456
481
|
v-shortkey.once="['e']"
|
|
457
482
|
class="hide"
|
package/components/SimpleBox.vue
CHANGED
|
@@ -191,6 +191,16 @@ export default {
|
|
|
191
191
|
value
|
|
192
192
|
});
|
|
193
193
|
},
|
|
194
|
+
|
|
195
|
+
tooltip(col) {
|
|
196
|
+
if (!col.tooltip) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const exists = this.$store.getters['i18n/exists'];
|
|
201
|
+
|
|
202
|
+
return exists(col.tooltip) ? this.t(col.tooltip) : col.tooltip;
|
|
203
|
+
},
|
|
194
204
|
}
|
|
195
205
|
|
|
196
206
|
};
|
|
@@ -230,7 +240,7 @@ export default {
|
|
|
230
240
|
>
|
|
231
241
|
<span
|
|
232
242
|
v-if="col.sort"
|
|
233
|
-
v-tooltip="col
|
|
243
|
+
v-tooltip="tooltip(col)"
|
|
234
244
|
>
|
|
235
245
|
<span v-html="labelFor(col)" />
|
|
236
246
|
<i
|
|
@@ -252,7 +262,7 @@ export default {
|
|
|
252
262
|
</span>
|
|
253
263
|
<span
|
|
254
264
|
v-else
|
|
255
|
-
v-tooltip="col
|
|
265
|
+
v-tooltip="tooltip(col)"
|
|
256
266
|
>{{ labelFor(col) }}</span>
|
|
257
267
|
</div>
|
|
258
268
|
</th>
|
|
@@ -405,11 +415,11 @@ export default {
|
|
|
405
415
|
color: var(--body-text);
|
|
406
416
|
|
|
407
417
|
.table-header-container {
|
|
408
|
-
display:
|
|
409
|
-
align-items: center;
|
|
418
|
+
display: inherit;
|
|
410
419
|
|
|
411
420
|
> span {
|
|
412
|
-
display:
|
|
421
|
+
display: flex;
|
|
422
|
+
align-items: center;
|
|
413
423
|
}
|
|
414
424
|
|
|
415
425
|
&.not-filterable {
|
|
@@ -304,6 +304,13 @@ export default {
|
|
|
304
304
|
useQueryParamsForSimpleFiltering: {
|
|
305
305
|
type: Boolean,
|
|
306
306
|
default: false
|
|
307
|
+
},
|
|
308
|
+
/**
|
|
309
|
+
* Manaul force the update of live and delayed cells. Change this number to kick off the update
|
|
310
|
+
*/
|
|
311
|
+
forceUpdateLiveAndDelayed: {
|
|
312
|
+
type: Number,
|
|
313
|
+
default: 0
|
|
307
314
|
}
|
|
308
315
|
},
|
|
309
316
|
|
|
@@ -389,6 +396,9 @@ export default {
|
|
|
389
396
|
page(neu, old) {
|
|
390
397
|
this.watcherUpdateLiveAndDelayed(neu, old);
|
|
391
398
|
},
|
|
399
|
+
forceUpdateLiveAndDelayed(neu, old) {
|
|
400
|
+
this.watcherUpdateLiveAndDelayed(neu, old);
|
|
401
|
+
},
|
|
392
402
|
|
|
393
403
|
// Ensure we update live and delayed columns on first load
|
|
394
404
|
initalLoad: {
|
|
@@ -401,16 +411,14 @@ export default {
|
|
|
401
411
|
immediate: true
|
|
402
412
|
},
|
|
403
413
|
|
|
404
|
-
|
|
414
|
+
// this is the flag that indicates that manual refresh data has been loaded
|
|
415
|
+
// and we should update the deferred cols
|
|
416
|
+
manualRefreshLoadingFinished: {
|
|
405
417
|
handler(neu, old) {
|
|
406
|
-
this
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (old && !neu) {
|
|
411
|
-
this.manualRefreshTimer = setTimeout(() => {
|
|
412
|
-
this.watcherUpdateLiveAndDelayed(neu, old);
|
|
413
|
-
}, 1000);
|
|
418
|
+
// this is merely to update the manual refresh button status
|
|
419
|
+
this.currentPhase = !neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
|
|
420
|
+
if (neu && neu !== old) {
|
|
421
|
+
this.$nextTick(() => this.updateLiveAndDelayed());
|
|
414
422
|
}
|
|
415
423
|
},
|
|
416
424
|
immediate: true
|
|
@@ -432,6 +440,10 @@ export default {
|
|
|
432
440
|
return !!(!this.loading && !this._didinit && this.rows?.length);
|
|
433
441
|
},
|
|
434
442
|
|
|
443
|
+
manualRefreshLoadingFinished() {
|
|
444
|
+
return !!(!this.loading && this._didinit && this.rows?.length && !this.isManualRefreshLoading);
|
|
445
|
+
},
|
|
446
|
+
|
|
435
447
|
fullColspan() {
|
|
436
448
|
let span = 0;
|
|
437
449
|
|
|
@@ -1530,7 +1542,6 @@ export default {
|
|
|
1530
1542
|
.actions.role-multi-action {
|
|
1531
1543
|
background-color: transparent;
|
|
1532
1544
|
border: none;
|
|
1533
|
-
font-size: 18px;
|
|
1534
1545
|
&:hover, &:focus {
|
|
1535
1546
|
background-color: var(--accent-btn);
|
|
1536
1547
|
box-shadow: none;
|
|
@@ -92,12 +92,12 @@ export default {
|
|
|
92
92
|
sortedTabs(tabs) {
|
|
93
93
|
const {
|
|
94
94
|
defaultTab,
|
|
95
|
-
useHash
|
|
96
|
-
$route: { hash }
|
|
95
|
+
useHash
|
|
97
96
|
} = this;
|
|
98
97
|
const activeTab = tabs.find(t => t.active);
|
|
99
98
|
|
|
100
|
-
const
|
|
99
|
+
const hash = useHash ? this.$route.hash : undefined;
|
|
100
|
+
const windowHash = useHash ? hash.slice(1) : undefined;
|
|
101
101
|
const windowHashTabMatch = tabs.find(t => t.name === windowHash && !t.active);
|
|
102
102
|
const firstTab = head(tabs) || null;
|
|
103
103
|
|
|
@@ -148,11 +148,7 @@ export default {
|
|
|
148
148
|
},
|
|
149
149
|
|
|
150
150
|
select(name/* , event */) {
|
|
151
|
-
const {
|
|
152
|
-
sortedTabs,
|
|
153
|
-
$route: { hash: routeHash },
|
|
154
|
-
$router: { currentRoute },
|
|
155
|
-
} = this;
|
|
151
|
+
const { sortedTabs } = this;
|
|
156
152
|
|
|
157
153
|
const selected = this.find(name);
|
|
158
154
|
const hashName = `#${ name }`;
|
|
@@ -160,13 +156,22 @@ export default {
|
|
|
160
156
|
if ( !selected || selected.disabled) {
|
|
161
157
|
return;
|
|
162
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Exclude logic with URL anchor (hash) for projects without routing logic (vue-router)
|
|
161
|
+
*/
|
|
162
|
+
if ( this.useHash ) {
|
|
163
|
+
const {
|
|
164
|
+
$route: { hash: routeHash },
|
|
165
|
+
$router: { currentRoute },
|
|
166
|
+
} = this;
|
|
163
167
|
|
|
164
|
-
|
|
165
|
-
|
|
168
|
+
if (this.useHash && routeHash !== hashName) {
|
|
169
|
+
const kurrentRoute = { ...currentRoute };
|
|
166
170
|
|
|
167
|
-
|
|
171
|
+
kurrentRoute.hash = hashName;
|
|
168
172
|
|
|
169
|
-
|
|
173
|
+
this.$router.replace(kurrentRoute);
|
|
174
|
+
}
|
|
170
175
|
}
|
|
171
176
|
|
|
172
177
|
for ( const tab of sortedTabs ) {
|
|
@@ -251,7 +256,7 @@ export default {
|
|
|
251
256
|
<i
|
|
252
257
|
v-if="hasIcon(tab)"
|
|
253
258
|
v-tooltip="t('validation.tab')"
|
|
254
|
-
class="conditions-alert-icon icon-error
|
|
259
|
+
class="conditions-alert-icon icon-error"
|
|
255
260
|
/>
|
|
256
261
|
</a>
|
|
257
262
|
</li>
|
|
@@ -274,7 +279,7 @@ export default {
|
|
|
274
279
|
class="btn bg-transparent"
|
|
275
280
|
@click="tabAddClicked"
|
|
276
281
|
>
|
|
277
|
-
<i class="icon icon-plus
|
|
282
|
+
<i class="icon icon-plus" />
|
|
278
283
|
</button>
|
|
279
284
|
<button
|
|
280
285
|
type="button"
|
|
@@ -282,7 +287,7 @@ export default {
|
|
|
282
287
|
:disabled="!sortedTabs.length"
|
|
283
288
|
@click="tabRemoveClicked"
|
|
284
289
|
>
|
|
285
|
-
<i class="icon icon-minus
|
|
290
|
+
<i class="icon icon-minus" />
|
|
286
291
|
</button>
|
|
287
292
|
</li>
|
|
288
293
|
</ul>
|
|
Binary file
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { mount, Wrapper } from '@vue/test-utils';
|
|
2
|
+
import AsyncButton, { ASYNC_BUTTON_STATES } from '@shell/components/AsyncButton.vue';
|
|
3
|
+
|
|
4
|
+
describe('component: AsyncButton', () => {
|
|
5
|
+
it('should render appropriately with default config', () => {
|
|
6
|
+
const mockExists = jest.fn().mockReturnValue(true);
|
|
7
|
+
const mockT = jest.fn().mockReturnValue('some-string');
|
|
8
|
+
|
|
9
|
+
const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
|
|
10
|
+
mocks: {
|
|
11
|
+
$store: {
|
|
12
|
+
getters: {
|
|
13
|
+
'i18n/exists': mockExists,
|
|
14
|
+
'i18n/t': mockT
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const button = wrapper.find('button');
|
|
21
|
+
const icon = wrapper.find('i');
|
|
22
|
+
const span = wrapper.find('span');
|
|
23
|
+
|
|
24
|
+
expect(wrapper.props().currentPhase).toBe(ASYNC_BUTTON_STATES.ACTION);
|
|
25
|
+
|
|
26
|
+
expect(button.exists()).toBe(true);
|
|
27
|
+
expect(button.classes()).toContain('btn');
|
|
28
|
+
expect(button.classes()).toContain('role-primary');
|
|
29
|
+
expect(button.props().name).toBeNull();
|
|
30
|
+
expect(button.props().type).toBe('button');
|
|
31
|
+
expect(button.props().disabled).toBe(false);
|
|
32
|
+
expect(button.props().tabIndex).toBeNull();
|
|
33
|
+
// we are mocking the getters, so it's to expect to find an icon
|
|
34
|
+
expect(icon.exists()).toBe(true);
|
|
35
|
+
expect(icon.classes()).toContain('icon');
|
|
36
|
+
expect(icon.classes()).toContain('icon-lg');
|
|
37
|
+
expect(icon.classes()).toContain('icon-some-string');
|
|
38
|
+
// we are mocking the getters, so it's to expect to find a label
|
|
39
|
+
expect(span.exists()).toBe(true);
|
|
40
|
+
expect(span.text()).toBe('some-string');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('click on async button should emit click with a proper state of waiting, disabled and spinning ::: CB true', () => {
|
|
44
|
+
jest.useFakeTimers();
|
|
45
|
+
|
|
46
|
+
const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
|
|
47
|
+
mocks: {
|
|
48
|
+
$store: {
|
|
49
|
+
getters: {
|
|
50
|
+
'i18n/exists': jest.fn(),
|
|
51
|
+
'i18n/t': jest.fn()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const spyDone = jest.spyOn(wrapper.vm, 'done');
|
|
58
|
+
|
|
59
|
+
wrapper.find('button').trigger('click');
|
|
60
|
+
|
|
61
|
+
expect(wrapper.emitted('click')).toHaveLength(1);
|
|
62
|
+
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.WAITING);
|
|
63
|
+
expect(wrapper.vm.isSpinning).toBe(true);
|
|
64
|
+
expect(wrapper.vm.isDisabled).toBe(true);
|
|
65
|
+
// testing cb function has been emitted
|
|
66
|
+
expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
|
|
67
|
+
|
|
68
|
+
// trigger the cb function so that we test state changes on AsyncButton
|
|
69
|
+
wrapper.emitted('click')![0][0](true);
|
|
70
|
+
|
|
71
|
+
expect(spyDone).toHaveBeenCalledWith(true);
|
|
72
|
+
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.SUCCESS);
|
|
73
|
+
|
|
74
|
+
// wait for button delay to be completed
|
|
75
|
+
jest.runAllTimers();
|
|
76
|
+
|
|
77
|
+
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ACTION);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('click on async button should emit click and update state properly ::: CB false', () => {
|
|
81
|
+
jest.useFakeTimers();
|
|
82
|
+
|
|
83
|
+
const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
|
|
84
|
+
mocks: {
|
|
85
|
+
$store: {
|
|
86
|
+
getters: {
|
|
87
|
+
'i18n/exists': jest.fn(),
|
|
88
|
+
'i18n/t': jest.fn()
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const spyDone = jest.spyOn(wrapper.vm, 'done');
|
|
95
|
+
|
|
96
|
+
wrapper.find('button').trigger('click');
|
|
97
|
+
|
|
98
|
+
expect(wrapper.emitted('click')).toHaveLength(1);
|
|
99
|
+
// testing cb function has been emitted
|
|
100
|
+
expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
|
|
101
|
+
|
|
102
|
+
// trigger the cb function so that we test state changes on AsyncButton
|
|
103
|
+
wrapper.emitted('click')![0][0](false);
|
|
104
|
+
|
|
105
|
+
expect(spyDone).toHaveBeenCalledWith(false);
|
|
106
|
+
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ERROR);
|
|
107
|
+
|
|
108
|
+
// wait for button delay to be completed
|
|
109
|
+
jest.runAllTimers();
|
|
110
|
+
|
|
111
|
+
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ACTION);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('click on async button should emit click and update state properly ::: CB "cancelled"', () => {
|
|
115
|
+
const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
|
|
116
|
+
mocks: {
|
|
117
|
+
$store: {
|
|
118
|
+
getters: {
|
|
119
|
+
'i18n/exists': jest.fn(),
|
|
120
|
+
'i18n/t': jest.fn()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const spyDone = jest.spyOn(wrapper.vm, 'done');
|
|
127
|
+
|
|
128
|
+
wrapper.find('button').trigger('click');
|
|
129
|
+
|
|
130
|
+
expect(wrapper.emitted('click')).toHaveLength(1);
|
|
131
|
+
// testing cb function has been emitted
|
|
132
|
+
expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
|
|
133
|
+
|
|
134
|
+
// trigger the cb function so that we test state changes on AsyncButton
|
|
135
|
+
wrapper.emitted('click')![0][0]('cancelled');
|
|
136
|
+
|
|
137
|
+
expect(spyDone).toHaveBeenCalledWith('cancelled');
|
|
138
|
+
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ACTION);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { shallowMount, RouterLinkStub } from '@vue/test-utils';
|
|
2
|
+
import BackLink from '@shell/components/BackLink.vue';
|
|
3
|
+
|
|
4
|
+
describe('component: BackLink', () => {
|
|
5
|
+
it('should render component with the correct data applied', () => {
|
|
6
|
+
const linkRoute = {
|
|
7
|
+
name: 'some-route-name',
|
|
8
|
+
params: { param1: 'paramval1' },
|
|
9
|
+
query: {
|
|
10
|
+
query1: 'queryval1',
|
|
11
|
+
query2: 'queryval2'
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const wrapper = shallowMount(BackLink, {
|
|
16
|
+
propsData: { link: linkRoute },
|
|
17
|
+
stubs: { NuxtLink: RouterLinkStub }
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const link = wrapper.findComponent(RouterLinkStub);
|
|
21
|
+
const icon = wrapper.find('i');
|
|
22
|
+
|
|
23
|
+
expect(link.exists()).toBe(true);
|
|
24
|
+
// assertion regarding the text will have to be pointed to whatever t() returns on the test
|
|
25
|
+
expect(link.text()).toBe('%generic.back%');
|
|
26
|
+
expect(link.classes()).toContain('back-link');
|
|
27
|
+
expect(link.props().to).toBe(linkRoute);
|
|
28
|
+
|
|
29
|
+
expect(icon.exists()).toBe(true);
|
|
30
|
+
expect(icon.classes()).toContain('icon');
|
|
31
|
+
expect(icon.classes()).toContain('icon-chevron-left');
|
|
32
|
+
});
|
|
33
|
+
});
|