@rancher/shell 0.1.3 → 0.1.4

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 (131) hide show
  1. package/assets/brand/suse/dark/rancher-logo.svg +1 -148
  2. package/assets/brand/suse/rancher-logo.svg +1 -130
  3. package/assets/images/featured/img1.jpg +0 -0
  4. package/assets/images/featured.jpg +0 -0
  5. package/assets/images/generic-plugin.svg +7 -0
  6. package/assets/styles/themes/_dark.scss +3 -0
  7. package/assets/styles/themes/_light.scss +3 -0
  8. package/assets/styles/themes/_suse.scss +1 -1
  9. package/assets/translations/en-us.yaml +183 -45
  10. package/assets/translations/zh-hans.yaml +21 -24
  11. package/components/AsyncButton.vue +17 -2
  12. package/components/ButtonDropdown.vue +4 -0
  13. package/components/Carousel.vue +291 -0
  14. package/components/CommunityLinks.vue +69 -18
  15. package/components/CruResource.vue +11 -3
  16. package/components/Dialog.vue +102 -0
  17. package/components/ExplorerMembers.vue +2 -4
  18. package/components/ExplorerProjectsNamespaces.vue +6 -7
  19. package/components/IconMessage.vue +9 -1
  20. package/components/LocaleSelector.vue +62 -29
  21. package/components/ResourceTable.vue +7 -2
  22. package/components/SimpleBox.vue +6 -4
  23. package/components/SortableTable/index.vue +11 -21
  24. package/components/Tabbed/Tab.vue +5 -0
  25. package/components/Tabbed/index.vue +29 -2
  26. package/components/auth/Principal.vue +1 -0
  27. package/components/fleet/FleetBundles.vue +8 -3
  28. package/components/fleet/FleetSummary.vue +6 -0
  29. package/components/form/KeyValue.vue +80 -58
  30. package/components/form/NameNsDescription.vue +10 -4
  31. package/components/form/ResourceTabs/index.vue +5 -1
  32. package/components/formatter/ClusterLink.vue +3 -7
  33. package/components/nav/NamespaceFilter.vue +3 -3
  34. package/components/nav/TopLevelMenu.vue +10 -28
  35. package/config/footer.js +13 -14
  36. package/config/labels-annotations.js +2 -1
  37. package/config/product/explorer.js +5 -4
  38. package/config/product/legacy.js +0 -47
  39. package/config/product/multi-cluster-apps.js +0 -12
  40. package/config/product/settings.js +12 -1
  41. package/config/product/uiplugins.js +17 -0
  42. package/config/settings.js +21 -2
  43. package/config/types.js +5 -1
  44. package/config/uiplugins.js +60 -0
  45. package/content/docs/en-us/getting-started.md +1 -26
  46. package/core/plugins.js +12 -0
  47. package/detail/provisioning.cattle.io.cluster.vue +3 -3
  48. package/detail/workload/index.vue +2 -2
  49. package/dialog/DiagnosticTimingsDialog.vue +116 -0
  50. package/dialog/RotateCertificatesDialog.vue +9 -3
  51. package/edit/auth/azuread.vue +28 -9
  52. package/edit/networking.k8s.io.ingress/index.vue +2 -2
  53. package/edit/persistentvolume/index.vue +3 -0
  54. package/edit/pod.vue +27 -0
  55. package/edit/provisioning.cattle.io.cluster/rke2.vue +76 -5
  56. package/edit/service.vue +7 -5
  57. package/edit/workload/__tests__/Upgrading.test.ts +1 -0
  58. package/edit/workload/index.vue +13 -1
  59. package/edit/workload/mixins/workload.js +13 -13
  60. package/edit/workload/storage/ContainerMountPaths.vue +240 -0
  61. package/edit/workload/storage/Mount.vue +1 -0
  62. package/edit/workload/storage/awsElasticBlockStore.vue +20 -1
  63. package/edit/workload/storage/azureDisk.vue +22 -2
  64. package/edit/workload/storage/azureFile.vue +20 -2
  65. package/edit/workload/storage/csi/index.vue +23 -1
  66. package/edit/workload/storage/gcePersistentDisk.vue +20 -2
  67. package/edit/workload/storage/index.vue +23 -49
  68. package/edit/workload/storage/vsphereVolume.vue +11 -1
  69. package/layouts/default.vue +14 -8
  70. package/layouts/home.vue +9 -4
  71. package/layouts/plain.vue +10 -5
  72. package/list/management.cattle.io.setting.vue +3 -3
  73. package/list/provisioning.cattle.io.cluster.vue +1 -1
  74. package/machine-config/harvester.vue +5 -3
  75. package/models/catalog.cattle.io.uiplugin.js +34 -0
  76. package/models/cluster/node.js +25 -2
  77. package/models/fleet.cattle.io.bundle.js +1 -1
  78. package/models/harvesterhci.io.management.cluster.js +11 -5
  79. package/models/provisioning.cattle.io.cluster.js +12 -6
  80. package/models/workload.js +5 -3
  81. package/nuxt.config.js +69 -25
  82. package/package.json +108 -109
  83. package/pages/auth/login.vue +1 -1
  84. package/pages/c/_cluster/apps/charts/index.vue +46 -1
  85. package/pages/c/_cluster/apps/charts/install.vue +10 -9
  86. package/pages/c/_cluster/explorer/index.vue +72 -9
  87. package/pages/c/_cluster/explorer/tools/index.vue +12 -5
  88. package/pages/c/_cluster/mcapps/index.vue +1 -1
  89. package/pages/c/_cluster/settings/brand.vue +0 -40
  90. package/pages/c/_cluster/settings/links.vue +200 -0
  91. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +232 -0
  92. package/pages/c/_cluster/uiplugins/InstallDialog.vue +242 -0
  93. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +284 -0
  94. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +130 -0
  95. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +253 -0
  96. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +115 -0
  97. package/pages/c/_cluster/uiplugins/index.vue +694 -0
  98. package/pages/diagnostic.vue +185 -101
  99. package/pages/docs/_doc.vue +3 -1
  100. package/pages/home.vue +21 -56
  101. package/pages/prefs.vue +108 -88
  102. package/pages/safeMode.vue +17 -0
  103. package/pages/support/index.vue +23 -15
  104. package/pkg/dynamic-importer.lib.js +4 -0
  105. package/plugins/dashboard-store/resource-class.js +2 -2
  106. package/plugins/formatters.js +15 -0
  107. package/plugins/plugin.js +56 -4
  108. package/plugins/steve/mutations.js +1 -1
  109. package/plugins/steve/subscribe.js +94 -72
  110. package/plugins/steve/web-worker.steve-sub-worker.js +24 -15
  111. package/promptRemove/management.cattle.io.globalrole.vue +47 -0
  112. package/promptRemove/management.cattle.io.roletemplate.vue +47 -0
  113. package/promptRemove/mixin/roleDeletionCheck.js +97 -0
  114. package/scripts/publish-shell.sh +1 -1
  115. package/scripts/sync-shell-deps +37 -0
  116. package/store/catalog.js +9 -8
  117. package/store/i18n.js +10 -1
  118. package/store/prefs.js +16 -0
  119. package/store/type-map.js +32 -5
  120. package/store/uiplugins.ts +15 -61
  121. package/utils/__tests__/object.test.ts +0 -24
  122. package/utils/__tests__/selector.test.ts +1 -1
  123. package/utils/dynamic-importer.js +4 -0
  124. package/utils/grafana.js +2 -6
  125. package/utils/socket.js +41 -20
  126. package/utils/string.js +1 -7
  127. package/utils/validators/formRules/__tests__/index.test.ts +108 -0
  128. package/utils/validators/formRules/index.ts +9 -1
  129. package/yarn-error.log +195 -0
  130. package/pages/plugins.vue +0 -387
  131. package/server/verdaccio-middleware.js +0 -56
