@rancher/shell 0.1.4 → 0.1.21
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/brand/suse/favicon.png +0 -0
- package/assets/images/generic-plugin.svg +1 -7
- package/assets/translations/en-us.yaml +81 -47
- package/components/CommunityLinks.vue +40 -49
- package/components/ExplorerProjectsNamespaces.vue +20 -3
- package/components/LazyImage.vue +21 -8
- package/components/PromptRemove.vue +2 -2
- package/components/ResourceList/Masthead.vue +21 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
- package/components/ResourceList/index.vue +9 -23
- package/components/SortableTable/index.vue +13 -10
- package/components/Tabbed/index.vue +25 -7
- package/components/TypeDescription.vue +10 -1
- package/components/fleet/FleetClusters.vue +6 -0
- package/components/fleet/FleetRepos.vue +7 -1
- package/components/form/Command.vue +5 -0
- package/components/form/EnvVars.vue +5 -0
- package/components/form/NameNsDescription.vue +3 -1
- package/components/form/NodeScheduling.vue +6 -1
- package/components/form/PodAffinity.vue +5 -0
- package/components/form/ServiceNameSelect.vue +5 -0
- package/components/form/ValueFromResource.vue +7 -1
- package/components/nav/TopLevelMenu.vue +2 -1
- package/config/home-links.js +155 -0
- package/config/private-label.js +1 -1
- package/config/product/manager.js +0 -2
- package/config/product/uiplugins.js +1 -1
- package/config/settings.js +3 -1
- package/config/uiplugins.js +63 -6
- package/config/version.js +17 -0
- package/core/plugin.ts +12 -0
- package/core/plugins.js +29 -5
- package/core/types.ts +6 -0
- package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
- package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
- package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
- package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
- package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
- package/creators/app/init +16 -17
- package/creators/app/package.json +6 -0
- package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/pkg/{index.ts → files/index.ts} +0 -0
- package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
- package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
- package/creators/pkg/init +1 -1
- package/creators/update/init +54 -0
- package/creators/update/package.json +20 -0
- package/creators/update/upgrade +56 -0
- package/creators/update/yarn-error.log +54 -0
- package/detail/workload/index.vue +1 -0
- package/edit/persistentvolume/index.vue +48 -13
- package/edit/persistentvolumeclaim.vue +31 -13
- package/edit/provisioning.cattle.io.cluster/rke2.vue +27 -19
- package/edit/workload/index.vue +19 -9
- package/edit/workload/mixins/workload.js +109 -114
- package/edit/workload/storage/index.vue +11 -17
- package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
- package/edit/workload/storage/secret.vue +6 -1
- package/list/catalog.cattle.io.app.vue +10 -9
- package/list/catalog.cattle.io.clusterrepo.vue +6 -61
- package/list/cis.cattle.io.clusterscan.vue +12 -12
- package/list/fleet.cattle.io.bundle.vue +33 -28
- package/list/fleet.cattle.io.cluster.vue +26 -22
- package/list/fleet.cattle.io.clustergroup.vue +6 -0
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
- package/list/fleet.cattle.io.gitrepo.vue +25 -14
- package/list/helm.cattle.io.projecthelmchart.vue +52 -33
- package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
- package/list/logging.banzaicloud.io.flow.vue +7 -14
- package/list/management.cattle.io.cluster.vue +26 -15
- package/list/management.cattle.io.feature.vue +13 -8
- package/list/management.cattle.io.user.vue +38 -19
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
- package/list/namespace.vue +14 -1
- package/list/node.vue +13 -16
- package/list/persistentvolume.vue +16 -9
- package/list/persistentvolumeclaim.vue +5 -8
- package/list/provisioning.cattle.io.cluster.vue +34 -8
- package/list/service.vue +24 -12
- package/list/ui.cattle.io.navlink.vue +6 -0
- package/list/workload.vue +2 -2
- package/middleware/authenticated.js +6 -0
- package/mixins/resource-fetch.js +12 -18
- package/mixins/resource-manager.js +126 -0
- package/models/catalog.cattle.io.uiplugin.js +4 -0
- package/models/pod.js +15 -5
- package/models/provisioning.cattle.io.cluster.js +4 -0
- package/models/workload.service.js +10 -0
- package/nuxt.config.js +2 -1
- package/package.json +1 -1
- package/pages/auth/login.vue +10 -0
- package/pages/auth/verify.vue +9 -0
- package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
- package/pages/c/_cluster/settings/links.vue +53 -101
- package/pages/c/_cluster/settings/performance.vue +90 -7
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +3 -3
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +71 -20
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +21 -5
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -7
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +23 -15
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +11 -4
- package/pages/c/_cluster/uiplugins/index.vue +179 -65
- package/pages/support/index.vue +31 -142
- package/plugins/dashboard-store/actions.js +19 -0
- package/plugins/dashboard-store/getters.js +20 -3
- package/plugins/dashboard-store/mutations.js +13 -7
- package/plugins/plugin.js +18 -15
- package/plugins/steve/getters.js +12 -0
- package/plugins/version.js +21 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
- package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
- package/rancher-components/components/BadgeState/index.ts +1 -0
- package/rancher-components/components/Banner/Banner.test.ts +13 -0
- package/rancher-components/components/Banner/Banner.vue +163 -0
- package/rancher-components/components/Banner/index.ts +1 -0
- package/rancher-components/components/Card/Card.vue +150 -0
- package/rancher-components/components/Card/index.ts +1 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
- package/rancher-components/components/Form/Checkbox/index.ts +1 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
- package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
- package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
- package/rancher-components/components/Form/Radio/index.ts +2 -0
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
- package/rancher-components/components/Form/TextArea/index.ts +1 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
- package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
- package/rancher-components/components/Form/index.ts +5 -0
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
- package/rancher-components/components/LabeledTooltip/index.ts +1 -0
- package/scripts/publish-shell.sh +39 -6
- package/scripts/record-deps.js +37 -0
- package/scripts/test-plugins-build.sh +8 -5
- package/scripts/typegen.sh +84 -0
- package/store/auth.js +3 -0
- package/store/index.js +12 -3
- package/types/shell/index.d.ts +3046 -0
- package/utils/favicon.js +8 -2
- package/utils/gc/gc-interval.ts +40 -0
- package/utils/gc/gc-root-store.js +76 -0
- package/utils/gc/gc-route-changed.ts +44 -0
- package/utils/gc/gc-types.ts +21 -0
- package/utils/gc/gc.ts +282 -0
- package/config/footer.js +0 -18
- package/creators/pkg/nuxt.config.js +0 -6
- package/yarn-error.log +0 -195
|
@@ -8,17 +8,35 @@ import { MODE, _IMPORT } from '@shell/config/query-params';
|
|
|
8
8
|
import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
|
|
9
9
|
import { mapFeature, HARVESTER as HARVESTER_FEATURE } from '@shell/store/features';
|
|
10
10
|
import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
11
|
+
import ResourceFetch from '@shell/mixins/resource-fetch';
|
|
11
12
|
|
|
12
13
|
export default {
|
|
13
14
|
components: {
|
|
14
15
|
Banner, ResourceTable, Masthead
|
|
15
16
|
},
|
|
17
|
+
mixins: [ResourceFetch],
|
|
18
|
+
props: {
|
|
19
|
+
loadResources: {
|
|
20
|
+
type: Array,
|
|
21
|
+
default: () => []
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
loadIndeterminate: {
|
|
25
|
+
type: Boolean,
|
|
26
|
+
default: false
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
incrementalLoadingIndicator: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: false
|
|
32
|
+
},
|
|
33
|
+
},
|
|
16
34
|
|
|
17
35
|
async fetch() {
|
|
18
36
|
const hash = {
|
|
37
|
+
rancherClusters: this.$fetchType(CAPI.RANCHER_CLUSTER),
|
|
19
38
|
normanClusters: this.$store.dispatch('rancher/findAll', { type: NORMAN.CLUSTER }),
|
|
20
39
|
mgmtClusters: this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }),
|
|
21
|
-
rancherClusters: this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }),
|
|
22
40
|
};
|
|
23
41
|
|
|
24
42
|
if ( this.$store.getters['management/canList'](SNAPSHOT) ) {
|
|
@@ -50,7 +68,6 @@ export default {
|
|
|
50
68
|
const res = await allHash(hash);
|
|
51
69
|
|
|
52
70
|
this.mgmtClusters = res.mgmtClusters;
|
|
53
|
-
this.rancherClusters = res.rancherClusters;
|
|
54
71
|
},
|
|
55
72
|
|
|
56
73
|
data() {
|
|
@@ -58,19 +75,18 @@ export default {
|
|
|
58
75
|
resource: CAPI.RANCHER_CLUSTER,
|
|
59
76
|
schema: this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER),
|
|
60
77
|
mgmtClusters: [],
|
|
61
|
-
rancherClusters: [],
|
|
62
78
|
};
|
|
63
79
|
},
|
|
64
80
|
|
|
65
81
|
computed: {
|
|
66
|
-
|
|
82
|
+
filteredRows() {
|
|
67
83
|
// If Harvester feature is enabled, hide Harvester Clusters
|
|
68
84
|
if (this.harvesterEnabled) {
|
|
69
|
-
return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.
|
|
85
|
+
return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.rows), this.$store);
|
|
70
86
|
}
|
|
71
87
|
|
|
72
88
|
// Otherwise, show Harvester clusters - these will be shown with a warning
|
|
73
|
-
return filterHiddenLocalCluster(this.
|
|
89
|
+
return filterHiddenLocalCluster(this.rows, this.$store);
|
|
74
90
|
},
|
|
75
91
|
|
|
76
92
|
hiddenHarvesterCount() {
|
|
@@ -82,7 +98,7 @@ export default {
|
|
|
82
98
|
return 0;
|
|
83
99
|
}
|
|
84
100
|
|
|
85
|
-
return this.
|
|
101
|
+
return this.rows.length - filterOnlyKubernetesClusters(this.rows).length;
|
|
86
102
|
},
|
|
87
103
|
|
|
88
104
|
createLocation() {
|
|
@@ -115,6 +131,13 @@ export default {
|
|
|
115
131
|
harvesterEnabled: mapFeature(HARVESTER_FEATURE),
|
|
116
132
|
},
|
|
117
133
|
|
|
134
|
+
$loadingResources() {
|
|
135
|
+
return {
|
|
136
|
+
loadResources: [CAPI.RANCHER_CLUSTER],
|
|
137
|
+
loadIndeterminate: true, // results are filtered so we wouldn't get the correct count on indicator...
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
|
|
118
141
|
mounted() {
|
|
119
142
|
window.c = this;
|
|
120
143
|
},
|
|
@@ -130,6 +153,9 @@ export default {
|
|
|
130
153
|
:resource="resource"
|
|
131
154
|
:create-location="createLocation"
|
|
132
155
|
component-testid="cluster-manager-list"
|
|
156
|
+
:show-incremental-loading-indicator="incrementalLoadingIndicator"
|
|
157
|
+
:load-resources="loadResources"
|
|
158
|
+
:load-indeterminate="loadIndeterminate"
|
|
133
159
|
>
|
|
134
160
|
<template v-if="canImport" slot="extraActions">
|
|
135
161
|
<n-link
|
|
@@ -142,7 +168,7 @@ export default {
|
|
|
142
168
|
</template>
|
|
143
169
|
</Masthead>
|
|
144
170
|
|
|
145
|
-
<ResourceTable :schema="schema" :rows="
|
|
171
|
+
<ResourceTable :schema="schema" :rows="filteredRows" :namespaced="false" :loading="loading">
|
|
146
172
|
<template #cell:summary="{row}">
|
|
147
173
|
<span v-if="!row.stateParts.length">{{ row.nodes.length }}</span>
|
|
148
174
|
</template>
|
package/list/service.vue
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import ResourceTable from '@shell/components/ResourceTable';
|
|
3
|
-
import Loading from '@shell/components/Loading';
|
|
4
3
|
import { NODE } from '@shell/config/types';
|
|
5
4
|
import { allHash } from '@shell/utils/promise';
|
|
5
|
+
import ResourceFetch from '@shell/mixins/resource-fetch';
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
8
|
name: 'ListService',
|
|
9
|
-
components: {
|
|
9
|
+
components: { ResourceTable },
|
|
10
|
+
mixins: [ResourceFetch],
|
|
11
|
+
props: {
|
|
12
|
+
resource: {
|
|
13
|
+
type: String,
|
|
14
|
+
required: true,
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
schema: {
|
|
18
|
+
type: Object,
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
|
|
10
23
|
// fetch nodes before loading this page, as they may be referenced in the Target table column
|
|
11
24
|
async fetch() {
|
|
12
25
|
const store = this.$store;
|
|
@@ -21,23 +34,22 @@ export default {
|
|
|
21
34
|
}
|
|
22
35
|
} catch {}
|
|
23
36
|
|
|
24
|
-
const hash = { rows:
|
|
37
|
+
const hash = { rows: this.$fetchType(this.resource) };
|
|
25
38
|
|
|
26
39
|
if (hasNodes) {
|
|
27
40
|
hash.nodes = store.dispatch(`${ inStore }/findAll`, { type: NODE });
|
|
28
41
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.rows = res.rows;
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
data() {
|
|
35
|
-
return { rows: [] };
|
|
42
|
+
await allHash(hash);
|
|
36
43
|
}
|
|
37
44
|
};
|
|
38
45
|
</script>
|
|
39
46
|
|
|
40
47
|
<template>
|
|
41
|
-
<
|
|
42
|
-
|
|
48
|
+
<ResourceTable
|
|
49
|
+
:schema="schema"
|
|
50
|
+
:rows="rows"
|
|
51
|
+
:headers="$attrs.headers"
|
|
52
|
+
:group-by="$attrs.groupBy"
|
|
53
|
+
:loading="loading"
|
|
54
|
+
/>
|
|
43
55
|
</template>
|
|
@@ -16,6 +16,11 @@ export default {
|
|
|
16
16
|
type: Array,
|
|
17
17
|
required: true,
|
|
18
18
|
},
|
|
19
|
+
|
|
20
|
+
loading: {
|
|
21
|
+
type: Boolean,
|
|
22
|
+
required: false,
|
|
23
|
+
},
|
|
19
24
|
},
|
|
20
25
|
|
|
21
26
|
computed: { ...mapGetters(['clusterId']) }
|
|
@@ -26,6 +31,7 @@ export default {
|
|
|
26
31
|
<ResourceTable
|
|
27
32
|
:schema="schema"
|
|
28
33
|
:rows="rows"
|
|
34
|
+
:loading="loading"
|
|
29
35
|
>
|
|
30
36
|
<template #cell:to="{row}">
|
|
31
37
|
<template v-if="row.spec && row.spec.toService">
|
package/list/workload.vue
CHANGED
|
@@ -76,7 +76,7 @@ export default {
|
|
|
76
76
|
return schema;
|
|
77
77
|
},
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
filteredRows() {
|
|
80
80
|
const out = [];
|
|
81
81
|
|
|
82
82
|
for ( const typeRows of this.resources ) {
|
|
@@ -151,5 +151,5 @@ export default {
|
|
|
151
151
|
</script>
|
|
152
152
|
|
|
153
153
|
<template>
|
|
154
|
-
<ResourceTable :loading="$fetchState.pending" :schema="schema" :rows="
|
|
154
|
+
<ResourceTable :loading="$fetchState.pending" :schema="schema" :rows="filteredRows" :overflow-y="true" />
|
|
155
155
|
</template>
|
|
@@ -234,6 +234,8 @@ export default async function({
|
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
|
+
|
|
238
|
+
store.dispatch('gcStartIntervals');
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
if (!process.server) {
|
|
@@ -245,6 +247,10 @@ export default async function({
|
|
|
245
247
|
window.location.href = backTo;
|
|
246
248
|
}
|
|
247
249
|
}
|
|
250
|
+
|
|
251
|
+
// GC should be notified of route change before any find/get request is made that might be used for that page
|
|
252
|
+
store.dispatch('gcRouteChanged', route);
|
|
253
|
+
|
|
248
254
|
// Load stuff
|
|
249
255
|
await applyProducts(store, $plugin);
|
|
250
256
|
// Setup a beforeEach hook once to keep track of the current product
|
package/mixins/resource-fetch.js
CHANGED
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
import { mapGetters } from 'vuex';
|
|
2
|
-
import {
|
|
3
|
-
COUNT, MANAGEMENT, POD, WORKLOAD_TYPES, WORKLOAD, SECRET
|
|
4
|
-
} from '@shell/config/types';
|
|
2
|
+
import { COUNT, MANAGEMENT } from '@shell/config/types';
|
|
5
3
|
import { SETTING, DEFAULT_PERF_SETTING } from '@shell/config/settings';
|
|
6
4
|
|
|
7
5
|
// Number of pages to fetch when loading incrementally
|
|
8
6
|
const PAGES = 4;
|
|
9
7
|
|
|
10
|
-
// restrict advanced features of manual refresh and incremental loading to these resource types
|
|
11
|
-
export const TYPES_RESTRICTED = [
|
|
12
|
-
SECRET,
|
|
13
|
-
POD,
|
|
14
|
-
WORKLOAD_TYPES.DEPLOYMENT,
|
|
15
|
-
WORKLOAD_TYPES.CRON_JOB,
|
|
16
|
-
WORKLOAD_TYPES.DAEMON_SET,
|
|
17
|
-
WORKLOAD_TYPES.JOB,
|
|
18
|
-
WORKLOAD_TYPES.STATEFUL_SET,
|
|
19
|
-
WORKLOAD_TYPES.REPLICA_SET,
|
|
20
|
-
WORKLOAD_TYPES.REPLICATION_CONTROLLER,
|
|
21
|
-
WORKLOAD
|
|
22
|
-
];
|
|
23
|
-
|
|
24
8
|
export default {
|
|
25
9
|
data() {
|
|
26
10
|
// fetching the settings related to manual refresh from global settings
|
|
@@ -66,7 +50,17 @@ export default {
|
|
|
66
50
|
}
|
|
67
51
|
},
|
|
68
52
|
|
|
69
|
-
computed: {
|
|
53
|
+
computed: {
|
|
54
|
+
...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }),
|
|
55
|
+
rows() {
|
|
56
|
+
const inStore = this.$store.getters['currentStore'](this.resource);
|
|
57
|
+
|
|
58
|
+
return this.$store.getters[`${ inStore }/all`](this.resource);
|
|
59
|
+
},
|
|
60
|
+
loading() {
|
|
61
|
+
return this.rows.length ? false : this.$fetchState.pending;
|
|
62
|
+
},
|
|
63
|
+
},
|
|
70
64
|
watch: {
|
|
71
65
|
refreshFlag(neu) {
|
|
72
66
|
// this is where the data assignment will trigger the update of the list view...
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { mapGetters } from 'vuex';
|
|
2
|
+
import { allHashSettled } from '@shell/utils/promise';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
computed: { ...mapGetters(['currentCluster']) },
|
|
6
|
+
data() {
|
|
7
|
+
return { isLoadingSecondaryResources: false };
|
|
8
|
+
},
|
|
9
|
+
methods: {
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* Function resourceManagerFetchSecondaryResources
|
|
13
|
+
* This method is used to fetch what is called "secondary resources", which can be defined as resources that are needed to populate
|
|
14
|
+
* the page/component itself (ex: used as options on a Select) but don't need to be put into Vuex store or watched to get constant updates.
|
|
15
|
+
* This method allows to fetch resources for a given namespace to reduce the amount of results instead of needing to fetch all and filtering afterwards.
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
* @param {String} resourceData.namespace - Namespace identifier
|
|
19
|
+
* @param {Object} resourceData.data - Object containing info about the data needed to be fetched and how it should be parsed. Note: The KEY NEEDS to be the resource TYPE!
|
|
20
|
+
* @param {Array} resourceData.data[TYPE].applyTo - The array of operations needed to be performed for the specific data TYPE
|
|
21
|
+
* @param {String} resourceData.data[TYPE].applyTo[x].var - The 'this' property name that should be populated with the data fetched
|
|
22
|
+
* @param {Boolean} resourceData.data[TYPE].applyTo[x].classify - Whether the data fetched should have a model applied to it
|
|
23
|
+
* @param {Function} resourceData.data[TYPE].applyTo[x].parsingFunc - Optional parsing function if the fetched data needs to be parsed
|
|
24
|
+
* @param {Boolean} onlyNamespaced - Only fetch namespaced resources
|
|
25
|
+
*/
|
|
26
|
+
async resourceManagerFetchSecondaryResources(resourceData, onlyNamespaced = false) {
|
|
27
|
+
const requests = {};
|
|
28
|
+
const namespace = resourceData.namespace;
|
|
29
|
+
|
|
30
|
+
// Only fetch types if the user is allowed to...
|
|
31
|
+
Object.keys(resourceData.data).forEach((type) => {
|
|
32
|
+
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
33
|
+
|
|
34
|
+
if (schema) {
|
|
35
|
+
let url = schema.links.collection;
|
|
36
|
+
|
|
37
|
+
if (schema?.attributes?.namespaced && namespace) {
|
|
38
|
+
const parts = url.split('/');
|
|
39
|
+
|
|
40
|
+
parts.splice(parts.length - 2, 0, `api`);
|
|
41
|
+
parts.splice(parts.length - 1, 0, `namespaces/${ namespace }`);
|
|
42
|
+
url = parts.join('/');
|
|
43
|
+
} else if (onlyNamespaced) {
|
|
44
|
+
// Type isn't namespaced and we've been requested to only fetch namespaced types
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
requests[type] = this.$store.dispatch('cluster/request', { url });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (Object.keys(requests).length) {
|
|
53
|
+
// this is the flag/variable that we need to apply to all places that rely on this data. Ex: LabeledSelect
|
|
54
|
+
this.isLoadingSecondaryResources = true;
|
|
55
|
+
const hash = await allHashSettled(requests);
|
|
56
|
+
const types = Object.keys(hash);
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < types.length; i++) {
|
|
59
|
+
const type = types[i];
|
|
60
|
+
const status = hash[type].status;
|
|
61
|
+
// if it's namespaced, we get the data on 'items' prop, for non-namespaced it's 'data' prop...
|
|
62
|
+
const requestData = hash[type].value.items || hash[type].value.data || hash[type].value;
|
|
63
|
+
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
64
|
+
|
|
65
|
+
if (status === 'fulfilled' && resourceData.data[type] && resourceData.data[type].applyTo?.length) {
|
|
66
|
+
for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
|
|
67
|
+
const apply = resourceData.data[type].applyTo[y];
|
|
68
|
+
let resources = requestData;
|
|
69
|
+
|
|
70
|
+
if (schema?.attributes?.namespaced) {
|
|
71
|
+
// The resources returned when requesting namespaced types do not contain id, type and links properties.
|
|
72
|
+
// This isn't perfect, or universally applicable, but will work for the current set of use cases
|
|
73
|
+
// To make this more generic
|
|
74
|
+
// - id param = this.$store.getters['cluster/keyFieldForType'](type)
|
|
75
|
+
// - id value = new dashboard-store getter, overwritten by steve store getter
|
|
76
|
+
requestData.forEach((item) => {
|
|
77
|
+
item.type = type;
|
|
78
|
+
item.id = `${ item.metadata.namespace }/${ item.metadata.name }`;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (apply.classify) {
|
|
83
|
+
resources = await this.$store.dispatch('cluster/createMany', requestData);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (apply.parsingFunc) {
|
|
87
|
+
this[apply.var] = apply.parsingFunc(resources);
|
|
88
|
+
} else {
|
|
89
|
+
this[apply.var] = resources;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else if (status === 'rejected') {
|
|
93
|
+
console.error(`Resource Manager - secondary data request for type ${ type } has failed`, status.error); // eslint-disable-line no-console
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.isLoadingSecondaryResources = false;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Clear the cached secondary resources
|
|
103
|
+
*
|
|
104
|
+
* @param {*} resourceData See resourceManagerFetchSecondaryResources
|
|
105
|
+
* @param {*} onlyNamespaced Clear only namespaced resources
|
|
106
|
+
*/
|
|
107
|
+
resourceManagerClearSecondaryResources(resourceData, onlyNamespaced = false) {
|
|
108
|
+
Object.keys(resourceData.data).forEach((type) => {
|
|
109
|
+
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
110
|
+
|
|
111
|
+
if (schema) {
|
|
112
|
+
if (!schema?.attributes?.namespaced && onlyNamespaced) {
|
|
113
|
+
// resource isn't namespaced and we're only interested in namespaced resources
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
|
|
118
|
+
const apply = resourceData.data[type].applyTo[y];
|
|
119
|
+
|
|
120
|
+
this[apply.var] = [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
};
|
package/models/pod.js
CHANGED
|
@@ -182,19 +182,29 @@ export default class Pod extends WorkloadService {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
save() {
|
|
185
|
+
const prev = { ...this };
|
|
186
|
+
|
|
185
187
|
const { metadata, spec } = this.spec.template;
|
|
186
188
|
|
|
187
189
|
this.spec = {
|
|
188
190
|
...this.spec,
|
|
189
|
-
metadata: {
|
|
190
|
-
...this.metadata,
|
|
191
|
-
...metadata
|
|
192
|
-
},
|
|
193
191
|
...spec
|
|
194
192
|
};
|
|
195
193
|
|
|
194
|
+
this.metadata = {
|
|
195
|
+
...this.metadata,
|
|
196
|
+
...metadata
|
|
197
|
+
};
|
|
198
|
+
|
|
196
199
|
delete this.spec.template;
|
|
197
200
|
|
|
198
|
-
|
|
201
|
+
// IF there is an error POD world model get overwritten
|
|
202
|
+
// For the workloads this need be reset back
|
|
203
|
+
return this._save(...arguments).catch((e) => {
|
|
204
|
+
this.spec = prev.spec;
|
|
205
|
+
this.metadata = prev.metadata;
|
|
206
|
+
|
|
207
|
+
return Promise.reject(e);
|
|
208
|
+
});
|
|
199
209
|
}
|
|
200
210
|
}
|
|
@@ -679,6 +679,10 @@ export default class ProvCluster extends SteveModel {
|
|
|
679
679
|
}
|
|
680
680
|
|
|
681
681
|
get supportsWindows() {
|
|
682
|
+
if (this.isK3s || this.isImportedK3s) {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
|
|
682
686
|
if ( this.isRke1 ) {
|
|
683
687
|
return this.mgmt?.spec?.windowsPreferedCluster || false;
|
|
684
688
|
}
|
|
@@ -123,6 +123,11 @@ export default class WorkloadService extends SteveModel {
|
|
|
123
123
|
|
|
124
124
|
return containers;
|
|
125
125
|
}
|
|
126
|
+
|
|
127
|
+
if ( this.spec.containers ) {
|
|
128
|
+
return this.spec.containers;
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
const { spec:{ template:{ spec:{ containers } } } } = this;
|
|
127
132
|
|
|
128
133
|
return containers;
|
|
@@ -135,6 +140,11 @@ export default class WorkloadService extends SteveModel {
|
|
|
135
140
|
|
|
136
141
|
return initContainers;
|
|
137
142
|
}
|
|
143
|
+
|
|
144
|
+
if (this.spec.initContainers) {
|
|
145
|
+
return this.spec.initContainers;
|
|
146
|
+
}
|
|
147
|
+
|
|
138
148
|
const { spec:{ template:{ spec:{ initContainers } } } } = this;
|
|
139
149
|
|
|
140
150
|
return initContainers;
|
package/nuxt.config.js
CHANGED
|
@@ -582,6 +582,7 @@ export default function(dir, _appConfig) {
|
|
|
582
582
|
{ src: path.join(NUXT_SHELL, 'plugins/plugin'), ssr: false }, // Load dyanmic plugins
|
|
583
583
|
{ src: path.join(NUXT_SHELL, 'plugins/codemirror-loader'), ssr: false },
|
|
584
584
|
{ src: path.join(NUXT_SHELL, 'plugins/formatters'), ssr: false }, // Populate formatters cache for sorted table
|
|
585
|
+
{ src: path.join(NUXT_SHELL, 'plugins/version'), ssr: false }, // Makes a fetch to the backend to get version metadata
|
|
585
586
|
],
|
|
586
587
|
|
|
587
588
|
// Proxy: https://github.com/nuxt-community/proxy-module#options
|
|
@@ -595,8 +596,8 @@ export default function(dir, _appConfig) {
|
|
|
595
596
|
'/v3-public': proxyOpts(api), // Rancher Unauthed API
|
|
596
597
|
'/api-ui': proxyOpts(api), // Browser API UI
|
|
597
598
|
'/meta': proxyMetaOpts(api), // Browser API UI
|
|
598
|
-
'/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
|
|
599
599
|
'/v1-*': proxyOpts(api), // SAML, KDM, etc
|
|
600
|
+
'/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
|
|
600
601
|
// These are for Ember embedding
|
|
601
602
|
'/c/*/edit': proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
|
|
602
603
|
'/k/': proxyOpts('https://127.0.0.1:8000'),
|
package/package.json
CHANGED
package/pages/auth/login.vue
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
setBrand,
|
|
27
27
|
setVendor
|
|
28
28
|
} from '@shell/config/private-label';
|
|
29
|
+
import loadPlugins from '@shell/plugins/plugin';
|
|
29
30
|
|
|
30
31
|
export default {
|
|
31
32
|
name: 'Login',
|
|
@@ -255,6 +256,15 @@ export default {
|
|
|
255
256
|
this.$cookies.remove(USERNAME);
|
|
256
257
|
}
|
|
257
258
|
|
|
259
|
+
// User logged with local login - we don't do any redirect/reload, so the boot-time plugin will not run again to laod the plugins
|
|
260
|
+
// so we manually load them here - other SSO auth providers bounce out and back to the Dashboard, so on the bounce-back
|
|
261
|
+
// the plugins will load via the boot-time plugin
|
|
262
|
+
await loadPlugins({
|
|
263
|
+
app: this.$store.app,
|
|
264
|
+
store: this.$store,
|
|
265
|
+
$plugin: this.$store.$plugin
|
|
266
|
+
});
|
|
267
|
+
|
|
258
268
|
if (this.firstLogin || user[0]?.mustChangePassword) {
|
|
259
269
|
this.$store.dispatch('auth/setInitialPass', this.password);
|
|
260
270
|
this.$router.push({ name: 'auth-setup' });
|
package/pages/auth/verify.vue
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { GITHUB_CODE, GITHUB_NONCE, BACK_TO } from '@shell/config/query-params';
|
|
3
3
|
import { get } from '@shell/utils/object';
|
|
4
4
|
import { base64Decode } from '@shell/utils/crypto';
|
|
5
|
+
import loadPlugins from '@shell/plugins/plugin';
|
|
6
|
+
|
|
5
7
|
const samlProviders = ['ping', 'adfs', 'keycloak', 'okta', 'shibboleth'];
|
|
6
8
|
|
|
7
9
|
function reply(err, code) {
|
|
@@ -60,6 +62,13 @@ export default {
|
|
|
60
62
|
if ( res._status === 200) {
|
|
61
63
|
const backTo = route.query[BACK_TO] || '/';
|
|
62
64
|
|
|
65
|
+
// Load plugins
|
|
66
|
+
await loadPlugins({
|
|
67
|
+
app: store.app,
|
|
68
|
+
store,
|
|
69
|
+
$plugin: store.$plugin
|
|
70
|
+
});
|
|
71
|
+
|
|
63
72
|
redirect(backTo);
|
|
64
73
|
} else {
|
|
65
74
|
redirect(`/auth/login?err=${ escape(res) }`);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Vue from 'vue';
|
|
3
|
+
|
|
4
|
+
import { _VIEW } from '@shell/config/query-params';
|
|
5
|
+
import { Checkbox } from '@components/Form/Checkbox';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: 'DefaultLinksEditor',
|
|
9
|
+
|
|
10
|
+
components: { Checkbox },
|
|
11
|
+
|
|
12
|
+
props: {
|
|
13
|
+
// Array of objects with key, label, value and enabled properties
|
|
14
|
+
value: {
|
|
15
|
+
type: Array,
|
|
16
|
+
default: () => [],
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
mode: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: true
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
computed: {
|
|
26
|
+
isView() {
|
|
27
|
+
return this.mode === _VIEW;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
methods: {
|
|
32
|
+
showhide(row, i, e) {
|
|
33
|
+
const value = this.value[i];
|
|
34
|
+
|
|
35
|
+
Vue.set(value, 'enabled', !!value.enabled);
|
|
36
|
+
this.$emit('input', this.value);
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<div class="key-value">
|
|
44
|
+
<div class="clearfix">
|
|
45
|
+
<h3>
|
|
46
|
+
{{ t('customLinks.settings.default') }}
|
|
47
|
+
</h3>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="kv-container">
|
|
51
|
+
<label class="text-label">
|
|
52
|
+
{{ t('customLinks.settings.keyLabel') }}
|
|
53
|
+
</label>
|
|
54
|
+
<label class="text-label">
|
|
55
|
+
{{ t('customLinks.settings.valueLabel') }}
|
|
56
|
+
</label>
|
|
57
|
+
<label class="text-label">
|
|
58
|
+
</label>
|
|
59
|
+
|
|
60
|
+
<template v-for="(row,i) in value">
|
|
61
|
+
<div :key="i+'key'" class="kv-item key" :class="{'link-hidden': !row.enabled}">
|
|
62
|
+
<span>{{ row.label }}</span>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div :key="i+'value'" class="kv-item value" :class="{'link-hidden': !row.enabled}">
|
|
66
|
+
<span>{{ row.value }}</span>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div v-if="!row.readonly && !isView" :key="i+'show'">
|
|
70
|
+
<Checkbox v-if="!isView" v-model="row.enabled" label-key="customLinks.settings.showLabel" @input="showhide(row, i, $event)" />
|
|
71
|
+
</div>
|
|
72
|
+
<div v-else :key="i+'show'"></div>
|
|
73
|
+
</template>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<style lang="scss" scoped>
|
|
79
|
+
.key-value {
|
|
80
|
+
width: 100%;
|
|
81
|
+
|
|
82
|
+
.kv-container {
|
|
83
|
+
display: grid;
|
|
84
|
+
align-items: center;
|
|
85
|
+
grid-template-columns: 1fr 1fr 50px;
|
|
86
|
+
column-gap: $column-gutter;
|
|
87
|
+
|
|
88
|
+
.kv-item {
|
|
89
|
+
background-color: var(--disabled-bg);
|
|
90
|
+
border: 1px solid var(--border);
|
|
91
|
+
border-radius: 5px;
|
|
92
|
+
width: 100%;
|
|
93
|
+
margin: 10px 0px 10px 0px;
|
|
94
|
+
height: 40px;
|
|
95
|
+
line-height: 40px;
|
|
96
|
+
padding: 0 10px;
|
|
97
|
+
|
|
98
|
+
&.link-hidden {
|
|
99
|
+
color: var(--disabled-text);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&.key {
|
|
103
|
+
align-self: flex-start;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</style>
|