@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
package/pages/support/index.vue
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { options } from '@shell/config/footer';
|
|
3
2
|
import BannerGraphic from '@shell/components/BannerGraphic';
|
|
4
|
-
import AsyncButton from '@shell/components/AsyncButton';
|
|
5
3
|
import IndentedPanel from '@shell/components/IndentedPanel';
|
|
6
|
-
import { Card } from '@components/Card';
|
|
7
4
|
import CommunityLinks from '@shell/components/CommunityLinks';
|
|
8
5
|
import { CATALOG, MANAGEMENT } from '@shell/config/types';
|
|
9
|
-
import { getVendor
|
|
6
|
+
import { getVendor } from '@shell/config/private-label';
|
|
10
7
|
import { SETTING } from '@shell/config/settings';
|
|
11
8
|
import { findBy } from '@shell/utils/array';
|
|
12
9
|
import { addParam } from '@shell/utils/url';
|
|
13
|
-
|
|
14
|
-
const KEY_REGEX = /^[0-9a-fA-F]{16}$/;
|
|
10
|
+
import { isRancherPrime } from '@shell/config/version';
|
|
15
11
|
|
|
16
12
|
export default {
|
|
17
13
|
layout: 'home',
|
|
@@ -19,8 +15,6 @@ export default {
|
|
|
19
15
|
components: {
|
|
20
16
|
BannerGraphic,
|
|
21
17
|
IndentedPanel,
|
|
22
|
-
AsyncButton,
|
|
23
|
-
Card,
|
|
24
18
|
CommunityLinks
|
|
25
19
|
},
|
|
26
20
|
|
|
@@ -50,7 +44,6 @@ export default {
|
|
|
50
44
|
if ( this.$store.getters['management/canList'](CATALOG.APP) ) {
|
|
51
45
|
this.apps = await this.$store.dispatch('management/findAll', { type: CATALOG.APP });
|
|
52
46
|
}
|
|
53
|
-
this.supportSetting = await fetchOrCreateSetting('has-support', 'false');
|
|
54
47
|
this.brandSetting = await fetchOrCreateSetting(SETTING.BRAND, '');
|
|
55
48
|
this.serverUrlSetting = await fetchOrCreateSetting(SETTING.SERVER_URL, '');
|
|
56
49
|
this.uiIssuesSetting = await this.$store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.ISSUES });
|
|
@@ -61,7 +54,6 @@ export default {
|
|
|
61
54
|
apps: [],
|
|
62
55
|
vendor: getVendor(),
|
|
63
56
|
supportKey: '',
|
|
64
|
-
supportSetting: null,
|
|
65
57
|
brandSetting: null,
|
|
66
58
|
uiIssuesSetting: null,
|
|
67
59
|
serverSetting: null,
|
|
@@ -79,6 +71,10 @@ export default {
|
|
|
79
71
|
return findBy(this.apps, 'metadata.name', 'rancher-csp-adapter' );
|
|
80
72
|
},
|
|
81
73
|
|
|
74
|
+
hasSupport() {
|
|
75
|
+
return this.hasAWSSupport || isRancherPrime();
|
|
76
|
+
},
|
|
77
|
+
|
|
82
78
|
hasAWSSupport() {
|
|
83
79
|
return !!this.cspAdapter;
|
|
84
80
|
},
|
|
@@ -101,74 +97,15 @@ export default {
|
|
|
101
97
|
return `${ this.serverUrl }/v1/generateSUSERancherSupportConfig`;
|
|
102
98
|
},
|
|
103
99
|
|
|
104
|
-
hasSupport() {
|
|
105
|
-
// NB: This is temporary until API implemented
|
|
106
|
-
return false;
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
options() {
|
|
110
|
-
if (!this.uiIssuesSetting?.value) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Load defaults for suppoet page
|
|
115
|
-
return options(true, this.uiIssuesSetting?.value);
|
|
116
|
-
},
|
|
117
|
-
|
|
118
100
|
title() {
|
|
119
101
|
return this.hasSupport ? 'support.suse.title' : 'support.community.title';
|
|
120
102
|
},
|
|
121
103
|
|
|
122
|
-
validSupportKey() {
|
|
123
|
-
return !!this.supportKey.match(KEY_REGEX);
|
|
124
|
-
},
|
|
125
|
-
|
|
126
104
|
sccLink() {
|
|
127
105
|
return this.hasAWSSupport ? addParam('https://scc.suse.com', 'from_marketplace', '1') : 'https://scc.suse.com';
|
|
128
106
|
}
|
|
129
107
|
},
|
|
130
108
|
|
|
131
|
-
methods: {
|
|
132
|
-
async addSubscription(done) {
|
|
133
|
-
try {
|
|
134
|
-
this.supportSetting.value = 'true';
|
|
135
|
-
this.brandSetting.value = 'suse';
|
|
136
|
-
await Promise.all([this.supportSetting.save(), this.brandSetting.save()]);
|
|
137
|
-
setBrand('suse');
|
|
138
|
-
done(true);
|
|
139
|
-
this.$modal.hide('toggle-support');
|
|
140
|
-
} catch {
|
|
141
|
-
done(false);
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
async removeSubscription(done) {
|
|
146
|
-
try {
|
|
147
|
-
this.supportSetting.value = 'false';
|
|
148
|
-
this.brandSetting.value = '';
|
|
149
|
-
await Promise.all([this.supportSetting.save(), this.brandSetting.save()]);
|
|
150
|
-
setBrand('');
|
|
151
|
-
done(true);
|
|
152
|
-
this.$modal.hide('toggle-support');
|
|
153
|
-
} catch {
|
|
154
|
-
done(false);
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
showDialog(isAdd) {
|
|
159
|
-
this.isRemoveDialog = isAdd;
|
|
160
|
-
this.supportKey = '';
|
|
161
|
-
this.$modal.show('toggle-support');
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
dialogOpened() {
|
|
165
|
-
const input = this.$refs.subscriptionIDInput;
|
|
166
|
-
|
|
167
|
-
if (input) {
|
|
168
|
-
input.focus();
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
}
|
|
172
109
|
};
|
|
173
110
|
</script>
|
|
174
111
|
<template>
|
|
@@ -177,10 +114,18 @@ export default {
|
|
|
177
114
|
|
|
178
115
|
<IndentedPanel>
|
|
179
116
|
<div class="content mt-20">
|
|
180
|
-
<div class="promo">
|
|
117
|
+
<div class="promo col main-panel">
|
|
181
118
|
<div class="box mb-20 box-primary">
|
|
182
119
|
<h2>{{ t('support.suse.access.title') }}</h2>
|
|
183
|
-
<div>
|
|
120
|
+
<div v-if="!hasSupport" class="external support-links mt-20">
|
|
121
|
+
<div class="support-link">
|
|
122
|
+
<a class="support-link" href="https://rancher.com/support-maintenance-terms" target="_blank" rel="noopener noreferrer nofollow">{{ t('support.community.learnMore') }}</a>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="support-link">
|
|
125
|
+
<a class="support-link" href="https://rancher.com/pricing" target="_blank" rel="noopener noreferrer nofollow">{{ t('support.community.pricing') }}</a>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div v-else>
|
|
184
129
|
<p class="pb-10">
|
|
185
130
|
{{ hasAWSSupport ? t("support.suse.access.aws.text") : t("support.suse.access.text") }}
|
|
186
131
|
</p>
|
|
@@ -198,74 +143,28 @@ export default {
|
|
|
198
143
|
<div>{{ t(`${key}.text`) }}</div>
|
|
199
144
|
</div>
|
|
200
145
|
</div>
|
|
201
|
-
|
|
202
|
-
<div v-if="!hasSupport" class="register row">
|
|
203
|
-
<div>
|
|
204
|
-
{{ t('support.subscription.haveSupport') }}
|
|
205
|
-
</div>
|
|
206
|
-
<button class="ml-5 btn role-secondary btn-sm" type="button" @click="showDialog(false)">
|
|
207
|
-
{{ t('support.subscription.addSubscription') }}
|
|
208
|
-
</button>
|
|
209
|
-
</div>
|
|
210
|
-
<div v-if="hasSupport && !hasAWSSupport" class="register row">
|
|
211
|
-
<a class="remove-link" @click="showDialog(true)">
|
|
212
|
-
{{ t('support.subscription.removeSubscription') }}
|
|
213
|
-
</a>
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
<div class="community">
|
|
217
|
-
<CommunityLinks :link-options="options">
|
|
218
|
-
<div v-if="!hasSupport" class="external support-links" :class="{ 'mt-15': !!options}">
|
|
219
|
-
<div class="support-link">
|
|
220
|
-
<a class="support-link" href="https://rancher.com/support-maintenance-terms" target="_blank" rel="noopener noreferrer nofollow">{{ t('support.community.learnMore') }}</a>
|
|
221
|
-
</div>
|
|
222
|
-
<div class="support-link">
|
|
223
|
-
<a class="support-link" href="https://rancher.com/pricing" target="_blank" rel="noopener noreferrer nofollow">{{ t('support.community.pricing') }}</a>
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
</CommunityLinks>
|
|
227
146
|
</div>
|
|
147
|
+
<CommunityLinks :is-support-page="true" class="community col side-panel span-3" />
|
|
228
148
|
</div>
|
|
229
149
|
</IndentedPanel>
|
|
230
|
-
<modal
|
|
231
|
-
name="toggle-support"
|
|
232
|
-
height="auto"
|
|
233
|
-
:width="340"
|
|
234
|
-
@opened="dialogOpened"
|
|
235
|
-
>
|
|
236
|
-
<Card :show-highlight-border="false" class="toggle-support">
|
|
237
|
-
<template #title>
|
|
238
|
-
{{ isRemoveDialog? t('support.subscription.removeTitle') : t('support.subscription.addTitle') }}
|
|
239
|
-
</template>
|
|
240
|
-
<template #body>
|
|
241
|
-
<div v-if="isRemoveDialog" class="mt-20">
|
|
242
|
-
{{ t('support.subscription.removeBody') }}
|
|
243
|
-
</div>
|
|
244
|
-
<div v-else class="mt-20">
|
|
245
|
-
<p class="pb-10">
|
|
246
|
-
{{ t('support.subscription.addLabel') }}
|
|
247
|
-
</p>
|
|
248
|
-
<input ref="subscriptionIDInput" v-model="supportKey" />
|
|
249
|
-
</div>
|
|
250
|
-
</template>
|
|
251
|
-
<template #actions>
|
|
252
|
-
<button type="button" class="btn role-secondary" @click="$modal.hide('toggle-support')">
|
|
253
|
-
{{ t('generic.cancel') }}
|
|
254
|
-
</button>
|
|
255
|
-
<AsyncButton v-if="!isRemoveDialog" :disabled="!validSupportKey" class="pull-right" @click="addSubscription" />
|
|
256
|
-
<AsyncButton v-else :action-label="t('generic.remove')" class="pull-right" @click="removeSubscription" />
|
|
257
|
-
</template>
|
|
258
|
-
</Card>
|
|
259
|
-
</modal>
|
|
260
150
|
</div>
|
|
261
151
|
</template>
|
|
262
152
|
<style lang="scss" scoped>
|
|
263
153
|
.content {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
154
|
+
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: stretch;
|
|
157
|
+
.col {
|
|
158
|
+
margin: 0
|
|
159
|
+
}
|
|
160
|
+
.main-panel {
|
|
161
|
+
flex: auto;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.side-panel {
|
|
165
|
+
margin-left: 1.75%;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
269
168
|
|
|
270
169
|
.toggle-support {
|
|
271
170
|
height: 100%;
|
|
@@ -280,16 +179,6 @@ export default {
|
|
|
280
179
|
}
|
|
281
180
|
}
|
|
282
181
|
|
|
283
|
-
.community {
|
|
284
|
-
border-left: 1px solid var(--border);
|
|
285
|
-
padding-left: 20px;
|
|
286
|
-
> h2 {
|
|
287
|
-
font-size: 18px;
|
|
288
|
-
font-weight: 300;
|
|
289
|
-
margin-bottom: 20px;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
182
|
.support-link:not(:first-child) {
|
|
294
183
|
margin: 15px 0 0 0;
|
|
295
184
|
}
|
|
@@ -5,6 +5,7 @@ import { SPOOFED_API_PREFIX, SPOOFED_PREFIX } from '@shell/store/type-map';
|
|
|
5
5
|
import { createYaml } from '@shell/utils/create-yaml';
|
|
6
6
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
7
7
|
import { normalizeType } from './normalize';
|
|
8
|
+
import garbageCollect from '@shell/utils/gc/gc';
|
|
8
9
|
|
|
9
10
|
export const _ALL = 'all';
|
|
10
11
|
export const _MERGE = 'merge';
|
|
@@ -316,6 +317,8 @@ export default {
|
|
|
316
317
|
dispatch('resource-fetch/updateManualRefreshIsLoading', false, { root: true });
|
|
317
318
|
}
|
|
318
319
|
|
|
320
|
+
garbageCollect.gcUpdateLastAccessed(ctx, type);
|
|
321
|
+
|
|
319
322
|
return all;
|
|
320
323
|
},
|
|
321
324
|
|
|
@@ -371,6 +374,8 @@ export default {
|
|
|
371
374
|
});
|
|
372
375
|
}
|
|
373
376
|
|
|
377
|
+
garbageCollect.gcUpdateLastAccessed(ctx, type);
|
|
378
|
+
|
|
374
379
|
return getters.matching( type, selector, namespace );
|
|
375
380
|
},
|
|
376
381
|
|
|
@@ -426,6 +431,8 @@ export default {
|
|
|
426
431
|
|
|
427
432
|
out = getters.byId(type, id);
|
|
428
433
|
|
|
434
|
+
garbageCollect.gcUpdateLastAccessed(ctx, type);
|
|
435
|
+
|
|
429
436
|
return out;
|
|
430
437
|
},
|
|
431
438
|
|
|
@@ -490,6 +497,10 @@ export default {
|
|
|
490
497
|
return classify(ctx, data);
|
|
491
498
|
},
|
|
492
499
|
|
|
500
|
+
createMany(ctx, data) {
|
|
501
|
+
return data.map(d => classify(ctx, d));
|
|
502
|
+
},
|
|
503
|
+
|
|
493
504
|
createPopulated(ctx, userData) {
|
|
494
505
|
const data = ctx.getters['defaultFor'](userData.type);
|
|
495
506
|
|
|
@@ -587,5 +598,13 @@ export default {
|
|
|
587
598
|
|
|
588
599
|
incrementLoadCounter({ commit }, resource) {
|
|
589
600
|
commit('incrementLoadCounter', resource);
|
|
601
|
+
},
|
|
602
|
+
|
|
603
|
+
garbageCollect(ctx, ignoreTypes) {
|
|
604
|
+
return garbageCollect.garbageCollect(ctx, ignoreTypes);
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
gcResetStore({ state }) {
|
|
608
|
+
garbageCollect.gcResetStore(state);
|
|
590
609
|
}
|
|
591
610
|
};
|
|
@@ -9,10 +9,11 @@ import Resource from '@shell/plugins/dashboard-store/resource-class';
|
|
|
9
9
|
import mutations from './mutations';
|
|
10
10
|
import { keyFieldFor, normalizeType } from './normalize';
|
|
11
11
|
import { lookup } from './model-loader';
|
|
12
|
+
import garbageCollect from '@shell/utils/gc/gc';
|
|
12
13
|
|
|
13
14
|
export default {
|
|
14
15
|
|
|
15
|
-
all: (state, getters) => (type) => {
|
|
16
|
+
all: (state, getters, rootState) => (type) => {
|
|
16
17
|
type = getters.normalizeType(type);
|
|
17
18
|
|
|
18
19
|
if ( !getters.typeRegistered(type) ) {
|
|
@@ -22,10 +23,14 @@ export default {
|
|
|
22
23
|
mutations.registerType(state, type);
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
garbageCollect.gcUpdateLastAccessed({
|
|
27
|
+
state, getters, rootState
|
|
28
|
+
}, type);
|
|
29
|
+
|
|
25
30
|
return state.types[type].list;
|
|
26
31
|
},
|
|
27
32
|
|
|
28
|
-
matching: (state, getters) => (type, selector, namespace) => {
|
|
33
|
+
matching: (state, getters, rootState) => (type, selector, namespace) => {
|
|
29
34
|
let all = getters['all'](type);
|
|
30
35
|
|
|
31
36
|
// Filter first by namespace if one is provided, since this is efficient
|
|
@@ -33,16 +38,24 @@ export default {
|
|
|
33
38
|
all = all.filter(obj => obj.namespace === namespace);
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
garbageCollect.gcUpdateLastAccessed({
|
|
42
|
+
state, getters, rootState
|
|
43
|
+
}, type);
|
|
44
|
+
|
|
36
45
|
return all.filter((obj) => {
|
|
37
46
|
return matches(obj, selector);
|
|
38
47
|
});
|
|
39
48
|
},
|
|
40
49
|
|
|
41
|
-
byId: (state, getters) => (type, id) => {
|
|
50
|
+
byId: (state, getters, rootState) => (type, id) => {
|
|
42
51
|
type = getters.normalizeType(type);
|
|
43
52
|
const entry = state.types[type];
|
|
44
53
|
|
|
45
54
|
if ( entry ) {
|
|
55
|
+
garbageCollect.gcUpdateLastAccessed({
|
|
56
|
+
state, getters, rootState
|
|
57
|
+
}, type);
|
|
58
|
+
|
|
46
59
|
return entry.map.get(id);
|
|
47
60
|
}
|
|
48
61
|
},
|
|
@@ -300,5 +313,9 @@ export default {
|
|
|
300
313
|
}
|
|
301
314
|
|
|
302
315
|
return 0;
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
gcIgnoreTypes: () => {
|
|
319
|
+
return {};
|
|
303
320
|
}
|
|
304
321
|
};
|
|
@@ -3,18 +3,19 @@ import { addObject, addObjects, clear, removeObject } from '@shell/utils/array';
|
|
|
3
3
|
import { SCHEMA } from '@shell/config/types';
|
|
4
4
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
5
5
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
6
|
+
import garbageCollect from '@shell/utils/gc/gc';
|
|
6
7
|
|
|
7
8
|
function registerType(state, type) {
|
|
8
9
|
let cache = state.types[type];
|
|
9
10
|
|
|
10
11
|
if ( !cache ) {
|
|
11
12
|
cache = {
|
|
12
|
-
list:
|
|
13
|
-
haveAll:
|
|
14
|
-
haveSelector:
|
|
15
|
-
revision:
|
|
16
|
-
generation:
|
|
17
|
-
loadCounter:
|
|
13
|
+
list: [],
|
|
14
|
+
haveAll: false,
|
|
15
|
+
haveSelector: {},
|
|
16
|
+
revision: 0, // The highest known resourceVersion from the server for this type
|
|
17
|
+
generation: 0, // Updated every time something is loaded for this type
|
|
18
|
+
loadCounter: 0, // Used to cancel incremental loads if the page changes during load
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
// Not enumerable so they don't get sent back to the client for SSR
|
|
@@ -120,6 +121,8 @@ export function forgetType(state, type) {
|
|
|
120
121
|
cache.map.clear();
|
|
121
122
|
delete state.types[type];
|
|
122
123
|
|
|
124
|
+
garbageCollect.gcResetType(state, type);
|
|
125
|
+
|
|
123
126
|
return true;
|
|
124
127
|
}
|
|
125
128
|
}
|
|
@@ -131,6 +134,8 @@ export function resetStore(state, commit) {
|
|
|
131
134
|
for ( const type of Object.keys(state.types) ) {
|
|
132
135
|
commit(`${ state.config.namespace }/forgetType`, type);
|
|
133
136
|
}
|
|
137
|
+
|
|
138
|
+
garbageCollect.gcResetStore(state);
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
export function remove(state, obj, getters) {
|
|
@@ -308,5 +313,6 @@ export default {
|
|
|
308
313
|
if (typeData) {
|
|
309
314
|
typeData.loadCounter++;
|
|
310
315
|
}
|
|
311
|
-
}
|
|
316
|
+
},
|
|
317
|
+
|
|
312
318
|
};
|
package/plugins/plugin.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// This plugin loads any UI Plugins at app load time
|
|
2
2
|
import { allHashSettled } from '@shell/utils/promise';
|
|
3
|
-
import {
|
|
3
|
+
import { shouldNotLoadPlugin, UI_PLUGIN_BASE_URL } from '@shell/config/uiplugins';
|
|
4
4
|
|
|
5
5
|
const META_NAME_PREFIX = 'app-autoload-';
|
|
6
6
|
|
|
7
|
-
export default async(context)
|
|
7
|
+
export default async function(context) {
|
|
8
8
|
// UI Plugins declared in the HTML head
|
|
9
9
|
const meta = context.app?.head?.meta || [];
|
|
10
10
|
const hash = {};
|
|
@@ -28,27 +28,28 @@ export default async(context) => {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (loadPlugins) {
|
|
31
|
-
|
|
31
|
+
// TODO: Get rancher version using the new API (can't use setting as we have not loading the store)
|
|
32
|
+
const rancherVersion = undefined;
|
|
32
33
|
|
|
33
34
|
// Fetch list of installed plugins from endpoint
|
|
34
35
|
try {
|
|
35
|
-
const res = await store.dispatch('management/request', {
|
|
36
|
-
url:
|
|
37
|
-
|
|
36
|
+
const res = await context.store.dispatch('management/request', {
|
|
37
|
+
url: `${ UI_PLUGIN_BASE_URL }/index.json`,
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: { accept: 'application/json' },
|
|
40
|
+
redirectUnauthorized: false,
|
|
38
41
|
});
|
|
39
42
|
|
|
40
43
|
if (res) {
|
|
41
44
|
const entries = res.entries || res.Entries || {};
|
|
42
45
|
|
|
43
46
|
Object.values(entries).forEach((plugin) => {
|
|
44
|
-
|
|
45
|
-
let url;
|
|
47
|
+
const shouldNotLoad = shouldNotLoadPlugin(plugin, rancherVersion); // Error key string or false
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
hash[plugin.name] = $plugin.loadAsyncByNameAndVersion(plugin.name, plugin.version, url);
|
|
49
|
+
if (!shouldNotLoad) {
|
|
50
|
+
hash[plugin.name] = context.$plugin.loadPluginAsync(plugin);
|
|
51
|
+
} else {
|
|
52
|
+
context.store.dispatch('uiplugins/setError', { name: plugin.name, error: shouldNotLoad });
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
}
|
|
@@ -67,8 +68,10 @@ export default async(context) => {
|
|
|
67
68
|
console.error(`Failed to load plugin: ${ name }`); // eslint-disable-line no-console
|
|
68
69
|
|
|
69
70
|
// Record error in the uiplugins store, so that we can show this to the user
|
|
70
|
-
context.store.dispatch('uiplugins/setError', { name, error:
|
|
71
|
+
context.store.dispatch('uiplugins/setError', { name, error: 'plugins.error.load' });
|
|
71
72
|
}
|
|
72
73
|
});
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
|
|
76
|
+
return true;
|
|
77
|
+
}
|
package/plugins/steve/getters.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isArray } from '@shell/utils/array';
|
|
2
2
|
import { BY_TYPE } from '@shell/plugins/dashboard-store/classify';
|
|
3
3
|
import { lookup } from '@shell/plugins/dashboard-store/model-loader';
|
|
4
|
+
import { NAMESPACE, SCHEMA, COUNT, UI } from '@shell/config/types';
|
|
4
5
|
|
|
5
6
|
import SteveModel from './steve-class';
|
|
6
7
|
import HybridModel, { cleanHybridResources } from './hybrid-class';
|
|
@@ -12,6 +13,13 @@ export const STEVE_MODEL_TYPES = {
|
|
|
12
13
|
BY_TYPE: 'byType'
|
|
13
14
|
};
|
|
14
15
|
|
|
16
|
+
const GC_IGNORE_TYPES = {
|
|
17
|
+
[COUNT]: true,
|
|
18
|
+
[NAMESPACE]: true,
|
|
19
|
+
[SCHEMA]: true,
|
|
20
|
+
[UI.NAV_LINK]: true,
|
|
21
|
+
};
|
|
22
|
+
|
|
15
23
|
export default {
|
|
16
24
|
urlOptions: () => (url, opt) => {
|
|
17
25
|
opt = opt || {};
|
|
@@ -110,4 +118,8 @@ export default {
|
|
|
110
118
|
return map?.list || [];
|
|
111
119
|
},
|
|
112
120
|
|
|
121
|
+
gcIgnoreTypes: () => {
|
|
122
|
+
return GC_IGNORE_TYPES;
|
|
123
|
+
}
|
|
124
|
+
|
|
113
125
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch version metadata from backend /rancherversion API and store it
|
|
3
|
+
*
|
|
4
|
+
* This metadata does not change for an installation of Rancher
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { setVersionData } from '@shell/config/version';
|
|
8
|
+
|
|
9
|
+
export default async function({ store }) {
|
|
10
|
+
try {
|
|
11
|
+
const response = await store.dispatch('rancher/request', {
|
|
12
|
+
url: '/rancherversion',
|
|
13
|
+
method: 'get',
|
|
14
|
+
redirectUnauthorized: false
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
setVersionData(response);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.warn('Failed to fetch Rancher version metadata', e); // eslint-disable-line no-console
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import Vue from 'vue';
|
|
2
|
+
import Vue, { VueConstructor } from 'vue';
|
|
3
3
|
import debounce from 'lodash/debounce';
|
|
4
4
|
import { _EDIT, _VIEW } from '@shell/config/query-params';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
interface Vue {
|
|
9
|
-
queueResize(): void;
|
|
10
|
-
}
|
|
6
|
+
interface TextAreaResize {
|
|
7
|
+
queueResize(): void;
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
export default
|
|
10
|
+
export default (
|
|
11
|
+
Vue as VueConstructor<Vue & TextAreaResize>
|
|
12
|
+
).extend({
|
|
14
13
|
inheritAttrs: false,
|
|
15
14
|
|
|
16
15
|
props: {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { BadgeState } from './index';
|
|
3
|
+
|
|
4
|
+
describe('BadgeState.vue', () => {
|
|
5
|
+
it('renders props.msg when passed', () => {
|
|
6
|
+
const label = 'Hello, World!';
|
|
7
|
+
|
|
8
|
+
const wrapper = shallowMount(BadgeState, { propsData: { label } });
|
|
9
|
+
|
|
10
|
+
expect(wrapper.find('span').text()).toMatch(label);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Vue, { PropType } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface Badge {
|
|
5
|
+
stateBackground: string;
|
|
6
|
+
stateDisplay: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Badge state component.
|
|
11
|
+
* <p>Represents a badge whose label and color is either taken from the value property or
|
|
12
|
+
* from the label and color properties. The state property takes precedence.</p>
|
|
13
|
+
*/
|
|
14
|
+
export default Vue.extend({
|
|
15
|
+
props: {
|
|
16
|
+
/**
|
|
17
|
+
* A value having the properties `stateBackground` and `stateDisplay`
|
|
18
|
+
*/
|
|
19
|
+
value: {
|
|
20
|
+
type: Object as PropType<Badge>,
|
|
21
|
+
default: null
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Badge color. `stateBackground` of the value property takes precedence if supplied
|
|
26
|
+
*/
|
|
27
|
+
color: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: null
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Optional icon to be shown before the label
|
|
34
|
+
*/
|
|
35
|
+
icon: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: null
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Label to display in the badge. `stateDisplay` of the value property takes precedence if supplied
|
|
42
|
+
*/
|
|
43
|
+
label: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: null
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
computed: {
|
|
50
|
+
bg(): string | null {
|
|
51
|
+
return this.value?.stateBackground || this.color;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
msg(): string | null {
|
|
55
|
+
return this.value?.stateDisplay || this.label;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<template>
|
|
62
|
+
<span :class="{'badge-state': true, [bg]: true}">
|
|
63
|
+
<i v-if="icon" class="icon" :class="{[icon]: true, 'mr-5': !!msg}" />{{ msg }}
|
|
64
|
+
</span>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
67
|
+
<style lang="scss" scoped>
|
|
68
|
+
.badge-state {
|
|
69
|
+
align-items: center;
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
padding: 2px 10px;
|
|
72
|
+
border: 1px solid transparent;
|
|
73
|
+
border-radius: 20px;
|
|
74
|
+
|
|
75
|
+
&.bg-info {
|
|
76
|
+
border-color: var(--primary);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.bg-error {
|
|
80
|
+
border-color: var(--error);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&.bg-warning {
|
|
84
|
+
border-color: var(--warning);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Successful states are de-emphasized by using [text-]color instead of background-color
|
|
88
|
+
&.bg-success {
|
|
89
|
+
color: var(--success);
|
|
90
|
+
background: transparent;
|
|
91
|
+
border-color: var(--success);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
95
|
+
<style lang="scss">
|
|
96
|
+
// TODO: #6005
|
|
97
|
+
// Investigate why this is here.. I don't think that styles for sortable table should belong here
|
|
98
|
+
.sortable-table TD .badge-state {
|
|
99
|
+
@include clip;
|
|
100
|
+
display: inline-block;
|
|
101
|
+
max-width: 100%;
|
|
102
|
+
position: relative;
|
|
103
|
+
max-width: 110px;
|
|
104
|
+
font-size: .85em;
|
|
105
|
+
vertical-align: middle;
|
|
106
|
+
}
|
|
107
|
+
</style>
|