@rancher/shell 3.0.11 → 3.0.12-rc.2

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 (219) hide show
  1. package/assets/images/providers/entraid-black.svg +4 -0
  2. package/assets/images/providers/entraid.svg +9 -0
  3. package/assets/images/vendor/entraid.svg +9 -0
  4. package/assets/styles/app.scss +0 -1
  5. package/assets/styles/base/_mixins.scss +31 -0
  6. package/assets/styles/base/_variables.scss +2 -0
  7. package/assets/styles/themes/_modern.scss +6 -5
  8. package/assets/translations/en-us.yaml +24 -21
  9. package/assets/translations/zh-hans.yaml +4 -11
  10. package/chart/__tests__/S3.test.ts +10 -3
  11. package/components/CountBox.vue +20 -0
  12. package/components/CreateDriver.vue +0 -12
  13. package/components/DetailText.vue +12 -3
  14. package/components/EmptyProductPage.vue +76 -0
  15. package/components/Resource/Detail/CopyToClipboard.vue +1 -2
  16. package/components/Resource/Detail/Metadata/KeyValueRow.vue +9 -3
  17. package/components/Resource/Detail/TitleBar/__tests__/__snapshots__/index.test.ts.snap +31 -0
  18. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +45 -1
  19. package/components/Resource/Detail/TitleBar/index.vue +1 -1
  20. package/components/Resource/Detail/ViewOptions/__tests__/__snapshots__/index.test.ts.snap +9 -0
  21. package/components/Resource/Detail/ViewOptions/__tests__/index.test.ts +62 -0
  22. package/components/Resource/Detail/ViewOptions/index.vue +2 -1
  23. package/components/ResourceList/Masthead.vue +25 -2
  24. package/components/SelectIconGrid.vue +5 -0
  25. package/components/SideNav.vue +13 -0
  26. package/components/__tests__/CountBox.test.ts +72 -0
  27. package/components/__tests__/DetailText.test.ts +113 -0
  28. package/components/__tests__/PromptModal.test.ts +2 -0
  29. package/components/fleet/FleetClusterTargets/index.vue +18 -1
  30. package/components/fleet/FleetClusters.vue +1 -0
  31. package/components/fleet/__tests__/FleetClusters.test.ts +71 -0
  32. package/components/form/InputWithSelect.vue +18 -10
  33. package/components/form/KeyValue.vue +17 -1
  34. package/components/form/LabeledSelect.vue +82 -24
  35. package/components/form/NodeScheduling.vue +17 -3
  36. package/components/form/PrivateRegistry.vue +69 -0
  37. package/components/form/Select.vue +73 -56
  38. package/components/form/ServiceNameSelect.vue +13 -11
  39. package/components/form/__tests__/KeyValue.test.ts +66 -0
  40. package/components/form/__tests__/NodeScheduling.test.ts +9 -0
  41. package/components/form/__tests__/PrivateRegistry.test.ts +133 -0
  42. package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
  43. package/components/formatter/WorkloadHealthScale.vue +3 -1
  44. package/components/nav/Group.vue +33 -9
  45. package/components/nav/Header.vue +56 -10
  46. package/components/nav/NotificationCenter/Notification.vue +4 -1
  47. package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
  48. package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
  49. package/components/nav/TopLevelMenu.vue +15 -1
  50. package/components/nav/Type.vue +8 -7
  51. package/components/nav/WindowManager/index.vue +2 -1
  52. package/components/nav/WorkspaceSwitcher.vue +13 -0
  53. package/components/nav/__tests__/Group.test.ts +67 -0
  54. package/components/nav/__tests__/Header.test.ts +235 -0
  55. package/components/nav/__tests__/Type.test.ts +20 -3
  56. package/components/templates/default.vue +34 -4
  57. package/components/templates/home.vue +12 -25
  58. package/components/templates/plain.vue +13 -26
  59. package/composables/useLabeledFormElement.ts +10 -2
  60. package/composables/useLabeledSelect.ts +60 -0
  61. package/composables/useUserRetentionValidation.ts +1 -49
  62. package/config/cookies.js +0 -1
  63. package/config/labels-annotations.js +1 -0
  64. package/config/pagination-table-headers.js +8 -1
  65. package/config/product/apps.js +2 -1
  66. package/config/product/auth.js +1 -0
  67. package/config/product/backup.js +1 -0
  68. package/config/product/compliance.js +1 -1
  69. package/config/product/explorer.js +25 -6
  70. package/config/product/fleet.js +1 -0
  71. package/config/product/gatekeeper.js +1 -0
  72. package/config/product/istio.js +1 -0
  73. package/config/product/logging.js +1 -0
  74. package/config/product/longhorn.js +2 -1
  75. package/config/product/manager.js +1 -0
  76. package/config/product/monitoring.js +1 -0
  77. package/config/product/navlinks.js +1 -0
  78. package/config/product/neuvector.js +2 -1
  79. package/config/product/settings.js +1 -0
  80. package/config/product/uiplugins.js +1 -0
  81. package/config/query-params.js +1 -0
  82. package/config/router/routes.js +0 -8
  83. package/core/__tests__/plugin-products-helpers.test.ts +454 -0
  84. package/core/__tests__/plugin-products.test.ts +3810 -0
  85. package/core/extension-manager-impl.js +30 -1
  86. package/core/plugin-products-base.ts +392 -0
  87. package/core/plugin-products-extending.ts +44 -0
  88. package/core/plugin-products-helpers.ts +263 -0
  89. package/core/plugin-products-top-level.ts +66 -0
  90. package/core/plugin-products-type-guards.ts +33 -0
  91. package/core/plugin-products.ts +50 -0
  92. package/core/plugin-types.ts +237 -0
  93. package/core/plugin.ts +45 -10
  94. package/core/productDebugger.js +48 -0
  95. package/core/types.ts +97 -11
  96. package/detail/__tests__/__snapshots__/fleet.cattle.io.bundle.test.ts.snap +52 -0
  97. package/detail/__tests__/fleet.cattle.io.bundle.test.ts +171 -0
  98. package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
  99. package/detail/fleet.cattle.io.bundle.vue +21 -34
  100. package/detail/management.cattle.io.fleetworkspace.vue +49 -0
  101. package/dialog/ExtensionCatalogInstallDialog.vue +1 -1
  102. package/dialog/InstallExtensionDialog.vue +6 -27
  103. package/dialog/UninstallExistingExtensionDialog.vue +141 -0
  104. package/dialog/UninstallExtensionDialog.vue +4 -26
  105. package/dialog/__tests__/UninstallExistingExtensionDialog.test.ts +114 -0
  106. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -0
  107. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
  108. package/edit/__tests__/kontainerDriver.test.ts +0 -13
  109. package/edit/__tests__/nodeDriver.test.ts +5 -11
  110. package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
  111. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  112. package/edit/auth/__tests__/oidc.test.ts +54 -0
  113. package/edit/auth/azuread.vue +1 -1
  114. package/edit/auth/oidc.vue +8 -0
  115. package/edit/kontainerDriver.vue +1 -2
  116. package/edit/nodeDriver.vue +0 -2
  117. package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
  118. package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
  119. package/edit/provisioning.cattle.io.cluster/__tests__/Ingress.test.ts +176 -0
  120. package/edit/provisioning.cattle.io.cluster/index.vue +70 -99
  121. package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -1
  122. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +6 -0
  123. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +7 -2
  124. package/initialize/App.vue +29 -2
  125. package/initialize/install-plugins.js +0 -2
  126. package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
  127. package/list/catalog.cattle.io.app.vue +25 -5
  128. package/list/management.cattle.io.feature.vue +1 -1
  129. package/list/management.cattle.io.fleetworkspace.vue +8 -0
  130. package/list/provisioning.cattle.io.cluster.vue +0 -1
  131. package/list/workload.vue +11 -4
  132. package/machine-config/amazonec2.vue +1 -0
  133. package/mixins/chart.js +40 -9
  134. package/mixins/resource-fetch.js +12 -3
  135. package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
  136. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
  137. package/models/__tests__/chart.test.ts +99 -6
  138. package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
  139. package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
  140. package/models/catalog.cattle.io.app.js +21 -17
  141. package/models/catalog.cattle.io.clusterrepo.js +39 -11
  142. package/models/chart.js +33 -19
  143. package/models/fleet-application.js +1 -1
  144. package/models/fleet.cattle.io.bundle.js +1 -1
  145. package/models/kontainerdriver.js +11 -0
  146. package/models/management.cattle.io.authconfig.js +5 -1
  147. package/models/management.cattle.io.cluster.js +0 -53
  148. package/models/management.cattle.io.feature.js +3 -3
  149. package/models/management.cattle.io.kontainerdriver.js +1 -26
  150. package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
  151. package/models/nodedriver.js +7 -0
  152. package/models/pod.js +18 -0
  153. package/models/workload.js +20 -2
  154. package/package.json +13 -13
  155. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +0 -1
  156. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +189 -0
  157. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
  158. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
  159. package/pages/c/_cluster/apps/charts/chart.vue +217 -33
  160. package/pages/c/_cluster/apps/charts/index.vue +2 -2
  161. package/pages/c/_cluster/apps/charts/install.vue +8 -3
  162. package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
  163. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
  164. package/pages/c/_cluster/settings/brand.vue +4 -4
  165. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +39 -2
  166. package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
  167. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +246 -23
  168. package/pages/c/_cluster/uiplugins/index.vue +166 -62
  169. package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -0
  170. package/plugins/dashboard-store/actions.js +3 -2
  171. package/plugins/dashboard-store/resource-class.js +62 -6
  172. package/plugins/plugin.js +16 -0
  173. package/plugins/steve/steve-pagination-utils.ts +7 -0
  174. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +205 -1
  175. package/rancher-components/Form/LabeledInput/LabeledInput.vue +82 -4
  176. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
  177. package/scripts/test-plugins-build.sh +5 -2
  178. package/scripts/typegen.sh +13 -1
  179. package/server/server-middleware.js +2 -2
  180. package/static/humans.txt +1 -0
  181. package/static/robots.txt +34 -0
  182. package/static/welcome-cow.svg +18 -0
  183. package/store/__tests__/catalog.test.ts +161 -11
  184. package/store/__tests__/type-map.test.ts +84 -24
  185. package/store/auth.js +0 -3
  186. package/store/catalog.js +60 -8
  187. package/store/type-map.js +42 -3
  188. package/tsconfig.paths.json +1 -0
  189. package/types/resources/pod.ts +18 -0
  190. package/types/shell/index.d.ts +8539 -2938
  191. package/types/store/dashboard-store.types.ts +5 -0
  192. package/types/store/pagination.types.ts +6 -0
  193. package/utils/__tests__/git.test.ts +270 -0
  194. package/utils/__tests__/inactivity.test.ts +316 -0
  195. package/utils/__tests__/object.test.ts +77 -0
  196. package/utils/__tests__/time.test.ts +14 -1
  197. package/utils/__tests__/url.test.ts +246 -0
  198. package/utils/axios.js +1 -4
  199. package/utils/dynamic-importer.js +3 -2
  200. package/utils/object.js +33 -2
  201. package/utils/pagination-utils.ts +1 -1
  202. package/utils/time.ts +5 -0
  203. package/utils/uiplugins.ts +12 -16
  204. package/utils/validators/__tests__/private-registry.test.ts +76 -0
  205. package/utils/validators/private-registry.ts +28 -0
  206. package/vue.config.js +0 -9
  207. package/assets/images/providers/azuread-black.svg +0 -22
  208. package/assets/images/providers/azuread.svg +0 -25
  209. package/assets/images/vendor/azuread.svg +0 -18
  210. package/assets/styles/fonts/_dots.scss +0 -18
  211. package/components/EmberPage.vue +0 -622
  212. package/components/EmberPageView.vue +0 -39
  213. package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
  214. package/mixins/labeled-form-element.ts +0 -225
  215. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
  216. package/pages/c/_cluster/manager/pages/_page.vue +0 -22
  217. package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
  218. package/plugins/ember-cookie.js +0 -17
  219. package/utils/ember-page.js +0 -30
