@rancher/shell 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/global/_button.scss +5 -1
- package/assets/styles/global/_columns.scss +4 -0
- package/assets/styles/global/_gauges.scss +1 -1
- package/assets/styles/global/_layout.scss +5 -2
- package/assets/styles/global/_select.scss +1 -4
- package/assets/styles/themes/_dark.scss +5 -4
- package/assets/styles/themes/_light.scss +4 -3
- package/assets/styles/themes/_suse.scss +1 -1
- package/assets/styles/vendor/vue-select.scss +4 -3
- package/assets/translations/en-us.yaml +673 -73
- package/assets/translations/zh-hans.yaml +720 -207
- package/chart/monitoring/steps/uninstall-v1.vue +2 -2
- package/cloud-credential/azure.vue +23 -0
- package/cloud-credential/harvester.vue +25 -62
- package/cloud-credential/pnap.vue +80 -0
- package/components/.DS_Store +0 -0
- package/components/ActionMenu.vue +28 -7
- package/components/AdvancedSection.vue +9 -2
- package/components/Alert.vue +2 -2
- package/components/ButtonDropdown.vue +0 -2
- package/components/ButtonGroup.vue +1 -0
- package/components/CollapsibleCard.vue +0 -1
- package/components/CruResource.vue +41 -4
- package/components/DetailTop.vue +72 -4
- package/components/DisableAuthProviderModal.vue +106 -0
- package/{rancher-components/components/Utils/DraggableZone → components}/DraggableZone.vue +0 -0
- package/components/ExplorerMembers.vue +253 -30
- package/components/ExplorerProjectsNamespaces.vue +77 -33
- package/components/ExtensionPanel.vue +42 -0
- package/components/GrowlManager.vue +3 -3
- package/components/IconOrSvg.vue +178 -0
- package/components/LogItem.vue +69 -0
- package/components/PodSecurityAdmission.vue +302 -0
- package/components/PromptModal.vue +1 -0
- package/components/ResourceDetail/Masthead.vue +69 -4
- package/components/ResourceDetail/index.vue +12 -5
- package/components/ResourceList/Masthead.vue +11 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +12 -2
- package/components/ResourceList/index.vue +66 -12
- package/components/ResourceList/resource-list.config.js +7 -0
- package/components/ResourceTable.vue +33 -6
- package/components/SimpleBox.vue +1 -1
- package/components/SortableTable/THead.vue +21 -14
- package/components/SortableTable/filtering.js +1 -1
- package/components/SortableTable/index.vue +21 -10
- package/components/SortableTable/selection.js +15 -3
- package/components/Tabbed/Tab.vue +1 -1
- package/components/Tabbed/index.vue +20 -15
- package/components/__tests__/.DS_Store +0 -0
- package/components/__tests__/AsyncButton.test.ts +140 -0
- package/components/__tests__/BackLink.test.ts +33 -0
- package/components/__tests__/ButtonGroup.test.ts +124 -0
- package/components/__tests__/ClusterBadge.test.ts +32 -0
- package/components/__tests__/CollapsibleCard.test.ts +64 -0
- package/components/__tests__/ConsumptionGauge.test.ts +88 -0
- package/components/__tests__/CruResource.test.ts +3 -2
- package/components/__tests__/FixedBanner.test.ts +129 -0
- package/components/__tests__/GrowlManager.test.ts +147 -0
- package/components/__tests__/NamespaceFilter.test.ts +33 -25
- package/components/__tests__/PercentageBar.test.ts +32 -0
- package/components/__tests__/PodSecurityAdmission.test.ts +398 -0
- package/components/auth/AuthBanner.vue +20 -10
- package/components/auth/RoleDetailEdit.vue +26 -17
- package/components/auth/SelectPrincipal.vue +36 -5
- package/components/form/ArrayList.vue +3 -35
- package/components/form/ArrayListGrouped.vue +13 -4
- package/components/form/ArrayListSelect.vue +5 -5
- package/components/form/Error.vue +8 -0
- package/components/form/KeyValue.vue +39 -7
- package/components/form/LabeledSelect.vue +5 -2
- package/components/form/Labels.vue +46 -16
- package/components/form/Members/ClusterPermissionsEditor.vue +17 -17
- package/components/form/Members/MembershipEditor.vue +12 -12
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +1 -1
- package/components/form/Probe.vue +3 -3
- package/components/form/ResourceQuota/Project.vue +6 -6
- package/components/form/ResourceTabs/index.vue +24 -6
- package/components/form/Security.vue +7 -6
- package/components/form/Select.vue +3 -2
- package/components/form/SelectOrCreateAuthSecret.vue +22 -29
- package/components/form/ServicePorts.vue +8 -0
- package/components/form/WorkloadPorts.vue +7 -1
- package/components/form/__tests__/ArrayList.test.ts +74 -0
- package/components/form/__tests__/ArrayListGrouped.test.ts +6 -4
- package/components/formatter/Checked.vue +1 -1
- package/components/formatter/ClusterLink.vue +5 -0
- package/components/formatter/IconIsDefault.vue +2 -2
- package/components/formatter/InternalExternalIP.vue +11 -8
- package/components/formatter/LiveDuration.vue +78 -0
- package/components/formatter/WorkloadHealthScale.vue +5 -3
- package/components/nav/Header.vue +74 -7
- package/components/nav/NamespaceFilter.vue +146 -63
- package/components/nav/TopLevelMenu.vue +22 -19
- package/components/nav/WindowManager/ContainerLogs.vue +83 -126
- package/components/nav/WindowManager/ContainerShell.vue +9 -7
- package/components/nav/WindowManager/Window.vue +2 -0
- package/components/nav/WindowManager/index.vue +10 -0
- package/config/elemental-types.js +9 -0
- package/config/features.js +2 -0
- package/config/home-links.js +4 -1
- package/config/pod-security-admission.ts +82 -0
- package/config/product/apps.js +1 -1
- package/config/product/auth.js +6 -5
- package/config/product/backup.js +1 -1
- package/config/product/explorer.js +6 -6
- package/config/product/fleet.js +1 -1
- package/config/product/manager.js +6 -2
- package/config/query-params.js +1 -0
- package/config/secret.js +0 -1
- package/config/settings.ts +26 -9
- package/config/table-headers.js +22 -11
- package/config/types.js +4 -1
- package/config/uiplugins.js +3 -3
- package/content/docs/zh-hans/getting-started.md +113 -137
- package/content/docs/zh-hans/whats-new.md +8 -46
- package/core/plugin-helpers.js +171 -0
- package/core/plugin.ts +61 -1
- package/core/plugins.js +33 -0
- package/core/types.ts +128 -2
- package/creators/pkg/package-lock.json +37 -0
- package/creators/pkg/package.json +1 -1
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +35 -9
- package/detail/service.vue +2 -9
- package/detail/workload/index.vue +0 -1
- package/dialog/AddClusterMemberDialog.vue +22 -28
- package/dialog/AddProjectMemberDialog.vue +53 -9
- package/dialog/DiagnosticTimingsDialog.vue +8 -7
- package/dialog/DrainNode.vue +44 -48
- package/dialog/ForceMachineRemoveDialog.vue +5 -7
- package/dialog/GenericPrompt.vue +15 -20
- package/dialog/RollbackWorkloadDialog.vue +15 -46
- package/dialog/RotateCertificatesDialog.vue +5 -7
- package/dialog/RotateEncryptionKeyDialog.vue +5 -9
- package/dialog/SaveAsRKETemplateDialog.vue +5 -13
- package/dialog/ScaleMachineDownDialog.vue +1 -1
- package/dialog/ScalePoolDownDialog.vue +121 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +3 -3
- package/edit/auth/azuread.vue +16 -16
- package/edit/auth/github.vue +8 -0
- package/edit/auth/googleoauth.vue +10 -1
- package/edit/auth/ldap/index.vue +10 -0
- package/edit/auth/oidc.vue +10 -0
- package/edit/auth/saml.vue +10 -0
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +3 -0
- package/edit/cloudcredential.vue +3 -7
- package/edit/logging-flow/Match.vue +39 -8
- package/edit/logging-flow/index.vue +27 -4
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +107 -0
- package/edit/management.cattle.io.project.vue +8 -1
- package/edit/management.cattle.io.setting.vue +5 -2
- package/edit/management.cattle.io.user.vue +7 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +36 -8
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +2 -2
- package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +14 -6
- package/edit/namespace.vue +18 -4
- package/edit/networking.k8s.io.ingress/Certificate.vue +1 -0
- package/edit/networking.k8s.io.ingress/IngressClass.vue +8 -6
- package/edit/networking.k8s.io.ingress/RulePath.vue +12 -6
- package/edit/networking.k8s.io.ingress/index.vue +8 -6
- package/edit/persistentvolume/index.vue +30 -27
- package/edit/persistentvolume/plugins/cephfs.vue +29 -29
- package/edit/persistentvolume/plugins/csi.vue +102 -62
- package/edit/persistentvolume/plugins/fc.vue +19 -19
- package/edit/persistentvolume/plugins/iscsi.vue +45 -45
- package/edit/persistentvolume/plugins/rbd.vue +39 -39
- package/edit/persistentvolumeclaim.vue +78 -75
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -7
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +10 -1
- package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +87 -27
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -6
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +96 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +29 -6
- package/edit/provisioning.cattle.io.cluster/rke2.vue +445 -154
- package/edit/secret/index.vue +3 -7
- package/edit/service.vue +3 -1
- package/edit/storage.k8s.io.storageclass/index.vue +100 -16
- package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +114 -0
- package/edit/workload/__tests__/index.test.ts +98 -0
- package/edit/workload/index.vue +58 -8
- package/edit/workload/mixins/workload.js +107 -70
- package/edit/workload/storage/ContainerMountPaths.vue +0 -10
- package/edit/workload/storage/emptyDir.vue +88 -0
- package/edit/workload/storage/ephemeralVolume/index.vue +1 -1
- package/edit/workload/storage/index.vue +8 -0
- package/edit/workload/storage/persistentVolumeClaim/index.vue +1 -1
- package/layouts/default.vue +57 -44
- package/list/__tests__/workload.test.ts +5 -2
- package/list/catalog.cattle.io.app.vue +1 -0
- package/list/cis.cattle.io.clusterscan.vue +1 -0
- package/list/fleet.cattle.io.bundle.vue +5 -6
- package/list/fleet.cattle.io.cluster.vue +6 -3
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +5 -6
- package/list/fleet.cattle.io.gitrepo.vue +4 -9
- package/list/helm.cattle.io.projecthelmchart.vue +1 -5
- package/list/logging.banzaicloud.io.clusterflow.vue +4 -1
- package/list/logging.banzaicloud.io.flow.vue +6 -5
- package/list/management.cattle.io.cluster.vue +1 -0
- package/list/management.cattle.io.feature.vue +3 -4
- package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +47 -0
- package/list/management.cattle.io.setting.vue +2 -2
- package/list/management.cattle.io.user.vue +4 -10
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +2 -7
- package/list/node.vue +8 -5
- package/list/persistentvolume.vue +3 -3
- package/list/persistentvolumeclaim.vue +3 -4
- package/list/provisioning.cattle.io.cluster.vue +18 -19
- package/list/service.vue +6 -14
- package/list/workload.vue +43 -38
- package/machine-config/azure.vue +429 -60
- package/machine-config/pnap.vue +288 -0
- package/mixins/auth-config.js +1 -3
- package/mixins/browser-tab-visibility.js +8 -14
- package/mixins/chart.js +1 -1
- package/mixins/create-edit-view/impl.js +4 -0
- package/mixins/create-edit-view/index.js +4 -2
- package/mixins/resource-fetch-namespaced.js +98 -0
- package/mixins/resource-fetch.js +79 -45
- package/mixins/resource-manager.js +1 -23
- package/models/apps.controllerrevision.js +7 -0
- package/models/apps.daemonset.js +18 -0
- package/models/apps.deployment.js +44 -0
- package/models/apps.replicaset.js +7 -0
- package/models/apps.statefulset.js +18 -0
- package/models/batch.job.js +7 -14
- package/models/cluster/node.js +10 -2
- package/models/cluster.x-k8s.io.machine.js +26 -4
- package/models/cluster.x-k8s.io.machinedeployment.js +12 -2
- package/models/event.js +7 -0
- package/models/logging.banzaicloud.io.flow.js +4 -0
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.clusterroletemplatebinding.js +1 -1
- package/models/management.cattle.io.globalrole.js +2 -2
- package/models/management.cattle.io.node.js +37 -2
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +4 -0
- package/models/management.cattle.io.project.js +30 -11
- package/models/management.cattle.io.setting.js +1 -1
- package/models/management.cattle.io.user.js +37 -1
- package/models/namespace.js +42 -5
- package/models/persistentvolume.js +14 -2
- package/models/pod.js +15 -0
- package/models/projectroletemplatebinding.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +61 -10
- package/models/rke-machine.cattle.io.pnapmachinetemplate.js +15 -0
- package/models/service.js +14 -13
- package/models/storage.k8s.io.storageclass.js +33 -18
- package/models/workload.js +38 -7
- package/nuxt.config.js +27 -17
- package/package.json +7 -7
- package/pages/about.vue +14 -2
- package/pages/c/_cluster/apps/charts/index.vue +21 -3
- package/pages/c/_cluster/apps/charts/install.vue +59 -22
- package/pages/c/_cluster/auth/config/_id.vue +6 -0
- package/pages/c/_cluster/auth/config/index.vue +8 -6
- package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
- package/pages/c/_cluster/auth/roles/index.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +51 -6
- package/pages/c/_cluster/longhorn/index.vue +1 -1
- package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +15 -4
- package/pages/c/_cluster/monitoring/index.vue +1 -1
- package/pages/c/_cluster/neuvector/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +48 -2
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +2 -0
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +42 -2
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +1 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +2 -0
- package/pages/c/_cluster/uiplugins/index.vue +42 -3
- package/pages/diagnostic.vue +5 -4
- package/pages/home.vue +105 -30
- package/pages/prefs.vue +23 -12
- package/pages/rio/mesh.vue +1 -1
- package/pkg/dynamic-importer.lib.js +8 -0
- package/pkg/vue.config.js +4 -0
- package/plugins/dashboard-store/__tests__/mutations.spec.js +406 -0
- package/plugins/dashboard-store/actions.js +32 -25
- package/plugins/dashboard-store/getters.js +50 -33
- package/plugins/dashboard-store/mutations.js +134 -28
- package/plugins/dashboard-store/resource-class.js +37 -42
- package/plugins/steve/actions.js +30 -0
- package/plugins/steve/caches/resourceCache.js +60 -0
- package/plugins/steve/getters.js +44 -1
- package/plugins/steve/mutations.js +97 -36
- package/plugins/steve/resourceWatcher.js +277 -0
- package/plugins/steve/schema.utils.js +25 -0
- package/plugins/steve/subscribe.js +288 -115
- package/plugins/steve/worker/index.js +17 -0
- package/plugins/steve/worker/web-worker.advanced.js +302 -0
- package/plugins/steve/{web-worker.steve-sub-worker.js → worker/web-worker.basic.js} +3 -44
- package/rancher-components/Card/Card.vue +3 -3
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -0
- package/rancher-components/StringList/StringList.test.ts +45 -420
- package/rancher-components/StringList/StringList.vue +1 -10
- package/rancher-components/components/Banner/Banner.test.ts +44 -0
- package/rancher-components/components/Banner/Banner.vue +130 -61
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +13 -22
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +8 -6
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +9 -9
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -1
- package/rancher-components/components/StringList/StringList.test.ts +7 -7
- package/rancher-components/components/StringList/StringList.vue +21 -15
- package/scripts/test-plugins-build.sh +8 -0
- package/static/loading-indicator.html +1 -1
- package/store/action-menu.js +4 -3
- package/store/index.js +54 -3
- package/store/plugins.js +0 -17
- package/store/pnap.js +128 -0
- package/store/prefs.js +4 -2
- package/store/type-map.js +81 -13
- package/types/pod-security-admission.ts +36 -0
- package/types/shell/index.d.ts +497 -396
- package/utils/__tests__/object.test.ts +17 -1
- package/utils/__tests__/pod-security-admission.test.ts +61 -0
- package/utils/async.ts +36 -0
- package/utils/color.js +45 -0
- package/utils/crypto/browserHashUtils.js +18 -0
- package/utils/dynamic-importer.js +8 -0
- package/utils/install-redirect.js +1 -1
- package/utils/object.js +24 -0
- package/utils/pod-security-admission.ts +39 -0
- package/utils/socket.js +61 -24
- package/utils/string.js +2 -0
- package/utils/svg-filter.js +301 -0
- package/utils/time.js +49 -0
- package/utils/validators/cidr.js +4 -0
- package/utils/validators/formRules/__tests__/index.test.ts +23 -3
- package/utils/validators/formRules/index.ts +14 -0
- package/config/product/harvester-manager.js +0 -162
- package/edit/harvesterhci.io.management.cluster.vue +0 -153
- package/list/harvesterhci.io.management.cluster.vue +0 -241
- package/machine-config/harvester.vue +0 -693
- package/models/harvesterhci.io.management.cluster.js +0 -228
- package/pages/c/_cluster/harvesterManager/index.vue +0 -24
- package/rancher-components/Card/Card.test.ts +0 -39
- package/rancher-components/Utils/DraggableZone/DraggableZone.vue +0 -181
- package/rancher-components/Utils/DraggableZone/index.ts +0 -1
- package/rancher-components/components/Utils/DraggableZone/index.ts +0 -1
|
@@ -3,7 +3,7 @@ import { mapGetters } from 'vuex';
|
|
|
3
3
|
import debounce from 'lodash/debounce';
|
|
4
4
|
import { NORMAN, STEVE } from '@shell/config/types';
|
|
5
5
|
import { ucFirst } from '@shell/utils/string';
|
|
6
|
-
import { isMac } from '@shell/utils/platform';
|
|
6
|
+
import { isAlternate, isMac } from '@shell/utils/platform';
|
|
7
7
|
import Import from '@shell/components/Import';
|
|
8
8
|
import BrandImage from '@shell/components/BrandImage';
|
|
9
9
|
import { getProduct } from '@shell/config/private-label';
|
|
@@ -15,6 +15,9 @@ import WorkspaceSwitcher from './WorkspaceSwitcher';
|
|
|
15
15
|
import TopLevelMenu from './TopLevelMenu';
|
|
16
16
|
import Jump from './Jump';
|
|
17
17
|
import { allHash } from '@shell/utils/promise';
|
|
18
|
+
import { ActionLocation, ExtensionPoint } from '@shell/core/types';
|
|
19
|
+
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
20
|
+
import IconOrSvg from '@shell/components/IconOrSvg';
|
|
18
21
|
|
|
19
22
|
const PAGE_HEADER_ACTION = 'page-action';
|
|
20
23
|
|
|
@@ -29,6 +32,7 @@ export default {
|
|
|
29
32
|
BrandImage,
|
|
30
33
|
ClusterBadge,
|
|
31
34
|
ClusterProviderIcon,
|
|
35
|
+
IconOrSvg
|
|
32
36
|
},
|
|
33
37
|
|
|
34
38
|
props: {
|
|
@@ -43,13 +47,15 @@ export default {
|
|
|
43
47
|
const shellShortcut = '(Ctrl+`)';
|
|
44
48
|
|
|
45
49
|
return {
|
|
46
|
-
show:
|
|
47
|
-
showTooltip:
|
|
48
|
-
kubeConfigCopying:
|
|
50
|
+
show: false,
|
|
51
|
+
showTooltip: false,
|
|
52
|
+
kubeConfigCopying: false,
|
|
49
53
|
searchShortcut,
|
|
50
54
|
shellShortcut,
|
|
51
55
|
LOGGED_OUT,
|
|
52
|
-
navHeaderRight:
|
|
56
|
+
navHeaderRight: null,
|
|
57
|
+
extensionHeaderActions: getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, this.$route),
|
|
58
|
+
ctx: this
|
|
53
59
|
};
|
|
54
60
|
},
|
|
55
61
|
|
|
@@ -170,6 +176,12 @@ export default {
|
|
|
170
176
|
if (nue && old && nue.id !== old.id) {
|
|
171
177
|
this.checkClusterName();
|
|
172
178
|
}
|
|
179
|
+
},
|
|
180
|
+
// since the Header is a "persistent component" we need to update it at every route change...
|
|
181
|
+
$route(nue) {
|
|
182
|
+
if (nue) {
|
|
183
|
+
this.extensionHeaderActions = getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, nue);
|
|
184
|
+
}
|
|
173
185
|
}
|
|
174
186
|
},
|
|
175
187
|
|
|
@@ -288,6 +300,33 @@ export default {
|
|
|
288
300
|
button.classList.remove('header-btn-active');
|
|
289
301
|
}
|
|
290
302
|
});
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
handleExtensionAction(action, event) {
|
|
306
|
+
const fn = action.invoke;
|
|
307
|
+
const opts = {
|
|
308
|
+
event,
|
|
309
|
+
action,
|
|
310
|
+
isAlt: isAlternate(event),
|
|
311
|
+
product: this.currentProduct.name,
|
|
312
|
+
cluster: this.currentCluster,
|
|
313
|
+
};
|
|
314
|
+
const enabled = action.enabled ? action.enabled.apply(this, [opts]) : true;
|
|
315
|
+
|
|
316
|
+
if (fn && enabled) {
|
|
317
|
+
fn.apply(this, [opts, []]);
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
handleExtensionTooltip(action) {
|
|
322
|
+
if (action.tooltipKey || action.tooltip) {
|
|
323
|
+
const tooltip = action.tooltipKey ? this.t(action.tooltipKey) : action.tooltip;
|
|
324
|
+
const shortcut = action.shortcutLabel ? action.shortcutLabel() : '';
|
|
325
|
+
|
|
326
|
+
return `${ tooltip } ${ shortcut }`;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return null;
|
|
291
330
|
}
|
|
292
331
|
}
|
|
293
332
|
};
|
|
@@ -502,6 +541,31 @@ export default {
|
|
|
502
541
|
</modal>
|
|
503
542
|
</div>
|
|
504
543
|
|
|
544
|
+
<!-- Extension header actions -->
|
|
545
|
+
<div
|
|
546
|
+
v-if="extensionHeaderActions.length"
|
|
547
|
+
class="header-buttons"
|
|
548
|
+
>
|
|
549
|
+
<button
|
|
550
|
+
v-for="action, i in extensionHeaderActions"
|
|
551
|
+
:key="`${action.label}${i}`"
|
|
552
|
+
v-tooltip="handleExtensionTooltip(action)"
|
|
553
|
+
v-shortkey="action.shortcutKey"
|
|
554
|
+
:disabled="action.enabled ? !action.enabled(ctx) : false"
|
|
555
|
+
type="button"
|
|
556
|
+
class="btn header-btn role-tertiary"
|
|
557
|
+
@shortkey="handleExtensionAction(action, $event)"
|
|
558
|
+
@click="handleExtensionAction(action, $event)"
|
|
559
|
+
>
|
|
560
|
+
<IconOrSvg
|
|
561
|
+
class="icon icon-lg"
|
|
562
|
+
:icon="action.icon"
|
|
563
|
+
:src="action.svg"
|
|
564
|
+
color="header"
|
|
565
|
+
/>
|
|
566
|
+
</button>
|
|
567
|
+
</div>
|
|
568
|
+
|
|
505
569
|
<div
|
|
506
570
|
v-if="showPageActions"
|
|
507
571
|
id="page-actions"
|
|
@@ -671,8 +735,6 @@ export default {
|
|
|
671
735
|
|
|
672
736
|
.vs__dropdown-toggle .vs__actions:after {
|
|
673
737
|
color: var(--body-text) !important;
|
|
674
|
-
font-size: 1.5rem;
|
|
675
|
-
padding-right: 4px;
|
|
676
738
|
}
|
|
677
739
|
|
|
678
740
|
.vs__dropdown-toggle {
|
|
@@ -816,6 +878,11 @@ export default {
|
|
|
816
878
|
background-color: var(--success);
|
|
817
879
|
color: var(--success-text);
|
|
818
880
|
}
|
|
881
|
+
|
|
882
|
+
img {
|
|
883
|
+
height: 20px;
|
|
884
|
+
width: 20px;
|
|
885
|
+
}
|
|
819
886
|
}
|
|
820
887
|
}
|
|
821
888
|
|
|
@@ -19,16 +19,17 @@ import { KEY } from '@shell/utils/platform';
|
|
|
19
19
|
export default {
|
|
20
20
|
data() {
|
|
21
21
|
return {
|
|
22
|
-
isOpen:
|
|
23
|
-
filter:
|
|
24
|
-
hidden:
|
|
25
|
-
total:
|
|
26
|
-
activeElement:
|
|
22
|
+
isOpen: false,
|
|
23
|
+
filter: '',
|
|
24
|
+
hidden: 0,
|
|
25
|
+
total: 0,
|
|
26
|
+
activeElement: null,
|
|
27
|
+
cachedFiltered: [],
|
|
27
28
|
};
|
|
28
29
|
},
|
|
29
30
|
|
|
30
31
|
computed: {
|
|
31
|
-
...mapGetters(['currentProduct']),
|
|
32
|
+
...mapGetters(['currentProduct', 'namespaceFilterMode']),
|
|
32
33
|
|
|
33
34
|
hasFilter() {
|
|
34
35
|
return this.filter.length > 0;
|
|
@@ -37,11 +38,26 @@ export default {
|
|
|
37
38
|
filtered() {
|
|
38
39
|
let out = this.options;
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
out = out.filter((item) => {
|
|
42
|
+
// Filter out anything not applicable to singleton selection
|
|
43
|
+
if (this.namespaceFilterMode) {
|
|
44
|
+
// We always show dividers, projects and namespaces
|
|
45
|
+
if (!['divider', 'project', this.namespaceFilterMode].includes(item.kind)) {
|
|
46
|
+
// Hide any invalid option that's not selected
|
|
47
|
+
return this.value.findIndex(v => v.id === item.id) >= 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Filter by the current filter
|
|
52
|
+
if (this.hasFilter) {
|
|
43
53
|
return item.kind !== SPECIAL && item.label.toLowerCase().includes(this.filter.toLowerCase());
|
|
44
|
-
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (out?.[0]?.kind === 'divider') {
|
|
60
|
+
out.splice(0, 1);
|
|
45
61
|
}
|
|
46
62
|
|
|
47
63
|
const mapped = this.value.reduce((m, v) => {
|
|
@@ -54,6 +70,8 @@ export default {
|
|
|
54
70
|
out.forEach((i) => {
|
|
55
71
|
i.selected = !!mapped[i.id] || (i.id === ALL && this.value && this.value.length === 0);
|
|
56
72
|
i.elementId = (i.id || '').replace('://', '_');
|
|
73
|
+
// Are we in singleton resource type mode, if so is this an allowed type?
|
|
74
|
+
i.enabled = !this.namespaceFilterMode || i.kind === this.namespaceFilterMode;
|
|
57
75
|
});
|
|
58
76
|
|
|
59
77
|
return out;
|
|
@@ -326,6 +344,21 @@ export default {
|
|
|
326
344
|
watch: {
|
|
327
345
|
value(neu) {
|
|
328
346
|
this.layout();
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* When there are thousands of entries certain actions (drop down opened, selection changed, etc) take a long time to complete (upwards
|
|
351
|
+
* of 5 seconds)
|
|
352
|
+
*
|
|
353
|
+
* This is caused by churn of the filtered and options computed properties causing multiple renders for each action.
|
|
354
|
+
*
|
|
355
|
+
* To break this multiple-render per cycle behaviour detatch `filtered` from the value used in `v-for`.
|
|
356
|
+
*
|
|
357
|
+
*/
|
|
358
|
+
filtered(neu) {
|
|
359
|
+
if (!!neu) {
|
|
360
|
+
this.cachedFiltered = neu;
|
|
361
|
+
}
|
|
329
362
|
}
|
|
330
363
|
},
|
|
331
364
|
|
|
@@ -427,7 +460,10 @@ export default {
|
|
|
427
460
|
e.preventDefault();
|
|
428
461
|
e.stopPropagation();
|
|
429
462
|
this.up();
|
|
430
|
-
} else if (e.keyCode === KEY.SPACE) {
|
|
463
|
+
} else if (e.keyCode === KEY.SPACE || e.keyCode === KEY.CR) {
|
|
464
|
+
if (this.namespaceFilterMode && !opt.enabled) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
431
467
|
e.preventDefault();
|
|
432
468
|
e.stopPropagation();
|
|
433
469
|
this.selectOption(opt);
|
|
@@ -545,9 +581,22 @@ export default {
|
|
|
545
581
|
|
|
546
582
|
const current = this.value;
|
|
547
583
|
const exists = current.findIndex(v => v.id === option.id);
|
|
584
|
+
const optionIsSelected = exists !== -1;
|
|
585
|
+
|
|
586
|
+
// Any type of mode means only a single resource can be selected. So clear out any stale
|
|
587
|
+
// values (multiple selected in another context OR a single one selected in this context)
|
|
588
|
+
if (this.namespaceFilterMode) {
|
|
589
|
+
if (current.length === 1 && optionIsSelected) {
|
|
590
|
+
// Don't deselect the only selected option
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
current.length = 0;
|
|
594
|
+
}
|
|
548
595
|
|
|
549
|
-
|
|
550
|
-
|
|
596
|
+
const remove = !this.namespaceFilterMode && optionIsSelected;
|
|
597
|
+
|
|
598
|
+
// Remove if it exists (or always add if in singleton mode - we've reset the list above)
|
|
599
|
+
if (remove) {
|
|
551
600
|
current.splice(exists, 1);
|
|
552
601
|
} else {
|
|
553
602
|
current.push(option);
|
|
@@ -559,6 +608,14 @@ export default {
|
|
|
559
608
|
document.activeElement.blur();
|
|
560
609
|
}
|
|
561
610
|
},
|
|
611
|
+
handleValueMouseDown(ns, event) {
|
|
612
|
+
this.removeOption(ns, event);
|
|
613
|
+
|
|
614
|
+
if (this.value.length === 0) {
|
|
615
|
+
this.open();
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
|
|
562
619
|
removeOption(ns, event) {
|
|
563
620
|
this.selectOption(ns);
|
|
564
621
|
event.preventDefault();
|
|
@@ -634,9 +691,11 @@ export default {
|
|
|
634
691
|
>
|
|
635
692
|
<div>{{ ns.label }}</div>
|
|
636
693
|
<i
|
|
694
|
+
v-if="!namespaceFilterMode"
|
|
637
695
|
class="icon icon-close"
|
|
638
696
|
:data-testid="`namespaces-values-close-${j}`"
|
|
639
697
|
@click="removeOption(ns, $event)"
|
|
698
|
+
@mousedown="handleValueMouseDown(ns, $event)"
|
|
640
699
|
/>
|
|
641
700
|
</div>
|
|
642
701
|
</div>
|
|
@@ -686,7 +745,19 @@ export default {
|
|
|
686
745
|
@click="filter = ''"
|
|
687
746
|
/>
|
|
688
747
|
</div>
|
|
689
|
-
<div
|
|
748
|
+
<div
|
|
749
|
+
v-if="namespaceFilterMode"
|
|
750
|
+
class="ns-singleton-info"
|
|
751
|
+
>
|
|
752
|
+
<i
|
|
753
|
+
v-tooltip="t('resourceList.nsFilterToolTip', { mode: namespaceFilterMode})"
|
|
754
|
+
class="icon icon-info"
|
|
755
|
+
/>
|
|
756
|
+
</div>
|
|
757
|
+
<div
|
|
758
|
+
v-else
|
|
759
|
+
class="ns-clear"
|
|
760
|
+
>
|
|
690
761
|
<i
|
|
691
762
|
class="icon icon-close"
|
|
692
763
|
@click="clear()"
|
|
@@ -700,18 +771,19 @@ export default {
|
|
|
700
771
|
role="list"
|
|
701
772
|
>
|
|
702
773
|
<div
|
|
703
|
-
v-for="(opt, i) in
|
|
774
|
+
v-for="(opt, i) in cachedFiltered"
|
|
704
775
|
:id="opt.elementId"
|
|
705
776
|
:key="opt.id"
|
|
706
777
|
tabindex="0"
|
|
707
778
|
class="ns-option"
|
|
779
|
+
:disabled="!opt.enabled"
|
|
708
780
|
:class="{
|
|
709
781
|
'ns-selected': opt.selected,
|
|
710
|
-
'ns-single-match':
|
|
782
|
+
'ns-single-match': cachedFiltered.length === 1 && !opt.selected,
|
|
711
783
|
}"
|
|
712
784
|
:data-testid="`namespaces-option-${i}`"
|
|
713
|
-
@click="selectOption(opt)"
|
|
714
|
-
@mouseover="mouseOver($event)"
|
|
785
|
+
@click="opt.enabled && selectOption(opt)"
|
|
786
|
+
@mouseover="opt.enabled && mouseOver($event)"
|
|
715
787
|
@keydown="itemKeyHandler($event, opt)"
|
|
716
788
|
>
|
|
717
789
|
<div
|
|
@@ -734,7 +806,7 @@ export default {
|
|
|
734
806
|
</div>
|
|
735
807
|
</div>
|
|
736
808
|
<div
|
|
737
|
-
v-if="
|
|
809
|
+
v-if="cachedFiltered.length === 0"
|
|
738
810
|
class="ns-none"
|
|
739
811
|
data-testid="namespaces-option-none"
|
|
740
812
|
>
|
|
@@ -775,16 +847,17 @@ export default {
|
|
|
775
847
|
}
|
|
776
848
|
|
|
777
849
|
.ns-clear {
|
|
850
|
+
&:hover {
|
|
851
|
+
color: var(--primary);
|
|
852
|
+
cursor: pointer;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.ns-singleton-info, .ns-clear {
|
|
778
857
|
align-items: center;
|
|
779
858
|
display: flex;
|
|
780
859
|
> i {
|
|
781
|
-
|
|
782
|
-
padding: 0 5px;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
&:hover {
|
|
786
|
-
color: var(--link);
|
|
787
|
-
cursor: pointer;
|
|
860
|
+
padding-right: 5px;
|
|
788
861
|
}
|
|
789
862
|
}
|
|
790
863
|
|
|
@@ -803,7 +876,6 @@ export default {
|
|
|
803
876
|
position: absolute;
|
|
804
877
|
right: 10px;
|
|
805
878
|
top: 5px;
|
|
806
|
-
font-size: 16px;
|
|
807
879
|
line-height: 24px;
|
|
808
880
|
text-align: center;
|
|
809
881
|
width: 24px;
|
|
@@ -811,7 +883,7 @@ export default {
|
|
|
811
883
|
|
|
812
884
|
.ns-dropdown-menu {
|
|
813
885
|
background-color: var(--header-bg);
|
|
814
|
-
border: 1px solid var(--
|
|
886
|
+
border: 1px solid var(--primary-border);
|
|
815
887
|
border-bottom-left-radius: var(--border-radius);
|
|
816
888
|
border-bottom-right-radius: var(--border-radius);
|
|
817
889
|
color: var(--header-btn-text);
|
|
@@ -837,12 +909,49 @@ export default {
|
|
|
837
909
|
padding-bottom: 10px;
|
|
838
910
|
}
|
|
839
911
|
|
|
840
|
-
.ns-option:focus {
|
|
841
|
-
background-color: var(--dropdown-hover-bg);
|
|
842
|
-
color: var(--dropdown-hover-text);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
912
|
.ns-option {
|
|
913
|
+
|
|
914
|
+
&[disabled] {
|
|
915
|
+
cursor: default;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
&:not([disabled]) {
|
|
919
|
+
&:focus {
|
|
920
|
+
background-color: var(--dropdown-hover-bg);
|
|
921
|
+
color: var(--dropdown-hover-text);
|
|
922
|
+
}
|
|
923
|
+
.ns-item {
|
|
924
|
+
&:hover, &:focus {
|
|
925
|
+
background-color: var(--dropdown-hover-bg);
|
|
926
|
+
color: var(--dropdown-hover-text);
|
|
927
|
+
cursor: pointer;
|
|
928
|
+
|
|
929
|
+
> i {
|
|
930
|
+
color: var(--dropdown-hover-text);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
&.ns-selected {
|
|
936
|
+
&:hover,&:focus {
|
|
937
|
+
.ns-item {
|
|
938
|
+
> * {
|
|
939
|
+
background-color: var(--dropdown-hover-bg);
|
|
940
|
+
color: var(--dropdown-hover-text);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
&.ns-selected:not(:hover) {
|
|
947
|
+
.ns-item {
|
|
948
|
+
> * {
|
|
949
|
+
color: var(--dropdown-hover-bg);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
846
955
|
.ns-item {
|
|
847
956
|
align-items: center;
|
|
848
957
|
display: flex;
|
|
@@ -862,33 +971,8 @@ export default {
|
|
|
862
971
|
white-space: nowrap;
|
|
863
972
|
}
|
|
864
973
|
|
|
865
|
-
&:hover, &:focus {
|
|
866
|
-
background-color: var(--dropdown-hover-bg);
|
|
867
|
-
color: var(--dropdown-hover-text);
|
|
868
|
-
cursor: pointer;
|
|
869
|
-
|
|
870
|
-
> i {
|
|
871
|
-
color: var(--dropdown-hover-text);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
&.ns-selected:not(:hover) {
|
|
876
|
-
.ns-item {
|
|
877
|
-
> * {
|
|
878
|
-
color: var(--dropdown-hover-bg);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
&.ns-selected {
|
|
883
|
-
&:hover,&:focus {
|
|
884
|
-
.ns-item {
|
|
885
|
-
> * {
|
|
886
|
-
background-color: var(--dropdown-hover-bg);
|
|
887
|
-
color: var(--dropdown-hover-text);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
974
|
}
|
|
975
|
+
|
|
892
976
|
&.ns-single-match {
|
|
893
977
|
.ns-item {
|
|
894
978
|
background-color: var(--dropdown-hover-bg);
|
|
@@ -915,7 +999,7 @@ export default {
|
|
|
915
999
|
&.ns-open {
|
|
916
1000
|
border-bottom-left-radius: 0;
|
|
917
1001
|
border-bottom-right-radius: 0;
|
|
918
|
-
border-color: var(--
|
|
1002
|
+
border-color: var(--primary-border);
|
|
919
1003
|
}
|
|
920
1004
|
|
|
921
1005
|
> .ns-values {
|
|
@@ -924,14 +1008,13 @@ export default {
|
|
|
924
1008
|
|
|
925
1009
|
&:hover {
|
|
926
1010
|
> i {
|
|
927
|
-
color: var(--
|
|
1011
|
+
color: var(--primary);
|
|
928
1012
|
}
|
|
929
1013
|
}
|
|
930
1014
|
|
|
931
1015
|
> i {
|
|
932
1016
|
height: $ns_dropdown_size;
|
|
933
1017
|
width: $ns_dropdown_size;
|
|
934
|
-
font-size: 20px;
|
|
935
1018
|
cursor: pointer;
|
|
936
1019
|
text-align: center;
|
|
937
1020
|
line-height: $ns_dropdown_size;
|
|
@@ -963,7 +1046,7 @@ export default {
|
|
|
963
1046
|
margin-left: 5px;
|
|
964
1047
|
|
|
965
1048
|
&:hover {
|
|
966
|
-
color: var(--
|
|
1049
|
+
color: var(--primary);
|
|
967
1050
|
};
|
|
968
1051
|
}
|
|
969
1052
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import BrandImage from '@shell/components/BrandImage';
|
|
3
3
|
import ClusterProviderIcon from '@shell/components/ClusterProviderIcon';
|
|
4
|
+
import IconOrSvg from '../IconOrSvg';
|
|
4
5
|
import { mapGetters } from 'vuex';
|
|
5
6
|
import $ from 'jquery';
|
|
6
7
|
import { CAPI, MANAGEMENT } from '@shell/config/types';
|
|
@@ -14,13 +15,13 @@ import { SETTING } from '@shell/config/settings';
|
|
|
14
15
|
import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
|
|
15
16
|
import { isRancherPrime } from '@shell/config/version';
|
|
16
17
|
|
|
17
|
-
const UNKNOWN = 'unknown';
|
|
18
|
-
const UI_VERSION = process.env.VERSION || UNKNOWN;
|
|
19
|
-
const UI_COMMIT = process.env.COMMIT || UNKNOWN;
|
|
20
|
-
|
|
21
18
|
export default {
|
|
22
19
|
|
|
23
|
-
components: {
|
|
20
|
+
components: {
|
|
21
|
+
BrandImage,
|
|
22
|
+
ClusterProviderIcon,
|
|
23
|
+
IconOrSvg
|
|
24
|
+
},
|
|
24
25
|
|
|
25
26
|
data() {
|
|
26
27
|
const { displayVersion, fullVersion } = getVersionInfo(this.$store);
|
|
@@ -30,8 +31,6 @@ export default {
|
|
|
30
31
|
shown: false,
|
|
31
32
|
displayVersion,
|
|
32
33
|
fullVersion,
|
|
33
|
-
uiCommit: UI_COMMIT,
|
|
34
|
-
uiVersion: UI_VERSION,
|
|
35
34
|
clusterFilter: '',
|
|
36
35
|
hasProvCluster,
|
|
37
36
|
};
|
|
@@ -145,6 +144,7 @@ export default {
|
|
|
145
144
|
return {
|
|
146
145
|
label: this.$store.getters['i18n/withFallback'](`product."${ p.name }"`, null, ucFirst(p.name)),
|
|
147
146
|
icon: `icon-${ p.icon || 'copy' }`,
|
|
147
|
+
svg: p.svg,
|
|
148
148
|
value: p.name,
|
|
149
149
|
removable: p.removable !== false,
|
|
150
150
|
inStore: p.inStore || 'cluster',
|
|
@@ -347,9 +347,9 @@ export default {
|
|
|
347
347
|
class="option"
|
|
348
348
|
:to="a.to"
|
|
349
349
|
>
|
|
350
|
-
<
|
|
351
|
-
|
|
352
|
-
:
|
|
350
|
+
<IconOrSvg
|
|
351
|
+
:icon="a.icon"
|
|
352
|
+
:src="a.svg"
|
|
353
353
|
/>
|
|
354
354
|
<div>{{ a.label }}</div>
|
|
355
355
|
</nuxt-link>
|
|
@@ -368,9 +368,9 @@ export default {
|
|
|
368
368
|
class="option"
|
|
369
369
|
:to="a.to"
|
|
370
370
|
>
|
|
371
|
-
<
|
|
372
|
-
|
|
373
|
-
:
|
|
371
|
+
<IconOrSvg
|
|
372
|
+
:icon="a.icon"
|
|
373
|
+
:src="a.svg"
|
|
374
374
|
/>
|
|
375
375
|
<div>{{ a.label }}</div>
|
|
376
376
|
</nuxt-link>
|
|
@@ -389,9 +389,9 @@ export default {
|
|
|
389
389
|
class="option"
|
|
390
390
|
:to="a.to"
|
|
391
391
|
>
|
|
392
|
-
<
|
|
393
|
-
|
|
394
|
-
:
|
|
392
|
+
<IconOrSvg
|
|
393
|
+
:icon="a.icon"
|
|
394
|
+
:src="a.svg"
|
|
395
395
|
/>
|
|
396
396
|
<div>{{ a.label }}</div>
|
|
397
397
|
</nuxt-link>
|
|
@@ -410,11 +410,11 @@ export default {
|
|
|
410
410
|
</div>
|
|
411
411
|
<div @click="hide()">
|
|
412
412
|
<nuxt-link
|
|
413
|
-
v-tooltip="{ content: fullVersion, classes: 'footer-tooltip' }"
|
|
414
413
|
:to="{ name: 'about' }"
|
|
415
414
|
class="version"
|
|
416
|
-
|
|
417
|
-
|
|
415
|
+
>
|
|
416
|
+
{{ t('about.title') }}
|
|
417
|
+
</nuxt-link>
|
|
418
418
|
</div>
|
|
419
419
|
</div>
|
|
420
420
|
</div>
|
|
@@ -505,6 +505,9 @@ export default {
|
|
|
505
505
|
margin-right: 8px;
|
|
506
506
|
fill: var(--link);
|
|
507
507
|
}
|
|
508
|
+
img {
|
|
509
|
+
margin-right: 8px;
|
|
510
|
+
}
|
|
508
511
|
|
|
509
512
|
> div {
|
|
510
513
|
color: var(--link);
|