@rancher/shell 0.1.1 → 0.1.3
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/translations/en-us.yaml +33 -769
- package/assets/translations/zh-hans.yaml +153 -781
- package/components/ActionMenu.vue +3 -3
- package/components/CodeMirror.vue +6 -8
- package/components/CommunityLinks.vue +1 -1
- package/components/ContainerResourceLimit.vue +14 -0
- package/components/ExplorerMembers.vue +123 -0
- package/components/ExplorerProjectsNamespaces.vue +405 -0
- package/components/GrafanaDashboard.vue +17 -2
- package/components/LocaleSelector.vue +81 -0
- package/components/PromptModal.vue +2 -3
- package/components/ResourceList/index.vue +1 -1
- package/components/ResourceTable.vue +3 -6
- package/components/SingleClusterInfo.vue +1 -1
- package/components/SortableTable/index.vue +23 -20
- package/components/SortableTable/selection.js +1 -0
- package/components/auth/AzureWarning.vue +5 -1
- package/components/auth/Principal.vue +1 -1
- package/components/auth/RoleDetailEdit.vue +32 -12
- package/components/fleet/FleetRepos.vue +0 -2
- package/components/form/NameNsDescription.vue +4 -6
- package/components/form/NodeScheduling.vue +1 -1
- package/components/form/ResourceTabs/index.vue +27 -18
- package/components/form/WorkloadPorts.vue +1 -1
- package/components/formatter/ClusterLink.vue +13 -0
- package/components/formatter/PodImages.vue +11 -1
- package/components/formatter/RKETemplateName.vue +37 -0
- package/components/formatter/WorkloadHealthScale.vue +1 -1
- package/components/nav/Header.vue +9 -9
- package/components/nav/NamespaceFilter.vue +7 -4
- package/components/nav/TopLevelMenu.vue +6 -43
- package/components/nav/WindowManager/ContainerLogs.vue +1 -1
- package/config/product/harvester-manager.js +64 -2
- package/config/product/manager.js +9 -0
- package/config/settings.js +17 -71
- package/config/table-headers.js +0 -1
- package/config/types.js +8 -26
- package/core/plugin-routes.ts +34 -22
- package/core/plugin.ts +15 -3
- package/core/plugins-loader.js +2 -0
- package/core/plugins.js +79 -36
- package/core/types.ts +7 -1
- package/creators/app/tsconfig.json +6 -1
- package/creators/pkg/init +3 -0
- package/creators/pkg/tsconfig.json +7 -2
- package/detail/provisioning.cattle.io.cluster.vue +23 -0
- package/detail/workload/index.vue +11 -5
- package/{components/dialog → dialog}/AddClusterMemberDialog.vue +0 -0
- package/{components/dialog → dialog}/AddCustomBadgeDialog.vue +0 -0
- package/{components/dialog → dialog}/AddProjectMemberDialog.vue +0 -0
- package/{components/dialog → dialog}/AddonConfigConfirmationDialog.vue +0 -0
- package/{components/dialog → dialog}/DrainNode.vue +0 -0
- package/{components/dialog → dialog}/ForceMachineRemoveDialog.vue +0 -0
- package/{components/dialog → dialog}/GenericPrompt.vue +0 -0
- package/{components/dialog → dialog}/RollbackWorkloadDialog.vue +0 -0
- package/{components/dialog → dialog}/RotateCertificatesDialog.vue +0 -0
- package/{components/dialog → dialog}/RotateEncryptionKeyDialog.vue +0 -0
- package/{components/dialog → dialog}/SaveAsRKETemplateDialog.vue +0 -0
- package/{components/dialog → dialog}/ScaleMachineDownDialog.vue +0 -0
- package/edit/auth/azuread.vue +20 -1
- package/edit/cloudcredential.vue +7 -1
- package/edit/management.cattle.io.project.vue +2 -2
- package/edit/namespace.vue +17 -10
- package/edit/networking.k8s.io.ingress/index.vue +2 -1
- package/edit/persistentvolumeclaim.vue +33 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +34 -6
- package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +21 -6
- package/edit/service.vue +1 -1
- package/edit/workload/index.vue +363 -15
- package/edit/workload/mixins/workload.js +62 -7
- package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +1 -0
- package/layouts/default.vue +52 -27
- package/layouts/error.vue +5 -1
- package/layouts/home.vue +6 -2
- package/list/harvesterhci.io.management.cluster.vue +74 -33
- package/list/namespace.vue +3 -5
- package/list/provisioning.cattle.io.cluster.vue +6 -0
- package/machine-config/amazonec2.vue +2 -0
- package/machine-config/harvester.vue +96 -49
- package/middleware/authenticated.js +56 -52
- package/mixins/brand.js +3 -4
- package/mixins/create-edit-view/impl.js +0 -8
- package/mixins/form-validation.js +1 -1
- package/mixins/resource-fetch.js +3 -1
- package/models/chart.js +1 -1
- package/models/cluster/node.js +12 -1
- package/models/fleet.cattle.io.bundle.js +26 -19
- package/models/harvesterhci.io.management.cluster.js +194 -5
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.clusterroletemplatebinding.js +9 -0
- package/models/management.cattle.io.globalrole.js +0 -19
- package/models/management.cattle.io.project.js +23 -2
- package/models/management.cattle.io.roletemplate.js +2 -21
- package/models/namespace.js +19 -3
- package/models/pod.js +19 -2
- package/models/provisioning.cattle.io.cluster.js +71 -0
- package/models/service.js +5 -1
- package/models/workload.js +4 -243
- package/models/workload.service.js +314 -0
- package/nuxt.config.js +14 -12
- package/package.json +3 -3
- package/pages/auth/login.vue +11 -2
- package/pages/auth/setup.vue +1 -1
- package/pages/c/_cluster/_product/members/index.vue +3 -93
- package/pages/c/_cluster/_product/projectsnamespaces.vue +6 -403
- package/pages/c/_cluster/apps/charts/install.vue +0 -6
- package/pages/c/_cluster/settings/performance.vue +19 -16
- package/pages/fail-whale.vue +1 -10
- package/pages/index.vue +18 -4
- package/pages/plugins.vue +2 -2
- package/pages/prefs.vue +8 -6
- package/pkg/auto-import.js +44 -7
- package/pkg/dynamic-plugin-loader.js +28 -0
- package/pkg/import.js +2 -2
- package/pkg/model-loader-require.lib.js +3 -0
- package/pkg/vue.config.js +9 -6
- package/plugins/console.js +10 -5
- package/plugins/dashboard-store/actions.js +8 -3
- package/plugins/dashboard-store/getters.js +7 -2
- package/plugins/dashboard-store/model-loader-require.js +12 -0
- package/plugins/dashboard-store/model-loader.js +4 -1
- package/plugins/dashboard-store/resource-class.js +10 -3
- package/plugins/steve/actions.js +1 -1
- package/plugins/steve/index.js +6 -4
- package/plugins/steve/steve-description-class.js +32 -0
- package/plugins/steve/subscribe.js +34 -23
- package/rancher-components/Banner/Banner.vue +2 -2
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +77 -0
- package/rancher-components/Form/Checkbox/Checkbox.vue +12 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +0 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +2 -0
- package/rancher-components/Form/Radio/RadioButton.vue +14 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
- package/{components/form → rancher-components/Form/ToggleSwitch}/ToggleSwitch.vue +18 -8
- package/rancher-components/Form/ToggleSwitch/index.ts +1 -0
- package/rancher-components/Form/index.ts +1 -0
- package/scripts/build-pkg.sh +48 -2
- package/scripts/drone-build-pkg.sh +31 -0
- package/scripts/publish-shell.sh +10 -11
- package/scripts/serve-pkgs +17 -10
- package/scripts/test-plugins-build.sh +18 -1
- package/store/catalog.js +3 -1
- package/store/i18n.js +16 -11
- package/store/index.js +4 -181
- package/store/prefs.js +30 -2
- package/store/type-map.js +16 -29
- package/types/{index.d.ts → rancher/index.d.ts} +0 -0
- package/utils/cluster.js +1 -1
- package/utils/custom-validators.js +1 -12
- package/utils/dynamic-importer.js +1 -1
- package/utils/validators/setting.js +0 -35
- package/components/FilterLabel.vue +0 -254
- package/components/HarvesterUpgradeProgressBarList.vue +0 -109
- package/components/VMConsoleBar.vue +0 -87
- package/components/dialog/harvester/AddHotplugModal.vue +0 -159
- package/components/dialog/harvester/BackupModal.vue +0 -117
- package/components/dialog/harvester/CloneTemplate.vue +0 -125
- package/components/dialog/harvester/EjectCDROMDialog.vue +0 -157
- package/components/dialog/harvester/ExportImageDialog.vue +0 -152
- package/components/dialog/harvester/MaintenanceDialog.vue +0 -94
- package/components/dialog/harvester/MigrationDialog.vue +0 -154
- package/components/dialog/harvester/RestoreDialog.vue +0 -153
- package/components/dialog/harvester/SupportBundle.vue +0 -217
- package/components/dialog/harvester/UnplugVolume.vue +0 -108
- package/components/form/SerialConsole/index.vue +0 -267
- package/components/formatter/AttachVMWithName.vue +0 -46
- package/components/formatter/CloudInitType.vue +0 -27
- package/components/formatter/HarvesterBackupTargetValidation.vue +0 -43
- package/components/formatter/HarvesterCPUUsed.vue +0 -122
- package/components/formatter/HarvesterDiskState.vue +0 -66
- package/components/formatter/HarvesterHostName.vue +0 -66
- package/components/formatter/HarvesterIpAddress.vue +0 -90
- package/components/formatter/HarvesterMemoryUsed.vue +0 -140
- package/components/formatter/HarvesterMigrationState.vue +0 -85
- package/components/formatter/HarvesterNodeName.vue +0 -49
- package/components/formatter/HarvesterStorageUsed.vue +0 -194
- package/components/formatter/HarvesterVmState.vue +0 -123
- package/components/nav/HarvesterUpgrade.vue +0 -232
- package/components/novnc/NovncConsole.vue +0 -93
- package/components/novnc/NovncConsoleItem.vue +0 -89
- package/components/novnc/NovncConsoleWrapper.vue +0 -243
- package/config/harvester-map.js +0 -44
- package/config/harvester-table-headers.js +0 -27
- package/config/product/harvester.js +0 -305
- package/detail/harvesterhci.io.host/HarvesterHostBasic.vue +0 -364
- package/detail/harvesterhci.io.host/HarvesterHostDisk.vue +0 -200
- package/detail/harvesterhci.io.host/HarvesterHostNetwork.vue +0 -89
- package/detail/harvesterhci.io.host/VirtualMachineInstance.vue +0 -134
- package/detail/harvesterhci.io.host/index.vue +0 -243
- package/detail/harvesterhci.io.virtualmachinebackup/index.vue +0 -221
- package/detail/harvesterhci.io.virtualmachineimage.vue +0 -118
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineBasics.vue +0 -279
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineEvents.vue +0 -75
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineKeypairs.vue +0 -114
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineMigration.vue +0 -79
- package/detail/kubevirt.io.virtualmachine/index.vue +0 -213
- package/edit/harvesterhci.io.cloudtemplate.vue +0 -123
- package/edit/harvesterhci.io.host/HarvesterDisk.vue +0 -262
- package/edit/harvesterhci.io.host/index.vue +0 -533
- package/edit/harvesterhci.io.keypair.vue +0 -112
- package/edit/harvesterhci.io.managedchart/index.vue +0 -25
- package/edit/harvesterhci.io.managedchart/rancher-monitoring.vue +0 -172
- package/edit/harvesterhci.io.networkattachmentdefinition.vue +0 -210
- package/edit/harvesterhci.io.setting/additional-ca.vue +0 -36
- package/edit/harvesterhci.io.setting/backup-target.vue +0 -182
- package/edit/harvesterhci.io.setting/http-proxy.vue +0 -79
- package/edit/harvesterhci.io.setting/index.vue +0 -201
- package/edit/harvesterhci.io.setting/overcommit-config.vue +0 -94
- package/edit/harvesterhci.io.setting/ssl-certificates.vue +0 -117
- package/edit/harvesterhci.io.setting/ssl-parameters.vue +0 -161
- package/edit/harvesterhci.io.setting/support-bundle-image.vue +0 -134
- package/edit/harvesterhci.io.setting/support-bundle-namespaces.vue +0 -73
- package/edit/harvesterhci.io.setting/vip-pools.vue +0 -244
- package/edit/harvesterhci.io.setting/vm-force-reset-policy.vue +0 -81
- package/edit/harvesterhci.io.virtualmachinebackup.vue +0 -256
- package/edit/harvesterhci.io.virtualmachineimage.vue +0 -364
- package/edit/harvesterhci.io.virtualmachinetemplateversion.vue +0 -340
- package/edit/harvesterhci.io.volume.vue +0 -195
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/AccessCredentialsUsers.vue +0 -190
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/index.vue +0 -212
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/basicAuth.vue +0 -94
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/sshkey.vue +0 -85
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/DataTemplate.vue +0 -153
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/index.vue +0 -279
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +0 -113
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/__tests__/HarvesterEditNetwork.test.ts +0 -41
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/base.vue +0 -281
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/index.vue +0 -142
- package/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue +0 -54
- package/edit/kubevirt.io.virtualmachine/VirtualMachineSSHKey.vue +0 -256
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/index.vue +0 -391
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditContainer.test.ts +0 -40
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditExisting.test.ts +0 -102
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVMImage.test.ts +0 -117
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVolume.test.ts +0 -74
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue +0 -132
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue +0 -303
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue +0 -285
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +0 -188
- package/edit/kubevirt.io.virtualmachine/index.vue +0 -642
- package/edit/network.harvesterhci.io.clusternetwork/index.vue +0 -19
- package/edit/network.harvesterhci.io.clusternetwork/vlan.vue +0 -134
- package/edit/workload/types/Deployment.vue +0 -377
- package/edit/workload/types/Generic.vue +0 -295
- package/list/harvesterhci.io.cloudtemplate.vue +0 -78
- package/list/harvesterhci.io.dashboard/HarvesterUpgrade.vue +0 -211
- package/list/harvesterhci.io.dashboard/UpgradeInfo.vue +0 -40
- package/list/harvesterhci.io.dashboard/index.vue +0 -752
- package/list/harvesterhci.io.host/index.vue +0 -186
- package/list/harvesterhci.io.networkattachmentdefinition.vue +0 -167
- package/list/harvesterhci.io.setting.vue +0 -241
- package/list/harvesterhci.io.virtualmachinebackup.vue +0 -172
- package/list/harvesterhci.io.virtualmachineimage.vue +0 -80
- package/list/harvesterhci.io.virtualmachinetemplateversion.vue +0 -173
- package/list/harvesterhci.io.volume.vue +0 -122
- package/list/kubevirt.io.virtualmachine.vue +0 -193
- package/mixins/harvester-vm/impl.js +0 -267
- package/mixins/harvester-vm/index.js +0 -1357
- package/models/harvester/configmap.js +0 -32
- package/models/harvester/harvesterhci.io.blockdevice.js +0 -55
- package/models/harvester/harvesterhci.io.keypair.js +0 -12
- package/models/harvester/harvesterhci.io.setting.js +0 -127
- package/models/harvester/harvesterhci.io.supportbundle.js +0 -35
- package/models/harvester/harvesterhci.io.upgrade.js +0 -226
- package/models/harvester/harvesterhci.io.virtualmachinebackup.js +0 -116
- package/models/harvester/harvesterhci.io.virtualmachineimage.js +0 -255
- package/models/harvester/harvesterhci.io.virtualmachinerestore.js +0 -43
- package/models/harvester/harvesterhci.io.virtualmachinetemplate.js +0 -69
- package/models/harvester/harvesterhci.io.virtualmachinetemplateversion.js +0 -227
- package/models/harvester/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -32
- package/models/harvester/kubevirt.io.virtualmachine.js +0 -850
- package/models/harvester/kubevirt.io.virtualmachineinstance.js +0 -142
- package/models/harvester/management.cattle.io.managedchart.js +0 -191
- package/models/harvester/management.cattle.io.setting.js +0 -40
- package/models/harvester/network.harvesterhci.io.clusternetwork.js +0 -100
- package/models/harvester/network.harvesterhci.io.nodenetwork.js +0 -34
- package/models/harvester/node.js +0 -255
- package/models/harvester/persistentvolumeclaim.js +0 -166
- package/models/harvester/pod.js +0 -185
- package/pages/c/_cluster/harvester/airgapupgrade/index.vue +0 -309
- package/pages/c/_cluster/harvester/console/_uid/serial.vue +0 -51
- package/pages/c/_cluster/harvester/console/_uid/vnc.vue +0 -52
- package/pages/c/_cluster/harvester/index.vue +0 -24
- package/pages/c/_cluster/harvester/support/index.vue +0 -154
- package/pkg/model-loader.lib.js +0 -3
- package/plugins/lookup.js +0 -50
- package/promptRemove/kubevirt.io.virtualmachine.vue +0 -164
- package/store/harvester-common.js +0 -126
- package/utils/validators/vm-datavolumes.js +0 -38
- package/utils/validators/vm-image.js +0 -32
- package/utils/validators/vm.js +0 -221
- package/yarn-error.log +0 -196
package/pages/index.vue
CHANGED
|
@@ -2,21 +2,35 @@
|
|
|
2
2
|
import { SEEN_WHATS_NEW } from '@shell/store/prefs';
|
|
3
3
|
import { getVersionInfo } from '@shell/utils/version';
|
|
4
4
|
|
|
5
|
+
const validRoute = (route, router) => {
|
|
6
|
+
return !!route && !!router.resolve(route)?.resolved?.matched?.length;
|
|
7
|
+
};
|
|
8
|
+
|
|
5
9
|
export default {
|
|
6
|
-
middleware({ redirect, store } ) {
|
|
10
|
+
middleware({ redirect, store, app } ) {
|
|
7
11
|
const seenWhatsNew = store.getters['prefs/get'](SEEN_WHATS_NEW);
|
|
8
12
|
const versionInfo = getVersionInfo(store);
|
|
9
13
|
const isSingleProduct = store.getters['isSingleProduct'];
|
|
14
|
+
const dashboardHome = { name: 'home' };
|
|
10
15
|
|
|
11
16
|
// If this is a new version, then take the user to the home page to view the release notes
|
|
12
17
|
if (versionInfo.fullVersion !== seenWhatsNew && !isSingleProduct) {
|
|
13
|
-
return redirect(
|
|
18
|
+
return redirect(dashboardHome);
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
// Take the user to the configured login route
|
|
17
21
|
const afterLoginRouteObject = store.getters['prefs/afterLoginRoute'];
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
// Confirm this is a valid route (it could have come from an uninstalled plugin)
|
|
24
|
+
if (validRoute(afterLoginRouteObject, app.router)) {
|
|
25
|
+
// Take the user to the configured login route
|
|
26
|
+
return redirect(afterLoginRouteObject);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (validRoute(isSingleProduct?.afterLoginRoute, app.router)) {
|
|
30
|
+
return redirect(isSingleProduct.afterLoginRoute);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return redirect(dashboardHome);
|
|
20
34
|
}
|
|
21
35
|
};
|
|
22
36
|
</script>
|
package/pages/plugins.vue
CHANGED
|
@@ -242,7 +242,7 @@ export default {
|
|
|
242
242
|
<LabeledInput v-model="location" label="Plugin URL" @input="updateLocation" />
|
|
243
243
|
</div>
|
|
244
244
|
<div class="dialog-buttons">
|
|
245
|
-
<button class="btn" @click="closeAddDialog()">
|
|
245
|
+
<button class="btn role-secondary" @click="closeAddDialog()">
|
|
246
246
|
Cancel
|
|
247
247
|
</button>
|
|
248
248
|
<button class="btn role-primary" @click="loadPlugin()">
|
|
@@ -268,7 +268,7 @@ export default {
|
|
|
268
268
|
<LabeledInput v-model="catalogUrl" label="Catalog URL" />
|
|
269
269
|
</div>
|
|
270
270
|
<div class="dialog-buttons">
|
|
271
|
-
<button class="btn" @click="closeAddCatalogDialog()">
|
|
271
|
+
<button class="btn role-secondary" @click="closeAddCatalogDialog()">
|
|
272
272
|
Cancel
|
|
273
273
|
</button>
|
|
274
274
|
<button class="btn role-primary" @click="addCatalog()">
|
package/pages/prefs.vue
CHANGED
|
@@ -159,8 +159,11 @@ export default {
|
|
|
159
159
|
<LandingPagePreference />
|
|
160
160
|
</div>
|
|
161
161
|
<hr />
|
|
162
|
-
<h4 v-t="'prefs.
|
|
163
|
-
<
|
|
162
|
+
<h4 v-t="'prefs.displaySettings.title'" />
|
|
163
|
+
<p class="set-landing-leadin">
|
|
164
|
+
{{ t('prefs.displaySettings.detail', {}, raw=true) }}
|
|
165
|
+
</p>
|
|
166
|
+
<div class="row mt-20">
|
|
164
167
|
<div class="col span-4">
|
|
165
168
|
<LabeledSelect
|
|
166
169
|
v-model="dateFormat"
|
|
@@ -175,7 +178,9 @@ export default {
|
|
|
175
178
|
:options="timeOptions"
|
|
176
179
|
/>
|
|
177
180
|
</div>
|
|
181
|
+
</div>
|
|
178
182
|
|
|
183
|
+
<div class="row mt-20">
|
|
179
184
|
<div class="col span-4">
|
|
180
185
|
<LabeledSelect
|
|
181
186
|
v-model.number="perPage"
|
|
@@ -186,9 +191,6 @@ export default {
|
|
|
186
191
|
placeholder="Select a row count"
|
|
187
192
|
/>
|
|
188
193
|
</div>
|
|
189
|
-
</div>
|
|
190
|
-
|
|
191
|
-
<div class="row mt-20">
|
|
192
194
|
<div class="col span-4">
|
|
193
195
|
<LabeledSelect
|
|
194
196
|
v-model.number="menuMaxClusters"
|
|
@@ -207,7 +209,7 @@ export default {
|
|
|
207
209
|
<h4 v-t="'prefs.advanced'" />
|
|
208
210
|
<Checkbox v-model="dev" :label="t('prefs.dev.label', {}, true)" />
|
|
209
211
|
<p class="wrap-text">
|
|
210
|
-
{{ t('prefs.advancedTooltip'
|
|
212
|
+
{{ t('prefs.advancedTooltip') }}
|
|
211
213
|
</p>
|
|
212
214
|
<br>
|
|
213
215
|
<Checkbox v-if="!isSingleProduct" v-model="hideDescriptions" :label="t('prefs.hideDesc.label')" class="mt-10" />
|
package/pkg/auto-import.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const contextFolders = ['chart', 'cloud-credential', 'content', 'detail', 'edit', 'list', 'machine-config', 'models', 'promptRemove', 'l10n', 'windowComponents', 'formatters'];
|
|
3
|
+
const contextFolders = ['chart', 'cloud-credential', 'content', 'detail', 'edit', 'list', 'machine-config', 'models', 'promptRemove', 'l10n', 'windowComponents', 'dialog', 'formatters'];
|
|
4
4
|
const contextMap = contextFolders.reduce((map, obj) => {
|
|
5
5
|
map[obj] = true;
|
|
6
6
|
|
|
@@ -11,6 +11,19 @@ function replaceAll(str, find, replace) {
|
|
|
11
11
|
return str.split(find).join(replace);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function registerFile(file, type, pkg, f) {
|
|
15
|
+
const importType = (f === 'models') ? 'require' : 'import';
|
|
16
|
+
const chunkName = (f === 'l10n') ? '' : `/* webpackChunkName: "${ f }" */`;
|
|
17
|
+
|
|
18
|
+
return ` $plugin.register('${ f }', '${ type }', () => ${ importType }(${ chunkName }'${ pkg }/${ f }/${ file }'));\n`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function register(file, pkg, f) {
|
|
22
|
+
const name = file.replace(/\.[^/.]+$/, '');
|
|
23
|
+
|
|
24
|
+
return registerFile(file, name, pkg, f);
|
|
25
|
+
}
|
|
26
|
+
|
|
14
27
|
// This function is used to generate the code to register models, edit, detail, list etc for a type
|
|
15
28
|
// This is used when building as a library - it does not use require.context - it scans the file system and build time.
|
|
16
29
|
// This ensures that the webpackChunkName is respected (require.context does not support this) - so when build as a library
|
|
@@ -20,13 +33,34 @@ function generateTypeImport(pkg, dir) {
|
|
|
20
33
|
|
|
21
34
|
// Auto-import if the folder exists
|
|
22
35
|
contextFolders.forEach((f) => {
|
|
23
|
-
|
|
36
|
+
const filePath = path.join(dir, f);
|
|
37
|
+
|
|
38
|
+
if (fs.existsSync(filePath)) {
|
|
24
39
|
fs.readdirSync(path.join(dir, f)).forEach((file) => {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
const fileStat = fs.lstatSync(path.join(filePath, file));
|
|
41
|
+
|
|
42
|
+
// Directories are special cases
|
|
43
|
+
if (fileStat.isDirectory()) {
|
|
44
|
+
// This might be a <type>/index.vue (aka nested component)
|
|
45
|
+
const indexFilePath = path.join(file, 'index.vue');
|
|
46
|
+
const fullIndexFilePath = path.join(filePath, indexFilePath);
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
if (fs.existsSync(fullIndexFilePath)) {
|
|
49
|
+
content += registerFile(indexFilePath, file, pkg, f);
|
|
50
|
+
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// This might be a <store name>/<model name|type>.js file (aka nested model)
|
|
55
|
+
if (f === 'models') {
|
|
56
|
+
fs.readdirSync(path.join(filePath, file)).forEach((store) => {
|
|
57
|
+
content += register(path.join(file, store), pkg, f);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
// This is a simple <resource type>.<file type> file
|
|
62
|
+
content += register(file, pkg, f);
|
|
63
|
+
}
|
|
30
64
|
});
|
|
31
65
|
}
|
|
32
66
|
});
|
|
@@ -48,7 +82,10 @@ function generateDynamicTypeImport(pkg, dir) {
|
|
|
48
82
|
// Auto-import if the folder exists
|
|
49
83
|
contextFolders.forEach((f) => {
|
|
50
84
|
if (fs.existsSync(path.join(dir, f))) {
|
|
51
|
-
|
|
85
|
+
const safeName = f.replace(/\/|-/g, '_');
|
|
86
|
+
let genImport = replaceAll(template, 'NAME', safeName);
|
|
87
|
+
|
|
88
|
+
genImport = replaceAll(genImport, 'DIR', f );
|
|
52
89
|
const importType = (f === 'models') ? 'require' : 'import';
|
|
53
90
|
// Ensure i18n chunks are named with the request name (which will be the locale)
|
|
54
91
|
const chunk = (f === 'l10n') ? '[request]' : f;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Some plugins won't be bundled with the dashboard build but loaded on demand at run time.
|
|
4
|
+
* This file allows 'manager' style plugins to defined how to determine if a unknown route
|
|
5
|
+
* belongs to one of their associated plugins and how that plugin can be loaded
|
|
6
|
+
*/
|
|
7
|
+
class DynamicPluginLoader {
|
|
8
|
+
dynamicPluginLoaders = [];
|
|
9
|
+
|
|
10
|
+
register(reg) {
|
|
11
|
+
this.dynamicPluginLoaders.push(reg);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async check({ route, store }) {
|
|
15
|
+
for (const dpl of this.dynamicPluginLoaders) {
|
|
16
|
+
// Check that the route is valid and then load the plugin associated with it
|
|
17
|
+
const res = await dpl.load({ route, store });
|
|
18
|
+
|
|
19
|
+
if (res) {
|
|
20
|
+
return res;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const dynamicPluginLoader = new DynamicPluginLoader();
|
|
27
|
+
|
|
28
|
+
export default dynamicPluginLoader;
|
package/pkg/import.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const _NAME = require.context('BASE/
|
|
1
|
+
const _NAME = require.context('BASE/DIR', true, /\.(vue|js|yaml)$/).keys();
|
|
2
2
|
|
|
3
3
|
_NAME.forEach((f) => {
|
|
4
4
|
let name = f.substr(2);
|
|
@@ -6,5 +6,5 @@ _NAME.forEach((f) => {
|
|
|
6
6
|
|
|
7
7
|
name = name.substr(0, ext);
|
|
8
8
|
|
|
9
|
-
$plugin.register('
|
|
9
|
+
$plugin.register('DIR', name, () => REQUIRE(CHUNK`BASE/DIR/${ name }EXT`)); // eslint-disable-line no-undef
|
|
10
10
|
});
|
package/pkg/vue.config.js
CHANGED
|
@@ -46,20 +46,23 @@ module.exports = function(dir) {
|
|
|
46
46
|
config.resolve.alias['~pkg'] = dir;
|
|
47
47
|
delete config.resolve.alias['@'];
|
|
48
48
|
|
|
49
|
-
// Prevent the dynamic importer and the model-loader from importing anything dynamically - we don't want all of the
|
|
49
|
+
// Prevent the dynamic importer and the model-loader-require from importing anything dynamically - we don't want all of the
|
|
50
50
|
// models etc when we build as a library
|
|
51
|
-
const
|
|
51
|
+
const dynamicImporterOverride = new webpack.NormalModuleReplacementPlugin(/dynamic-importer$/, (resource) => {
|
|
52
52
|
resource.request = path.join(__dirname, 'dynamic-importer.lib.js');
|
|
53
53
|
});
|
|
54
|
-
const
|
|
55
|
-
|
|
54
|
+
const modelLoaderImporterOverride = new webpack.NormalModuleReplacementPlugin(/model-loader-require$/, (resource) => {
|
|
55
|
+
const fileName = 'model-loader-require.lib.js';
|
|
56
|
+
const pkgModelLoaderRequire = path.join(dir, fileName);
|
|
57
|
+
|
|
58
|
+
resource.request = fs.existsSync(pkgModelLoaderRequire) ? pkgModelLoaderRequire : path.join(__dirname, fileName);
|
|
56
59
|
});
|
|
57
60
|
|
|
58
61
|
// Auto-generate module to import the types (model, detail, edit etc)
|
|
59
62
|
const autoImportPlugin = new VirtualModulesPlugin({ 'node_modules/@rancher/auto-import': generateTypeImport('@pkg', dir) });
|
|
60
63
|
|
|
61
|
-
config.plugins.unshift(
|
|
62
|
-
config.plugins.unshift(
|
|
64
|
+
config.plugins.unshift(dynamicImporterOverride);
|
|
65
|
+
config.plugins.unshift(modelLoaderImporterOverride);
|
|
63
66
|
config.plugins.unshift(autoImportPlugin);
|
|
64
67
|
// config.plugins.unshift(debug);
|
|
65
68
|
|
package/plugins/console.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
export default (
|
|
3
|
-
const logTypes = ['
|
|
2
|
+
export default () => {
|
|
3
|
+
const logTypes = ['warn', 'error'];
|
|
4
4
|
const MAX_LOGS_STORED = 400;
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
if (!process.env.dev) {
|
|
7
|
+
console.logLog = console.log.bind(console);
|
|
8
|
+
console.infoLog = console.info.bind(console);
|
|
9
|
+
logTypes.push('log');
|
|
10
|
+
logTypes.push('info');
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
console.warnLog = console.warn.bind(console);
|
|
14
|
+
console.errorLog = console.error.bind(console);
|
|
10
15
|
console.logs = [];
|
|
11
16
|
|
|
12
17
|
logTypes.forEach((type) => {
|
|
@@ -319,7 +319,12 @@ export default {
|
|
|
319
319
|
return all;
|
|
320
320
|
},
|
|
321
321
|
|
|
322
|
-
async findMatching(ctx, {
|
|
322
|
+
async findMatching(ctx, {
|
|
323
|
+
type,
|
|
324
|
+
selector,
|
|
325
|
+
opt,
|
|
326
|
+
namespace
|
|
327
|
+
}) {
|
|
323
328
|
const {
|
|
324
329
|
getters, commit, dispatch, rootGetters
|
|
325
330
|
} = ctx;
|
|
@@ -332,7 +337,7 @@ export default {
|
|
|
332
337
|
commit('registerType', type);
|
|
333
338
|
}
|
|
334
339
|
if ( opt.force !== true && getters['haveSelector'](type, selector) ) {
|
|
335
|
-
return getters.matching( type, selector );
|
|
340
|
+
return getters.matching( type, selector, namespace );
|
|
336
341
|
}
|
|
337
342
|
|
|
338
343
|
const typeOptions = rootGetters['type-map/optionsFor'](type);
|
|
@@ -366,7 +371,7 @@ export default {
|
|
|
366
371
|
});
|
|
367
372
|
}
|
|
368
373
|
|
|
369
|
-
return getters.matching( type, selector );
|
|
374
|
+
return getters.matching( type, selector, namespace );
|
|
370
375
|
},
|
|
371
376
|
|
|
372
377
|
// opt:
|
|
@@ -25,8 +25,13 @@ export default {
|
|
|
25
25
|
return state.types[type].list;
|
|
26
26
|
},
|
|
27
27
|
|
|
28
|
-
matching: (state, getters) => (type, selector) => {
|
|
29
|
-
|
|
28
|
+
matching: (state, getters) => (type, selector, namespace) => {
|
|
29
|
+
let all = getters['all'](type);
|
|
30
|
+
|
|
31
|
+
// Filter first by namespace if one is provided, since this is efficient
|
|
32
|
+
if (namespace) {
|
|
33
|
+
all = all.filter(obj => obj.namespace === namespace);
|
|
34
|
+
}
|
|
30
35
|
|
|
31
36
|
return all.filter((obj) => {
|
|
32
37
|
return matches(obj, selector);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch a model from the dashboard's local model's folder
|
|
3
|
+
*
|
|
4
|
+
* Splitting this out into a separate function means packages can
|
|
5
|
+
* override this to ensure dashboard models aren't bundled with it
|
|
6
|
+
*
|
|
7
|
+
* @param {string} type
|
|
8
|
+
* @returns Model for the given type
|
|
9
|
+
*/
|
|
10
|
+
export default function modelLoaderRequire(type) {
|
|
11
|
+
return require(`@shell/models/${ type }`);
|
|
12
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeType } from './normalize';
|
|
2
|
+
import modelLoaderRequire from './model-loader-require';
|
|
2
3
|
|
|
3
4
|
const cache = {};
|
|
4
5
|
|
|
@@ -16,7 +17,9 @@ function find(cache, type, rootState) {
|
|
|
16
17
|
let base;
|
|
17
18
|
|
|
18
19
|
if (!pluginModel) {
|
|
19
|
-
|
|
20
|
+
// Model hasn't come from a plugin, fall back on something reasonable
|
|
21
|
+
// by default this is the dashboard's local models folder
|
|
22
|
+
base = modelLoaderRequire(type);
|
|
20
23
|
} else if (typeof pluginModel === 'function') {
|
|
21
24
|
// pluginModel could be an object in the case the plugin is built-in
|
|
22
25
|
base = pluginModel();
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
validateDnsLikeTypes,
|
|
25
25
|
validateLength,
|
|
26
26
|
} from '@shell/utils/validators';
|
|
27
|
-
import formRulesGenerator from '@shell/utils/validators/formRules';
|
|
27
|
+
import formRulesGenerator from '@shell/utils/validators/formRules/index';
|
|
28
28
|
import jsyaml from 'js-yaml';
|
|
29
29
|
import compact from 'lodash/compact';
|
|
30
30
|
import forIn from 'lodash/forIn';
|
|
@@ -1587,8 +1587,15 @@ export default class Resource {
|
|
|
1587
1587
|
if (!isEmpty(validatorName) && validatorExists) {
|
|
1588
1588
|
CustomValidators[validatorName](pathValue, this.$rootGetters, errors, validatorArgs, displayKey, data);
|
|
1589
1589
|
} else if (!isEmpty(validatorName) && !validatorExists) {
|
|
1590
|
-
//
|
|
1591
|
-
|
|
1590
|
+
// Check if validator is imported from plugin
|
|
1591
|
+
const pluginValidator = this.$rootState.$plugin?.getValidator(validatorName);
|
|
1592
|
+
|
|
1593
|
+
if (pluginValidator) {
|
|
1594
|
+
pluginValidator(pathValue, this.$rootGetters, errors, validatorArgs, displayKey, data);
|
|
1595
|
+
} else {
|
|
1596
|
+
// eslint-disable-next-line
|
|
1597
|
+
console.warn(this.t('validation.custom.missing', { validatorName }));
|
|
1598
|
+
}
|
|
1592
1599
|
}
|
|
1593
1600
|
});
|
|
1594
1601
|
});
|
package/plugins/steve/actions.js
CHANGED
|
@@ -178,7 +178,7 @@ export default {
|
|
|
178
178
|
const res = err.response;
|
|
179
179
|
|
|
180
180
|
// Go to the logout page for 401s, unless redirectUnauthorized specifically disables (for the login page)
|
|
181
|
-
if ( opt.redirectUnauthorized !== false &&
|
|
181
|
+
if ( opt.redirectUnauthorized !== false && res.status === 401 ) {
|
|
182
182
|
dispatch('auth/logout', opt.logoutOnError, { root: true });
|
|
183
183
|
}
|
|
184
184
|
|
package/plugins/steve/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import getters, { STEVE_MODEL_TYPES } from './getters';
|
|
|
10
10
|
import mutations from './mutations';
|
|
11
11
|
import actions from './actions';
|
|
12
12
|
|
|
13
|
-
function SteveFactory(namespace, baseUrl) {
|
|
13
|
+
export function SteveFactory(namespace, baseUrl) {
|
|
14
14
|
return {
|
|
15
15
|
...coreStoreModule,
|
|
16
16
|
|
|
@@ -50,6 +50,10 @@ function SteveFactory(namespace, baseUrl) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
export const steveStoreInit = (store, ctx) => {
|
|
54
|
+
createWorker(store, ctx);
|
|
55
|
+
};
|
|
56
|
+
|
|
53
57
|
export default (config) => {
|
|
54
58
|
config.namespace = config.namespace || '';
|
|
55
59
|
|
|
@@ -67,8 +71,6 @@ export default (config) => {
|
|
|
67
71
|
return coreStore(
|
|
68
72
|
SteveFactory(config.namespace, config.baseUrl),
|
|
69
73
|
config,
|
|
70
|
-
|
|
71
|
-
createWorker(store, ctx);
|
|
72
|
-
}
|
|
74
|
+
steveStoreInit
|
|
73
75
|
);
|
|
74
76
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import SteveModel from './steve-class';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SteveModel that supports the description being in the root 'description' property.
|
|
5
|
+
*/
|
|
6
|
+
export default class SteveDescriptionModel extends SteveModel {
|
|
7
|
+
// Preserve description
|
|
8
|
+
constructor(data, ctx, rehydrateNamespace = null, setClone = false) {
|
|
9
|
+
const _description = data.description;
|
|
10
|
+
|
|
11
|
+
super(data, ctx, rehydrateNamespace, setClone);
|
|
12
|
+
this.description = _description;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get description() {
|
|
16
|
+
return this._description;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
set description(value) {
|
|
20
|
+
this._description = value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Ensure when we clone that we preserve the desription
|
|
24
|
+
toJSON() {
|
|
25
|
+
const data = super.toJSON();
|
|
26
|
+
|
|
27
|
+
data.description = this.description;
|
|
28
|
+
delete data._description;
|
|
29
|
+
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { addObject, clear, removeObject } from '@shell/utils/array';
|
|
2
2
|
import { get } from '@shell/utils/object';
|
|
3
|
-
import { COUNT, SCHEMA } from '@shell/config/types';
|
|
3
|
+
import { COUNT, MANAGEMENT, SCHEMA } from '@shell/config/types';
|
|
4
|
+
import { SETTING } from '@shell/config/settings';
|
|
4
5
|
import Socket, {
|
|
5
6
|
EVENT_CONNECTED,
|
|
6
7
|
EVENT_DISCONNECTED,
|
|
@@ -456,28 +457,38 @@ export const actions = {
|
|
|
456
457
|
clearTimeout(state.queueTimer);
|
|
457
458
|
state.queueTimer = null;
|
|
458
459
|
if (e.type === EVENT_DISCONNECT_ERROR) {
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
url
|
|
479
|
-
|
|
480
|
-
|
|
460
|
+
// determine if websocket notifications are disabled
|
|
461
|
+
const perfSetting = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
|
|
462
|
+
let disableGrowl = false;
|
|
463
|
+
|
|
464
|
+
if ( perfSetting?.value ) {
|
|
465
|
+
disableGrowl = JSON.parse(perfSetting.value).disableWebsocketNotification || false;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if ( !disableGrowl ) {
|
|
469
|
+
// do not send a growl notification unless the socket stays disconnected for more than MINIMUM_TIME_DISCONNECTED
|
|
470
|
+
setTimeout(() => {
|
|
471
|
+
if (state.socket.isConnected()) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const dateFormat = escapeHtml( rootGetters['prefs/get'](DATE_FORMAT));
|
|
475
|
+
const timeFormat = escapeHtml( rootGetters['prefs/get'](TIME_FORMAT));
|
|
476
|
+
const time = e?.srcElement?.disconnectedAt || Date.now();
|
|
477
|
+
|
|
478
|
+
const timeFormatted = `${ day(time).format(`${ dateFormat } ${ timeFormat }`) }`;
|
|
479
|
+
const url = e?.srcElement?.url;
|
|
480
|
+
|
|
481
|
+
const t = rootGetters['i18n/t'];
|
|
482
|
+
|
|
483
|
+
dispatch('growl/error', {
|
|
484
|
+
title: t('growl.disconnected.title'),
|
|
485
|
+
message: t('growl.disconnected.message', { url, time: timeFormatted }, { raw: true }),
|
|
486
|
+
icon: 'error',
|
|
487
|
+
earliestClose: time + MINIMUM_TIME_NOTIFIED + MINIMUM_TIME_DISCONNECTED,
|
|
488
|
+
url
|
|
489
|
+
}, { root: true });
|
|
490
|
+
}, MINIMUM_TIME_DISCONNECTED);
|
|
491
|
+
}
|
|
481
492
|
} else {
|
|
482
493
|
// if the error is not a disconnect error, the socket never worked: log whether the current browser is safari
|
|
483
494
|
console.error(`WebSocket Connection Error [${ getters.storeName }]`, e.detail); // eslint-disable-line no-console
|
|
@@ -131,8 +131,8 @@ export default Vue.extend({
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
&.secondary {
|
|
134
|
-
background: var(--
|
|
135
|
-
border-left: solid $left-border-size var(--
|
|
134
|
+
background: var(--default-banner-bg);
|
|
135
|
+
border-left: solid $left-border-size var(--default);
|
|
136
136
|
color: var(--body-text);
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { Checkbox } from './index';
|
|
3
|
+
|
|
4
|
+
describe('Checkbox.vue', () => {
|
|
5
|
+
it('is unchecked by default', () => {
|
|
6
|
+
const wrapper = shallowMount(Checkbox);
|
|
7
|
+
const cbInput = wrapper.find('input[type="checkbox"]').element as HTMLInputElement;
|
|
8
|
+
|
|
9
|
+
expect(cbInput.checked).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('renders a true value', () => {
|
|
13
|
+
const wrapper = shallowMount(Checkbox, { propsData: { value: true } });
|
|
14
|
+
const cbInput = wrapper.find('input[type="checkbox"]').element as HTMLInputElement;
|
|
15
|
+
|
|
16
|
+
expect(cbInput.checked).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('updates from false to true when props change', async () => {
|
|
20
|
+
const wrapper = shallowMount(Checkbox);
|
|
21
|
+
const cbInput = wrapper.find('input[type="checkbox"]').element as HTMLInputElement;
|
|
22
|
+
|
|
23
|
+
expect(cbInput.checked).toBe(false);
|
|
24
|
+
|
|
25
|
+
await wrapper.setProps({ value: true });
|
|
26
|
+
|
|
27
|
+
expect(cbInput.checked).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('emits an input event with a true value', async () => {
|
|
31
|
+
const wrapper = shallowMount(Checkbox);
|
|
32
|
+
const event = {
|
|
33
|
+
target: { tagName: 'input', href: null },
|
|
34
|
+
stopPropagation: () => { },
|
|
35
|
+
preventDefault: () => { }
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
(wrapper.vm as any).clicked(event);
|
|
39
|
+
await wrapper.vm.$nextTick();
|
|
40
|
+
|
|
41
|
+
expect(wrapper.emitted().input?.length).toBe(1);
|
|
42
|
+
expect(wrapper.emitted().input?.[0][0]).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('emits an input event with a custom valueWhenTrue', async () => {
|
|
46
|
+
const valueWhenTrue = 'BIG IF TRUE';
|
|
47
|
+
const event = {
|
|
48
|
+
target: { tagName: 'input', href: null },
|
|
49
|
+
stopPropagation: () => { },
|
|
50
|
+
preventDefault: () => { }
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const wrapper = shallowMount(Checkbox, { propsData: { value: false, valueWhenTrue } });
|
|
54
|
+
|
|
55
|
+
(wrapper.vm as any).clicked(event);
|
|
56
|
+
await wrapper.vm.$nextTick();
|
|
57
|
+
|
|
58
|
+
expect(wrapper.emitted().input?.length).toBe(1);
|
|
59
|
+
expect(wrapper.emitted().input?.[0][0]).toBe(valueWhenTrue);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('updates from valueWhenTrue to falsy', async () => {
|
|
63
|
+
const valueWhenTrue = 'REAL HUGE IF FALSE';
|
|
64
|
+
const event = {
|
|
65
|
+
target: { tagName: 'input', href: null },
|
|
66
|
+
stopPropagation: () => { },
|
|
67
|
+
preventDefault: () => { }
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const wrapper = shallowMount(Checkbox, { propsData: { value: valueWhenTrue, valueWhenTrue } });
|
|
71
|
+
|
|
72
|
+
(wrapper.vm as any).clicked(event);
|
|
73
|
+
await wrapper.vm.$nextTick();
|
|
74
|
+
|
|
75
|
+
expect(wrapper.emitted().input?.[0][0]).toBe(null);
|
|
76
|
+
})
|
|
77
|
+
});
|