@@ -0,0 +1,291 @@
1
+ <script>
2
+ import { get } from '@shell/utils/object';
3
+ import { BadgeState } from '@components/BadgeState';
4
+
5
+ export default {
6
+ components: { BadgeState },
7
+ name: 'Carousel',
8
+ props: {
9
+ sliders: {
10
+ type: Array,
11
+ required: true,
12
+ },
13
+ keyField: {
14
+ type: String,
15
+ default: 'key',
16
+ },
17
+ asLink: {
18
+ type: Boolean,
19
+ default: false,
20
+ },
21
+ linkField: {
22
+ type: String,
23
+ default: 'link'
24
+ },
25
+ targetField: {
26
+ type: String,
27
+ default: 'target',
28
+ },
29
+ rel: {
30
+ type: String,
31
+ default: 'noopener noreferrer nofollow'
32
+ },
33
+ },
34
+ data() {
35
+ return {
36
+ slider: this.sliders,
37
+ activeItemId: 0,
38
+ autoScroll: true
39
+ };
40
+ },
41
+
42
+ computed: {
43
+
44
+ trackStyle() {
45
+ const sliderItem = this.activeItemId * 100 / this.slider.length;
46
+ const width = 60 * this.slider.length;
47
+
48
+ return `transform: translateX(-${ sliderItem }%); width: ${ width }%`;
49
+ },
50
+ },
51
+
52
+ methods: {
53
+ get,
54
+
55
+ select(slide, i) {
56
+ this.$emit('clicked', slide, i);
57
+ },
58
+
59
+ scrollSlide(i) {
60
+ this.autoScroll = false;
61
+ this.activeItemId = i;
62
+ setTimeout(() => {
63
+ this.slidePosition();
64
+ }, 400);
65
+ },
66
+
67
+ nextPrev(item) {
68
+ this.autoScroll = false;
69
+ if (item === 'next' && this.activeItemId < this.slider.length - 1) {
70
+ this.activeItemId++;
71
+ }
72
+
73
+ if (item === 'prev' && this.activeItemId > 0) {
74
+ this.activeItemId--;
75
+ }
76
+
77
+ this.slidePosition();
78
+ },
79
+
80
+ timer() {
81
+ setInterval(this.autoScrollSlide, 2000);
82
+ },
83
+ autoScrollSlide() {
84
+ if (this.activeItemId < this.slider.length && this.autoScroll ) {
85
+ this.activeItemId++;
86
+ }
87
+
88
+ if (this.activeItemId > this.slider.length - 1) {
89
+ this.autoScroll = false;
90
+ this.activeItemId = 0;
91
+ }
92
+ this.slidePosition();
93
+ },
94
+
95
+ slidePosition() {
96
+ if (this.activeItemId <= 1) {
97
+ this.$refs.slide[this.slider.length - 1].style.left = '-93%';
98
+ this.$refs.slide[0].style.left = '7%';
99
+ } else {
100
+ this.$refs.slide[this.slider.length - 1].style.left = '7%';
101
+ this.$refs.slide[0].style.left = '107%';
102
+ }
103
+ }
104
+ },
105
+
106
+ mounted() {
107
+ this.timer();
108
+ }
109
+ };
110
+
111
+ </script>
112
+
113
+ <template>
114
+ <div class="slider">
115
+ <div id="slide-track" ref="slider" :style="trackStyle" class="slide-track">
116
+ <div
117
+ :is="asLink ? 'a' : 'div'"
118
+ v-for="(slide, i) in sliders"
119
+ :id="`slide` + i"
120
+ ref="slide"
121
+ :key="get(slide, keyField)"
122
+ class="slide"
123
+ :href="asLink ? get(slide, linkField) : null"
124
+ :target="get(slide, targetField)"
125
+ :rel="rel"
126
+ @click="select(slide, i)"
127
+ >
128
+ <div class="slide-content">
129
+ <div class="slide-img">
130
+ <img :src="slide.icon ? slide.icon : `/_nuxt/shell/assets/images/generic-catalog.svg`" />
131
+ </div>
132
+ <div class="slide-content-right">
133
+ <BadgeState :label="slide.repoName" color="slider-badge mb-20" />
134
+ <h1>{{ slide.chartNameDisplay }}</h1>
135
+ <p>{{ slide.chartDescription }}</p>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ <div class="controls">
141
+ <div
142
+ v-for="(slide, i) in slider"
143
+ :key="i"
144
+ class="control-item"
145
+ :class="{'active': activeItemId === i}"
146
+ @click="scrollSlide(i, slider.length)"
147
+ ></div>
148
+ </div>
149
+ <div ref="prev" class="prev" :class="[activeItemId === 0 ? 'disabled' : 'prev']" @click="nextPrev('prev')">
150
+ <i class="icon icon-chevron-left icon-4x"></i>
151
+ </div>
152
+ <div ref="next" class="next" :class="[activeItemId === slider.length - 1 ? 'disabled' : 'next']" @click="nextPrev('next')">
153
+ <i class="icon icon-chevron-right icon-4x"></i>
154
+ </div>
155
+ </div>
156
+ </template>
157
+
158
+ <style lang='scss' scoped>
159
+ .slider {
160
+ margin: auto;
161
+ position: relative;
162
+ width: 100%;
163
+ place-items: center;
164
+ overflow: hidden;
165
+ margin-bottom: 30px;
166
+ min-width: 700px;
167
+
168
+ &:hover {
169
+ .prev,
170
+ .next {
171
+ display: block;
172
+ }
173
+ }
174
+ }
175
+
176
+ .slide-track {
177
+ display: flex;
178
+ animation: scrolls 10s ;
179
+ position: relative;
180
+ transition: 1s ease-in-out;
181
+ }
182
+
183
+ .slider-badge {
184
+ background: var(--app-partner-accent);
185
+ color: var(--body-bg);
186
+ }
187
+ .slide {
188
+ min-height: 210px;
189
+ width: 60%;
190
+ max-width: 60%;
191
+ margin: 0 10px;
192
+ position: relative;
193
+ border: 1px solid var(--tabbed-border);
194
+ border-radius: var(--border-radius);
195
+ left: 7%;
196
+ cursor: pointer;
197
+
198
+ &:last-child {
199
+ left: -93%;
200
+ }
201
+
202
+ .slide-header {
203
+ background: var(--default);
204
+ width: 100%;
205
+ padding: 10px 15px;
206
+ }
207
+ .slide-content {
208
+ display: flex;
209
+ padding: 30px;
210
+
211
+ .slide-img {
212
+ width: 150px;
213
+ background: var(--card-badge-text);
214
+ border-radius: calc(2 * var(--border-radius));
215
+
216
+ img {
217
+ width: 100%;
218
+ }
219
+ }
220
+
221
+ .slide-content-right {
222
+ border-left: 1px solid var(--tabbed-border);
223
+ margin-left: 30px;
224
+ padding-left: 30px;
225
+
226
+ span {
227
+ margin: 0;
228
+ }
229
+ }
230
+
231
+ }
232
+ }
233
+
234
+ .slider::before,
235
+ .slider::after {
236
+ background: linear-gradient(to right, var(--slider-light-bg) 0%, var(--slider-light-bg-right) 100%);
237
+ content: "";
238
+ height: 100%;
239
+ position: absolute;
240
+ width: 15%;
241
+ z-index: z-index('overContent');
242
+ }
243
+
244
+ .slider::before {
245
+ left: 0;
246
+ top: 0;
247
+ }
248
+ .slider::after{
249
+ right: -1px;
250
+ top: 0;
251
+ transform: rotate(180deg);
252
+ }
253
+
254
+ .controls {
255
+ width: 100%;
256
+ display: flex;
257
+ justify-content: center;
258
+ margin-top: 10px;
259
+
260
+ .control-item {
261
+ width: 10px;
262
+ height: 10px;
263
+ border-radius: 50%;
264
+ background: var(--scrollbar-thumb);
265
+ margin: 5px;
266
+ cursor: pointer;
267
+
268
+ &.active {
269
+ background:var(--body-text);
270
+ }
271
+ }
272
+ }
273
+ .prev,
274
+ .next {
275
+ position: absolute;
276
+ z-index: 20;
277
+ top: 90px;
278
+ display: none;
279
+ cursor: pointer;
280
+
281
+ &.disabled .icon {
282
+ color: var(--disabled-bg);
283
+ cursor: not-allowed;
284
+ }
285
+ }
286
+
287
+ .next {
288
+ right: 0;
289
+ }
290
+
291
+ </style>
@@ -7,6 +7,8 @@ import { SETTING } from '@shell/config/settings';
7
7
  import { mapGetters } from 'vuex';
