dashboard-shell-shell 3.0.5-test.3 → 3.0.5-test.5

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.
Files changed (30) hide show
  1. package/assets/styles/global/_button.scss +7 -7
  2. package/assets/styles/global/_tooltip.scss +4 -4
  3. package/assets/styles/themes/_light.scss +3 -1
  4. package/assets/translations/zh-hans.yaml +76 -0
  5. package/components/ActionDropdown.vue +1 -1
  6. package/components/CopyToClipboard.vue +15 -0
  7. package/components/Drawer/Chrome.vue +2 -2
  8. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +23 -23
  9. package/components/Drawer/ResourceDetailDrawer/index.vue +2 -2
  10. package/components/ExplorerMembers.vue +18 -3
  11. package/components/PodSecurityAdmission.vue +1 -1
  12. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +1 -3
  13. package/components/Resource/Detail/Metadata/KeyValue.vue +8 -4
  14. package/components/Resource/Detail/Metadata/index.vue +2 -1
  15. package/components/Resource/Detail/TitleBar/Title.vue +4 -3
  16. package/components/Resource/Detail/TitleBar/index.vue +103 -24
  17. package/components/ResourceDetail/Masthead/legacy.vue +235 -164
  18. package/components/ResourceDetail/legacy.vue +29 -13
  19. package/components/SortableTable/index.vue +1 -1
  20. package/components/Tabbed/index.vue +1 -1
  21. package/components/auth/Principal.vue +35 -11
  22. package/components/breadcrumb/index.vue +340 -0
  23. package/components/form/LabeledSelect.vue +3 -2
  24. package/components/form/Taints.vue +2 -1
  25. package/components/form/WorkloadPorts.vue +143 -123
  26. package/edit/workload/index.vue +3 -3
  27. package/package.json +1 -1
  28. package/rancher-components/BadgeState/BadgeState.vue +33 -52
  29. package/rancher-components/RcDropdown/RcDropdownMenu.vue +8 -7
  30. package/store/i18n.js +3 -0
