@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.5
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 +1 -1
- package/assets/styles/global/_layout.scss +4 -0
- package/assets/translations/en-us.yaml +183 -51
- package/assets/translations/zh-hans.yaml +1 -7
- package/chart/monitoring/ClusterSelector.vue +0 -21
- package/chart/monitoring/prometheus/index.vue +6 -3
- package/components/ActionDropdownShell.vue +5 -3
- package/components/ButtonGroup.vue +26 -1
- package/components/CruResource.vue +212 -16
- package/components/ExplorerMembers.vue +8 -4
- package/components/ExplorerProjectsNamespaces.vue +10 -6
- package/components/GrowlManager.vue +4 -0
- package/components/MgmtNodeList.vue +184 -0
- package/components/PromptRestore.vue +93 -32
- package/components/Questions/index.vue +1 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
- package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
- package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
- package/components/ResourceDetail/index.vue +1 -1
- package/components/ResourceList/Masthead.vue +7 -1
- package/components/ResourceList/index.vue +82 -1
- package/components/ResourceTable.vue +1 -0
- package/components/RichTranslation.vue +5 -2
- package/components/Setting.vue +1 -0
- package/components/SortableTable/index.vue +4 -3
- package/components/SubtleLink.vue +31 -6
- package/components/Tabbed/Tab.vue +29 -3
- package/components/Tabbed/index.vue +25 -3
- package/components/TableOfContents/TableOfContents.vue +109 -0
- package/components/TableOfContents/composables.ts +258 -0
- package/components/Window/ContainerShell.vue +21 -11
- package/components/Window/__tests__/ContainerShell.test.ts +107 -37
- package/components/Wizard.vue +23 -5
- package/components/__tests__/ButtonGroup.test.ts +56 -0
- package/components/__tests__/PromptRestore.test.ts +169 -19
- package/components/fleet/AppCoChartGrid.vue +401 -0
- package/components/fleet/AppCoEmptyState.vue +127 -0
- package/components/fleet/AppCoPageHeader.vue +119 -0
- package/components/fleet/AppCoVersionSelect.vue +70 -0
- package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
- package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
- package/components/fleet/FleetClusterTargets/index.vue +189 -146
- package/components/fleet/FleetIntro.vue +7 -3
- package/components/fleet/FleetNoWorkspaces.vue +7 -3
- package/components/fleet/FleetSecretSelector.vue +5 -3
- package/components/fleet/FleetValuesFrom.vue +8 -2
- package/components/fleet/GitRepoAdvancedTab.vue +1 -0
- package/components/fleet/GitRepoMetadataTab.vue +5 -0
- package/components/fleet/GitRepoTargetTab.vue +0 -2
- package/components/fleet/HelmOpAdvancedTab.vue +19 -53
- package/components/fleet/HelmOpAppCoConfigTab.vue +597 -0
- package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
- package/components/fleet/HelmOpMetadataTab.vue +5 -0
- package/components/fleet/HelmOpResourcesSection.vue +82 -0
- package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
- package/components/fleet/HelmOpTargetTab.vue +64 -60
- package/components/fleet/HelmOpValuesTab.vue +129 -105
- package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
- package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
- package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
- package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
- package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
- package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
- package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
- package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
- package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
- package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
- package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
- package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
- package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
- package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
- package/components/fleet/dashboard/Empty.vue +8 -4
- package/components/fleet/dashboard/ResourceCard.vue +28 -0
- package/components/fleet/dashboard/ResourceDetails.vue +28 -0
- package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
- package/components/form/ArrayList.vue +61 -4
- package/components/form/FileSelector.vue +39 -1
- package/components/form/KeyValue.vue +23 -2
- package/components/form/LabeledSelect.vue +39 -1
- package/components/form/Labels.vue +22 -3
- package/components/form/NameNsDescription.vue +13 -5
- package/components/form/PrivateRegistry.constants.ts +7 -0
- package/components/form/PrivateRegistry.vue +253 -18
- package/components/form/ResourceTabs/index.vue +1 -0
- package/components/form/SelectOrCreateAuthSecret.vue +140 -17
- package/components/form/__tests__/FileSelector.test.ts +23 -0
- package/components/form/__tests__/NameNsDescription.test.ts +75 -0
- package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
- package/components/formatter/EtcdSnapshotName.vue +73 -0
- package/components/formatter/InternalExternalIP.vue +10 -4
- package/components/formatter/ServiceTargets.vue +26 -7
- package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
- package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
- package/components/nav/Header.vue +12 -1
- package/components/nav/TopLevelMenu.vue +7 -2
- package/components/nav/__tests__/Header.test.ts +15 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
- package/components/templates/default.vue +16 -4
- package/components/templates/home.vue +9 -4
- package/components/templates/plain.vue +9 -4
- package/composables/useHelmOpResources.test.ts +56 -0
- package/composables/useHelmOpResources.ts +32 -0
- package/composables/useStateColor.test.ts +325 -0
- package/composables/useStateColor.ts +128 -0
- package/config/features.js +1 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +3 -0
- package/config/product/explorer.js +17 -4
- package/config/product/manager.js +8 -0
- package/config/router/index.js +16 -0
- package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
- package/config/router/navigation-guards/authentication.js +10 -4
- package/config/router/routes.js +20 -6
- package/config/secret.ts +10 -0
- package/config/settings.ts +6 -4
- package/config/table-headers.js +3 -4
- package/config/types.js +16 -0
- package/core/plugin-products-base.ts +3 -3
- package/core/plugin-types.ts +83 -30
- package/core/plugin.ts +3 -0
- package/core/types-provisioning.ts +34 -1
- package/core/types.ts +15 -2
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
- package/detail/__tests__/workload.test.ts +3 -152
- package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +109 -7
- package/detail/workload/index.vue +12 -55
- package/dialog/RotateEncryptionKeyDialog.vue +33 -9
- package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
- package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +206 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
- package/edit/auth/__tests__/azuread.test.ts +34 -9
- package/edit/auth/__tests__/github.test.ts +234 -0
- package/edit/auth/__tests__/oidc.test.ts +26 -6
- package/edit/auth/__tests__/saml.test.ts +196 -0
- package/edit/auth/azuread.vue +128 -95
- package/edit/auth/github.vue +72 -13
- package/edit/auth/ldap/__tests__/index.test.ts +206 -0
- package/edit/auth/ldap/config.vue +8 -0
- package/edit/auth/ldap/index.vue +75 -1
- package/edit/auth/oidc.vue +119 -73
- package/edit/auth/saml.vue +76 -12
- package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
- package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
- package/edit/fleet.cattle.io.gitrepo.vue +70 -16
- package/edit/fleet.cattle.io.helmop.vue +542 -141
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
- package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
- package/edit/management.cattle.io.user.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +89 -11
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
- package/list/group.principal.vue +5 -4
- package/list/harvesterhci.io.management.cluster.vue +8 -9
- package/list/management.cattle.io.user.vue +12 -9
- package/list/provisioning.cattle.io.cluster.vue +16 -10
- package/mixins/__tests__/auth-config.test.ts +90 -0
- package/mixins/__tests__/chart.test.ts +94 -0
- package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
- package/mixins/auth-config.js +7 -0
- package/mixins/chart.js +11 -2
- package/mixins/child-hook.js +12 -6
- package/mixins/create-edit-view/impl.js +5 -3
- package/mixins/resource-fetch-api-pagination.js +21 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
- package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
- package/models/__tests__/fleet-application.test.ts +175 -0
- package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
- package/models/__tests__/management.cattle.io.node.ts +22 -0
- package/models/__tests__/namespace.test.ts +36 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +205 -0
- package/models/__tests__/secret.test.ts +68 -1
- package/models/__tests__/workload.test.ts +401 -26
- package/models/catalog.cattle.io.clusterrepo.js +28 -4
- package/models/compliance.cattle.io.clusterscan.js +39 -4
- package/models/fleet-application.js +4 -0
- package/models/fleet.cattle.io.helmop.js +20 -1
- package/models/management.cattle.io.cluster.js +39 -5
- package/models/management.cattle.io.node.js +44 -3
- package/models/namespace.js +1 -1
- package/models/pod.js +46 -3
- package/models/provisioning.cattle.io.cluster.js +64 -14
- package/models/rke.cattle.io.etcdsnapshot.js +17 -9
- package/models/secret.js +19 -0
- package/models/workload.js +120 -20
- package/models/workload.service.js +5 -0
- package/package.json +14 -13
- package/pages/about.vue +5 -6
- package/pages/auth/login.vue +0 -35
- package/pages/auth/setup.vue +11 -0
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
- package/pages/c/_cluster/apps/charts/chart.vue +2 -1
- package/pages/c/_cluster/apps/charts/index.vue +48 -10
- package/pages/c/_cluster/apps/charts/install.vue +236 -144
- package/pages/c/_cluster/auth/roles/index.vue +5 -4
- package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
- package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
- package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
- package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
- package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
- package/pages/c/_cluster/fleet/application/create.vue +187 -136
- package/pages/c/_cluster/fleet/application/index.vue +5 -3
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
- package/pages/c/_cluster/fleet/index.vue +2 -2
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
- package/pages/c/_cluster/uiplugins/index.vue +15 -0
- package/pages/fail-whale.vue +16 -11
- package/pages/home.vue +16 -46
- package/pkg/require-asset.lib.js +25 -0
- package/pkg/vue.config.js +7 -0
- package/plugins/clean-html.d.ts +9 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +177 -0
- package/plugins/dashboard-store/getters.js +0 -1
- package/plugins/dashboard-store/resource-class.js +114 -19
- package/plugins/steve/__tests__/actions.test.ts +212 -0
- package/plugins/steve/actions.js +96 -0
- package/plugins/steve/steve-pagination-utils.ts +1 -1
- package/rancher-components/Accordion/Accordion.vue +53 -9
- package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
- package/rancher-components/Form/Radio/RadioButton.vue +17 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
- package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
- package/rancher-components/RcButton/RcButton.test.ts +103 -0
- package/rancher-components/RcButton/RcButton.vue +94 -15
- package/rancher-components/RcButton/index.ts +1 -1
- package/rancher-components/RcButton/types.ts +3 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
- package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
- package/rancher-components/RcSection/RcSection.vue +28 -3
- package/scripts/extension/helm/package/Dockerfile +1 -1
- package/scripts/test-plugins-build.sh +2 -1
- package/store/__tests__/features.test.ts +131 -0
- package/store/__tests__/growl.test.ts +374 -0
- package/store/__tests__/modal.test.ts +131 -0
- package/store/__tests__/notifications.test.ts +434 -0
- package/store/__tests__/slideInPanel.test.ts +88 -0
- package/store/__tests__/type-map.utils.test.ts +433 -0
- package/store/catalog.js +57 -0
- package/store/features.js +4 -0
- package/store/plugins.js +7 -4
- package/types/components/buttonGroup.ts +5 -0
- package/types/shell/index.d.ts +166 -70
- package/utils/__tests__/auth.test.ts +273 -0
- package/utils/__tests__/computed.test.ts +193 -0
- package/utils/__tests__/cspAdaptor.test.ts +163 -0
- package/utils/__tests__/dom.test.ts +81 -0
- package/utils/__tests__/duration.test.ts +37 -1
- package/utils/__tests__/dynamic-importer.test.ts +102 -0
- package/utils/__tests__/fleet-appco.test.ts +312 -0
- package/utils/__tests__/monitoring.test.ts +130 -0
- package/utils/__tests__/object.test.ts +22 -0
- package/utils/__tests__/operation-cr.test.ts +34 -0
- package/utils/__tests__/platform.test.ts +91 -0
- package/utils/__tests__/position.test.ts +237 -0
- package/utils/__tests__/provider.test.ts +51 -1
- package/utils/__tests__/queue.test.ts +232 -0
- package/utils/__tests__/release-notes.test.ts +221 -0
- package/utils/__tests__/router.test.js +254 -1
- package/utils/__tests__/select.test.ts +208 -0
- package/utils/__tests__/time.test.ts +265 -1
- package/utils/__tests__/title.test.ts +47 -0
- package/utils/__tests__/width.test.ts +53 -0
- package/utils/__tests__/window.test.ts +158 -0
- package/utils/__tests__/xccdf.test.ts +126 -6
- package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
- package/utils/crypto/__tests__/index.test.ts +144 -0
- package/utils/duration.ts +104 -0
- package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
- package/utils/dynamic-content/info.ts +2 -1
- package/utils/error.js +13 -0
- package/utils/fleet-appco.ts +323 -0
- package/utils/object.js +22 -2
- package/utils/operation-cr.js +19 -0
- package/utils/provider.ts +12 -0
- package/utils/require-asset.ts +7 -0
- package/utils/validators/__tests__/container-images.test.ts +104 -0
- package/utils/validators/__tests__/flow-output.test.ts +91 -0
- package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
- package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
- package/utils/validators/__tests__/private-registry.test.ts +27 -15
- package/utils/validators/private-registry.ts +15 -4
- package/utils/xccdf.ts +39 -42
- package/vue.config.js +1 -1
- package/pages/support/index.vue +0 -264
- package/utils/duration.js +0 -43
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
accordions: {
|
|
4
|
+
type: Array,
|
|
5
|
+
required: true,
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const handleScrollTo = (entry, event) => {
|
|
10
|
+
entry?.scrollTo?.();
|
|
11
|
+
event?.currentTarget?.blur?.();
|
|
12
|
+
};
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div class="toc-root">
|
|
17
|
+
<div class="toc-container">
|
|
18
|
+
<h4>
|
|
19
|
+
{{ t('cruResource.tableOfContents.jumpTo') }}
|
|
20
|
+
</h4>
|
|
21
|
+
<ul>
|
|
22
|
+
<li
|
|
23
|
+
v-for="(acc, i) in props.accordions"
|
|
24
|
+
:key="i"
|
|
25
|
+
:data-testid="`toc-list-item-${i}`"
|
|
26
|
+
>
|
|
27
|
+
<button
|
|
28
|
+
v-if="acc.scrollTo"
|
|
29
|
+
type="button"
|
|
30
|
+
class="btn role-link accordion-link"
|
|
31
|
+
@click="handleScrollTo(acc, $event)"
|
|
32
|
+
>
|
|
33
|
+
{{ acc.label }}
|
|
34
|
+
</button>
|
|
35
|
+
<span v-else>{{ acc.label }}</span>
|
|
36
|
+
<template v-if="acc?.children?.length">
|
|
37
|
+
<ul data-testid="toc-list">
|
|
38
|
+
<li
|
|
39
|
+
v-for="(childAcc, j) in acc.children"
|
|
40
|
+
:key="j"
|
|
41
|
+
:data-testid="`toc-list-item-${i}-${j}`"
|
|
42
|
+
>
|
|
43
|
+
<button
|
|
44
|
+
v-if="childAcc.scrollTo"
|
|
45
|
+
type="button"
|
|
46
|
+
class="btn role-link accordion-link"
|
|
47
|
+
@click="handleScrollTo(childAcc, $event)"
|
|
48
|
+
>
|
|
49
|
+
{{ childAcc.label }}
|
|
50
|
+
</button>
|
|
51
|
+
<span v-else>{{ childAcc.label }}</span>
|
|
52
|
+
</li>
|
|
53
|
+
</ul>
|
|
54
|
+
</template>
|
|
55
|
+
</li>
|
|
56
|
+
</ul>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<style lang="scss" scoped>
|
|
62
|
+
ul {
|
|
63
|
+
list-style-type: none;
|
|
64
|
+
margin: 0;
|
|
65
|
+
padding: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
li:not(:last-child) {
|
|
69
|
+
margin-bottom: var(--gap);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
h4 {
|
|
73
|
+
margin-bottom: 12px;
|
|
74
|
+
margin-top: 0px
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
li ul {
|
|
78
|
+
padding-left: var(--gap-md);
|
|
79
|
+
& li {
|
|
80
|
+
margin-top: var(--gap);
|
|
81
|
+
margin-bottom: 0px;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.toc-container {
|
|
86
|
+
padding: var(--gap-md);
|
|
87
|
+
border-radius: var(--border-radius);
|
|
88
|
+
background-color: var(--subtle-overlay-bg);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.accordion-link {
|
|
92
|
+
padding: 0px;
|
|
93
|
+
min-height: 0px;
|
|
94
|
+
line-height: 1.3em;
|
|
95
|
+
white-space: normal;
|
|
96
|
+
overflow-wrap: anywhere;
|
|
97
|
+
word-break: break-word;
|
|
98
|
+
text-align: left;
|
|
99
|
+
display: block;
|
|
100
|
+
width: 100%;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
li > span {
|
|
104
|
+
white-space: normal;
|
|
105
|
+
overflow-wrap: anywhere;
|
|
106
|
+
word-break: break-word;
|
|
107
|
+
display: block;
|
|
108
|
+
}
|
|
109
|
+
</style>
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import debounce from 'lodash/debounce';
|
|
2
|
+
import { randomStr } from '@shell/utils/string';
|
|
3
|
+
import {
|
|
4
|
+
computed, inject, onMounted, onUnmounted, provide, ref, watch
|
|
5
|
+
} from 'vue';
|
|
6
|
+
import type {
|
|
7
|
+
ComputedRef,
|
|
8
|
+
Ref,
|
|
9
|
+
VNode
|
|
10
|
+
} from 'vue';
|
|
11
|
+
|
|
12
|
+
type SummaryInfo = {
|
|
13
|
+
id: string;
|
|
14
|
+
label?: ComputedRef<string> | string;
|
|
15
|
+
scrollTo?: () => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type SummaryComponent = {
|
|
19
|
+
summary: SummaryInfo;
|
|
20
|
+
summaryID: string;
|
|
21
|
+
$options?: { name?: string };
|
|
22
|
+
$?: { type?: { name?: string } };
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type SummaryEntry = {
|
|
26
|
+
node: VNode;
|
|
27
|
+
children: SummaryEntry[];
|
|
28
|
+
label?: string | ComputedRef<string>;
|
|
29
|
+
scrollTo?: () => void;
|
|
30
|
+
component?: SummaryComponent;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type RegisterComponent = (component?: SummaryComponent | null) => void;
|
|
34
|
+
|
|
35
|
+
type FormSummaryContext = {
|
|
36
|
+
registerComponent: RegisterComponent;
|
|
37
|
+
unRegisterComponent: RegisterComponent;
|
|
38
|
+
refreshComponents: () => void;
|
|
39
|
+
updateComponentLabel: (summaryID: string, label: string) => boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type ElementWithVNodeChildren = {
|
|
43
|
+
children?: ArrayLike<Element>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type ElementWithSummaryID = HTMLElement & {
|
|
47
|
+
summaryID?: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Unique key used by provide/inject so each form subtree gets its own
|
|
51
|
+
// summary registration context
|
|
52
|
+
const FORM_SUMMARY_KEY = Symbol('formSummary');
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* useFormSummary will determine the relative position of all descendant components
|
|
56
|
+
* that are using the useInSummary composable. It is used to build summaries of elaborate form components
|
|
57
|
+
* that may have interactable elements deeply nested in child components. The list of located components
|
|
58
|
+
* returned by locateComponentsByNamePattern includes access to the component instance and a scrollTo method.
|
|
59
|
+
*/
|
|
60
|
+
export function useFormSummary(rootComponentRef: Readonly<Ref<HTMLElement | null>>) {
|
|
61
|
+
const registeredComponents = ref<Record<string, SummaryComponent>>({});
|
|
62
|
+
const locatedComponents = ref<SummaryEntry[]>([]);
|
|
63
|
+
const buildTree = (
|
|
64
|
+
components: SummaryEntry[] = [],
|
|
65
|
+
node?: any,
|
|
66
|
+
found = new Set<string>()
|
|
67
|
+
) => {
|
|
68
|
+
let nextInput = components;
|
|
69
|
+
|
|
70
|
+
const summaryID = node?.el ? (node?.el as ElementWithSummaryID | null | undefined)?.summaryID || '' : node?.summaryID || '';
|
|
71
|
+
const component = registeredComponents.value[summaryID];
|
|
72
|
+
const summary = component?.summary;
|
|
73
|
+
|
|
74
|
+
if (component && summary && registeredComponents.value[summary.id] && !found.has(summary.id)) {
|
|
75
|
+
found.add(summary.id);
|
|
76
|
+
|
|
77
|
+
const out: SummaryEntry = {
|
|
78
|
+
node: node as VNode,
|
|
79
|
+
children: [],
|
|
80
|
+
...summary,
|
|
81
|
+
scrollTo: component ? () => scrollToComponent(component) : undefined
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
out.component = component;
|
|
85
|
+
|
|
86
|
+
components.push(out);
|
|
87
|
+
nextInput = out.children;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!node) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const children = node.el ? Array.from((node.el as ElementWithVNodeChildren | null | undefined)?.children ?? []) : Array.from(node.children ?? []);
|
|
95
|
+
|
|
96
|
+
children.forEach((child: any) => {
|
|
97
|
+
buildTree(nextInput, child, found);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return components;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const locateRegisteredComponents = () => {
|
|
104
|
+
if (rootComponentRef?.value) {
|
|
105
|
+
locatedComponents.value = buildTree([], rootComponentRef.value) || [];
|
|
106
|
+
} else {
|
|
107
|
+
locatedComponents.value = [];
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// when forms initially this is called synchonously by every component using the summary composable
|
|
112
|
+
// debounce without a delay reduces that to one call on initial page load
|
|
113
|
+
const debouncedLocateRegisteredComponents = debounce(locateRegisteredComponents);
|
|
114
|
+
|
|
115
|
+
// onMounted fires on the calling component (CruResource) after its template refs are
|
|
116
|
+
// populated and after all children have run their own onMounted hooks. This guarantees
|
|
117
|
+
// rootComponentRef is available and all child registrations have arrived.
|
|
118
|
+
onMounted(() => {
|
|
119
|
+
debouncedLocateRegisteredComponents();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const findParent = (component: SummaryComponent) => {
|
|
123
|
+
const walk = (entries: SummaryEntry[] = [], parent: SummaryEntry | null = null): SummaryEntry | null => {
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (entry?.component?.summary?.id === component?.summary?.id) {
|
|
126
|
+
return parent;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (entry?.children?.length) {
|
|
130
|
+
const found = walk(entry.children, entry);
|
|
131
|
+
|
|
132
|
+
if (found) {
|
|
133
|
+
return found;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return null;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return walk(locatedComponents.value);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const updateComponentLabel = (summaryID: string, label: string) => {
|
|
145
|
+
const walk = (entries: SummaryEntry[] = []): boolean => {
|
|
146
|
+
for (const entry of entries) {
|
|
147
|
+
if (entry?.component?.summary?.id === summaryID) {
|
|
148
|
+
entry.label = label;
|
|
149
|
+
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (entry?.children?.length && walk(entry.children)) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return false;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return walk(locatedComponents.value);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const scrollToComponent = (component: SummaryComponent) => {
|
|
165
|
+
const parent = findParent(component);
|
|
166
|
+
|
|
167
|
+
if (parent?.component) {
|
|
168
|
+
scrollToComponent(parent.component);
|
|
169
|
+
}
|
|
170
|
+
if (component?.summary?.scrollTo) {
|
|
171
|
+
component.summary.scrollTo();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const registerComponent: RegisterComponent = (component) => {
|
|
176
|
+
if (!component || !component.summary?.id) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
registeredComponents.value[component.summary?.id] = component;
|
|
180
|
+
debouncedLocateRegisteredComponents();
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const unRegisterComponent: RegisterComponent = (component) => {
|
|
184
|
+
if (!component || !component.summary?.id) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
delete registeredComponents.value[component.summary?.id];
|
|
189
|
+
debouncedLocateRegisteredComponents();
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Provide the register/unregister functions to all descendants
|
|
193
|
+
provide<FormSummaryContext>(FORM_SUMMARY_KEY, {
|
|
194
|
+
registerComponent,
|
|
195
|
+
unRegisterComponent,
|
|
196
|
+
refreshComponents: debouncedLocateRegisteredComponents,
|
|
197
|
+
updateComponentLabel,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return { locatedComponents };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Hook to register a component in the summary system.
|
|
205
|
+
* Injects register/unregister from the nearest ancestor that called useFormSummary().
|
|
206
|
+
* When the component is mounted (including after v-if re-reveals it), it re-registers
|
|
207
|
+
* into the correct scoped context. Components using inFormSummary will register themselves
|
|
208
|
+
* with the nearest ancestor containing useFormSummary
|
|
209
|
+
*
|
|
210
|
+
* @param options.scrollTo - Scroll handler. The ToC system calls this function when the
|
|
211
|
+
* user navigates to this component via the Table of Contents. Use this to perform any
|
|
212
|
+
* additional work before scrolling (e.g. expanding an accordion, revealing a tab).
|
|
213
|
+
* @param options.label - Label for this component's ToC entry. Accepts a plain string or
|
|
214
|
+
* a `ComputedRef<string>`.
|
|
215
|
+
* @param options.elementRef - A template ref pointing to the component's root element.
|
|
216
|
+
* Used by the ToC system to locate this component during DOM tree traversal.
|
|
217
|
+
*/
|
|
218
|
+
export function useInSummary(options: { scrollTo: () => void; label: ComputedRef<string> | string; elementRef: Readonly<Ref<HTMLElement | null>> }) {
|
|
219
|
+
const {
|
|
220
|
+
registerComponent = () => {},
|
|
221
|
+
unRegisterComponent = () => {},
|
|
222
|
+
refreshComponents = () => {},
|
|
223
|
+
updateComponentLabel = () => false
|
|
224
|
+
} = inject<FormSummaryContext>(FORM_SUMMARY_KEY) || {};
|
|
225
|
+
|
|
226
|
+
const { scrollTo, label, elementRef } = options;
|
|
227
|
+
|
|
228
|
+
const summaryID = randomStr();
|
|
229
|
+
const summary: SummaryInfo = { id: summaryID, scrollTo };
|
|
230
|
+
|
|
231
|
+
// Wrap a plain string in a computed so the type is always ComputedRef<string>.
|
|
232
|
+
summary.label = typeof label === 'string' ? computed(() => label) : label;
|
|
233
|
+
|
|
234
|
+
watch(summary.label, (label) => {
|
|
235
|
+
const updated = updateComponentLabel(summaryID, label);
|
|
236
|
+
|
|
237
|
+
if (!updated) {
|
|
238
|
+
refreshComponents();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
onMounted(() => {
|
|
243
|
+
if (elementRef.value) {
|
|
244
|
+
(elementRef.value as ElementWithSummaryID).summaryID = summaryID;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
registerComponent({ summary, summaryID } as SummaryComponent);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
onUnmounted(() => {
|
|
251
|
+
// Unregister by summary ID — only the ID is needed for deletion
|
|
252
|
+
const stub = { summary } as SummaryComponent;
|
|
253
|
+
|
|
254
|
+
unRegisterComponent(stub);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return { summary };
|
|
258
|
+
}
|
|
@@ -80,7 +80,6 @@ export default {
|
|
|
80
80
|
fitAddon: null,
|
|
81
81
|
searchAddon: null,
|
|
82
82
|
webglAddon: null,
|
|
83
|
-
canvasAddon: null,
|
|
84
83
|
isOpen: false,
|
|
85
84
|
isOpening: false,
|
|
86
85
|
backlog: [],
|
|
@@ -168,7 +167,7 @@ export default {
|
|
|
168
167
|
try {
|
|
169
168
|
const schema = this.$store.getters[`cluster/schemaFor`](NODE);
|
|
170
169
|
|
|
171
|
-
if (schema) {
|
|
170
|
+
if (schema && nodeId) {
|
|
172
171
|
await this.$store.dispatch('cluster/find', { type: NODE, id: nodeId });
|
|
173
172
|
}
|
|
174
173
|
} catch {}
|
|
@@ -215,14 +214,13 @@ export default {
|
|
|
215
214
|
|
|
216
215
|
async setupTerminal() {
|
|
217
216
|
const docStyle = getComputedStyle(document.querySelector('body'));
|
|
218
|
-
const xterm = await import(/* webpackChunkName: "xterm" */ 'xterm');
|
|
217
|
+
const xterm = await import(/* webpackChunkName: "xterm" */ '@xterm/xterm');
|
|
219
218
|
|
|
220
219
|
const addons = await allHash({
|
|
221
|
-
fit: import(/* webpackChunkName: "xterm" */ 'xterm
|
|
222
|
-
webgl: import(/* webpackChunkName: "xterm" */ 'xterm
|
|
223
|
-
weblinks: import(/* webpackChunkName: "xterm" */ 'xterm
|
|
224
|
-
search: import(/* webpackChunkName: "xterm" */ 'xterm
|
|
225
|
-
canvas: import(/* webpackChunkName: "xterm" */ 'xterm-addon-canvas')
|
|
220
|
+
fit: import(/* webpackChunkName: "xterm" */ '@xterm/addon-fit'),
|
|
221
|
+
webgl: import(/* webpackChunkName: "xterm" */ '@xterm/addon-webgl'),
|
|
222
|
+
weblinks: import(/* webpackChunkName: "xterm" */ '@xterm/addon-web-links'),
|
|
223
|
+
search: import(/* webpackChunkName: "xterm" */ '@xterm/addon-search'),
|
|
226
224
|
});
|
|
227
225
|
|
|
228
226
|
const terminal = new xterm.Terminal({
|
|
@@ -242,9 +240,21 @@ export default {
|
|
|
242
240
|
terminal.loadAddon(new addons.weblinks.WebLinksAddon());
|
|
243
241
|
terminal.open(this.$refs.xterm);
|
|
244
242
|
|
|
243
|
+
// if user is using Safari with webGPU disabled, webglAddon will silently fail
|
|
244
|
+
// and we do not have a way to detect that.
|
|
245
|
+
// To avoid it, default to DOM rendering for Safari browsers
|
|
245
246
|
try {
|
|
246
|
-
|
|
247
|
-
|
|
247
|
+
const ua = window.navigator.userAgent.toLowerCase();
|
|
248
|
+
const isSafari = ua.includes('safari') &&
|
|
249
|
+
!ua.includes('crios') && // Chrome iOS
|
|
250
|
+
!ua.includes('fxios') && // Firefox iOS
|
|
251
|
+
!ua.includes('edgios') && // Edge iOS
|
|
252
|
+
!ua.includes('opr'); // Opera
|
|
253
|
+
|
|
254
|
+
if (!isSafari) {
|
|
255
|
+
this.webglAddon = new addons.webgl.WebglAddon();
|
|
256
|
+
terminal.loadAddon(this.webglAddon);
|
|
257
|
+
}
|
|
248
258
|
} catch (e) {
|
|
249
259
|
// Some browsers (Safari) don't support the webgl renderer, so don't use it.
|
|
250
260
|
this.webglAddon = null;
|
|
@@ -288,7 +298,7 @@ export default {
|
|
|
288
298
|
}
|
|
289
299
|
|
|
290
300
|
const url = addParams(
|
|
291
|
-
`${ this.pod.links
|
|
301
|
+
`${ this.pod.links?.view.replace(/^http/, 'ws') }/exec`,
|
|
292
302
|
{
|
|
293
303
|
container: this.container,
|
|
294
304
|
stdout: 1,
|
|
@@ -12,47 +12,72 @@ jest.mock('@shell/utils/crypto', () => {
|
|
|
12
12
|
return {
|
|
13
13
|
__esModule: true,
|
|
14
14
|
...originalModule,
|
|
15
|
-
base64Decode: jest.fn().mockImplementation((str:
|
|
15
|
+
base64Decode: jest.fn().mockImplementation((str:string) => str)
|
|
16
16
|
};
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
const mockOnData = jest.fn();
|
|
20
|
+
const mockLoadAddon = jest.fn();
|
|
21
|
+
const mockOpen = jest.fn();
|
|
22
|
+
const mockFocus = jest.fn();
|
|
23
|
+
const mockWrite = jest.fn();
|
|
24
|
+
const mockWriteln = jest.fn();
|
|
25
|
+
const mockReset = jest.fn();
|
|
26
|
+
const mockOnResize = jest.fn();
|
|
27
|
+
const mockPaste = jest.fn();
|
|
28
|
+
const mockDispose = jest.fn();
|
|
29
|
+
const mockClear = jest.fn();
|
|
30
|
+
|
|
31
|
+
jest.mock(/* webpackChunkName: "xterm" */ '@xterm/xterm', () => {
|
|
32
|
+
return {
|
|
33
|
+
Terminal: class {
|
|
34
|
+
onData = mockOnData;
|
|
35
|
+
loadAddon = mockLoadAddon;
|
|
36
|
+
open = mockOpen;
|
|
37
|
+
focus = mockFocus;
|
|
38
|
+
write = mockWrite;
|
|
39
|
+
writeln = mockWriteln;
|
|
40
|
+
reset = mockReset;
|
|
41
|
+
onResize = mockOnResize;
|
|
42
|
+
paste = mockPaste;
|
|
43
|
+
dispose = mockDispose;
|
|
44
|
+
clear = mockClear;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const mockFit = jest.fn();
|
|
50
|
+
const mockProposeDimensions = jest.fn().mockImplementation(() => ({ rows: 1, cols: 1 }));
|
|
51
|
+
|
|
52
|
+
jest.mock(/* webpackChunkName: "@xterm" */ '@xterm/addon-fit', () => {
|
|
53
|
+
return {
|
|
54
|
+
FitAddon: class {
|
|
55
|
+
fit = mockFit;
|
|
56
|
+
proposeDimensions = mockProposeDimensions;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
jest.mock(/* webpackChunkName: "@xterm" */ '@xterm/addon-web-links', () => {
|
|
62
|
+
return { WebLinksAddon: class {} };
|
|
63
|
+
}, { virtual: true });
|
|
64
|
+
|
|
65
|
+
jest.mock(/* webpackChunkName: "@xterm" */ '@xterm/addon-search', () => {
|
|
66
|
+
return {
|
|
67
|
+
SearchAddon: class {
|
|
68
|
+
findNext = jest.fn(); findPrevious = jest.fn();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}, { virtual: true });
|
|
72
|
+
|
|
73
|
+
jest.mock(/* webpackChunkName: "@xterm" */ '@xterm/addon-webgl', () => {
|
|
74
|
+
return { WebglAddon: class {} };
|
|
75
|
+
}, { virtual: true });
|
|
76
|
+
|
|
19
77
|
describe('component: ContainerShell', () => {
|
|
20
78
|
const action = jest.fn();
|
|
21
79
|
const translate = jest.fn();
|
|
22
80
|
const schemaFor = jest.fn();
|
|
23
|
-
const onData = jest.fn();
|
|
24
|
-
const loadAddon = jest.fn();
|
|
25
|
-
const open = jest.fn();
|
|
26
|
-
const focus = jest.fn();
|
|
27
|
-
const fit = jest.fn();
|
|
28
|
-
const proposeDimensions = jest.fn().mockImplementation(() => {
|
|
29
|
-
return { rows: 1 };
|
|
30
|
-
});
|
|
31
|
-
const write = jest.fn();
|
|
32
|
-
const writeln = jest.fn();
|
|
33
|
-
const reset = jest.fn();
|
|
34
|
-
|
|
35
|
-
jest.mock(/* webpackChunkName: "xterm" */ 'xterm', () => {
|
|
36
|
-
return {
|
|
37
|
-
Terminal: class {
|
|
38
|
-
onData = onData;
|
|
39
|
-
loadAddon = loadAddon;
|
|
40
|
-
open = open;
|
|
41
|
-
focus = focus;
|
|
42
|
-
write = write;
|
|
43
|
-
writeln = writeln;
|
|
44
|
-
reset = reset
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
});
|
|
48
|
-
jest.mock(/* webpackChunkName: "xterm" */ 'xterm-addon-fit', () => {
|
|
49
|
-
return {
|
|
50
|
-
FitAddon: class {
|
|
51
|
-
fit = fit
|
|
52
|
-
proposeDimensions = proposeDimensions
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
});
|
|
56
81
|
|
|
57
82
|
const defaultContainerShellParams = {
|
|
58
83
|
propsData: {
|
|
@@ -77,7 +102,8 @@ describe('component: ContainerShell', () => {
|
|
|
77
102
|
dispatch: action,
|
|
78
103
|
getters: {
|
|
79
104
|
'i18n/t': translate,
|
|
80
|
-
'cluster/schemaFor': schemaFor
|
|
105
|
+
'cluster/schemaFor': schemaFor,
|
|
106
|
+
'prefs/theme': jest.fn().mockReturnValue('dark')
|
|
81
107
|
}
|
|
82
108
|
}
|
|
83
109
|
},
|
|
@@ -87,6 +113,7 @@ describe('component: ContainerShell', () => {
|
|
|
87
113
|
const resetMocks = () => {
|
|
88
114
|
// Clear all instances and calls to constructor and all methods:
|
|
89
115
|
jest.clearAllMocks();
|
|
116
|
+
jest.restoreAllMocks();
|
|
90
117
|
defaultContainerShellParams.propsData.pod.os = 'linux';
|
|
91
118
|
};
|
|
92
119
|
|
|
@@ -99,7 +126,14 @@ describe('component: ContainerShell', () => {
|
|
|
99
126
|
return wrapper;
|
|
100
127
|
};
|
|
101
128
|
|
|
102
|
-
it
|
|
129
|
+
it('test that we are calling the xterm terminal and fitAddon class method mocks correctly', async() => {
|
|
130
|
+
resetMocks();
|
|
131
|
+
await wrapperPostMounted(defaultContainerShellParams);
|
|
132
|
+
|
|
133
|
+
expect(mockLoadAddon).toHaveBeenCalledWith(expect.any(Object));
|
|
134
|
+
expect(mockOpen).toHaveBeenCalledWith(expect.any(HTMLElement));
|
|
135
|
+
expect(mockFit).toHaveBeenCalledWith();
|
|
136
|
+
});
|
|
103
137
|
|
|
104
138
|
it('creates a window on the page', async() => {
|
|
105
139
|
resetMocks();
|
|
@@ -110,6 +144,26 @@ describe('component: ContainerShell', () => {
|
|
|
110
144
|
expect(windowComponent.isVisible()).toBe(true);
|
|
111
145
|
});
|
|
112
146
|
|
|
147
|
+
it('does not load webgl addon on Safari browser', async() => {
|
|
148
|
+
resetMocks();
|
|
149
|
+
|
|
150
|
+
const originalUserAgent = window.navigator.userAgent;
|
|
151
|
+
|
|
152
|
+
Object.defineProperty(window.navigator, 'userAgent', {
|
|
153
|
+
value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15',
|
|
154
|
+
configurable: true
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const wrapper = await wrapperPostMounted(defaultContainerShellParams);
|
|
158
|
+
|
|
159
|
+
expect(wrapper.vm.webglAddon).toBeNull();
|
|
160
|
+
|
|
161
|
+
Object.defineProperty(window.navigator, 'userAgent', {
|
|
162
|
+
value: originalUserAgent,
|
|
163
|
+
configurable: true
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
113
167
|
it('the find action for the node is called if schemaFor finds a schema for NODE', async() => {
|
|
114
168
|
resetMocks();
|
|
115
169
|
const testSchemaFindsSchemaParams = {
|
|
@@ -242,7 +296,23 @@ describe('component: ContainerShell', () => {
|
|
|
242
296
|
expect(wrapper.vm.os).toBe('linux');
|
|
243
297
|
});
|
|
244
298
|
|
|
245
|
-
it
|
|
299
|
+
it('test that fit and flush are operating properly', async() => {
|
|
300
|
+
resetMocks();
|
|
301
|
+
const wrapper = await wrapperPostMounted(defaultContainerShellParams);
|
|
302
|
+
|
|
303
|
+
mockFit.mockClear();
|
|
304
|
+
|
|
305
|
+
if (typeof wrapper.vm.fit === 'function') {
|
|
306
|
+
wrapper.vm.fit();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
expect(mockFit).toHaveBeenCalledWith();
|
|
310
|
+
|
|
311
|
+
if (typeof wrapper.vm.flush === 'function') {
|
|
312
|
+
wrapper.vm.flush();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
246
316
|
it.todo('test that we are properly feeding the terminal the commandOnFirstConnect prop correctly on connected');
|
|
247
317
|
|
|
248
318
|
it('the socket message event sets data props correctly', async() => {
|
package/components/Wizard.vue
CHANGED
|
@@ -109,6 +109,11 @@ export default {
|
|
|
109
109
|
default: null
|
|
110
110
|
},
|
|
111
111
|
|
|
112
|
+
showStepHeader: {
|
|
113
|
+
type: Boolean,
|
|
114
|
+
default: true
|
|
115
|
+
},
|
|
116
|
+
|
|
112
117
|
// The set of labels to display for the finish AsyncButton
|
|
113
118
|
finishMode: {
|
|
114
119
|
type: String,
|
|
@@ -119,6 +124,11 @@ export default {
|
|
|
119
124
|
errors: {
|
|
120
125
|
type: Array,
|
|
121
126
|
default: null,
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
beforeGoToStep: {
|
|
130
|
+
type: Function,
|
|
131
|
+
default: null
|
|
122
132
|
}
|
|
123
133
|
},
|
|
124
134
|
|
|
@@ -212,7 +222,7 @@ export default {
|
|
|
212
222
|
},
|
|
213
223
|
|
|
214
224
|
methods: {
|
|
215
|
-
goToStep(number, fromNav) {
|
|
225
|
+
async goToStep(number, fromNav) {
|
|
216
226
|
if (number < 1) {
|
|
217
227
|
return;
|
|
218
228
|
}
|
|
@@ -228,6 +238,14 @@ export default {
|
|
|
228
238
|
return;
|
|
229
239
|
}
|
|
230
240
|
|
|
241
|
+
if (this.beforeGoToStep && fromNav) {
|
|
242
|
+
try {
|
|
243
|
+
await this.beforeGoToStep(this.activeStep, selected);
|
|
244
|
+
} catch {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
231
249
|
this.activeStep = selected;
|
|
232
250
|
|
|
233
251
|
this.$emit('next', { step: selected });
|
|
@@ -289,7 +307,7 @@ export default {
|
|
|
289
307
|
>
|
|
290
308
|
<div>
|
|
291
309
|
<div class="header">
|
|
292
|
-
<div class="title">
|
|
310
|
+
<div :class="['title', !showStepHeader ? 'mmb-4' : '']">
|
|
293
311
|
<div
|
|
294
312
|
v-if="showBanner"
|
|
295
313
|
class="top choice-banner"
|
|
@@ -328,7 +346,7 @@ export default {
|
|
|
328
346
|
</slot>
|
|
329
347
|
<!-- Step number with subtext -->
|
|
330
348
|
<div
|
|
331
|
-
v-if="activeStep && showSteps"
|
|
349
|
+
v-if="activeStep && showSteps && showStepHeader"
|
|
332
350
|
class="subtitle"
|
|
333
351
|
>
|
|
334
352
|
<h2>{{ !!headerMode ? t(`wizard.${headerMode}`) : t(`asyncButton.${finishMode}.action`) }}: {{ t('wizard.step', {number:activeStepIndex+1}) }}</h2>
|
|
@@ -596,10 +614,10 @@ $spacer: 10px;
|
|
|
596
614
|
flex-basis: 100%;
|
|
597
615
|
border-top: 1px solid var(--border);
|
|
598
616
|
position: relative;
|
|
599
|
-
top:
|
|
617
|
+
top: 23px;
|
|
600
618
|
|
|
601
619
|
.cru__content & {
|
|
602
|
-
top:
|
|
620
|
+
top: 17px;
|
|
603
621
|
}
|
|
604
622
|
}
|
|
605
623
|
}
|