@rancher/shell 0.4.0 → 0.5.0
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/images/providers/ovhcloudmks.svg +122 -0
- package/assets/images/providers/ovhcloudpubliccloud.svg +122 -0
- package/assets/styles/global/_layout.scss +99 -0
- package/assets/translations/en-us.yaml +30 -5
- package/assets/translations/zh-hans.yaml +1 -1
- package/babel.config.js +7 -1
- package/chart/monitoring/alerting/index.vue +7 -21
- package/chart/monitoring/grafana/index.vue +55 -0
- package/chart/monitoring/index.vue +51 -17
- package/chart/monitoring/prometheus/index.vue +37 -43
- package/chart/rancher-backup/index.vue +2 -1
- package/cloud-credential/azure.vue +4 -17
- package/components/AsyncButton.vue +17 -5
- package/components/Certificates.vue +164 -0
- package/components/CodeMirror.vue +19 -21
- package/components/CruResource.vue +1 -0
- package/components/DraggableZone.vue +2 -2
- package/components/EtcdInfoBanner.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +25 -1
- package/components/IconOrSvg.vue +1 -1
- package/components/LandingPagePreference.vue +1 -4
- package/components/PodSecurityAdmission.vue +2 -2
- package/components/Questions/index.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +16 -3
- package/components/ResourceTable.vue +14 -2
- package/components/ResourceYaml.vue +5 -0
- package/components/SideNav.vue +1 -1
- package/components/SingleClusterInfo.vue +1 -4
- package/components/Tabbed/index.vue +12 -0
- package/components/fleet/FleetRepos.vue +62 -27
- package/components/fleet/FleetResources.vue +6 -1
- package/components/form/ArrayListSelect.vue +10 -0
- package/components/form/Error.vue +3 -3
- package/components/form/Footer.vue +2 -2
- package/components/form/GitPicker.vue +83 -38
- package/components/form/KeyValue.vue +4 -0
- package/components/form/LabeledSelect.vue +4 -0
- package/components/formatter/Checked.vue +11 -3
- package/components/formatter/FleetClusterSummaryGraph.vue +27 -0
- package/components/formatter/FleetSummaryGraph.vue +23 -11
- package/components/formatter/LiveDuration.vue +1 -1
- package/components/formatter/PercentageBar.vue +1 -1
- package/components/formatter/__tests__/Checked.test.ts +19 -0
- package/components/nav/Group.vue +2 -2
- package/components/nav/Header.vue +0 -1
- package/components/nav/TopLevelMenu.vue +36 -6
- package/components/nav/Type.vue +1 -3
- package/components/nav/WindowManager/ContainerLogs.vue +101 -3
- package/components/nav/WindowManager/ContainerShell.vue +6 -1
- package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +186 -0
- package/components/nav/WindowManager/index.vue +11 -10
- package/components/nav/__tests__/TopLevelMenu.test.ts +33 -0
- package/components/nav/__tests__/Type.test.ts +1 -1
- package/components/nuxt/nuxt-child.js +14 -78
- package/components/nuxt/nuxt.js +1 -1
- package/{layouts → components/templates}/blank.vue +1 -1
- package/{layouts → components/templates}/default.vue +8 -98
- package/{layouts → components/templates}/error.vue +10 -19
- package/{layouts → components/templates}/home.vue +4 -1
- package/{layouts → components/templates}/plain.vue +4 -1
- package/{layouts → components/templates}/standalone.vue +1 -1
- package/{layouts → components/templates}/unauthenticated.vue +1 -1
- package/composables/useCompactInput.test.ts +36 -0
- package/composables/useCompactInput.ts +20 -0
- package/composables/useLabeledFormElement.test.ts +135 -0
- package/composables/useLabeledFormElement.ts +138 -0
- package/config/harvester-manager-types.js +2 -0
- package/config/private-label.js +22 -0
- package/config/product/explorer.js +3 -0
- package/config/product/fleet.js +6 -1
- package/config/product/manager.js +8 -2
- package/config/query-params.js +1 -0
- package/config/router.js +385 -364
- package/config/settings.ts +1 -0
- package/config/store.js +1 -1
- package/config/system-namespaces.js +3 -0
- package/config/table-headers.js +47 -0
- package/core/plugin-routes.ts +56 -114
- package/core/plugin.ts +16 -10
- package/core/plugins-loader.js +7 -9
- package/core/plugins.js +0 -3
- package/creators/app/files/.gitlab-ci.yml +1 -1
- package/detail/fleet.cattle.io.cluster.vue +11 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -3
- package/dialog/ScaleMachineDownDialog.vue +34 -17
- package/edit/__tests__/service.test.ts +89 -0
- package/edit/auth/googleoauth.vue +1 -5
- package/edit/cloudcredential.vue +2 -0
- package/edit/configmap.vue +2 -1
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +2 -2
- package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +1 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +15 -7
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +112 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +473 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/{CustomCommand.tests.ts → CustomCommand.test.ts} +4 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +73 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +7 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/index.vue +92 -36
- package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -583
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +137 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +157 -0
- package/edit/provisioning.cattle.io.cluster/{Basics.vue → tabs/Basics.vue} +94 -19
- package/edit/provisioning.cattle.io.cluster/{MachinePool.vue → tabs/MachinePool.vue} +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +135 -0
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +189 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +144 -0
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/index.vue +76 -0
- package/edit/service.vue +12 -0
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.js +25 -71
- package/initialize/client.js +21 -162
- package/initialize/index.js +27 -123
- package/list/management.cattle.io.feature.vue +1 -7
- package/list/node.vue +1 -0
- package/machine-config/__tests__/vmwarevsphere.test.ts +100 -21
- package/machine-config/vmwarevsphere.vue +73 -51
- package/middleware/authenticated.js +10 -17
- package/mixins/auth-config.js +2 -7
- package/mixins/brand.js +29 -41
- package/mixins/create-edit-view/index.js +2 -2
- package/mixins/labeled-form-element.ts +6 -1
- package/models/__tests__/management.cattle.io.node.ts +85 -0
- package/models/__tests__/management.cattle.io.nodepool.ts +83 -0
- package/models/__tests__/namespace.test.ts +49 -9
- package/models/__tests__/workload.test.ts +91 -0
- package/models/cluster/node.js +4 -4
- package/models/cluster.x-k8s.io.machinedeployment.js +14 -0
- package/models/fleet.cattle.io.cluster.js +4 -0
- package/models/fleet.cattle.io.gitrepo.js +56 -13
- package/models/management.cattle.io.kontainerdriver.js +1 -1
- package/models/management.cattle.io.node.js +18 -14
- package/models/management.cattle.io.nodepool.js +17 -0
- package/models/namespace.js +1 -1
- package/models/pod.js +20 -0
- package/models/provisioning.cattle.io.cluster.js +20 -3
- package/models/secret.js +117 -18
- package/models/workload.js +16 -0
- package/models/workload.service.js +18 -0
- package/package.json +10 -9
- package/pages/about.vue +0 -1
- package/pages/account/create-key.vue +0 -1
- package/pages/account/index.vue +0 -1
- package/pages/auth/login.vue +0 -1
- package/pages/auth/logout.vue +0 -2
- package/pages/auth/setup.vue +0 -4
- package/pages/auth/verify.vue +14 -8
- package/pages/c/_cluster/apps/charts/install.vue +4 -4
- package/pages/c/_cluster/apps/index.vue +0 -2
- package/pages/c/_cluster/auth/index.vue +0 -2
- package/pages/c/_cluster/ecm/index.vue +0 -2
- package/pages/c/_cluster/explorer/index.vue +28 -2
- package/pages/c/_cluster/fleet/index.vue +1 -1
- package/pages/c/_cluster/index.vue +0 -2
- package/pages/c/_cluster/settings/banners.vue +0 -2
- package/pages/c/_cluster/settings/brand.vue +0 -2
- package/pages/c/_cluster/settings/index.vue +0 -2
- package/pages/c/_cluster/settings/links.vue +0 -1
- package/pages/c/_cluster/settings/performance.vue +0 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +2 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +10 -46
- package/pages/c/_cluster/uiplugins/index.vue +0 -2
- package/pages/diagnostic.vue +1 -2
- package/pages/fail-whale.vue +0 -1
- package/pages/prefs.vue +0 -1
- package/pages/support/index.vue +2 -8
- package/pkg/auto-import.js +1 -1
- package/plugins/axios.js +0 -36
- package/plugins/back-button.js +3 -5
- package/plugins/codemirror-loader.js +1 -1
- package/plugins/codemirror.js +41 -0
- package/plugins/dashboard-store/__tests__/{mutations.spec.ts → mutations.test.ts} +1 -1
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +49 -0
- package/plugins/dashboard-store/__tests__/utils/store-mocks.ts +7 -0
- package/plugins/dashboard-store/actions.js +30 -4
- package/plugins/dashboard-store/classify.js +1 -18
- package/plugins/dashboard-store/getters.js +10 -5
- package/plugins/dashboard-store/index.js +0 -12
- package/plugins/dashboard-store/mutations.js +0 -4
- package/plugins/dashboard-store/resource-class.js +59 -18
- package/plugins/steve/__tests__/steve-class.spec.ts +59 -0
- package/plugins/steve/__tests__/utils/steve-mocks.ts +31 -0
- package/plugins/steve/getters.js +4 -1
- package/plugins/steve/norman-class.js +19 -0
- package/plugins/steve/steve-class.js +22 -0
- package/plugins/steve/subscribe.js +4 -10
- package/rancher-components/Accordion/Accordion.test.ts +45 -0
- package/rancher-components/Accordion/Accordion.vue +86 -0
- package/rancher-components/Accordion/index.ts +1 -0
- package/rancher-components/BadgeState/BadgeState.vue +3 -3
- package/rancher-components/Banner/Banner.vue +2 -2
- package/rancher-components/Card/Card.vue +3 -3
- package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +65 -24
- package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
- package/rancher-components/Form/Radio/RadioButton.vue +13 -7
- package/rancher-components/Form/Radio/RadioGroup.test.ts +30 -0
- package/rancher-components/Form/Radio/RadioGroup.vue +8 -3
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
- package/rancher-components/StringList/StringList.test.ts +270 -0
- package/rancher-components/StringList/StringList.vue +65 -26
- package/rancher-components/components/Accordion/Accordion.test.ts +45 -0
- package/rancher-components/components/Accordion/Accordion.vue +86 -0
- package/rancher-components/components/Accordion/index.ts +1 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +3 -3
- package/rancher-components/components/Banner/Banner.vue +2 -2
- package/rancher-components/components/Card/Card.vue +3 -3
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +3 -3
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +57 -24
- package/rancher-components/components/Form/Radio/RadioButton.vue +13 -7
- package/rancher-components/components/Form/Radio/RadioGroup.vue +4 -3
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +9 -4
- package/rancher-components/components/StringList/StringList.vue +8 -8
- package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +50 -0
- package/scripts/extension/parse-tag-name +2 -2
- package/scripts/publish-shell.sh +10 -0
- package/scripts/test-plugins-build.sh +85 -9
- package/server/har-file.js +183 -0
- package/store/catalog.js +1 -1
- package/store/features.js +1 -0
- package/store/i18n.js +11 -0
- package/store/index.js +10 -11
- package/store/prefs.js +33 -35
- package/store/type-map.js +8 -7
- package/tsconfig.json +35 -9
- package/tsconfig.paths.json +21 -0
- package/types/shell/index.d.ts +427 -234
- package/types/vue-shim.d.ts +42 -0
- package/utils/__tests__/create-yaml.test.ts +60 -0
- package/utils/axios.js +0 -19
- package/utils/azure.js +24 -0
- package/utils/create-yaml.js +17 -10
- package/utils/git.ts +1 -1
- package/utils/monitoring.js +1 -1
- package/utils/nuxt.js +18 -39
- package/utils/object.js +14 -0
- package/utils/router.scrollBehavior.js +12 -14
- package/utils/time.js +1 -1
- package/utils/url.ts +1 -1
- package/vue.config.js +23 -2
- package/.DS_Store +0 -0
- package/assets/images/providers/aks-black.svg +0 -28
- package/assets/images/providers/aks.svg +0 -31
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -234
- package/initialize/layouts.ts +0 -26
- package/mixins/fetch.server.js +0 -73
- package/pages/c/index.vue +0 -9
- package/pages/rio/mesh.vue +0 -508
- package/plugins/transitions.js +0 -4
- package/scripts/.DS_Store +0 -0
- package/scripts/verdaccio.log +0 -205
- package/tsconfig.default.json +0 -46
- package/yarn-error.log +0 -200
- /package/components/form/__tests__/{NameNsDescription.ts → NameNsDescription.test.ts} +0 -0
- /package/edit/networking.k8s.io.networkpolicy/__tests__/utils/{selectors.ts → selectors.test.ts} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{AgentConfiguration.vue → tabs/AgentConfiguration.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{MemberRoles.vue → tabs/MemberRoles.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{S3Config.vue → tabs/etcd/S3Config.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{ACE.vue → tabs/networking/ACE.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{RegistryConfigs.vue → tabs/registries/RegistryConfigs.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{RegistryMirrors.vue → tabs/registries/RegistryMirrors.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{DrainOptions.vue → tabs/upgrade/DrainOptions.vue} +0 -0
- /package/plugins/dashboard-store/__tests__/{actions.spec.ts → actions.test.ts} +0 -0
- /package/plugins/dashboard-store/__tests__/{getters.spec.ts → getters.test.ts} +0 -0
- /package/rancher-components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
- /package/rancher-components/components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import ContainerLogs from '@shell/components/nav/WindowManager/ContainerLogs.vue';
|
|
3
|
+
import { base64Encode } from '@shell/utils/crypto';
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
5
|
+
import { addEventListener } from '@shell/utils/socket';
|
|
6
|
+
|
|
7
|
+
jest.mock('@shell/utils/socket');
|
|
8
|
+
|
|
9
|
+
const getDefaultOptions = () => {
|
|
10
|
+
return {
|
|
11
|
+
propsData: {
|
|
12
|
+
tab: {},
|
|
13
|
+
active: true,
|
|
14
|
+
height: 100,
|
|
15
|
+
pod: {
|
|
16
|
+
spec: { nodeName: 'nodeId' },
|
|
17
|
+
links: { view: 'url' },
|
|
18
|
+
os: 'linux'
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
data() {
|
|
22
|
+
return { range: '30 minute' };
|
|
23
|
+
},
|
|
24
|
+
mocks: {
|
|
25
|
+
$store: {
|
|
26
|
+
getters: {
|
|
27
|
+
'prefs/get': jest.fn(),
|
|
28
|
+
'i18n/t': jest.fn(),
|
|
29
|
+
currentProduct: { inStore: 'cluster' }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
describe('component: ContainerLogs', () => {
|
|
37
|
+
it('should receive messages correctly', async() => {
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
const wrapper = await shallowMount(ContainerLogs, getDefaultOptions());
|
|
40
|
+
|
|
41
|
+
const data1 = 'container logs test1\n';
|
|
42
|
+
const messageCallback = addEventListener.mock.calls.find(([e]) => e === 'message')[1];
|
|
43
|
+
|
|
44
|
+
messageCallback({ detail: { data: base64Encode(data1) } });
|
|
45
|
+
|
|
46
|
+
await wrapper.vm.$nextTick();
|
|
47
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
48
|
+
expect(wrapper.vm.backlog[0].rawMsg).toBe(data1.trimEnd());
|
|
49
|
+
const data2 = 'container logs test2 中文日志内容测试\n';
|
|
50
|
+
|
|
51
|
+
messageCallback({ detail: { data: base64Encode(data2) } });
|
|
52
|
+
await wrapper.vm.$nextTick();
|
|
53
|
+
expect(wrapper.vm.backlog).toHaveLength(2);
|
|
54
|
+
expect(wrapper.vm.backlog[1].rawMsg).toBe(data2.trimEnd());
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should not fail for an empty message/string', async() => {
|
|
58
|
+
jest.clearAllMocks();
|
|
59
|
+
const wrapper = await shallowMount(ContainerLogs, getDefaultOptions());
|
|
60
|
+
|
|
61
|
+
const data1 = '';
|
|
62
|
+
const messageCallback = addEventListener.mock.calls.find(([e]) => e === 'message')[1];
|
|
63
|
+
|
|
64
|
+
messageCallback({ detail: { data: base64Encode(data1) } });
|
|
65
|
+
await wrapper.vm.$nextTick();
|
|
66
|
+
expect(wrapper.vm.backlog).toHaveLength(0);
|
|
67
|
+
expect(wrapper.vm.filtered).toHaveLength(0);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should merge the message which be truncated line', async() => {
|
|
71
|
+
jest.clearAllMocks();
|
|
72
|
+
const wrapper = await shallowMount(ContainerLogs, getDefaultOptions());
|
|
73
|
+
const part1 = 'container logs part1';
|
|
74
|
+
const messageCallback = addEventListener.mock.calls.find(([e]) => e === 'message')[1];
|
|
75
|
+
|
|
76
|
+
messageCallback({ detail: { data: base64Encode(part1) } });
|
|
77
|
+
await wrapper.vm.$nextTick();
|
|
78
|
+
|
|
79
|
+
expect(wrapper.vm.backlog).toHaveLength(0);
|
|
80
|
+
const part2 = 'container logs part2\n';
|
|
81
|
+
|
|
82
|
+
messageCallback({ detail: { data: base64Encode(part2) } });
|
|
83
|
+
await wrapper.vm.$nextTick();
|
|
84
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
85
|
+
expect(wrapper.vm.backlog[0].rawMsg).toBe(`${ part1 }${ part2 }`.trimEnd());
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should merge truncated 2-byte utf-8 character messages', async() => {
|
|
89
|
+
jest.clearAllMocks();
|
|
90
|
+
const wrapper = await shallowMount(ContainerLogs, getDefaultOptions());
|
|
91
|
+
// Contains 2-byte utf-8 character message with one character truncation
|
|
92
|
+
const message = '¡¢£¤¥\n';
|
|
93
|
+
const arr = Buffer.from(message);
|
|
94
|
+
|
|
95
|
+
const part1 = arr.slice(0, 3).toString('base64');
|
|
96
|
+
const part2 = arr.slice(3).toString('base64');
|
|
97
|
+
|
|
98
|
+
const messageCallback = addEventListener.mock.calls.find(([e]) => e === 'message')[1];
|
|
99
|
+
|
|
100
|
+
messageCallback({ detail: { data: part1 } });
|
|
101
|
+
await wrapper.vm.$nextTick();
|
|
102
|
+
expect(wrapper.vm.backlog).toHaveLength(0);
|
|
103
|
+
messageCallback({ detail: { data: part2 } });
|
|
104
|
+
await wrapper.vm.$nextTick();
|
|
105
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
106
|
+
expect(wrapper.vm.backlog[0].rawMsg).toBe(message.trimEnd());
|
|
107
|
+
});
|
|
108
|
+
it('should merge truncated 3-byte utf-8 character messages', async() => {
|
|
109
|
+
jest.clearAllMocks();
|
|
110
|
+
const wrapper = await shallowMount(ContainerLogs, getDefaultOptions());
|
|
111
|
+
// Contains 3-byte utf-8 character message with one character truncation
|
|
112
|
+
const message = 'ࠀࠁࠂࠃ\n';
|
|
113
|
+
const arr = Buffer.from(message);
|
|
114
|
+
// Truncate at the fourth byte
|
|
115
|
+
const part1 = arr.slice(0, 4).toString('base64');
|
|
116
|
+
const part2 = arr.slice(4).toString('base64');
|
|
117
|
+
|
|
118
|
+
const messageCallback = addEventListener.mock.calls.find(([e]) => e === 'message')[1];
|
|
119
|
+
|
|
120
|
+
messageCallback({ detail: { data: part1 } });
|
|
121
|
+
await wrapper.vm.$nextTick();
|
|
122
|
+
expect(wrapper.vm.backlog).toHaveLength(0);
|
|
123
|
+
messageCallback({ detail: { data: part2 } });
|
|
124
|
+
await wrapper.vm.$nextTick();
|
|
125
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
126
|
+
expect(wrapper.vm.backlog[0].rawMsg).toBe(message.trimEnd());
|
|
127
|
+
|
|
128
|
+
// Truncate at the fifth byte
|
|
129
|
+
const part3 = arr.slice(0, 5).toString('base64');
|
|
130
|
+
const part4 = arr.slice(5).toString('base64');
|
|
131
|
+
|
|
132
|
+
messageCallback({ detail: { data: part3 } });
|
|
133
|
+
await wrapper.vm.$nextTick();
|
|
134
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
135
|
+
messageCallback({ detail: { data: part4 } });
|
|
136
|
+
await wrapper.vm.$nextTick();
|
|
137
|
+
expect(wrapper.vm.backlog).toHaveLength(2);
|
|
138
|
+
expect(wrapper.vm.backlog[1].rawMsg).toBe(message.trimEnd());
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should merge truncated 4-byte utf-8 character messages', async() => {
|
|
142
|
+
jest.clearAllMocks();
|
|
143
|
+
const wrapper = await shallowMount(ContainerLogs, getDefaultOptions());
|
|
144
|
+
// Contains 4-byte utf-8 character message with one character truncation
|
|
145
|
+
const message = '𐀀𐀁𐀂𐀃\n';
|
|
146
|
+
const arr = Buffer.from(message);
|
|
147
|
+
|
|
148
|
+
// Truncate at the fifth byte
|
|
149
|
+
const part1 = arr.slice(0, 5).toString('base64');
|
|
150
|
+
const part2 = arr.slice(5).toString('base64');
|
|
151
|
+
|
|
152
|
+
const messageCallback = addEventListener.mock.calls.find(([e]) => e === 'message')[1];
|
|
153
|
+
|
|
154
|
+
messageCallback({ detail: { data: part1 } });
|
|
155
|
+
await wrapper.vm.$nextTick();
|
|
156
|
+
expect(wrapper.vm.backlog).toHaveLength(0);
|
|
157
|
+
messageCallback({ detail: { data: part2 } });
|
|
158
|
+
await wrapper.vm.$nextTick();
|
|
159
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
160
|
+
expect(wrapper.vm.backlog[0].rawMsg).toBe(message.trimEnd());
|
|
161
|
+
|
|
162
|
+
// Truncate at the sixth byte
|
|
163
|
+
const part3 = arr.slice(0, 6).toString('base64');
|
|
164
|
+
const part4 = arr.slice(6).toString('base64');
|
|
165
|
+
|
|
166
|
+
messageCallback({ detail: { data: part3 } });
|
|
167
|
+
await wrapper.vm.$nextTick();
|
|
168
|
+
expect(wrapper.vm.backlog).toHaveLength(1);
|
|
169
|
+
messageCallback({ detail: { data: part4 } });
|
|
170
|
+
await wrapper.vm.$nextTick();
|
|
171
|
+
expect(wrapper.vm.backlog).toHaveLength(2);
|
|
172
|
+
expect(wrapper.vm.backlog[1].rawMsg).toBe(message.trimEnd());
|
|
173
|
+
|
|
174
|
+
// Truncate at the seventh byte
|
|
175
|
+
const part5 = arr.slice(0, 7).toString('base64');
|
|
176
|
+
const part6 = arr.slice(7).toString('base64');
|
|
177
|
+
|
|
178
|
+
messageCallback({ detail: { data: part5 } });
|
|
179
|
+
await wrapper.vm.$nextTick();
|
|
180
|
+
expect(wrapper.vm.backlog).toHaveLength(2);
|
|
181
|
+
messageCallback({ detail: { data: part6 } });
|
|
182
|
+
await wrapper.vm.$nextTick();
|
|
183
|
+
expect(wrapper.vm.backlog).toHaveLength(3);
|
|
184
|
+
expect(wrapper.vm.backlog[2].rawMsg).toBe(message.trimEnd());
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -20,10 +20,6 @@ export default {
|
|
|
20
20
|
|
|
21
21
|
height: {
|
|
22
22
|
get() {
|
|
23
|
-
if ( process.server ) {
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
23
|
if ( this.userHeight ) {
|
|
28
24
|
return this.userHeight;
|
|
29
25
|
}
|
|
@@ -52,10 +48,6 @@ export default {
|
|
|
52
48
|
|
|
53
49
|
width: {
|
|
54
50
|
get() {
|
|
55
|
-
if ( process.server ) {
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
51
|
if (this.userWidth) {
|
|
60
52
|
return this.userWidth;
|
|
61
53
|
}
|
|
@@ -342,7 +334,8 @@ export default {
|
|
|
342
334
|
/>
|
|
343
335
|
<span class="tab-label"> {{ tab.label }}</span>
|
|
344
336
|
<i
|
|
345
|
-
|
|
337
|
+
data-testid="wm-tab-close-button"
|
|
338
|
+
class="closer icon icon-fw icon-x wm-closer-button"
|
|
346
339
|
@click.stop="close(tab.id)"
|
|
347
340
|
/>
|
|
348
341
|
</div>
|
|
@@ -440,9 +433,16 @@ export default {
|
|
|
440
433
|
margin-left: 5px;
|
|
441
434
|
border: 1px solid var(--body-text);
|
|
442
435
|
border-radius: var(--border-radius);
|
|
436
|
+
line-height: 12px;
|
|
437
|
+
font-size: 10px;
|
|
438
|
+
width: 14px;
|
|
439
|
+
align-self: center;
|
|
440
|
+
display: flex;
|
|
441
|
+
justify-content: center;
|
|
443
442
|
|
|
444
443
|
&:hover {
|
|
445
|
-
|
|
444
|
+
border-color: var(--link-border);
|
|
445
|
+
color: var(--link-border);
|
|
446
446
|
}
|
|
447
447
|
}
|
|
448
448
|
}
|
|
@@ -502,4 +502,5 @@ export default {
|
|
|
502
502
|
border-right: var(--nav-border-size) solid var(--nav-border);
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
|
+
|
|
505
506
|
</style>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mount, Wrapper } from '@vue/test-utils';
|
|
2
2
|
import TopLevelMenu from '@shell/components/nav/TopLevelMenu';
|
|
3
|
+
import { SETTING } from '@shell/config/settings';
|
|
3
4
|
|
|
4
5
|
// DISCLAIMER: This should not be added here, although we have several store requests which are irrelevant
|
|
5
6
|
const defaultStore = {
|
|
@@ -32,6 +33,38 @@ describe('topLevelMenu', () => {
|
|
|
32
33
|
expect(cluster.exists()).toBe(true);
|
|
33
34
|
});
|
|
34
35
|
|
|
36
|
+
it('should not "crash" the component if the structure of banner settings is in an old format', () => {
|
|
37
|
+
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
38
|
+
mocks: {
|
|
39
|
+
$store: {
|
|
40
|
+
getters: {
|
|
41
|
+
'management/all': () => [{ name: 'whatever' },
|
|
42
|
+
// object based on https://github.com/rancher/dashboard/issues/10140#issuecomment-1883252402
|
|
43
|
+
{
|
|
44
|
+
id: SETTING.BANNERS,
|
|
45
|
+
value: JSON.stringify({
|
|
46
|
+
banner: {
|
|
47
|
+
color: '#78c9cf',
|
|
48
|
+
background: '#27292e',
|
|
49
|
+
text: 'Hello World!'
|
|
50
|
+
},
|
|
51
|
+
showHeader: 'true',
|
|
52
|
+
showFooter: 'true'
|
|
53
|
+
})
|
|
54
|
+
}],
|
|
55
|
+
...defaultStore
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
stubs: ['BrandImage', 'nuxt-link']
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(wrapper.vm.globalBannerSettings).toStrictEqual({
|
|
63
|
+
headerFont: '2em',
|
|
64
|
+
footerFont: '2em'
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
35
68
|
describe('searching a term', () => {
|
|
36
69
|
describe('should displays a no results message if have clusters but', () => {
|
|
37
70
|
it('given no matching clusters', () => {
|
|
@@ -5,7 +5,7 @@ import Type from '@shell/components/nav/Type.vue';
|
|
|
5
5
|
jest.mock('vue-router');
|
|
6
6
|
|
|
7
7
|
// Configuration text
|
|
8
|
-
const className = '
|
|
8
|
+
const className = 'router-link-active';
|
|
9
9
|
|
|
10
10
|
describe('component: Type', () => {
|
|
11
11
|
describe('should not use highlight class', () => {
|
|
@@ -18,10 +18,8 @@ export default {
|
|
|
18
18
|
|
|
19
19
|
data.nuxtChild = true
|
|
20
20
|
const _parent = parent
|
|
21
|
-
const transitions = parent.$nuxt.nuxt.transitions
|
|
22
|
-
const defaultTransition = parent.$nuxt.nuxt.defaultTransition
|
|
23
|
-
|
|
24
21
|
let depth = 0
|
|
22
|
+
|
|
25
23
|
while (parent) {
|
|
26
24
|
if (parent.$vnode && parent.$vnode.data.nuxtChild) {
|
|
27
25
|
depth++
|
|
@@ -29,48 +27,18 @@ export default {
|
|
|
29
27
|
parent = parent.$parent
|
|
30
28
|
}
|
|
31
29
|
data.nuxtChildDepth = depth
|
|
32
|
-
const transition = transitions[depth] || defaultTransition
|
|
33
|
-
const transitionProps = {}
|
|
34
|
-
transitionsKeys.forEach((key) => {
|
|
35
|
-
if (typeof transition[key] !== 'undefined') {
|
|
36
|
-
transitionProps[key] = transition[key]
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
30
|
|
|
40
31
|
const listeners = {}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
window.$nuxt.$nextTick(() => {
|
|
52
|
-
window.$nuxt.$emit('triggerScroll')
|
|
53
|
-
})
|
|
54
|
-
if (beforeEnter) {
|
|
55
|
-
return beforeEnter.call(_parent, el)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// make sure that leave is called asynchronous (fix #5703)
|
|
61
|
-
if (transition.css === false) {
|
|
62
|
-
const leave = listeners.leave
|
|
63
|
-
|
|
64
|
-
// only add leave listener when user didnt provide one
|
|
65
|
-
// or when it misses the done argument
|
|
66
|
-
if (!leave || leave.length < 2) {
|
|
67
|
-
listeners.leave = (el, done) => {
|
|
68
|
-
if (leave) {
|
|
69
|
-
leave.call(_parent, el)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
_parent.$nextTick(done)
|
|
73
|
-
}
|
|
32
|
+
|
|
33
|
+
// Add triggerScroll event on beforeEnter (fix #1376)
|
|
34
|
+
const beforeEnter = listeners.beforeEnter
|
|
35
|
+
listeners.beforeEnter = (el) => {
|
|
36
|
+
// Ensure to trigger scroll event after calling scrollBehavior
|
|
37
|
+
window.$nuxt.$nextTick(() => {
|
|
38
|
+
window.$nuxt.$emit('triggerScroll')
|
|
39
|
+
})
|
|
40
|
+
if (beforeEnter) {
|
|
41
|
+
return beforeEnter.call(_parent, el)
|
|
74
42
|
}
|
|
75
43
|
}
|
|
76
44
|
|
|
@@ -80,43 +48,11 @@ export default {
|
|
|
80
48
|
routerView = h('keep-alive', { props: props.keepAliveProps }, [routerView])
|
|
81
49
|
}
|
|
82
50
|
|
|
51
|
+
// this needs to be a "transition" or another non-rendering component,
|
|
52
|
+
// otherwise we will break pages like the charts wizard or the extensions main screen (DOM would render an additional element and break CSS)
|
|
53
|
+
// we can deal with this later once we remove this component and <nuxt /> component
|
|
83
54
|
return h('transition', {
|
|
84
|
-
props: transitionProps,
|
|
85
55
|
on: listeners
|
|
86
56
|
}, [routerView])
|
|
87
57
|
}
|
|
88
58
|
}
|
|
89
|
-
|
|
90
|
-
const transitionsKeys = [
|
|
91
|
-
'name',
|
|
92
|
-
'mode',
|
|
93
|
-
'appear',
|
|
94
|
-
'css',
|
|
95
|
-
'type',
|
|
96
|
-
'duration',
|
|
97
|
-
'enterClass',
|
|
98
|
-
'leaveClass',
|
|
99
|
-
'appearClass',
|
|
100
|
-
'enterActiveClass',
|
|
101
|
-
'enterActiveClass',
|
|
102
|
-
'leaveActiveClass',
|
|
103
|
-
'appearActiveClass',
|
|
104
|
-
'enterToClass',
|
|
105
|
-
'leaveToClass',
|
|
106
|
-
'appearToClass'
|
|
107
|
-
]
|
|
108
|
-
|
|
109
|
-
const listenersKeys = [
|
|
110
|
-
'beforeEnter',
|
|
111
|
-
'enter',
|
|
112
|
-
'afterEnter',
|
|
113
|
-
'enterCancelled',
|
|
114
|
-
'beforeLeave',
|
|
115
|
-
'leave',
|
|
116
|
-
'afterLeave',
|
|
117
|
-
'leaveCancelled',
|
|
118
|
-
'beforeAppear',
|
|
119
|
-
'appear',
|
|
120
|
-
'afterAppear',
|
|
121
|
-
'appearCancelled'
|
|
122
|
-
]
|
package/components/nuxt/nuxt.js
CHANGED
|
@@ -248,7 +248,10 @@ export default {
|
|
|
248
248
|
v-if="clusterAndRouteReady"
|
|
249
249
|
class="main-layout"
|
|
250
250
|
>
|
|
251
|
-
<
|
|
251
|
+
<router-view
|
|
252
|
+
:key="$route.path"
|
|
253
|
+
class="outlet"
|
|
254
|
+
/>
|
|
252
255
|
<ActionMenu />
|
|
253
256
|
<PromptRemove />
|
|
254
257
|
<PromptRestore />
|
|
@@ -282,7 +285,10 @@ export default {
|
|
|
282
285
|
v-else-if="unmatchedRoute"
|
|
283
286
|
class="main-layout"
|
|
284
287
|
>
|
|
285
|
-
<
|
|
288
|
+
<router-view
|
|
289
|
+
:key="$route.path"
|
|
290
|
+
class="outlet"
|
|
291
|
+
/>
|
|
286
292
|
</main>
|
|
287
293
|
<div
|
|
288
294
|
v-if="$refs.draggableZone"
|
|
@@ -304,99 +310,3 @@ export default {
|
|
|
304
310
|
<DraggableZone ref="draggableZone" />
|
|
305
311
|
</div>
|
|
306
312
|
</template>
|
|
307
|
-
<style lang="scss">
|
|
308
|
-
.dashboard-root {
|
|
309
|
-
display: flex;
|
|
310
|
-
flex-direction: column;
|
|
311
|
-
height: 100vh;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
.dashboard-content {
|
|
315
|
-
display: grid;
|
|
316
|
-
position: relative;
|
|
317
|
-
flex: 1 1 auto;
|
|
318
|
-
overflow-y: auto;
|
|
319
|
-
min-height: 0px;
|
|
320
|
-
|
|
321
|
-
&.dashboard-padding-left {
|
|
322
|
-
padding-left: $app-bar-collapsed-width;
|
|
323
|
-
|
|
324
|
-
.overlay-content-mode {
|
|
325
|
-
left: calc(var(--nav-width) + $app-bar-collapsed-width);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
&.pin-right {
|
|
330
|
-
grid-template-areas:
|
|
331
|
-
"header header header"
|
|
332
|
-
"nav main wm";
|
|
333
|
-
grid-template-rows: var(--header-height) auto;
|
|
334
|
-
grid-template-columns: var(--nav-width) auto var(--wm-width, 0px);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
&.pin-bottom {
|
|
338
|
-
grid-template-areas:
|
|
339
|
-
"header header"
|
|
340
|
-
"nav main"
|
|
341
|
-
"wm wm";
|
|
342
|
-
grid-template-rows: var(--header-height) auto var(--wm-height, 0px);
|
|
343
|
-
grid-template-columns: var(--nav-width) auto;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
&.pin-left {
|
|
347
|
-
grid-template-areas:
|
|
348
|
-
"header header header"
|
|
349
|
-
"wm nav main";
|
|
350
|
-
grid-template-rows: var(--header-height) auto;
|
|
351
|
-
grid-template-columns: var(--wm-width, 0px) var(--nav-width) auto;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
> HEADER {
|
|
355
|
-
grid-area: header;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
.default-side-nav {
|
|
359
|
-
grid-area: nav;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
.wm {
|
|
364
|
-
grid-area: wm;
|
|
365
|
-
overflow-y: hidden;
|
|
366
|
-
z-index: 1;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.localeSelector {
|
|
370
|
-
::v-deep .popover-inner {
|
|
371
|
-
padding: 50px 0;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
::v-deep .popover-arrow {
|
|
375
|
-
display: none;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
::v-deep .popover:focus {
|
|
379
|
-
outline: 0;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
li {
|
|
383
|
-
padding: 8px 20px;
|
|
384
|
-
|
|
385
|
-
&:hover {
|
|
386
|
-
background-color: var(--primary-hover-bg);
|
|
387
|
-
color: var(--primary-hover-text);
|
|
388
|
-
text-decoration: none;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
.drag-start {
|
|
394
|
-
z-index: 1000;
|
|
395
|
-
opacity: 0.5;
|
|
396
|
-
transition: opacity .3s ease;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
.drag-end {
|
|
400
|
-
opacity: 1;
|
|
401
|
-
}
|
|
402
|
-
</style>
|
|
@@ -5,18 +5,15 @@ export default {
|
|
|
5
5
|
name: 'NuxtError',
|
|
6
6
|
mixins: [Brand],
|
|
7
7
|
middleware: ['unauthenticated'],
|
|
8
|
-
props: {
|
|
9
|
-
error: {
|
|
10
|
-
type: Object,
|
|
11
|
-
default: null
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
8
|
|
|
15
9
|
data() {
|
|
16
10
|
return { ready: false };
|
|
17
11
|
},
|
|
18
12
|
|
|
19
13
|
computed: {
|
|
14
|
+
error() {
|
|
15
|
+
return window.$nuxt.nuxt.err || {};
|
|
16
|
+
},
|
|
20
17
|
statusCode() {
|
|
21
18
|
return (this.error && this.error.statusCode) || 599;
|
|
22
19
|
},
|
|
@@ -24,6 +21,11 @@ export default {
|
|
|
24
21
|
return this.error.message || '';
|
|
25
22
|
}
|
|
26
23
|
},
|
|
24
|
+
watch: {
|
|
25
|
+
message(neu) {
|
|
26
|
+
document.title = neu;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
27
29
|
|
|
28
30
|
mounted() {
|
|
29
31
|
// If the page isn't a sub-path of the base url, redirect to it instead of saying not found.
|
|
@@ -40,19 +42,8 @@ export default {
|
|
|
40
42
|
setTimeout(() => {
|
|
41
43
|
this.ready = true;
|
|
42
44
|
}, 1000);
|
|
45
|
+
document.title = this.message;
|
|
43
46
|
},
|
|
44
|
-
|
|
45
|
-
head() {
|
|
46
|
-
return {
|
|
47
|
-
title: this.message,
|
|
48
|
-
meta: [
|
|
49
|
-
{
|
|
50
|
-
name: 'viewport',
|
|
51
|
-
content: 'width=device-width,initial-scale=1.0,minimum-scale=1.0'
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
47
|
};
|
|
57
48
|
</script>
|
|
58
49
|
|
|
@@ -112,7 +103,7 @@ export default {
|
|
|
112
103
|
-ms-text-size-adjust: 100%;
|
|
113
104
|
-webkit-text-size-adjust: 100%;
|
|
114
105
|
-webkit-font-smoothing: antialiased;
|
|
115
|
-
position:
|
|
106
|
+
position: fixed;
|
|
116
107
|
top: 0;
|
|
117
108
|
left: 0;
|
|
118
109
|
right: 0;
|
|
@@ -70,7 +70,10 @@ export default {
|
|
|
70
70
|
<Header :simple="true" />
|
|
71
71
|
<main class="main-layout">
|
|
72
72
|
<IndentedPanel class="pt-20">
|
|
73
|
-
<
|
|
73
|
+
<router-view
|
|
74
|
+
:key="$route.path"
|
|
75
|
+
class="outlet"
|
|
76
|
+
/>
|
|
74
77
|
</IndentedPanel>
|
|
75
78
|
<ActionMenu />
|
|
76
79
|
<PromptRemove />
|