@@ -1,622 +0,0 @@
1
- <script>
2
- import Loading from '@shell/components/Loading';
3
- import { mapGetters, mapState } from 'vuex';
4
- import { NAME as MANAGER } from '@shell/config/product/manager';
5
- import { CAPI, MANAGEMENT } from '@shell/config/types';
6
- import { SETTING } from '@shell/config/settings';
7
- import { findEmberPage, clearEmberInactiveTimer, startEmberInactiveTimer, EMBER_FRAME } from '@shell/utils/ember-page';
8
-
9
- const EMBER_FRAME_HIDE_CLASS = 'ember-iframe-hidden';
10
- const PAGE_CHECK_TIMEOUT = 30000;
11
- const WINDOW_MANAGER = 'horizontal-window-manager';
12
-
13
- // Pages that we should intercept when loaded in the IFRAME and instead
14
- // navigate to a page in Cluster Dashboard
15
- // example if the Ember clusters page that is navigated to when the user presses cancel on some pages
16
- // we intercept this and go the the vue Clusters page instead
17
- const INTERCEPTS = {
18
- 'global-admin.clusters.index': {
19
- name: 'c-cluster-product-resource',
20
- params: {
21
- cluster: '',
22
- product: MANAGER,
23
- resource: CAPI.RANCHER_CLUSTER,
24
- }
25
- },
26
- 'authenticated.cluster.index': {
27
- name: 'c-cluster-product-resource',
28
- params: {
29
- cluster: '',
30
- product: MANAGER,
31
- resource: CAPI.RANCHER_CLUSTER,
32
- }
33
- },
34
- 'authenticated.cluster.istio.cluster-setting': { name: 'c-cluster-explorer-tools' },
35
- };
36
-
37
- export default {
38
- emits: ['before-nav'],
39
-
40
- components: { Loading },
41
-
42
- props: {
43
- src: {
44
- type: String,
45
- required: true
46
- },
47
- pop: {
48
- type: Boolean,
49
- default: false
50
- },
51
- inline: {
52
- type: String,
53
- default: ''
54
- },
55
- // force inline pages to reuse cached Ember pages
56
- forceInlineReuse: {
57
- type: Boolean,
58
- default: false
59
- },
60
- // Do not reuse cached pages
61
- forceNew: {
62
- type: Boolean,
63
- default: false
64
- }
65
- },
66
-
67
- data() {
68
- return {
69
- iframeEl: null,
70
- loaded: true,
71
- loadRequired: false,
72
- emberCheck: null,
73
- error: false,
74
- heightSync: null,
75
- frameHeight: -1,
76
- frameWidth: -1,
77
- wmHeight: -1,
78
- showHeaderBanner: false,
79
- showFooterBanner: false,
80
- };
81
- },
82
-
83
- computed: {
84
- ...mapGetters({ theme: 'prefs/theme' }),
85
- ...mapGetters(['clusterId', 'productId']),
86
- ...mapState('wm', ['open']),
87
- locale() {
88
- return this.$store.getters['i18n/current']();
89
- }
90
- },
91
-
92
- watch: {
93
- theme(theme) {
94
- this.notifyTheme(theme);
95
- },
96
-
97
- // Update when source property changes
98
- src(nue, old) {
99
- if (nue !== old) {
100
- this.initFrame();
101
- }
102
- },
103
-
104
- // Watch on the window manager opening/closing
105
- open(nue, old) {
106
- if (nue !== old) {
107
- if (nue) {
108
- this.syncSize();
109
- } else {
110
- clearTimeout(this.heightSync);
111
- const iframeEl = findEmberPage();
112
-
113
- // Reset the height when the window manager is closed
114
- this.heightSync = null;
115
- this.wmHeight = -1;
116
-
117
- if (iframeEl) {
118
- iframeEl.style.height = '';
119
- }
120
- }
121
- }
122
- },
123
- locale() {
124
- this.syncLocale();
125
- }
126
- },
127
-
128
- mounted() {
129
- // Embedded page visited, so cancel time to remove IFRAME when inactive
130
- clearEmberInactiveTimer();
131
- window.addEventListener('message', this.receiveMessage);
132
- this.initFrame();
133
- },
134
-
135
- beforeUnmount() {
136
- window.removeEventListener('message', this.receiveMessage);
137
-
138
- if (this.heightSync) {
139
- clearTimeout(this.heightSync);
140
- }
141
-
142
- if (this.inline) {
143
- const iframeEl = findEmberPage();
144
-
145
- // Remove the IFRAME - we can't reuse it one its been moved inline
146
- if (iframeEl) {
147
- iframeEl.remove();
148
- }
149
- }
150
-
151
- // Hide the iframe
152
- if (this.iframeEl) {
153
- this.iframeEl.classList.add(EMBER_FRAME_HIDE_CLASS);
154
- }
155
-
156
- // Cancel any pending http request to check Ember UI availability
157
- if (this.emberCheck) {
158
- this.emberCheck.cancel('User left page');
159
- }
160
-
161
- // Set up a timer to remove the IFrame after a period of inactivity
162
- startEmberInactiveTimer();
163
- },
164
-
165
- methods: {
166
- addBannerClasses(elm, prefix) {
167
- if (!elm) {
168
- return;
169
- }
170
-
171
- elm.classList.remove(`${ prefix }-top-banner`);
172
- elm.classList.remove(`${ prefix }-one-banner`);
173
- elm.classList.remove(`${ prefix }-two-banners`);
174
-
175
- if (this.showHeaderBanner) {
176
- elm.classList.add(`${ prefix }-top-banner`);
177
- if (this.showFooterBanner) {
178
- elm.classList.add(`${ prefix }-two-banners`);
179
- }
180
- } else if (this.showFooterBanner) {
181
- elm.classList.add(`${ prefix }-one-banner`);
182
- }
183
- },
184
-
185
- async initFrame() {
186
- const bannerSetting = await this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.BANNERS);
187
-
188
- try {
189
- const parsed = JSON.parse(bannerSetting.value);
190
-
191
- this.showHeaderBanner = parsed.showHeader === 'true';
192
- this.showFooterBanner = parsed.showFooter === 'true';
193
- } catch {}
194
-
195
- this.loaded = true;
196
- this.loadRequired = false;
197
-
198
- // Get the existing iframe if it exists
199
- let iframeEl = findEmberPage();
200
-
201
- // If the iframe already exists, check if it is ready for us to reuse
202
- // by navigating within the app that is already loaded
203
- if (iframeEl !== null) {
204
- const ready = iframeEl.getAttribute('data-ready') === 'true';
205
- const lastDidLoad = iframeEl.getAttribute('data-loaded') === 'true';
206
- const doNotReuse = (!!this.inline && !this.forceInlineReuse) || this.forceNew;
207
- // Was not inline but now is - can't reuse
208
- const inlineChanged = !!this.inline && (iframeEl.parentElement === document.body);
209
-
210
- if (!ready || doNotReuse || !lastDidLoad || inlineChanged) {
211
- iframeEl.remove();
212
- iframeEl = null;
213
- }
214
- }
215
-
216
- if (iframeEl === null && process.env.dev) {
217
- // Fetch a page to check that the Ember UI is available
218
- try {
219
- this.error = false;
220
- this.loaded = false;
221
- this.emberCheck = this.$axios.CancelToken.source();
222
-
223
- // Make a head request to a known asset of the Ember UI
224
- const pageUrl = `${ window.location.origin }/assets/images/logos/rke.svg`;
225
- const response = await this.$axios.head(pageUrl, {
226
- timeout: PAGE_CHECK_TIMEOUT,
227
- cancelToken: this.emberCheck.token,
228
- });
229
-
230
- if (response.status !== 200) {
231
- this.loaded = true;
232
- this.error = true;
233
- }
234
- } catch (e) {
235
- if (!this.$axios.isCancel(e)) {
236
- this.loaded = true;
237
- this.error = true;
238
- }
239
- }
240
- }
241
-
242
- if (this.error) {
243
- return;
244
- }
245
-
246
- if (iframeEl === null) {
247
- iframeEl = document.createElement('iframe');
248
- iframeEl.setAttribute('id', EMBER_FRAME);
249
- iframeEl.setAttribute('data-testid', EMBER_FRAME);
250
- iframeEl.classList.add(EMBER_FRAME_HIDE_CLASS);
251
-
252
- if (this.inline) {
253
- const frameParent = document.getElementById(this.inline);
254
-
255
- frameParent.appendChild(iframeEl);
256
- } else {
257
- document.body.append(iframeEl);
258
- }
259
- iframeEl.setAttribute('src', this.src);
260
- } else {
261
- // Reset scroll position to top
262
- if (iframeEl.contentWindow?.scrollTo) {
263
- iframeEl.contentWindow.scrollTo(0, 0);
264
- }
265
-
266
- // Post a message to navigate within the existing app
267
- iframeEl.contentWindow.postMessage({
268
- action: 'navigate',
269
- name: this.src
270
- });
271
-
272
- // Ensure iframe gets the latest theme if it has changed
273
- this.notifyTheme(this.theme);
274
-
275
- const currentUrl = iframeEl.contentWindow.location.pathname;
276
- const src = this.trimURL(this.src);
277
-
278
- if (src !== currentUrl) {
279
- iframeEl.classList.add(EMBER_FRAME_HIDE_CLASS);
280
- } else {
281
- iframeEl.classList.remove(EMBER_FRAME_HIDE_CLASS);
282
- }
283
- }
284
-
285
- this.iframeEl = iframeEl;
286
-
287
- if (!this.inline) {
288
- iframeEl.classList.add('ember-iframe');
289
- iframeEl.classList.remove('ember-iframe-inline');
290
- this.addBannerClasses(this.$refs.emberPage, 'fixed');
291
- this.addBannerClasses(iframeEl, 'ember-iframe');
292
-
293
- // If the window manager is open, sync the size
294
- if (this.open) {
295
- this.syncSize();
296
- }
297
- } else {
298
- iframeEl.classList.remove('ember-iframe');
299
- iframeEl.classList.add('ember-iframe-inline');
300
- iframeEl.height = 0;
301
- this.syncSize();
302
- }
303
- },
304
-
305
- syncSize() {
306
- if (this.heightSync) {
307
- clearTimeout(this.heightSync);
308
- }
309
-
310
- this.heightSync = setTimeout(() => {
311
- this.dosyncSize();
312
- this.syncSize();
313
- }, 500);
314
- },
315
-
316
- dosyncSize() {
317
- if (this.inline) {
318
- const iframeEl = findEmberPage();
319
- const doc = iframeEl.contentWindow.document;
320
- const app = doc.getElementById('application');
321
- const h = app?.offsetHeight;
322
-
323
- if (h && this.frameHeight !== h) {
324
- this.frameHeight = h;
325
- iframeEl.height = h;
326
- }
327
-
328
- const frameParent = document.getElementById(this.inline);
329
- const w = frameParent.offsetWidth;
330
-
331
- if (w && this.frameWidth !== w) {
332
- this.frameWidth = w;
333
- iframeEl.width = w;
334
- }
335
- } else {
336
- // Ensure the height takes into count the window manger height
337
- const wm = document.getElementById(WINDOW_MANAGER);
338
-
339
- if (wm) {
340
- const wmh = wm.offsetHeight;
341
-
342
- if (wmh !== this.wmHeight) {
343
- // Adjust the bottom
344
- const iframeEl = findEmberPage();
345
-
346
- iframeEl.style.height = `calc(100vh - var(--header-height) - ${ wmh }px)`;
347
- this.wmHeight = wmh;
348
- }
349
- }
350
- }
351
- },
352
-
353
- notifyTheme(theme) {
354
- const iframeEl = findEmberPage();
355
-
356
- if (iframeEl) {
357
- const emberTheme = theme === 'light' ? 'ui-light' : 'ui-dark';
358
-
359
- // Ensure the embedded UI uses the correct theme
360
- iframeEl.contentWindow.postMessage({
361
- action: 'set-theme',
362
- name: emberTheme
363
- });
364
- }
365
- },
366
-
367
- trimURL(url) {
368
- if (url && url.endsWith('/')) {
369
- url = url.substr(0, url.length - 1);
370
- }
371
-
372
- return url;
373
- },
374
-
375
- // We use PostMessage between the Embedded Ember UI and the Dashboard UI
376
- receiveMessage(event) {
377
- const msg = event.data;
378
-
379
- if (msg.action === 'navigate') {
380
- this.$router.replace({
381
- name: 'c-cluster-explorer',
382
- params: { cluster: msg.cluster }
383
- });
384
- } else if (msg.action === 'before-navigation') {
385
- this.$emit('before-nav', msg.target);
386
-
387
- // Ember willTransition event
388
- if (INTERCEPTS[msg.target]) {
389
- const dest = INTERCEPTS[msg.target];
390
-
391
- if (this.isCurrentRoute(dest)) {
392
- this.setLoaded(true);
393
-
394
- return;
395
- }
396
-
397
- this.setLoaded(false);
398
- this.$router.replace(this.fillRoute(dest));
399
- }
400
- } else if (msg.action === 'loading') {
401
- this.setLoaded(!msg.state);
402
- this.updateFrameVisibility();
403
- } else if (msg.action === 'ready') {
404
- // Echo back a ping
405
- this.iframeEl.contentWindow.postMessage({ action: 'echo-back' });
406
- this.iframeEl.setAttribute('data-ready', true);
407
-
408
- const doc = this.iframeEl.contentWindow?.document?.body;
409
-
410
- if (this.inline) {
411
- doc.classList.add('embedded-no-overflow');
412
- } else {
413
- doc.classList.remove('embedded-no-overflow');
414
- }
415
- this.syncLocale();
416
- } else if (msg.action === 'need-to-load') {
417
- this.loadRequired = true;
418
- } else if (msg.action === 'did-transition') {
419
- if (!this.loadRequired) {
420
- this.setLoaded(true);
421
- this.updateFrameVisibility();
422
- this.dosyncSize();
423
- }
424
- } else if (msg.action === 'dashboard') {
425
- this.iframeEl.setAttribute('data-ready', false);
426
- this.$router.replace(msg.page);
427
- } else if (msg.action === 'reload') {
428
- this.loaded = false;
429
- this.iframeEl.remove();
430
- this.initFrame();
431
- } else if ( msg.action === 'logout' ) {
432
- this.loaded = false;
433
- this.iframeEl.remove();
434
- this.initFrame();
435
- this.$store.dispatch('auth/logout');
436
- }
437
- },
438
-
439
- setLoaded(loaded) {
440
- this.loaded = loaded;
441
- if (this.iframeEl) {
442
- this.iframeEl.setAttribute('data-loaded', loaded);
443
- }
444
- },
445
-
446
- updateFrameVisibility() {
447
- if (this.loaded) {
448
- if (this.iframeEl) {
449
- this.iframeEl.classList.remove(EMBER_FRAME_HIDE_CLASS);
450
-
451
- // Notify the embedded UI of the primary and primary text colors
452
- const primary = window.getComputedStyle(document.body).getPropertyValue('--primary');
453
- const primaryText = window.getComputedStyle(document.body).getPropertyValue('--primary-text');
454
-
455
- this.iframeEl.contentWindow.postMessage({
456
- action: 'colors',
457
- primary,
458
- primaryText,
459
- });
460
- }
461
- }
462
- },
463
-
464
- fillRoute(route) {
465
- if (typeof route === 'object') {
466
- // Fill in standard params
467
- if (route.params) {
468
- if ('cluster' in route.params) {
469
- route.params.cluster = this.clusterId;
470
- }
471
- if ('product' in route.params) {
472
- route.params.product = this.productId;
473
- }
474
- }
475
- }
476
-
477
- return route;
478
- },
479
-
480
- isCurrentRoute(route) {
481
- const current = this.$route;
482
-
483
- if (current.name === route.name) {
484
- let same = true;
485
-
486
- Object.keys(current.params).forEach((p) => {
487
- if (route.params[p] !== current.params[p]) {
488
- same = false;
489
- }
490
- });
491
-
492
- return same;
493
- }
494
-
495
- return false;
496
- },
497
-
498
- syncLocale() {
499
- const iframeEl = findEmberPage();
500
-
501
- iframeEl?.contentWindow?.ls('user-language')?.sideLoadLanguage(this.locale);
502
- }
503
- }
504
- };
505
- </script>
506
-
507
- <template>
508
- <div
509
- ref="emberPage"
510
- class="ember-page"
511
- >
512
- <Loading
513
- v-if="!inline"
514
- :loading="!loaded"
515
- mode="content"
516
- :no-delay="true"
517
- />
518
- <div
519
- v-if="inline && !loaded"
520
- v-clean-html="t('generic.loading', {}, true)"
521
- class="inline-loading"
522
- />
523
- <div
524
- v-if="error"
525
- class="ember-page-error"
526
- >
527
- <div>{{ t('embedding.unavailable') }}</div>
528
- <button
529
- class="btn role-primary"
530
- @click="initFrame()"
531
- >
532
- {{ t('embedding.retry') }}
533
- </button>
534
- </div>
535
- </div>
536
- </template>
537
-
538
- <style lang="scss" scoped>
539
- $banner-height: 2em;
540
-
541
- .fixed-top-banner {
542
- top: calc(#{$banner-height} + var(--header-height));
543
- }
544
-
545
- .fixed-one-banner {
546
- height: calc(100vh - var(--header-height) - #{$banner-height});
547
- }
548
-
549
- .fixed-two-banners {
550
- height: calc(100vh - var(--header-height) - #{$banner-height} - #{$banner-height});
551
- }
552
-
553
- .ember-page {
554
- display: flex;
555
- height: 100%;
556
- padding: 0;
557
- }
558
-
559
- .frame {
560
- flex: 1;
561
- visibility: hidden;
562
- }
563
- .frame.pop {
564
- margin: -20px;
565
- }
566
-
567
- .loading {
568
- visibility: visible;
569
- }
570
- .ember-page-error {
571
- display: flex;
572
- align-items: center;
573
- flex: 1;
574
- flex-direction: column;
575
- justify-content: center;
576
- > div {
577
- font-size: 20px;
578
- padding-bottom: 20px;
579
- }
580
- }
581
- .inline-loading {
582
- border: 1px solid var(--border);
583
- border-radius: 5px;
584
- padding: 10px;
585
- text-align: center;
586
- width: 100%;
587
- }
588
- </style>
589
- <style lang="scss">
590
- $banner-height: 2em;
591
-
592
- .ember-iframe {
593
- border: 0;
594
- left: calc(var(--nav-width) + $app-bar-collapsed-width);
595
- height: calc(100vh - var(--header-height));
596
- position: absolute;
597
- top: var(--header-height);
598
- width: calc(100vw - var(--nav-width) - $app-bar-collapsed-width);
599
- visibility: show;
600
- }
601
-
602
- .ember-iframe-top-banner {
603
- top: calc(#{$banner-height} + var(--header-height));
604
- }
605
-
606
- .ember-iframe-one-banner {
607
- height: calc(100vh - var(--header-height) - #{$banner-height});
608
- }
609
-
610
- .ember-iframe-two-banners {
611
- height: calc(100vh - var(--header-height) - #{$banner-height} - #{$banner-height});
612
- }
613
-
614
- .ember-iframe-inline {
615
- border: 0;
616
- overflow: hidden;
617
- }
618
-
619
- .ember-iframe-hidden {
620
- visibility: hidden;
621
- }
622
- </style>
@@ -1,39 +0,0 @@
1
- <script>
2
- import EmberPage from '@shell/components/EmberPage';
3
-
4
- export default {
5
- components: { EmberPage },
6
-
7
- props: {
8
- pages: {
9
- type: Object,
10
- required: true
11
- },
12
- },
13
-
14
- data() {
15
- const page = this.$route.params.page;
16
- let src;
17
-
18
- if (page) {
19
- src = this.pages[page];
20
- }
21
-
22
- return {
23
- src,
24
- page
25
- };
26
- },
27
- };
28
- </script>
29
-
30
- <template>
31
- <EmberPage
32
- v-if="src"
33
- :src="src"
34
- />
35
- <div v-else>
36
- <h1>{{ t('generic.notFound') }}</h1>
37
- <h2>{{ page }}</h2>
38
- </div>
39
- </template>