@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
|
@@ -3,6 +3,7 @@ import StatusCard from '@shell/components/Resource/Detail/Card/StatusCard/index.
|
|
|
3
3
|
import StatusBar from '@shell/components/Resource/Detail/StatusBar.vue';
|
|
4
4
|
import StatusRow from '@shell/components/Resource/Detail/StatusRow.vue';
|
|
5
5
|
import Scaler from '@shell/components/Resource/Detail/Card/Scaler.vue';
|
|
6
|
+
import type { SummaryResult } from '@shell/components/Resource/Detail/Card/StateCard/composables';
|
|
6
7
|
|
|
7
8
|
describe('component: StatusCard', () => {
|
|
8
9
|
const mockResource = (stateDisplay: string, stateSimpleColor: string) => ({
|
|
@@ -106,4 +107,64 @@ describe('component: StatusCard', () => {
|
|
|
106
107
|
expect(wrapper.findComponent(Scaler).exists()).toBe(false);
|
|
107
108
|
});
|
|
108
109
|
});
|
|
110
|
+
|
|
111
|
+
describe('with summaryData', () => {
|
|
112
|
+
it('should render StatusBar and StatusRows from summary counts', () => {
|
|
113
|
+
const summaryData: SummaryResult = {
|
|
114
|
+
count: 5,
|
|
115
|
+
summary: [{ property: 'metadata.state.name', counts: { running: { total: 3 }, error: { total: 2 } } }]
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const wrapper = mountCard({ summaryData });
|
|
119
|
+
|
|
120
|
+
expect(wrapper.findComponent(StatusBar).exists()).toBe(true);
|
|
121
|
+
expect(wrapper.findAllComponents(StatusRow)).toHaveLength(2);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should use summaryData over resources when both are provided', () => {
|
|
125
|
+
const summaryData: SummaryResult = {
|
|
126
|
+
count: 4,
|
|
127
|
+
summary: [{ property: 'metadata.state.name', counts: { running: { total: 3 }, completed: { total: 1 } } }]
|
|
128
|
+
};
|
|
129
|
+
const resources = [
|
|
130
|
+
mockResource('Running', 'text-success'),
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
const wrapper = mountCard({ summaryData, resources });
|
|
134
|
+
|
|
135
|
+
expect(wrapper.findAllComponents(StatusRow)).toHaveLength(2);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should fall back to resources when summaryData has no summary', () => {
|
|
139
|
+
const summaryData: SummaryResult = { count: 0, summary: null };
|
|
140
|
+
const resources = [
|
|
141
|
+
mockResource('Running', 'text-success'),
|
|
142
|
+
mockResource('Error', 'text-error'),
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
const wrapper = mountCard({ summaryData, resources });
|
|
146
|
+
|
|
147
|
+
expect(wrapper.findAllComponents(StatusRow)).toHaveLength(2);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should show noResourcesMessage when summaryData has no counts', () => {
|
|
151
|
+
const summaryData: SummaryResult = { count: 0, summary: [] };
|
|
152
|
+
|
|
153
|
+
const wrapper = mountCard({ summaryData, noResourcesMessage: 'No pods' });
|
|
154
|
+
|
|
155
|
+
expect(wrapper.findComponent(StatusBar).exists()).toBe(false);
|
|
156
|
+
expect(wrapper.find('.text-deemphasized').text()).toBe('No pods');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should render a single state from summary', () => {
|
|
160
|
+
const summaryData: SummaryResult = {
|
|
161
|
+
count: 2,
|
|
162
|
+
summary: [{ property: 'metadata.state.name', counts: { active: { total: 2 } } }]
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const wrapper = mountCard({ summaryData });
|
|
166
|
+
|
|
167
|
+
expect(wrapper.findAllComponents(StatusRow)).toHaveLength(1);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
109
170
|
});
|
|
@@ -8,10 +8,13 @@ import { useI18n } from '@shell/composables/useI18n';
|
|
|
8
8
|
import { StateColor } from '@shell/utils/style';
|
|
9
9
|
import { computed } from 'vue';
|
|
10
10
|
import { useStore } from 'vuex';
|
|
11
|
+
import { colorForState as colorForStateFn, stateDisplay as stateDisplayFn } from '@shell/plugins/dashboard-store/resource-class';
|
|
12
|
+
import type { SummaryResult } from '@shell/components/Resource/Detail/Card/StateCard/composables';
|
|
11
13
|
|
|
12
14
|
export interface Props {
|
|
13
15
|
title: string;
|
|
14
16
|
resources?: any[];
|
|
17
|
+
summaryData?: SummaryResult | null;
|
|
15
18
|
showScaling?: boolean;
|
|
16
19
|
noResourcesMessage?: string;
|
|
17
20
|
}
|
|
@@ -23,23 +26,47 @@ const i18n = useI18n(store);
|
|
|
23
26
|
|
|
24
27
|
const props = withDefaults(defineProps<Props>(), {
|
|
25
28
|
resources: undefined,
|
|
29
|
+
summaryData: undefined,
|
|
26
30
|
showScaling: false,
|
|
27
31
|
noResourcesMessage: undefined
|
|
28
32
|
});
|
|
29
33
|
const emit = defineEmits(['decrease', 'increase']);
|
|
30
34
|
|
|
35
|
+
const summaryStateCounts = computed(() => {
|
|
36
|
+
const summary = props.summaryData?.summary;
|
|
37
|
+
|
|
38
|
+
if (!summary?.length) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const entry = summary.find((s) => s.property === 'metadata.state.name');
|
|
43
|
+
|
|
44
|
+
return entry?.counts || null;
|
|
45
|
+
});
|
|
46
|
+
|
|
31
47
|
const segmentAccumulator = computed(() => {
|
|
32
48
|
interface Value {
|
|
33
49
|
count: number;
|
|
34
50
|
}
|
|
35
51
|
const accumulator: {[key in StateColor]?: Value} = {};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const stateCounts = summaryStateCounts.value;
|
|
53
|
+
|
|
54
|
+
if (stateCounts) {
|
|
55
|
+
for (const [state, stateCount] of Object.entries(stateCounts)) {
|
|
56
|
+
const colorRaw = colorForStateFn(state) as string;
|
|
57
|
+
const color = (colorRaw?.replace('text-', '') || 'disabled') as StateColor;
|
|
58
|
+
|
|
59
|
+
accumulator[color] = accumulator[color] || { count: 0 };
|
|
60
|
+
accumulator[color].count += stateCount.total;
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
props.resources?.forEach((resource: any) => {
|
|
64
|
+
const color: StateColor = resource.stateSimpleColor || 'disabled';
|
|
65
|
+
|
|
66
|
+
accumulator[color] = accumulator[color] || { count: 0 };
|
|
67
|
+
accumulator[color].count++;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
43
70
|
|
|
44
71
|
return accumulator;
|
|
45
72
|
});
|
|
@@ -50,21 +77,40 @@ const rowAccumulator = computed(() => {
|
|
|
50
77
|
color: StateColor;
|
|
51
78
|
}
|
|
52
79
|
const accumulator: {[key in string]: Value} = {};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
80
|
+
const stateCounts = summaryStateCounts.value;
|
|
81
|
+
|
|
82
|
+
if (stateCounts) {
|
|
83
|
+
for (const [state, stateCount] of Object.entries(stateCounts)) {
|
|
84
|
+
const display = stateDisplayFn(state) as string;
|
|
85
|
+
const colorRaw = colorForStateFn(state) as string;
|
|
86
|
+
const color = (colorRaw?.replace('text-', '') || 'disabled') as StateColor;
|
|
87
|
+
|
|
88
|
+
accumulator[display] = accumulator[display] || { count: 0, color };
|
|
89
|
+
accumulator[display].count += stateCount.total;
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
props.resources?.forEach((resource: any) => {
|
|
93
|
+
const color = (resource.stateSimpleColor?.replace('text-', '') || 'disabled') as StateColor;
|
|
94
|
+
|
|
95
|
+
accumulator[resource.stateDisplay] = accumulator[resource.stateDisplay] || { count: 0, color };
|
|
96
|
+
accumulator[resource.stateDisplay].count++;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
59
99
|
|
|
60
100
|
return accumulator;
|
|
61
101
|
});
|
|
62
102
|
|
|
63
103
|
const percent = (count: number, total: number) => {
|
|
64
|
-
return count / total * 100;
|
|
104
|
+
return total > 0 ? count / total * 100 : 0;
|
|
65
105
|
};
|
|
66
106
|
|
|
67
|
-
const count = computed(() =>
|
|
107
|
+
const count = computed(() => {
|
|
108
|
+
if (summaryStateCounts.value) {
|
|
109
|
+
return props.summaryData?.count ?? 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return props.resources?.length ?? 0;
|
|
113
|
+
});
|
|
68
114
|
|
|
69
115
|
const segmentColors = computed(() => Object.keys(segmentAccumulator.value) as StateColor[]);
|
|
70
116
|
const segments = computed(() => segmentColors.value.map((color: StateColor) => ({
|
|
@@ -103,6 +103,8 @@ const getRowValueId = (row:Row): string => `value-${ row.label }:${ row.value }`
|
|
|
103
103
|
flex-direction: column;
|
|
104
104
|
|
|
105
105
|
.row {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
106
108
|
gap: 8px;
|
|
107
109
|
|
|
108
110
|
// Hide clearfix pseudo-elements inherited from the global .row class
|
|
@@ -110,9 +110,12 @@ const showConfigurationMoreFocusSelector = computed(() => `[data-testid="${ show
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
.row {
|
|
113
|
-
display: block;
|
|
114
|
-
width: 100%;
|
|
115
113
|
display: inline-block;
|
|
114
|
+
width: 100%;
|
|
115
|
+
|
|
116
|
+
&::before, &::after {
|
|
117
|
+
display: none;
|
|
118
|
+
}
|
|
116
119
|
|
|
117
120
|
&:not(:nth-child(2)) {
|
|
118
121
|
margin-top: 4px;
|
|
@@ -92,18 +92,14 @@ const previewId = randomStr();
|
|
|
92
92
|
max-width: calc(100%);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
.rc-tag {
|
|
96
|
-
display: inline-block;
|
|
97
|
-
line-height: normal;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
95
|
.tag-data {
|
|
101
96
|
display: inline-block;
|
|
102
97
|
overflow: hidden;
|
|
103
98
|
text-overflow: ellipsis;
|
|
104
99
|
white-space: nowrap;
|
|
100
|
+
min-width: 0;
|
|
105
101
|
max-width: calc(100%);
|
|
106
|
-
line-height:
|
|
102
|
+
line-height: 1;
|
|
107
103
|
}
|
|
108
104
|
|
|
109
105
|
& .btn.btn-medium.rc-button.variant-ghost {
|
|
@@ -74,6 +74,11 @@ export default {
|
|
|
74
74
|
default: false
|
|
75
75
|
},
|
|
76
76
|
|
|
77
|
+
showFavorite: {
|
|
78
|
+
type: Boolean,
|
|
79
|
+
default: true
|
|
80
|
+
},
|
|
81
|
+
|
|
77
82
|
/**
|
|
78
83
|
* Inherited global identifier prefix for tests
|
|
79
84
|
* Define a term based on the parent component to avoid conflicts on multiple components
|
|
@@ -202,7 +207,7 @@ export default {
|
|
|
202
207
|
<div class="title">
|
|
203
208
|
<h1 class="m-0">
|
|
204
209
|
<TabTitle>{{ _typeDisplay }}</TabTitle> <Favorite
|
|
205
|
-
v-if="isExplorer"
|
|
210
|
+
v-if="isExplorer && showFavorite"
|
|
206
211
|
:resource="favoriteResource || resource"
|
|
207
212
|
/>
|
|
208
213
|
</h1>
|
|
@@ -267,6 +272,7 @@ export default {
|
|
|
267
272
|
'title actions'
|
|
268
273
|
'sub-header sub-header'
|
|
269
274
|
'state-banner state-banner';
|
|
275
|
+
margin-bottom: 24px;
|
|
270
276
|
}
|
|
271
277
|
|
|
272
278
|
.sub-header {
|
|
@@ -10,6 +10,9 @@ import { PanelLocation, ExtensionPoint } from '@shell/core/types';
|
|
|
10
10
|
import ExtensionPanel from '@shell/components/ExtensionPanel';
|
|
11
11
|
import { sameContents } from '@shell/utils/array';
|
|
12
12
|
import perfSettingsUtils from '@shell/utils/perf-setting.utils';
|
|
13
|
+
import { BadgeState } from '@components/BadgeState';
|
|
14
|
+
import { stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
15
|
+
import { useStateColor } from '@shell/composables/useStateColor';
|
|
13
16
|
|
|
14
17
|
export default {
|
|
15
18
|
name: ResourceListComponentName,
|
|
@@ -20,10 +23,17 @@ export default {
|
|
|
20
23
|
Masthead,
|
|
21
24
|
ResourceLoadingIndicator,
|
|
22
25
|
IconMessage,
|
|
23
|
-
ExtensionPanel
|
|
26
|
+
ExtensionPanel,
|
|
27
|
+
BadgeState,
|
|
24
28
|
},
|
|
25
29
|
mixins: [ResourceFetch],
|
|
26
30
|
|
|
31
|
+
setup() {
|
|
32
|
+
const { toStateColor } = useStateColor();
|
|
33
|
+
|
|
34
|
+
return { toStateColor };
|
|
35
|
+
},
|
|
36
|
+
|
|
27
37
|
props: {
|
|
28
38
|
hasAdvancedFiltering: {
|
|
29
39
|
type: Boolean,
|
|
@@ -155,6 +165,41 @@ export default {
|
|
|
155
165
|
return perfSettingsUtils.incrementalLoadingUtils.isEnabled(this.calcCanPaginate(), this.perfConfig);
|
|
156
166
|
},
|
|
157
167
|
|
|
168
|
+
activeStateFilters() {
|
|
169
|
+
const raw = this.$route?.query?.stateFilter;
|
|
170
|
+
|
|
171
|
+
if (!raw) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const states = raw.split(',').filter(Boolean);
|
|
176
|
+
|
|
177
|
+
return states.map((s) => {
|
|
178
|
+
const match = this.rows.find((row) => row.metadata?.state?.name === s);
|
|
179
|
+
|
|
180
|
+
if (match) {
|
|
181
|
+
return {
|
|
182
|
+
label: match.stateDisplay,
|
|
183
|
+
color: match.stateBackground,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
label: stateDisplay(s, true),
|
|
189
|
+
color: `bg-${ this.toStateColor(s, this.resource) }`,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
methods: {
|
|
197
|
+
clearStateFilter() {
|
|
198
|
+
const query = { ...this.$route.query };
|
|
199
|
+
|
|
200
|
+
delete query.stateFilter;
|
|
201
|
+
this.$router.push({ ...this.$route, query });
|
|
202
|
+
},
|
|
158
203
|
},
|
|
159
204
|
|
|
160
205
|
watch: {
|
|
@@ -260,6 +305,28 @@ export default {
|
|
|
260
305
|
:load-resources="loadResources"
|
|
261
306
|
:load-indeterminate="loadIndeterminate"
|
|
262
307
|
>
|
|
308
|
+
<template
|
|
309
|
+
v-if="activeStateFilters.length"
|
|
310
|
+
#subHeader
|
|
311
|
+
>
|
|
312
|
+
<div class="state-filter-bar text-muted">
|
|
313
|
+
{{ t('resourceList.stateFilterApplied') }}
|
|
314
|
+
<BadgeState
|
|
315
|
+
v-for="state in activeStateFilters"
|
|
316
|
+
:key="state.label"
|
|
317
|
+
:color="state.color"
|
|
318
|
+
:label="state.label"
|
|
319
|
+
class="badge-state-font-size"
|
|
320
|
+
/>
|
|
321
|
+
<span>.</span>
|
|
322
|
+
<a
|
|
323
|
+
role="button"
|
|
324
|
+
@click="clearStateFilter"
|
|
325
|
+
>
|
|
326
|
+
{{ t('resourceList.clearStateFilter') }}
|
|
327
|
+
</a>
|
|
328
|
+
</div>
|
|
329
|
+
</template>
|
|
263
330
|
<template #extraActions>
|
|
264
331
|
<slot name="extraActions" />
|
|
265
332
|
</template>
|
|
@@ -317,4 +384,18 @@ export default {
|
|
|
317
384
|
top: 10px;
|
|
318
385
|
right: 10px;
|
|
319
386
|
}
|
|
387
|
+
|
|
388
|
+
.state-filter-bar {
|
|
389
|
+
display: flex;
|
|
390
|
+
align-items: center;
|
|
391
|
+
gap: 4px;
|
|
392
|
+
|
|
393
|
+
a {
|
|
394
|
+
cursor: pointer;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.badge-state-font-size {
|
|
399
|
+
font-size: .85em;
|
|
400
|
+
}
|
|
320
401
|
</style>
|
|
@@ -74,8 +74,11 @@ export default defineComponent({
|
|
|
74
74
|
const content = enclosingTagName ? match[2] : '';
|
|
75
75
|
|
|
76
76
|
if (slots[tagName]) {
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const slotContent = slots[tagName]({ content: purifyHTML(content) });
|
|
78
|
+
|
|
79
|
+
if (slotContent) {
|
|
80
|
+
children.push(...slotContent);
|
|
81
|
+
}
|
|
79
82
|
} else if (ALLOWED_TAGS.includes(tagName.toLowerCase())) {
|
|
80
83
|
// If it's an allowed HTML tag, render it directly.
|
|
81
84
|
if (content) {
|
package/components/Setting.vue
CHANGED
|
@@ -1125,7 +1125,6 @@ export default {
|
|
|
1125
1125
|
v-clean-tooltip="actionTooltip"
|
|
1126
1126
|
type="button"
|
|
1127
1127
|
variant="primary"
|
|
1128
|
-
size="large"
|
|
1129
1128
|
:class="{[bulkActionClass]:true}"
|
|
1130
1129
|
:disabled="!act.enabled"
|
|
1131
1130
|
:data-testid="componentTestid + '-' + act.action"
|
|
@@ -1146,6 +1145,7 @@ export default {
|
|
|
1146
1145
|
:disabled="!selectedRows.length"
|
|
1147
1146
|
:hidden-actions="hiddenActions"
|
|
1148
1147
|
:action-tooltip="actionTooltip"
|
|
1148
|
+
size="medium"
|
|
1149
1149
|
@click="applyTableAction"
|
|
1150
1150
|
@mouseover="setBulkActionOfInterest"
|
|
1151
1151
|
@mouseleave="setBulkActionOfInterest"
|
|
@@ -1158,10 +1158,11 @@ export default {
|
|
|
1158
1158
|
:disable-button="!selectedRows.length"
|
|
1159
1159
|
size="sm"
|
|
1160
1160
|
>
|
|
1161
|
-
<template #button-content>
|
|
1161
|
+
<template #button-content="{ buttonSize }">
|
|
1162
1162
|
<button
|
|
1163
1163
|
ref="actionDropDown"
|
|
1164
1164
|
class="btn bg-primary mr-0"
|
|
1165
|
+
:class="buttonSize"
|
|
1165
1166
|
:disabled="!selectedRows.length"
|
|
1166
1167
|
>
|
|
1167
1168
|
<i class="icon icon-gear" />
|
|
@@ -1874,7 +1875,7 @@ export default {
|
|
|
1874
1875
|
}
|
|
1875
1876
|
|
|
1876
1877
|
.search-box {
|
|
1877
|
-
height:
|
|
1878
|
+
height: 32px;
|
|
1878
1879
|
margin-left: 10px;
|
|
1879
1880
|
min-width: 180px;
|
|
1880
1881
|
}
|
|
@@ -1,25 +1,50 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
2
3
|
import { RouterLink, RouteLocationRaw } from 'vue-router';
|
|
3
4
|
|
|
4
5
|
export interface Props {
|
|
5
|
-
to
|
|
6
|
+
to?: RouteLocationRaw;
|
|
7
|
+
href?: string;
|
|
8
|
+
target?: string;
|
|
9
|
+
openInNewTabLabel?: string;
|
|
6
10
|
}
|
|
7
11
|
|
|
8
|
-
const
|
|
12
|
+
const props = defineProps<Props>();
|
|
13
|
+
|
|
14
|
+
const isExternal = computed(() => !!props.href);
|
|
9
15
|
</script>
|
|
10
16
|
|
|
11
17
|
<template>
|
|
12
|
-
<
|
|
18
|
+
<component
|
|
19
|
+
:is="isExternal ? 'a' : RouterLink"
|
|
13
20
|
class="subtle-link"
|
|
14
|
-
|
|
21
|
+
v-bind="isExternal
|
|
22
|
+
? { href, target, rel: target === '_blank' ? 'noopener noreferrer nofollow' : undefined }
|
|
23
|
+
: { to }"
|
|
15
24
|
>
|
|
16
|
-
<
|
|
17
|
-
|
|
25
|
+
<span
|
|
26
|
+
v-if="openInNewTabLabel"
|
|
27
|
+
class="sr-only"
|
|
28
|
+
>{{ openInNewTabLabel }}</span>
|
|
29
|
+
<slot name="default" /><span v-if="openInNewTabLabel"> </span><i
|
|
30
|
+
v-if="openInNewTabLabel"
|
|
31
|
+
class="link-icon icon icon-external-link"
|
|
32
|
+
/>
|
|
33
|
+
</component>
|
|
18
34
|
</template>
|
|
19
35
|
|
|
20
36
|
<style lang="scss" scoped>
|
|
21
37
|
.subtle-link {
|
|
22
38
|
text-decoration: underline;
|
|
23
39
|
color: var(--body-text);
|
|
40
|
+
|
|
41
|
+
&:hover,
|
|
42
|
+
&:active {
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.link-icon {
|
|
48
|
+
display: inline;
|
|
24
49
|
}
|
|
25
50
|
</style>
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { useTabCountWatcher } from '@shell/components/form/ResourceTabs/composable';
|
|
3
|
+
import { useInSummary } from '@shell/components/TableOfContents/composables';
|
|
4
|
+
import { computed, inject, useTemplateRef } from 'vue';
|
|
5
|
+
import { useStore } from 'vuex';
|
|
6
|
+
import { useI18n } from '@shell/composables/useI18n';
|
|
3
7
|
|
|
4
8
|
export default {
|
|
5
|
-
|
|
9
|
+
name: 'Tab',
|
|
10
|
+
|
|
11
|
+
inject: ['addTab', 'removeTab', 'sideTabs', 'select'],
|
|
6
12
|
|
|
7
13
|
emits: ['active'],
|
|
8
14
|
|
|
@@ -64,9 +70,28 @@ export default {
|
|
|
64
70
|
},
|
|
65
71
|
|
|
66
72
|
setup(props) {
|
|
67
|
-
const
|
|
73
|
+
const select = inject('select');
|
|
74
|
+
const store = useStore();
|
|
75
|
+
const { t } = useI18n(store);
|
|
76
|
+
const label = computed(() => {
|
|
77
|
+
if (props.labelKey && typeof t === 'function') {
|
|
78
|
+
return t(props.labelKey);
|
|
79
|
+
}
|
|
68
80
|
|
|
69
|
-
|
|
81
|
+
return props.label ?? props.name;
|
|
82
|
+
});
|
|
83
|
+
const { count, isCountVisible } = useTabCountWatcher();
|
|
84
|
+
const summarizedContainerRef = useTemplateRef('tab-summarized-container');
|
|
85
|
+
// when a Tab is scrolled to, call its Tabbed's 'select' method to ensure the Tab is active
|
|
86
|
+
const { summary } = useInSummary({
|
|
87
|
+
scrollTo: () => select(props.name),
|
|
88
|
+
label,
|
|
89
|
+
elementRef: summarizedContainerRef,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
inferredCount: count, isInferredCountVisible: isCountVisible, summary
|
|
94
|
+
};
|
|
70
95
|
},
|
|
71
96
|
|
|
72
97
|
data() {
|
|
@@ -143,6 +168,7 @@ export default {
|
|
|
143
168
|
<section
|
|
144
169
|
v-show="active"
|
|
145
170
|
:id="name"
|
|
171
|
+
ref="tab-summarized-container"
|
|
146
172
|
:aria-hidden="!active"
|
|
147
173
|
role="tabpanel"
|
|
148
174
|
:aria-labelledby="`tab-${name}`"
|
|
@@ -7,10 +7,11 @@ import findIndex from 'lodash/findIndex';
|
|
|
7
7
|
import { ExtensionPoint, TabLocation } from '@shell/core/types';
|
|
8
8
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
9
9
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
10
|
-
import { ref } from 'vue';
|
|
10
|
+
import { computed, ref, useTemplateRef } from 'vue';
|
|
11
11
|
import { useIsInResourceDetailDrawer } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
|
|
12
12
|
import { useIsInResourceDetailPage } from '@shell/composables/resourceDetail';
|
|
13
13
|
import { useIsInResourceCreatePage, useIsInResourceEditPage } from '@shell/composables/cruResource';
|
|
14
|
+
import { useInSummary } from '@shell/components/TableOfContents/composables';
|
|
14
15
|
|
|
15
16
|
export default {
|
|
16
17
|
name: 'Tabbed',
|
|
@@ -94,6 +95,17 @@ export default {
|
|
|
94
95
|
removeBorders: {
|
|
95
96
|
type: Boolean,
|
|
96
97
|
default: false,
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* title is NOT displayed within the Tabbed component itself
|
|
102
|
+
* this prop is used to determine a label to use for the set of tabs in the table of contents component
|
|
103
|
+
* if a title is not provided a random string will be used
|
|
104
|
+
* components using the table of contents may exclude tabbed and only show tab components, too
|
|
105
|
+
*/
|
|
106
|
+
title: {
|
|
107
|
+
type: String,
|
|
108
|
+
default: null,
|
|
97
109
|
}
|
|
98
110
|
},
|
|
99
111
|
|
|
@@ -101,6 +113,8 @@ export default {
|
|
|
101
113
|
const tabs = this.tabs;
|
|
102
114
|
|
|
103
115
|
return {
|
|
116
|
+
select: this.select,
|
|
117
|
+
|
|
104
118
|
sideTabs: this.sideTabs,
|
|
105
119
|
|
|
106
120
|
addTab(tab) {
|
|
@@ -156,14 +170,20 @@ export default {
|
|
|
156
170
|
},
|
|
157
171
|
},
|
|
158
172
|
|
|
159
|
-
setup() {
|
|
173
|
+
setup(props) {
|
|
160
174
|
const isInResourceDetailDrawer = ref(useIsInResourceDetailDrawer());
|
|
161
175
|
const isInResourceDetailPage = ref(useIsInResourceDetailPage());
|
|
162
176
|
const isInResourceEditPage = ref(useIsInResourceEditPage());
|
|
163
177
|
const isInResourceCreatePage = ref(useIsInResourceCreatePage());
|
|
178
|
+
const tabbedSummarizedContainer = useTemplateRef('tabbed-summarized-container');
|
|
179
|
+
const { summary } = useInSummary({
|
|
180
|
+
label: computed(() => props.title ?? ''),
|
|
181
|
+
scrollTo: () => tabbedSummarizedContainer.value?.scrollIntoView(true),
|
|
182
|
+
elementRef: tabbedSummarizedContainer,
|
|
183
|
+
});
|
|
164
184
|
|
|
165
185
|
return {
|
|
166
|
-
isInResourceDetailDrawer, isInResourceDetailPage, isInResourceEditPage, isInResourceCreatePage
|
|
186
|
+
isInResourceDetailDrawer, isInResourceDetailPage, isInResourceEditPage, isInResourceCreatePage, summary
|
|
167
187
|
};
|
|
168
188
|
},
|
|
169
189
|
|
|
@@ -311,6 +331,7 @@ export default {
|
|
|
311
331
|
|
|
312
332
|
<template>
|
|
313
333
|
<div
|
|
334
|
+
ref="tabbed-summarized-container"
|
|
314
335
|
class="tabbed-container"
|
|
315
336
|
:class="{
|
|
316
337
|
'side-tabs': !!sideTabs,
|
|
@@ -435,6 +456,7 @@ export default {
|
|
|
435
456
|
<component
|
|
436
457
|
:is="tab.component"
|
|
437
458
|
:resource="resource"
|
|
459
|
+
@select="select(tab.name)"
|
|
438
460
|
/>
|
|
439
461
|
</Tab>
|
|
440
462
|
</div>
|