8
8
 
9
9
  export default {
10
+ name: 'CommunityLinks',
11
+
10
12
  components: { SimpleBox },
11
13
 
12
14
  props: {
@@ -21,12 +23,27 @@ export default {
21
23
  mixins: [Closeable],
22
24
 
23
25
  async fetch() {
24
- this.uiIssuesSetting = await this.$store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.ISSUES });
25
- this.communitySetting = await this.$store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.COMMUNITY_LINKS });
26
+ // If user already have custom links and uiIssueSetting Doc URL set
27
+ // This should already be in the uiCustomLinks
28
+ try {
29
+ this.uiCustomLinks = await this.$store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.UI_CUSTOM_LINKS });
30
+ } catch (err) {
31
+
32
+ }
33
+
34
+ // Fallback:
35
+ // NB: this.uiIssueSetting is deprecated now.
36
+ if (!this.uiCustomLinks) {
37
+ try {
38
+ this.uiIssuesSetting = await this.$store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.ISSUES });
39
+ } catch (err) {
40
+
41
+ }
42
+ }
26
43
  },
27
44
 
28
45
  data() {
29
- return { uiIssuesSetting: null, communitySetting: null };
46
+ return { uiCustomLinks: null, uiIssuesSetting: null };
30
47
  },
31
48
 
