dashboard-shell-shell 1.0.1000000117 → 1.0.1000000118
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/base/_functions.scss +0 -0
- package/assets/styles/base/_mixins.scss +1 -1
- package/assets/styles/global/_button.scss +10 -17
- package/assets/styles/global/_form.scss +2 -2
- package/assets/styles/global/_labeled-input.scss +2 -6
- package/assets/styles/global/_select.scss +7 -6
- package/assets/styles/global/_table.scss +2 -3
- package/assets/styles/global/_tooltip.scss +1 -8
- package/assets/styles/themes/_dark.scss +0 -2
- package/assets/styles/themes/_light.scss +2 -5
- package/assets/styles/vendor/vue-select.scss +1 -2
- package/assets/translations/en-us.yaml +3 -1
- package/assets/translations/zh-hans.yaml +28 -51
- package/components/ActionDropdown.vue +0 -1
- package/components/ActionMenuShell.vue +3 -6
- package/components/BrandImage.vue +0 -22
- package/components/ClusterIconMenu.vue +1 -1
- package/components/CodeMirror.vue +0 -1
- package/components/CruResource.vue +1 -1
- package/components/CruResourceFooter.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +24 -4
- package/components/GlobalRoleBindings.vue +48 -112
- package/components/IndentedPanel.vue +10 -4
- package/components/PromptRemove.vue +3 -3
- package/components/ResourceDetail/Masthead.vue +242 -190
- package/components/ResourceDetail/index.vue +5 -20
- package/components/ResourceList/Masthead.vue +84 -146
- package/components/ResourceList/ResourceLoadingIndicator.vue +2 -5
- package/components/ResourceTable.vue +1 -76
- package/components/SideNav.vue +29 -66
- package/components/SortableTable/THead.vue +0 -6
- package/components/SortableTable/index.vue +388 -481
- package/components/Tabbed/index.vue +5 -4
- package/components/auth/Principal.vue +2 -3
- package/components/auth/RoleDetailEdit.vue +5 -58
- package/components/auth/SelectPrincipal.vue +0 -1
- package/components/form/BannerSettings.vue +16 -18
- package/components/form/ChangePassword.vue +4 -4
- package/components/form/ColorInput.vue +8 -32
- package/components/form/Footer.vue +1 -1
- package/components/form/InputWithSelect.vue +0 -2
- package/components/form/KeyValue.vue +7 -31
- package/components/form/LabeledSelect.vue +178 -178
- package/components/form/Members/ClusterPermissionsEditor.vue +2 -1
- package/components/form/Members/MembershipEditor.vue +1 -1
- package/components/form/NameNsDescription.vue +11 -24
- package/components/form/Password.vue +2 -6
- package/components/form/ResourceQuota/Namespace.vue +1 -1
- package/components/form/ResourceQuota/NamespaceRow.vue +10 -13
- package/components/form/ResourceQuota/ProjectRow.vue +1 -0
- package/components/form/Select.vue +2 -2
- package/components/nav/Favorite.vue +1 -5
- package/components/nav/Group.vue +23 -69
- package/components/nav/Header.vue +17 -82
- package/components/nav/HeaderPageActionMenu.vue +0 -1
- package/components/nav/NamespaceFilter.vue +3 -0
- package/components/nav/TopLevelMenu.vue +119 -182
- package/components/nav/Type.vue +11 -48
- package/components/rancherResourceDetail/Masthead.vue +769 -0
- package/components/rancherResourceDetail/__tests__/Masthead.test.ts +65 -0
- package/components/rancherResourceDetail/index.vue +591 -0
- package/components/rancherResourceList/Masthead.vue +375 -0
- package/components/rancherResourceList/ResourceLoadingIndicator.vue +140 -0
- package/components/rancherResourceList/index.vue +307 -0
- package/components/rancherResourceList/resource-list.config.js +7 -0
- package/components/rancherResourceTable.vue +783 -0
- package/components/rancherSortableTable/THead.vue +561 -0
- package/components/rancherSortableTable/actions.js +153 -0
- package/components/rancherSortableTable/advanced-filtering.js +272 -0
- package/components/rancherSortableTable/debug.js +117 -0
- package/components/rancherSortableTable/filtering.js +290 -0
- package/components/rancherSortableTable/grouping.js +48 -0
- package/components/rancherSortableTable/index.vue +2712 -0
- package/components/rancherSortableTable/paging.js +155 -0
- package/components/rancherSortableTable/selection.js +629 -0
- package/components/rancherSortableTable/sortable-config.ts +4 -0
- package/components/rancherSortableTable/sorting.js +129 -0
- package/composables/useClickOutside.ts +1 -1
- package/config/product/auth.js +7 -16
- package/config/product/explorer.js +1 -1
- package/config/product/settings.js +8 -17
- package/config/settings.ts +0 -28
- package/edit/management.cattle.io.user.vue +4 -17
- package/edit/networking.k8s.io.ingress/RulePath.vue +1 -1
- package/edit/token.vue +1 -1
- package/list/harvesterhci.io.management.cluster.vue +0 -17
- package/list/management.cattle.io.setting.vue +13 -22
- package/list/management.cattle.io.user.vue +14 -25
- package/list/provisioning.cattle.io.cluster.vue +7 -6
- package/mixins/brand.js +0 -17
- package/package.json +1 -1
- package/pages/auth/login.vue +29 -84
- package/pages/c/_cluster/auth/roles/index.vue +14 -61
- package/pages/c/_cluster/settings/banners.vue +101 -174
- package/pages/c/_cluster/settings/brand.vue +301 -348
- package/pages/c/_cluster/settings/performance.vue +38 -61
- package/pages/home.vue +21 -70
- package/pages/prefs.vue +23 -25
- package/pkg/tsconfig.json +9 -9
- package/pkg/vue.config.js +1 -1
- package/promptRemove/mixin/roleDeletionCheck.js +2 -2
- package/scripts/clean +0 -0
- package/scripts/extension/bundle +0 -0
- package/scripts/extension/helm/scripts/package +0 -0
- package/scripts/extension/helm/scripts/patch +0 -0
- package/scripts/extension/helm/scripts/version +0 -0
- package/scripts/extension/helmpatch +0 -0
- package/scripts/extension/parse-tag-name +0 -0
- package/scripts/extension/publish +0 -0
- package/scripts/publish-shell.sh +60 -86
- package/scripts/serve-pkgs +0 -0
- package/scripts/sync-shell-deps +0 -0
- package/scripts/typegen.sh +28 -44
- package/store/i18n.js +5 -5
- package/store/prefs.js +5 -17
- package/store/type-map.js +1 -2
- package/types/cloud-shell/index.d.ts +11014 -0
- package/types/shell/index.d.ts +1 -1
- package/utils/error.js +0 -4
- package/utils/router.js +3 -3
- package/vue.config.js +6 -1
- package/assets/images/action.svg +0 -6
- package/assets/images/pl/logo.png +0 -0
- /package/components/{ResourceList → rancherResourceList}/Masthead-btn.vue +0 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { mapGetters } from 'vuex';
|
|
3
|
+
import Favorite from '@shell/components/nav/Favorite';
|
|
4
|
+
import TypeDescription from '@shell/components/TypeDescription';
|
|
5
|
+
import { get } from '@shell/utils/object';
|
|
6
|
+
import { AS, _YAML } from '@shell/config/query-params';
|
|
7
|
+
import ResourceLoadingIndicator from './ResourceLoadingIndicator';
|
|
8
|
+
import TabTitle from '@shell/components/TabTitle';
|
|
9
|
+
import { harvesterhci2cloud, cloud2harvesterhci } from '@shell/utils/router'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resource List Masthead component.
|
|
13
|
+
*/
|
|
14
|
+
export default {
|
|
15
|
+
|
|
16
|
+
name: 'MastheadResourceList',
|
|
17
|
+
|
|
18
|
+
components: {
|
|
19
|
+
Favorite,
|
|
20
|
+
TypeDescription,
|
|
21
|
+
ResourceLoadingIndicator,
|
|
22
|
+
TabTitle
|
|
23
|
+
},
|
|
24
|
+
props: {
|
|
25
|
+
resource: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
favoriteResource: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: null
|
|
32
|
+
},
|
|
33
|
+
schema: {
|
|
34
|
+
type: Object,
|
|
35
|
+
default: null,
|
|
36
|
+
},
|
|
37
|
+
typeDisplay: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: null,
|
|
40
|
+
},
|
|
41
|
+
isCreatable: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: null,
|
|
44
|
+
},
|
|
45
|
+
isYamlCreatable: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: null,
|
|
48
|
+
},
|
|
49
|
+
createLocation: {
|
|
50
|
+
type: Object,
|
|
51
|
+
default: null,
|
|
52
|
+
},
|
|
53
|
+
yamlCreateLocation: {
|
|
54
|
+
type: Object,
|
|
55
|
+
default: null,
|
|
56
|
+
},
|
|
57
|
+
createButtonLabel: {
|
|
58
|
+
type: String,
|
|
59
|
+
default: null
|
|
60
|
+
},
|
|
61
|
+
loadResources: {
|
|
62
|
+
type: Array,
|
|
63
|
+
default: () => []
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
loadIndeterminate: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: false
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
showIncrementalLoadingIndicator: {
|
|
72
|
+
type: Boolean,
|
|
73
|
+
default: false
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Inherited global identifier prefix for tests
|
|
78
|
+
* Define a term based on the parent component to avoid conflicts on multiple components
|
|
79
|
+
*/
|
|
80
|
+
componentTestid: {
|
|
81
|
+
type: String,
|
|
82
|
+
default: 'masthead'
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
mainButtonVisible: {
|
|
86
|
+
type: Boolean,
|
|
87
|
+
default: true
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
data() {
|
|
92
|
+
const params = { ...this.$route.params };
|
|
93
|
+
|
|
94
|
+
params.resource = params.resource
|
|
95
|
+
|
|
96
|
+
const formRoute = { name: `${ this.$route.name }-create`, params };
|
|
97
|
+
|
|
98
|
+
const hasEditComponent = this.$store.getters['type-map/hasCustomEdit'](this.resource);
|
|
99
|
+
|
|
100
|
+
const yamlRoute = {
|
|
101
|
+
name: `${ this.$route.name }-create`,
|
|
102
|
+
params,
|
|
103
|
+
query: { [AS]: _YAML },
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const tabList = ['集群配置'];
|
|
107
|
+
|
|
108
|
+
const description = ''
|
|
109
|
+
return {
|
|
110
|
+
formRoute,
|
|
111
|
+
yamlRoute,
|
|
112
|
+
hasEditComponent,
|
|
113
|
+
tabList,
|
|
114
|
+
description
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
computed: {
|
|
119
|
+
get,
|
|
120
|
+
...mapGetters(['isExplorer', 'currentCluster']),
|
|
121
|
+
|
|
122
|
+
resourceName() {
|
|
123
|
+
if (this.schema) {
|
|
124
|
+
return this.$store.getters['type-map/labelFor'](this.schema);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return this.resource;
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
_typeDisplay() {
|
|
131
|
+
if ( this.typeDisplay !== null) {
|
|
132
|
+
return this.typeDisplay;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if ( !this.schema ) {
|
|
136
|
+
return '?';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this.$store.getters['type-map/labelFor'](this.schema, 99);
|
|
140
|
+
},
|
|
141
|
+
_descriptionDisplay() {
|
|
142
|
+
const key = this.$route.path.split('/'.pop());
|
|
143
|
+
|
|
144
|
+
return this.$store.getters['i18n/t'](`typeDescription."${ key.toLowerCase() }"`);
|
|
145
|
+
},
|
|
146
|
+
demoDisplay() {
|
|
147
|
+
// const product = this.$store.getters['productId'];
|
|
148
|
+
// const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], this._createLocation.params.resource);
|
|
149
|
+
|
|
150
|
+
// const parts = productId?.split('::') || [];
|
|
151
|
+
// const newString = 'root';
|
|
152
|
+
|
|
153
|
+
// if (!parts.includes(newString)) {
|
|
154
|
+
// parts.unshift(newString); // 将字符串添加到数组第一位
|
|
155
|
+
// }
|
|
156
|
+
|
|
157
|
+
// const partsEn = parts.map((item) => {
|
|
158
|
+
// return this.$store.getters['i18n/t'](`typeLabel."${ item.toLowerCase() }"`);
|
|
159
|
+
// });
|
|
160
|
+
|
|
161
|
+
// return partsEn;
|
|
162
|
+
|
|
163
|
+
const breadcrumbList = {
|
|
164
|
+
'harvesterhci.io.management.cluster': {
|
|
165
|
+
origin: 'Harvester 集群',
|
|
166
|
+
bread: ['虚拟化管理'],
|
|
167
|
+
description: '还没有添加描述。。。。'
|
|
168
|
+
},
|
|
169
|
+
'management.cattle.io.user': {
|
|
170
|
+
origin: '用户',
|
|
171
|
+
bread: ['用户 & 认证'],
|
|
172
|
+
description: '还没有添加描述。。。。'
|
|
173
|
+
},
|
|
174
|
+
'management.cattle.io.setting':{
|
|
175
|
+
origin: '基础设置',
|
|
176
|
+
bread: ['全局设置'],
|
|
177
|
+
description: '还没有添加描述。。。。'
|
|
178
|
+
},
|
|
179
|
+
'management.cattle.io.feature':{
|
|
180
|
+
origin: '功能开关',
|
|
181
|
+
bread: ['全局设置'],
|
|
182
|
+
description: '还没有添加描述。。。。'
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
const resourcePath = this.$route.params.resource || ''
|
|
186
|
+
|
|
187
|
+
const breadcrumb = []
|
|
188
|
+
if (breadcrumbList[resourcePath] && Object.keys(breadcrumbList[resourcePath]).length > 0) {
|
|
189
|
+
breadcrumb.push(...breadcrumbList[resourcePath].bread)
|
|
190
|
+
this.description = breadcrumbList[resourcePath].description
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return breadcrumb
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
_isYamlCreatable() {
|
|
197
|
+
if ( this.isYamlCreatable !== null) {
|
|
198
|
+
return this.isYamlCreatable;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return this.schema && this._isCreatable && this.$store.getters['type-map/optionsFor'](this.resource).canYaml;
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
_isCreatable() {
|
|
205
|
+
// Does not take into account hasEditComponent, such that _isYamlCreatable works
|
|
206
|
+
if ( this.isCreatable !== null) {
|
|
207
|
+
return this.isCreatable;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// blocked-post means you can post through norman, but not through steve.
|
|
211
|
+
if ( this.schema && !this.schema?.collectionMethods.find((x) => ['blocked-post', 'post'].includes(x.toLowerCase())) ) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return this.$store.getters['type-map/optionsFor'](this.resource).isCreatable;
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
_createLocation() {
|
|
219
|
+
return this.createLocation || this.formRoute;
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
_yamlCreateLocation() {
|
|
223
|
+
return this.yamlCreateLocation || this.yamlRoute;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
_createButtonlabel() {
|
|
227
|
+
return this.createButtonLabel || this.t('resourceList.head.create');
|
|
228
|
+
},
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
</script>
|
|
232
|
+
|
|
233
|
+
<template>
|
|
234
|
+
<!-- 顶部 header,带有子标题(subheader)样式类 -->
|
|
235
|
+
<header class="with-subheader">
|
|
236
|
+
<div style="display: flex;width: 100%;">
|
|
237
|
+
<div style="flex: 1;">
|
|
238
|
+
<!-- 标题区域 -->
|
|
239
|
+
<div class="title">
|
|
240
|
+
<div class="excram-list">
|
|
241
|
+
<span
|
|
242
|
+
v-for="(item,index) in demoDisplay"
|
|
243
|
+
:key="index"
|
|
244
|
+
>
|
|
245
|
+
<span v-if="item">{{ item }}</span>
|
|
246
|
+
<span v-if="item">/</span>
|
|
247
|
+
</span>
|
|
248
|
+
<span class="excram-last-name">{{ _typeDisplay }}</span>
|
|
249
|
+
</div>
|
|
250
|
+
<h1 style="display: flex;align-items: center;" class="m-0 descrip-name">
|
|
251
|
+
<TabTitle>{{ _typeDisplay }}</TabTitle>
|
|
252
|
+
<!-- 子标题区域 -->
|
|
253
|
+
<div class="sub-header">
|
|
254
|
+
<slot name="subHeader">
|
|
255
|
+
<!--Slot content-->
|
|
256
|
+
</slot>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<!-- <Favorite
|
|
260
|
+
v-if="isExplorer"
|
|
261
|
+
:resource="favoriteResource || resource"
|
|
262
|
+
/> -->
|
|
263
|
+
|
|
264
|
+
<ResourceLoadingIndicator
|
|
265
|
+
style="margin-left: 10px;"
|
|
266
|
+
v-if="showIncrementalLoadingIndicator"
|
|
267
|
+
:resources="loadResources"
|
|
268
|
+
:indeterminate="loadIndeterminate"
|
|
269
|
+
/>
|
|
270
|
+
</h1>
|
|
271
|
+
|
|
272
|
+
<!-- 插槽:typeDescription,用于插入类型描述组件 -->
|
|
273
|
+
<div v-if="description" class="masthod-title-description">
|
|
274
|
+
{{ description }}
|
|
275
|
+
</div>
|
|
276
|
+
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<!-- 操作按钮区域 -->
|
|
283
|
+
<div
|
|
284
|
+
v-if="!(tabList.includes(_typeDisplay)) && mainButtonVisible"
|
|
285
|
+
class="actions-container"
|
|
286
|
+
style="min-height: 32px;align-self: flex-end;"
|
|
287
|
+
>
|
|
288
|
+
<slot name="actions">
|
|
289
|
+
<div class="actions">
|
|
290
|
+
<slot name="extraActions" />
|
|
291
|
+
|
|
292
|
+
<slot name="createButton">
|
|
293
|
+
<router-link
|
|
294
|
+
v-if="hasEditComponent && _isCreatable"
|
|
295
|
+
:to="_createLocation"
|
|
296
|
+
class="btn role-primary"
|
|
297
|
+
:data-testid="componentTestid+'-create'"
|
|
298
|
+
>
|
|
299
|
+
{{ _createButtonlabel }}
|
|
300
|
+
</router-link>
|
|
301
|
+
<router-link
|
|
302
|
+
v-else-if="_isYamlCreatable"
|
|
303
|
+
:to="_yamlCreateLocation"
|
|
304
|
+
class="btn role-primary"
|
|
305
|
+
:data-testid="componentTestid+'-create-yaml'"
|
|
306
|
+
>
|
|
307
|
+
{{ t("resourceList.head.createFromYaml") }}
|
|
308
|
+
</router-link>
|
|
309
|
+
</slot>
|
|
310
|
+
</div>
|
|
311
|
+
</slot>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
<div
|
|
315
|
+
v-if="!(tabList.includes(_typeDisplay))"
|
|
316
|
+
style="width: 110%;height: 1px;background-color: #D7D7D7;margin-top: 16px;margin-left: -20px;margin-right: -20px;"
|
|
317
|
+
/>
|
|
318
|
+
</header>
|
|
319
|
+
</template>
|
|
320
|
+
|
|
321
|
+
<style lang="scss" scoped>
|
|
322
|
+
|
|
323
|
+
.title {
|
|
324
|
+
/* align-items: center;
|
|
325
|
+
display: flex; */
|
|
326
|
+
h1 {
|
|
327
|
+
margin: 0;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
header {
|
|
332
|
+
/* margin-bottom: 20px; */
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
header.with-subheader {
|
|
336
|
+
/* grid-template-areas:
|
|
337
|
+
'type-banner type-banner'
|
|
338
|
+
'title actions'
|
|
339
|
+
'sub-header sub-header'
|
|
340
|
+
'state-banner state-banner'; */
|
|
341
|
+
position: relative;
|
|
342
|
+
display: flex;
|
|
343
|
+
margin-bottom: 16px;
|
|
344
|
+
flex-direction: column;
|
|
345
|
+
}
|
|
346
|
+
.excram-list{
|
|
347
|
+
font-size: 14px;
|
|
348
|
+
line-height: 22px;
|
|
349
|
+
margin-bottom: 20px;
|
|
350
|
+
font-family: 'Microsoft YaHei';
|
|
351
|
+
}
|
|
352
|
+
.excram-last-name{
|
|
353
|
+
color: var(--primary);
|
|
354
|
+
}
|
|
355
|
+
.descrip-name{
|
|
356
|
+
font-size: 26px;
|
|
357
|
+
font-family: 'Microsoft YaHei';
|
|
358
|
+
}
|
|
359
|
+
.masthod-title-description{
|
|
360
|
+
font-family: 'Microsoft YaHei';
|
|
361
|
+
margin-top: 20px;
|
|
362
|
+
}
|
|
363
|
+
.actions-container{
|
|
364
|
+
/* display: flex; */
|
|
365
|
+
/* margin-left: 0px; */
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.sub-header {
|
|
369
|
+
font-size: 16px;
|
|
370
|
+
margin-left: 5px;
|
|
371
|
+
.btn {
|
|
372
|
+
text-align: left !important;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
</style>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { COUNT } from '@shell/config/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Loading Indicator for resources - used when we are loading resources incrementally, by page
|
|
6
|
+
*/
|
|
7
|
+
export default {
|
|
8
|
+
|
|
9
|
+
name: 'ResourceLoadingIndicator',
|
|
10
|
+
|
|
11
|
+
props: {
|
|
12
|
+
resources: {
|
|
13
|
+
type: Array,
|
|
14
|
+
required: true,
|
|
15
|
+
},
|
|
16
|
+
indeterminate: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: false,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
data() {
|
|
23
|
+
const inStore = this.$store.getters['currentStore'](this.resource);
|
|
24
|
+
|
|
25
|
+
return { inStore };
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
computed: {
|
|
29
|
+
// Count of rows - either from the data provided or from the rows for the first resource
|
|
30
|
+
rowsCount() {
|
|
31
|
+
if (this.resources.length > 0) {
|
|
32
|
+
const existingData = this.$store.getters[`${ this.inStore }/all`](this.resources[0]) || [];
|
|
33
|
+
|
|
34
|
+
return (existingData || []).length;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return 0;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// Have we loaded all resources for the types that are needed
|
|
41
|
+
haveAll() {
|
|
42
|
+
return this.resources.reduce((acc, r) => {
|
|
43
|
+
return acc && this.$store.getters[`${ this.inStore }/haveAll`](r);
|
|
44
|
+
}, true);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Total of all counts of all resources for all of the resources being loaded
|
|
48
|
+
total() {
|
|
49
|
+
const clusterCounts = this.$store.getters[`${ this.inStore }/all`](COUNT);
|
|
50
|
+
|
|
51
|
+
return this.resources.reduce((acc, r) => {
|
|
52
|
+
const resourceCounts = clusterCounts?.[0]?.counts?.[r];
|
|
53
|
+
const resourceCount = resourceCounts?.summary?.count;
|
|
54
|
+
const count = resourceCount || 0;
|
|
55
|
+
|
|
56
|
+
return acc + count;
|
|
57
|
+
}, 0);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// Total count of all of the resources for all of the resources being loaded
|
|
61
|
+
count() {
|
|
62
|
+
return this.resources.reduce((acc, r) => {
|
|
63
|
+
return acc + (this.$store.getters[`${ this.inStore }/all`](r) || []).length;
|
|
64
|
+
}, 0);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// Width style to enable the progress bar style presentation
|
|
68
|
+
width() {
|
|
69
|
+
const progress = Math.ceil(100 * (this.count / this.total));
|
|
70
|
+
|
|
71
|
+
return `${ progress }%`;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<template>
|
|
78
|
+
<div
|
|
79
|
+
v-if="count && !haveAll"
|
|
80
|
+
class="resource-loading-indicator"
|
|
81
|
+
>
|
|
82
|
+
<div class="inner">
|
|
83
|
+
<div class="resource-loader">
|
|
84
|
+
<div class="rl-bg">
|
|
85
|
+
<i class="icon icon-spinner icon-spin" /><span>{{ t( 'resourceLoadingIndicator.loading' ) }} <span v-if="!indeterminate">{{ count }} / {{ total }}</span></span>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
<div
|
|
89
|
+
class="resource-loader"
|
|
90
|
+
:style="{width}"
|
|
91
|
+
>
|
|
92
|
+
<div class="rl-fg">
|
|
93
|
+
<i class="icon icon-spinner icon-spin" /><span>{{ t( 'resourceLoadingIndicator.loading' ) }} <span v-if="!indeterminate">{{ count }} / {{ total }}</span></span>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<style lang="scss" scoped>
|
|
101
|
+
.resource-loading-indicator {
|
|
102
|
+
border: 1px solid var(--link);
|
|
103
|
+
border-radius: 10px;
|
|
104
|
+
position: relative;
|
|
105
|
+
width: min-content;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
|
|
108
|
+
.resource-loader:last-child {
|
|
109
|
+
position: absolute;
|
|
110
|
+
top: 0;
|
|
111
|
+
|
|
112
|
+
background-color: var(--link);
|
|
113
|
+
color: var(--link-text);
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
white-space: nowrap;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.resource-loader {
|
|
119
|
+
padding: 1px 10px;
|
|
120
|
+
width: max-content;
|
|
121
|
+
height: 20px;
|
|
122
|
+
|
|
123
|
+
.rl-fg, .rl-bg {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-content: center;
|
|
126
|
+
font-size: 12px;
|
|
127
|
+
|
|
128
|
+
> i {
|
|
129
|
+
font-size: 18px;
|
|
130
|
+
line-height: 18px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
> span {
|
|
134
|
+
margin-top: 2px;
|
|
135
|
+
margin-left: 5px;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
</style>
|