@@ -0,0 +1,340 @@
1
+ <script>
2
+ import { KUBERNETES, PROJECT } from '@shell/config/labels-annotations';
3
+ import { FLEET, NAMESPACE, MANAGEMENT, HELM } from '@shell/config/types';
4
+ import ButtonGroup from '@shell/components/ButtonGroup';
5
+ // import { BadgeState } from '@components/BadgeState';
6
+ import DotState from '@shell/components/DotState.vue';
7
+ import { Banner } from '@components/Banner';
8
+ import { get } from '@shell/utils/object';
9
+ import { NAME as FLEET_NAME } from '@shell/config/product/fleet';
10
+ import { HIDE_SENSITIVE } from '@shell/store/prefs';
11
+ import {
12
+ AS, _DETAIL, _CONFIG, _YAML, MODE, _CREATE, _EDIT, _VIEW, _UNFLAG, _GRAPH
13
+ } from '@shell/config/query-params';
14
+ import { ExtensionPoint, PanelLocation } from '@shell/core/types';
15
+ import ExtensionPanel from '@shell/components/ExtensionPanel';
16
+ import TabTitle from '@shell/components/TabTitle';
17
+ import ActionMenu from '@shell/components/ActionMenuShell.vue';
18
+ import { useRuntimeFlag } from '@shell/composables/useRuntimeFlag';
19
+ import { useStore } from 'vuex';
20
+
21
+ // i18n-uses resourceDetail.header.*
22
+
23
+ /**
24
+ * Resource Detail Masthead component.
25
+ *
26
+ * ToDo: this component seem to be picking up a lot of logic from special cases, could be simplified down to parameters and then customized per use-case via wrapper component
27
+ */
28
+ export default {
29
+
30
+ name: 'MastheadResourceDetail',
31
+
32
+ components: {
33
+ // BadgeState,
34
+ DotState,
35
+ Banner,
36
+ ButtonGroup,
37
+ ExtensionPanel,
38
+ TabTitle,
39
+ ActionMenu,
40
+ },
41
+ props: {
42
+ value: {
43
+ type: Object,
44
+ default: () => {
45
+ return {};
46
+ }
47
+ },
48
+
49
+ mode: {
50
+ type: String,
51
+ default: 'view'
52
+ },
53
+
54
+ realMode: {
55
+ type: String,
56
+ default: 'view'
57
+ },
58
+
59
+ as: {
60
+ type: String,
61
+ default: _YAML,
62
+ },
63
+
64
+ storeOverride: {
65
+ type: String,
66
+ default: null,
67
+ },
68
+
69
+ resource: {
70
+ type: String,
71
+ default: null,
72
+ },
73
+
74
+ resourceSubtype: {
75
+ type: String,
76
+ default: null,
77
+ },
78
+
79
+ parentRouteOverride: {
80
+ type: String,
81
+ default: null,
82
+ },
83
+
84
+ },
85
+
86
+ setup() {
87
+ const store = useStore();
88
+ const { featureDropdownMenu } = useRuntimeFlag(store);
89
+
90
+ return { featureDropdownMenu };
91
+ },
92
+
93
+ data() {
94
+ return {
95
+ DETAIL_VIEW: _DETAIL,
96
+ extensionType: ExtensionPoint.PANEL,
97
+ extensionLocation: PanelLocation.DETAILS_MASTHEAD,
98
+ Svg: require('~shell/assets/images/API.svg')
99
+ };
100
+ },
101
+
102
+ computed: {
103
+ dev() {
104
+ return this.$store.getters['prefs/dev'];
105
+ },
106
+
107
+ schema() {
108
+ const inStore = this.storeOverride || this.$store.getters['currentStore'](this.resource);
109
+
110
+ return this.$store.getters[`${ inStore }/schemaFor`]( this.resource );
111
+ },
112
+
113
+ isProjectHelmChart() {
114
+ return this.schema?.id === HELM.PROJECTHELMCHART;
115
+ },
116
+
117
+ shouldHifenize() {
118
+ return (this.mode === 'view' || this.mode === 'edit') && this.resourceSubtype?.length && this.value?.nameDisplay?.length;
119
+ },
120
+
121
+ parent() {
122
+ const displayName = this.value?.parentNameOverride || this.$store.getters['type-map/labelFor'](this.schema);
123
+ const product = this.$store.getters['currentProduct'].name;
124
+
125
+ const defaultLocation = {
126
+ name: 'c-cluster-product-resource',
127
+ params: {
128
+ resource: this.resource,
129
+ product,
130
+ }
131
+ };
132
+
133
+ const location = this.value?.parentLocationOverride || defaultLocation;
134
+
135
+ if (this.parentRouteOverride) {
136
+ location.name = this.parentRouteOverride;
137
+ }
138
+
139
+ const typeOptions = this.$store.getters[`type-map/optionsFor`]( this.resource );
140
+
141
+ // 转换为中文
142
+ const displayName_zh_hans = {
143
+ 'GlobalRole': '全局角色',
144
+ 'RoleTemplate': '集群角色',
145
+ }
146
+ if (displayName_zh_hans[displayName]) {
147
+ displayName = displayName_zh_hans[displayName]
148
+ }
149
+
150
+ if (displayName == '集群角色' && (this.$route.query?.roleContext == 'NAMESPACE' || location.hash == '#NAMESPACE')) {
151
+ displayName = '项目或资源组角色'
152
+ }
153
+
154
+ const out = {
155
+ displayName, location, ...typeOptions
156
+ };
157
+
158
+ return out;
159
+ },
160
+
161
+
162
+ displayName() {
163
+ let displayName = this.value.nameDisplay;
164
+
165
+ if (this.isProjectHelmChart) {
166
+ displayName = this.value.projectDisplayName;
167
+ }
168
+
169
+ return this.shouldHifenize ? ` - ${ displayName }` : displayName;
170
+ },
171
+
172
+ demoDisplay() {
173
+ const product = this.$store.getters['productId'];
174
+
175
+ const resources = this.location?.params?.resource || ''
176
+
177
+ const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], resources);
178
+
179
+ if (productId === undefined) {
180
+ return '';
181
+ }
182
+ const parts = productId.split('::');
183
+ const newString = 'root';
184
+
185
+ if (!parts?.includes(newString)) {
186
+ parts.unshift(newString); // 将字符串添加到数组第一位
187
+ }
188
+
189
+ const partsEn = parts.map((item) => {
190
+ return this.$store.getters['i18n/t'](`typeLabel."${ item.toLowerCase() }"`);
191
+ });
192
+
193
+ return partsEn;
194
+ },
195
+ menuIcon() {
196
+ const product = this.$store.getters['productId'];
197
+
198
+ const resources = this.location?.params?.resource || ''
199
+
200
+ return this.$store.getters['type-map/groupsForVirTypes'](product, resources);
201
+ },
202
+
203
+ location() {
204
+ const { parent } = this;
205
+
206
+ return parent?.location;
207
+ },
208
+
209
+ },
210
+
211
+ methods: {
212
+ get,
213
+ }
214
+ };
215
+ </script>
216
+
217
+ <template>
218
+ <div class="masthead">
219
+ <div class="title">
220
+ <!-- 创建api密钥不需要面包屑 -->
221
+ <div
222
+ v-if="!(parentRouteOverride === 'account' && resource=== 'token')"
223
+ class="excram-list"
224
+ >
225
+ <span
226
+ v-for="(item,index) in demoDisplay"
227
+ :key="index"
228
+ >
229
+ <span>{{ item }}</span>
230
+ <span>/</span>
231
+ </span>
232
+ <span class="excram-last-name">
233
+ {{ (realMode === 'view'? '查看': realMode === 'edit' ? '编辑':'创建') + parent.displayName }}
234
+ </span>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </template>
239
+
240
+ <style lang='scss' scoped>
241
+
242
+ HEADER {
243
+ margin: 0;
244
+ }
245
+
246
+ .primaryheader {
247
+ display: flex;
248
+ flex-direction: row;
249
+ align-items: center;
250
+ font-size:14px;
251
+ height: 50px;
252
+
253
+ h1 {
254
+ margin: 0;
255
+ }
256
+ }
257
+
258
+ .subheader{
259
+ display: flex;
260
+ flex-direction: row;
261
+ color: var(--input-label);
262
+ & > * {
263
+ margin: 5px 20px 5px 0px;
264
+ }
265
+
266
+ .live-data {
267
+ color: var(--body-text)
268
+ }
269
+ }
270
+
271
+ .state-banner {
272
+ margin: 3px 0 0 0;
273
+ }
274
+
275
+ .masthead-state {
276
+ font-size: initial;
277
+ display: inline-block;
278
+ position: relative;
279
+ /* top: -2px; */
280
+ font-size: 12px;
281
+ margin-left: 5px;
282
+ }
283
+
284
+ .masthead-istio {
285
+ .icon {
286
+ vertical-align: middle;
287
+ color: var(--primary);
288
+ }
289
+ }
290
+
291
+ .left-right-split {
292
+ display: grid;
293
+ align-items: center;
294
+
295
+ .left-half {
296
+ grid-column: 1;
297
+ }
298
+
299
+ .right-half {
300
+ grid-column: 2;
301
+ }
302
+ }
303
+
304
+ .resource-external {
305
+ font-size: 18px;
306
+ }
307
+ .excram-list{
308
+ font-size: 14px;
309
+ margin-bottom: 20px;
310
+ }
311
+ .excram-last-name{
312
+ color: var(--link);
313
+ }
314
+ .valid{
315
+ color: #d7d7d7;
316
+ margin: 0px 10px;
317
+ }
318
+ .detailIcon-span{
319
+ width: 24px;
320
+ height: 24px;
321
+ display: inline-block;
322
+ position: relative;
323
+ background: var(--primary);
324
+ margin-right: 10px;
325
+ }
326
+ .detailIcon{
327
+ position: absolute;
328
+ color: #fff;
329
+ font-size: 38px;
330
+ left: 4px;
331
+ top: -2px;
332
+ }
333
+ .primary-title{
334
+ display: flex;
335
+ align-items: center;
336
+ }
337
+ .detailIcon-span-title{
338
+ font-weight: bold;
339
+ }
340
+ </style>
@@ -326,6 +326,7 @@ export default {
326
326
  <template>
327
327
  <div style="display: flex;">
328
328
  <div
329
+ v-if="hasLabel"
329
330
  :class="{ 'labeled-container': true, raised, empty, [mode]: true, 'is-lable': isLabel }"
330
331
  :style="{ border: 'none', width: selectWidth===''?'160px':selectWidth,lineHeight: '32px' }"
331
332
  >
@@ -348,7 +349,7 @@ export default {
348
349
  ref="select"
349
350
  class="labeled-select"
350
351
  :class="[
351
- $attrs.class,
352
+ $attrs.class && $attrs.class.replace('mb-20', ''),
352
353
  {
353
354
  disabled: isView || disabled,
354
355
  focused,
@@ -529,7 +530,7 @@ export default {
529
530
  // Prevent namespace field from wiggling or changing
530
531
  // height when it is toggled from a LabeledInput to a
531
532
  // LabeledSelect.
532
- padding-bottom: 1px;
533
+ // padding-bottom: 1px;
533
534
  &:deep() .vs__actions:after {
534
535
  padding-top: 10px;
535
536
  }
@@ -112,6 +112,7 @@ export default {
112
112
 
113
113
  <style lang="scss" scoped>
114
114
  .compact-select {
115
- height: 40px;
115
+ height: 32px;
116
+ overflow: hidden;
116
117
  }
117
118
  </style>
@@ -280,145 +280,163 @@ export default {
280
280
  'show-ipam': showIpam,
281
281
  }"
282
282
  >
283
- <div class="service-type">
284
- <LabeledSelect
285
- v-model:value="row._serviceType"
286
- :mode="mode"
287
- :label="t('workload.container.ports.createService')"
288
- :options="serviceTypes"
289
- :disabled="canNotAccessService"
290
- :tooltip="serviceTypeTooltip"
291
- @update:value="queueUpdate"
292
- />
293
- </div>
294
-
295
- <div class="portName">
296
- <LabeledInput
297
- ref="name"
298
- v-model:value="row.name"
299
- :mode="mode"
300
- :label="t('workload.container.ports.name')"
301
- @update:value="queueUpdate"
302
- />
303
- </div>
283
+
284
+ <div class="row mt-20">
285
+ <div
286
+ v-if="!row._showHost && row._serviceType !== 'LoadBalancer' && row._serviceType !== 'NodePort'"
287
+ class="add-host col"
288
+ >
289
+ <button
290
+ :disabled="mode==='view'"
291
+ type="button"
292
+ class="btn btn-sm role-tertiary"
293
+ @click="row._showHost = true"
294
+ >
295
+ {{ t('workloadPorts.addHost') }}
296
+ </button>
297
+ </div>
304
298
 
305
- <div class="port">
306
- <LabeledInput
307
- v-model:value.number="row.containerPort"
308
- :mode="mode"
309
- type="number"
310
- min="1"
311
- max="65535"
312
- placeholder="e.g. 8080"
313
- :label="t('workload.container.ports.containerPort')"
314
- :required="row._serviceType === 'LoadBalancer' "
315
- @update:value="queueUpdate"
316
- />
317
- </div>
299
+ <div
300
+ v-if="showRemove"
301
+ class="remove"
302
+ >
303
+ <button
304
+ type="button"
305
+ class="btn role-link"
306
+ @click="remove(idx)"
307
+ >
308
+ {{ t('workloadPorts.remove') }}
309
+ </button>
310
+ </div>
318
311
 
319
- <div class="protocol col">
320
- <LabeledSelect
321
- v-model:value="row.protocol"
322
- :mode="mode"
323
- :options="workloadPortOptions"
324
- :multiple="false"
325
- :label="t('workload.container.ports.protocol')"
326
- @update:value="queueUpdate"
327
- />
328
312
  </div>
329
313
 
330
- <div
331
- v-if="row._showHost"
332
- class="targetPort"
333
- >
334
- <LabeledInput
335
- ref="port"
336
- v-model:value.number="row.hostPort"
337
- :mode="mode"
338
- type="number"
339
- min="1"
340
- max="65535"
341
- placeholder="e.g. 80"
342
- :label="t('workload.container.ports.hostPort')"
343
- @update:value="queueUpdate"
344
- />
314
+ <div class="row">
315
+ <div class="service-type col span-6">
316
+ <LabeledSelect
317
+ v-model:value="row._serviceType"
318
+ :mode="mode"
319
+ :label="t('workload.container.ports.createService')"
320
+ :options="serviceTypes"
321
+ :disabled="canNotAccessService"
322
+ :tooltip="serviceTypeTooltip"
323
+ @update:value="queueUpdate"
324
+ />
325
+ </div>
326
+
327
+ <div class="portName col span-6">
328
+ <LabeledInput
329
+ ref="name"
330
+ v-model:value="row.name"
331
+ :mode="mode"
332
+ :label="t('workload.container.ports.name')"
333
+ @update:value="queueUpdate"
334
+ />
335
+ </div>
345
336
  </div>
346
337
 
347
- <div
348
- v-if="row._showHost"
349
- class="hostip"
350
- >
351
- <LabeledInput
352
- ref="port"
353
- v-model:value="row.hostIP"
354
- :mode="mode"
355
- placeholder="e.g. 1.1.1.1"
356
- :label="t('workload.container.ports.hostIP')"
357
- @update:value="queueUpdate"
358
- />
338
+ <div class="row">
339
+ <div class="port col span-6">
340
+ <LabeledInput
341
+ v-model:value.number="row.containerPort"
342
+ :mode="mode"
343
+ type="number"
344
+ min="1"
345
+ max="65535"
346
+ placeholder="e.g. 8080"
347
+ :label="t('workload.container.ports.containerPort')"
348
+ :required="row._serviceType === 'LoadBalancer' "
349
+ @update:value="queueUpdate"
350
+ />
351
+ </div>
352
+
353
+ <div class="protocol col span-6">
354
+ <LabeledSelect
355
+ v-model:value="row.protocol"
356
+ :mode="mode"
357
+ :options="workloadPortOptions"
358
+ :multiple="false"
359
+ :label="t('workload.container.ports.protocol')"
360
+ @update:value="queueUpdate"
361
+ />
362
+ </div>
359
363
  </div>
360
364
 
361
- <div
362
- v-if="!row._showHost && row._serviceType !== 'LoadBalancer' && row._serviceType !== 'NodePort'"
363
- class="add-host"
364
- >
365
- <button
366
- :disabled="mode==='view'"
367
- type="button"
368
- class="btn btn-sm role-tertiary"
369
- @click="row._showHost = true"
365
+ <div class="row">
366
+ <div
367
+ v-if="row._showHost"
368
+ class="targetPort col span-6"
370
369
  >
371
- {{ t('workloadPorts.addHost') }}
372
- </button>
373
- </div>
374
-
375
- <div v-if="row._serviceType === 'LoadBalancer' || row._serviceType === 'NodePort'">
376
- <LabeledInput
377
- ref="port"
378
- v-model:value.number="row._listeningPort"
379
- type="number"
380
- :mode="mode"
381
- :label="t('workload.container.ports.listeningPort')"
382
- :required="row._serviceType === 'LoadBalancer' "
383
- @update:value="queueUpdate"
384
- />
385
- </div>
386
-
387
- <div v-if="showIpam && row._serviceType === 'LoadBalancer' && row.protocol === 'TCP'">
388
- <div v-if="idx === ipamIndex">
389
- <LabeledSelect
390
- v-model:value="row._ipam"
370
+ <LabeledInput
371
+ ref="port"
372
+ v-model:value.number="row.hostPort"
391
373
  :mode="mode"
392
- :options="ipamOptions"
393
- :label="t('servicesPage.harvester.ipam.label')"
394
- :disabled="mode === 'edit'"
374
+ type="number"
375
+ min="1"
376
+ max="65535"
377
+ placeholder="e.g. 80"
378
+ :label="t('workload.container.ports.hostPort')"
395
379
  @update:value="queueUpdate"
396
380
  />
397
381
  </div>
398
- <div v-else>
399
- <LabeledSelect
400
- v-model:value="rows[ipamIndex]._ipam"
382
+
383
+ <div
384
+ v-if="row._showHost"
385
+ class="hostip col span-6"
386
+ >
387
+ <LabeledInput
388
+ ref="port"
389
+ v-model:value="row.hostIP"
401
390
  :mode="mode"
402
- :options="ipamOptions"
403
- :label="t('servicesPage.harvester.ipam.label')"
404
- :disabled="true"
391
+ placeholder="e.g. 1.1.1.1"
392
+ :label="t('workload.container.ports.hostIP')"
405
393
  @update:value="queueUpdate"
406
394
  />
407
395
  </div>
408
396
  </div>
409
397
 
410
- <div
411
- v-if="showRemove"
412
- class="remove"
413
- >
414
- <button
415
- type="button"
416
- class="btn role-link"
417
- @click="remove(idx)"
398
+ <div class="row">
399
+ <div
400
+ v-if="row._serviceType === 'LoadBalancer' || row._serviceType === 'NodePort'"
401
+ class="col"
418
402
  >
419
- {{ t('workloadPorts.remove') }}
420
- </button>
403
+ <LabeledInput
404
+ ref="port"
405
+ v-model:value.number="row._listeningPort"
406
+ type="number"
407
+ :mode="mode"
408
+ :label="t('workload.container.ports.listeningPort')"
409
+ :required="row._serviceType === 'LoadBalancer' "
410
+ @update:value="queueUpdate"
411
+ />
412
+ </div>
421
413
  </div>
414
+
415
+ <div class="row">
416
+ <div v-if="showIpam && row._serviceType === 'LoadBalancer' && row.protocol === 'TCP'">
417
+ <div v-if="idx === ipamIndex">
418
+ <LabeledSelect
419
+ v-model:value="row._ipam"
420
+ :mode="mode"
421
+ :options="ipamOptions"
422
+ :label="t('servicesPage.harvester.ipam.label')"
423
+ :disabled="mode === 'edit'"
424
+ @update:value="queueUpdate"
425
+ />
426
+ </div>
427
+ <div v-else>
428
+ <LabeledSelect
429
+ v-model:value="rows[ipamIndex]._ipam"
430
+ :mode="mode"
431
+ :options="ipamOptions"
432
+ :label="t('servicesPage.harvester.ipam.label')"
433
+ :disabled="true"
434
+ @update:value="queueUpdate"
435
+ />
436
+ </div>
437
+ </div>
438
+ </div>
439
+
422
440
  </div>
423
441
  <div
424
442
  v-if="showAdd"
@@ -447,11 +465,11 @@ $checkbox: 75;
447
465
  }
448
466
  }
449
467
  .ports-headers, .ports-row{
450
- display: grid;
451
- grid-template-columns: 28% 28% 15% 10% 75px 0.5fr;
452
- grid-column-gap: $column-gutter;
453
- margin-bottom: 10px;
454
- align-items: center;
468
+ // display: grid;
469
+ // grid-template-columns: 28% 28% 15% 10% 75px 0.5fr;
470
+ // grid-column-gap: $column-gutter;
471
+ // margin-bottom: 20px;
472
+ // align-items: center;
455
473
  & .port{
456
474
  display: flex;
457
475
  justify-content: space-between;
@@ -475,6 +493,7 @@ $checkbox: 75;
475
493
  }
476
494
 
477
495
  .add-host {
496
+ margin-right: 20px;
478
497
  justify-self: center;
479
498
  }
480
499
 
@@ -492,6 +511,7 @@ $checkbox: 75;
492
511
 
493
512
  .remove BUTTON {
494
513
  padding: 0px;
514
+ min-width: auto;
495
515
  }
496
516
 
497
517
  .ports-row INPUT {