32
49
  computed: {
@@ -35,25 +52,42 @@ export default {
35
52
  'selectedLocaleLabel'
36
53
  ]),
37
54
 
55
+ hasOptions() {
56
+ return !!Object.keys(this.options).length || !!Object.keys(this.$slots).length;
57
+ },
58
+
38
59
  options() {
60
+ // Link options are provided
39
61
  if (Object.keys(this.linkOptions).length > 0) {
40
62
  return this.linkOptions;
41
63
  }
42
64
 
43
- if (this.communitySetting?.value === 'false') {
44
- return options(this.uiIssuesSetting?.value, true);
65
+ // Custom links set from settings
66
+ if (!!this.uiCustomLinks?.value) {
67
+ try {
68
+ const customLinks = JSON.parse(this.uiCustomLinks.value);
69
+
70
+ if (Array.isArray(customLinks)) {
71
+ return customLinks.reduce((prev, curr) => {
72
+ prev[curr.key] = curr.value;
73
+
74
+ return prev;
75
+ }, {});
76
+ }
77
+ } catch (e) {
78
+ console.error('Could not parse custom links setting', e); // eslint-disable-line no-console
79
+ }
45
80
  }
46
81
 
47
- return options(this.uiIssuesSetting?.value);
82
+ // Fallback
83
+ return options(false, this.uiIssuesSetting?.value);
48
84
  },
49
-
50
- title() {
51
- const hasCustomizedFileIssueLink = this.uiIssuesSetting?.value;
52
-
53
- return hasCustomizedFileIssueLink ? 'landing.support' : 'landing.community.title';
54
- }
55
85
  },
56
86
  methods: {
87
+ getLabel(label) {
88
+ return this.$store.getters['i18n/withFallback'](`customLinks.defaults.${ label }`, null, label);
89
+ },
90
+
57
91
  show() {
58
92
  this.$modal.show('wechat-modal');
59
93
  },
@@ -65,12 +99,20 @@ export default {
65
99
  </script>
66
100
 
67
101
  <template>
68
- <div>
69
- <SimpleBox :title="t(title)" :pref="pref" :pref-key="prefKey">
102
+ <div v-if="hasOptions">
103
+ <SimpleBox :pref="pref" :pref-key="prefKey">
104
+ <template #title>
105
+ <h2>
106
+ {{ t('customLinks.displayTitle') }}
107
+ </h2>
108
+ </template>
70
109
  <div v-for="(value, name) in options" :key="name" class="support-link">
71
- <a v-t="name" :href="value" target="_blank" rel="noopener noreferrer nofollow" />
110
+ <n-link v-if="value.startsWith('/') " :to="value">
111
+ {{ getLabel(name) }}
112
+ </n-link>
113
+ <a v-else :href="value" rel="noopener noreferrer nofollow" target="_blank"> {{ getLabel(name) }} </a>
72
114
  </div>
73
-
115
+ <slot />
74
116
  <div v-if="selectedLocaleLabel === t('locale.zh-hans')" class="support-link">
75
117
  <a class="link" @click="show">
76
118
  {{ t('footer.wechat.title') }}
@@ -97,8 +139,17 @@ export default {
97
139
  </template>
98
140
 
99
141
  <style lang='scss' scoped>
100
- .support-link:not(:first-child) {
101
- margin-top: 15px;
142
+ h2 {
143
+ display: flex;
144
+ align-items: center;
145
+
146
+ i {
147
+ font-size: 12px;
148
+ margin-left: 5px;
149
+ }
150
+ }
151
+ .support-link:not(:last-child) {
152
+ margin-bottom: 15px;
102
153
  }
103
154
 
104
155
  .wechat-modal {
@@ -2,7 +2,7 @@
2
2
  import isEmpty from 'lodash/isEmpty';
3
3
  import { createYaml } from '@shell/utils/create-yaml';
4
4
  import { clone, get } from '@shell/utils/object';
5
- import { SCHEMA } from '@shell/config/types';
5
+ import { SCHEMA, NAMESPACE } from '@shell/config/types';
6
6
  import ResourceYaml from '@shell/components/ResourceYaml';
7
7
  import { Banner } from '@components/Banner';
8
8
  import AsyncButton from '@shell/components/AsyncButton';
@@ -329,10 +329,18 @@ export default {
329
329
 
330
330
  async createNamespaceIfNeeded() {
331
331
  const inStore = this.$store.getters['currentStore'](this.resource);
332
+ const newNamespaceName = get(this.resource, this.namespaceKey);
333
+ let namespaceAlreadyExists = false;
332
334
 
333
- if (this.createNamespace) {
335
+ try {
336
+ // This is in a try-catch block because the call to fetch
337
+ // a namespace throws an error if the namespace is not found.
338
+ namespaceAlreadyExists = !!(await this.$store.dispatch(`${ inStore }/find`, { type: NAMESPACE, id: newNamespaceName }));
339
+ } catch {}
340
+
341
+ if (this.createNamespace && !namespaceAlreadyExists) {
334
342
  try {
335
- const newNamespace = await this.$store.dispatch(`${ inStore }/createNamespace`, { name: get(this.resource, this.namespaceKey) }, { root: true });
343
+ const newNamespace = await this.$store.dispatch(`${ inStore }/createNamespace`, { name: newNamespaceName }, { root: true });
336
344
 
337
345
  newNamespace.applyDefaults();
338
346
  await newNamespace.save();
@@ -0,0 +1,102 @@
1
+ <script>
2
+ import AsyncButton from '@shell/components/AsyncButton';
3
+
4
+ export default {
5
+ components: { AsyncButton },
6
+
7
+ props: {
8
+ name: {
9
+ type: String,
10
+ required: true,
11
+ },
12
+
13
+ title: {
14
+ type: String,
15
+ required: true,
16
+ },
17
+
18
+ mode: {
19
+ type: String,
20
+ default: '',
21
+ }
22
+ },
23
+
24
+ data() {
25
+ return { closed: false };
26
+ },
27
+
28
+ methods: {
29
+ beforeOpen() {
30
+ this.closed = false;
31
+ },
32
+
33
+ ok(btnCb) {
34
+ const callback = (ok) => {
35
+ btnCb(ok);
36
+ if (ok) {
37
+ this.closeDialog(true);
38
+ }
39
+ };
40
+
41
+ this.$emit('okay', callback);
42
+ },
43
+
44
+ closeDialog(result) {
45
+ if (!this.closed) {
46
+ this.$modal.hide(this.name);
47
+ this.$emit('closed', result);
48
+ this.closed = true;
49
+ }
50
+ },
51
+ }
52
+ };
53
+ </script>
54
+
55
+ <template>
56
+ <modal
57
+ :name="name"
58
+ height="auto"
59
+ :scrollable="true"
60
+ @closed="closeDialog(false)"
61
+ @before-open="beforeOpen"
62
+ >
63
+ <div class="modal-dialog">
64
+ <h4>
65
+ {{ title }}
66
+ </h4>
67
+ <slot></slot>
68
+ <div class="dialog-buttons mt-20">
69
+ <slot name="buttons"></slot>
70
+ <div v-if="!$slots.buttons">
71
+ <button class="btn role-secondary" @click="closeDialog(false)">
72
+ {{ t('generic.cancel') }}
73
+ </button>
74
+ <button v-if="!mode" class="btn role-primary ml-10" @click="closeDialog(true)">
75
+ {{ t('generic.ok') }}
76
+ </button>
77
+ <AsyncButton v-else :mode="mode" class="ml-10" @click="ok" />
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </modal>
82
+ </template>
83
+
84
+ <style lang="scss" scoped>
85
+ .modal-dialog {
86
+ padding: 10px;
87
+
88
+ h4 {
89
+ font-weight: bold;
90
+ }
91
+
92
+ .dialog-buttons {
93
+ display: flex;
94
+ justify-content: flex-end;
95
+ margin-top: 10px;
96
+
97
+ > *:not(:last-child) {
98
+ margin-right: 10px;
99
+ }
100
+ }
101
+ }
102
+ </style>
@@ -1,7 +1,6 @@
1
1
  <script>
2
2
  import { MANAGEMENT, NORMAN, VIRTUAL_TYPES } from '@shell/config/types';
3
3
  import ResourceTable from '@shell/components/ResourceTable';
4
- import Loading from '@shell/components/Loading';
5
4
  import Masthead from '@shell/components/ResourceList/Masthead';
6
5
  import { AGE, ROLE, STATE, PRINCIPAL } from '@shell/config/table-headers';
7
6
  import { canViewClusterPermissionsEditor } from '@shell/components/form/Members/ClusterPermissionsEditor.vue';
@@ -17,7 +16,6 @@ export default {
17
16
 
18
17
  components: {
19
18
  Banner,
20
- Loading,
21
19
  Masthead,
22
20
  ResourceTable
23
21
  },
@@ -96,8 +94,7 @@ export default {
96
94
  </script>
97
95
 
98
96
  <template>
99
- <Loading v-if="$fetchState.pending || !currentCluster" />
100
- <div v-else>
97
+ <div>
101
98
  <Masthead
102
99
  :schema="schema"
103
100
  :resource="resource"
@@ -116,6 +113,7 @@ export default {
116
113
  :rows="filteredClusterRoleTemplateBindings"
117
114
  :groupable="false"
118
115
  :namespaced="false"
116
+ :loading="$fetchState.pending || !currentCluster"
119
117
  sub-search="subSearch"
120
118
  :sub-fields="['nameDisplay']"
121
119
  />
@@ -4,10 +4,9 @@ import ResourceTable from '@shell/components/ResourceTable';
4
4
  import { STATE, AGE, NAME } from '@shell/config/table-headers';
5
5
  import { uniq } from '@shell/utils/array';
6
6
  import { MANAGEMENT, NAMESPACE, VIRTUAL_TYPES } from '@shell/config/types';
7
- import Loading from '@shell/components/Loading';
8
7
  import { PROJECT_ID } from '@shell/config/query-params';
9
8
  import Masthead from '@shell/components/ResourceList/Masthead';
10
- import { mapPref, GROUP_RESOURCES, DEV } from '@shell/store/prefs';
9
+ import { mapPref, GROUP_RESOURCES, ALL_NAMESPACES } from '@shell/store/prefs';
11
10
  import MoveModal from '@shell/components/MoveModal';
12
11
  import { defaultTableSortGenerationFn } from '@shell/components/ResourceTable.vue';
13
12
  import { NAMESPACE_FILTER_ALL_ORPHANS } from '@shell/utils/namespace-filter';
@@ -15,7 +14,7 @@ import { NAMESPACE_FILTER_ALL_ORPHANS } from '@shell/utils/namespace-filter';
15
14
  export default {
16
15
  name: 'ListProjectNamespace',
17
16
  components: {
18
- Loading, Masthead, MoveModal, ResourceTable
17
+ Masthead, MoveModal, ResourceTable
19
18
  },
20
19
 
21
20
  props: {
@@ -184,8 +183,8 @@ export default {
184
183
  return this.groupPreference === 'none' ? this.rows : this.rowsWithFakeNamespaces;
185
184
  },
186
185
  rows() {
187
- if (this.$store.getters['prefs/get'](DEV)) {
188
- // If developer tools are turned on in the user preferences,
186
+ if (this.$store.getters['prefs/get'](ALL_NAMESPACES)) {
187
+ // If all namespaces options are turned on in the user preferences,
189
188
  // return all namespaces including system namespaces and RBAC
190
189
  // management namespaces.
191
190
  return this.activeNamespaces;
@@ -302,8 +301,7 @@ export default {
302
301
  </script>
303
302
 
304
303
  <template>
305
- <Loading v-if="$fetchState.pending || !currentCluster" />
306
- <div v-else class="project-namespaces">
304
+ <div class="project-namespaces">
307
305
  <Masthead
308
306
  :schema="projectSchema"
309
307
  :type-display="t('projectNamespaces.label')"
@@ -321,6 +319,7 @@ export default {
321
319
  :rows="filteredRows"
322
320
  :groupable="true"
323
321
  :sort-generation-fn="sortGenerationFn"
322
+ :loading="$fetchState.pending || !currentCluster"
324
323
  group-tooltip="resourceTable.groupBy.project"
325
324
  key-field="_key"
326
325
  v-on="$listeners"
@@ -21,12 +21,16 @@ export default {
21
21
  type: String,
22
22
  default: null
23
23
  },
24
+ subtle: {
25
+ type: Boolean,
26
+ default: false,
27
+ }
24
28
  },
25
29
  };
26
30
  </script>
27
31
 
28
32
  <template>
29
- <div class="message-icon" :class="{'vertical': vertical}">
33
+ <div class="message-icon" :class="{'vertical': vertical, 'subtle': subtle}">
30
34
  <i class="icon" :class="{ [icon]: true, [iconState]: !!iconState}" />
31
35
  <div class="message">
32
36
  <slot name="message">
@@ -47,6 +51,10 @@ export default {
47
51
  width: 100%;
48
52
  }
49
53
 
54
+ .subtle {
55
+ opacity: 0.7;
56
+ }
57
+
50
58
  .message-icon {
51
59
  display: flex;
52
60
  align-items: center;