@rancher/shell 0.3.5 → 0.3.6

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 (116) hide show
  1. package/assets/images/providers/outscale.svg +19 -0
  2. package/assets/styles/base/_basic.scss +18 -0
  3. package/assets/styles/base/_mixins.scss +0 -11
  4. package/assets/styles/base/_variables.scss +2 -4
  5. package/assets/styles/global/_button.scss +12 -2
  6. package/assets/translations/en-us.yaml +22 -1
  7. package/assets/translations/zh-hans.yaml +30 -10
  8. package/chart/gatekeeper.vue +3 -2
  9. package/chart/istio.vue +29 -3
  10. package/components/BrandImage.vue +1 -4
  11. package/components/Carousel.vue +85 -37
  12. package/components/EtcdInfoBanner.vue +7 -3
  13. package/components/ExplorerMembers.vue +100 -5
  14. package/components/ExplorerProjectsNamespaces.vue +32 -2
  15. package/components/GrafanaDashboard.vue +9 -2
  16. package/components/SortableTable/index.vue +23 -11
  17. package/components/SortableTable/selection.js +58 -50
  18. package/components/Wizard.vue +4 -2
  19. package/components/auth/RoleDetailEdit.vue +2 -2
  20. package/components/form/HookOption.vue +14 -10
  21. package/components/form/Labels.vue +32 -27
  22. package/components/form/MatchExpressions.vue +2 -2
  23. package/components/form/Members/ClusterPermissionsEditor.vue +32 -7
  24. package/components/form/NameNsDescription.vue +1 -1
  25. package/components/form/ProjectMemberEditor.vue +46 -21
  26. package/components/form/Tolerations.vue +4 -1
  27. package/components/form/ValueFromResource.vue +14 -9
  28. package/components/form/WorkloadPorts.vue +2 -2
  29. package/components/form/__tests__/NameNsDescription.ts +27 -0
  30. package/components/formatter/WorkloadHealthScale.vue +8 -2
  31. package/components/nav/NamespaceFilter.vue +8 -0
  32. package/{nuxt/components → components/nuxt}/nuxt.js +1 -1
  33. package/{nuxt → config}/middleware.js +8 -8
  34. package/config/product/explorer.js +24 -3
  35. package/config/query-params.js +1 -0
  36. package/config/router.js +1 -1
  37. package/{nuxt → config}/store.js +82 -79
  38. package/config/table-headers.js +46 -12
  39. package/config/types.js +7 -0
  40. package/core/plugin.ts +4 -2
  41. package/core/types.ts +258 -1
  42. package/creators/app/files/tsconfig.json +0 -1
  43. package/creators/app/files/vue.config.js +0 -1
  44. package/creators/pkg/files/.github/workflows/build-extension.yml +3 -4
  45. package/creators/pkg/files/tsconfig.json +0 -1
  46. package/creators/pkg/pkg.package.json +3 -3
  47. package/detail/constraints.gatekeeper.sh.constraint.vue +14 -7
  48. package/detail/fleet.cattle.io.clustergroup.vue +7 -1
  49. package/edit/fleet.cattle.io.gitrepo.vue +16 -1
  50. package/edit/logging.banzaicloud.io.output/index.vue +18 -5
  51. package/edit/logging.banzaicloud.io.output/providers/loki.vue +1 -0
  52. package/edit/namespace.vue +12 -8
  53. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -4
  54. package/edit/provisioning.cattle.io.cluster/import.vue +23 -25
  55. package/edit/provisioning.cattle.io.cluster/rke2.vue +96 -18
  56. package/edit/workload/mixins/workload.js +6 -7
  57. package/edit/workload/storage/Mount.vue +3 -3
  58. package/initialize/App.js +206 -0
  59. package/{nuxt → initialize}/client.js +406 -360
  60. package/{nuxt → initialize}/index.js +21 -22
  61. package/layouts/standalone.vue +13 -0
  62. package/list/catalog.cattle.io.clusterrepo.vue +1 -0
  63. package/list/rbac.authorization.k8s.io.clusterrolebinding.vue +48 -0
  64. package/list/workload.vue +6 -4
  65. package/mixins/chart.js +29 -1
  66. package/mixins/fetch.client.js +95 -0
  67. package/{nuxt/mixins → mixins}/fetch.server.js +30 -26
  68. package/mixins/labeled-form-element.ts +2 -2
  69. package/models/constraints.gatekeeper.sh.constraint.js +37 -0
  70. package/models/pod.js +4 -0
  71. package/models/rbac.authorization.k8s.io.clusterrolebinding.js +16 -0
  72. package/models/rbac.authorization.k8s.io.rolebinding.js +16 -0
  73. package/package.json +9 -13
  74. package/pages/c/_cluster/apps/charts/install.vue +61 -39
  75. package/pages/diagnostic.vue +32 -25
  76. package/pages/rio/mesh.vue +1 -2
  77. package/pkg/tsconfig.json +0 -1
  78. package/plugins/clean-html-directive.js +3 -0
  79. package/plugins/dashboard-store/index.js +1 -1
  80. package/plugins/plugin.js +0 -14
  81. package/plugins/portal-vue.js +4 -0
  82. package/rancher-components/components/Banner/Banner.test.ts +3 -5
  83. package/rancher-components/components/Banner/Banner.vue +1 -0
  84. package/rancher-components/components/Form/Radio/RadioButton.test.ts +31 -0
  85. package/rancher-components/components/Form/Radio/RadioButton.vue +14 -3
  86. package/scripts/extension/publish +42 -23
  87. package/scripts/serve-pkgs +6 -2
  88. package/store/type-map.js +1 -1
  89. package/tsconfig.json +0 -1
  90. package/types/rancher/index.d.ts +2 -0
  91. package/types/shell/index.d.ts +353 -284
  92. package/utils/__tests__/grafana.test.ts +44 -0
  93. package/utils/axios.js +190 -0
  94. package/{nuxt → utils}/cookie-universal-nuxt.js +7 -6
  95. package/utils/dom.js +15 -0
  96. package/utils/grafana.js +35 -16
  97. package/{nuxt/utils.js → utils/nuxt.js} +265 -236
  98. package/utils/router.scrollBehavior.js +1 -1
  99. package/vue.config.js +30 -19
  100. package/nuxt/App.js +0 -210
  101. package/nuxt/axios.js +0 -186
  102. package/nuxt/empty.js +0 -1
  103. package/nuxt/jsonp.js +0 -82
  104. package/nuxt/loading.html +0 -39
  105. package/nuxt/mixins/fetch.client.js +0 -90
  106. package/nuxt/portal-vue.js +0 -4
  107. package/nuxt/server.js +0 -312
  108. package/nuxt/views/app.template.html +0 -9
  109. package/nuxt/views/error.html +0 -23
  110. package/plugins/dashboard-store/extensions.js +0 -22
  111. /package/{nuxt/components → components/nuxt}/nuxt-build-indicator.vue +0 -0
  112. /package/{nuxt/components → components/nuxt}/nuxt-child.js +0 -0
  113. /package/{nuxt/components → components/nuxt}/nuxt-error.vue +0 -0
  114. /package/{nuxt/components → components/nuxt}/nuxt-link.client.js +0 -0
  115. /package/{nuxt/components → components/nuxt}/nuxt-link.server.js +0 -0
  116. /package/{nuxt/components → components/nuxt}/nuxt-loading.vue +0 -0
@@ -1,21 +1,20 @@
1
1
  import Vue from 'vue';
2
- import Vuex from 'vuex';
3
2
  import Meta from 'vue-meta';
4
3
  import ClientOnly from 'vue-client-only';
5
4
  import NoSsr from 'vue-no-ssr';
6
5
  import { createRouter } from '../config/router.js';
7
- import NuxtChild from './components/nuxt-child.js';
6
+ import NuxtChild from '../components/nuxt/nuxt-child.js';
8
7
  import NuxtError from '../layouts/error.vue';
9
- import Nuxt from './components/nuxt.js';
8
+ import Nuxt from '../components/nuxt/nuxt.js';
10
9
  import App from './App.js';
11
- import { setContext, getLocation, getRouteData, normalizeError } from './utils';
12
- import { createStore } from './store.js';
10
+ import { setContext, getLocation, getRouteData, normalizeError } from '../utils/nuxt';
11
+ import { createStore } from '../config/store.js';
13
12
 
14
13
  /* Plugins */
15
14
 
16
- import './portal-vue.js';
17
- import cookieUniversalNuxt from './cookie-universal-nuxt.js';
18
- import axios from './axios.js';
15
+ import '../plugins/portal-vue.js';
16
+ import cookieUniversalNuxt from '../utils/cookie-universal-nuxt.js';
17
+ import axios from '../utils/axios.js';
19
18
  import plugins from '../core/plugins.js';
20
19
  import pluginsLoader from '../core/plugins-loader.js';
21
20
  import axiosShell from '../plugins/axios';
@@ -42,7 +41,7 @@ import backButton from '../plugins/back-button';
42
41
  import plugin from '../plugins/plugin';
43
42
  import codeMirror from '../plugins/codemirror-loader';
44
43
  import '../plugins/formatters';
45
- import version from '../plugins/version';
44
+ import version from '../plugins/version';
46
45
  import steveCreateWorker from '../plugins/steve-create-worker';
47
46
 
48
47
  // Component: <ClientOnly>
@@ -55,7 +54,7 @@ Vue.component(NoSsr.name, {
55
54
  if (process.client && !NoSsr._warned) {
56
55
  NoSsr._warned = true;
57
56
 
58
- console.warn('<no-ssr> has been deprecated and will be removed in Nuxt 3, please use <client-only> instead');
57
+ console.warn('<no-ssr> has been deprecated and will be removed in Nuxt 3, please use <client-only> instead'); // eslint-disable-line no-console
59
58
  }
60
59
 
61
60
  return NoSsr.render(h, ctx);
@@ -92,16 +91,6 @@ const defaultTransition = {
92
91
  name: 'page', mode: 'out-in', appear: true, appearClass: 'appear', appearActiveClass: 'appear-active', appearToClass: 'appear-to'
93
92
  };
94
93
 
95
- const originalRegisterModule = Vuex.Store.prototype.registerModule;
96
-
97
- function registerModule(path, rawModule, options = {}) {
98
- const preserveState = process.client && (
99
- Array.isArray(path) ? !!path.reduce((namespacedState, path) => namespacedState && namespacedState[path], this.state) : path in this.state
100
- );
101
-
102
- return originalRegisterModule.call(this, path, rawModule, { preserveState, ...options });
103
- }
104
-
105
94
  async function createApp(ssrContext, config = {}) {
106
95
  const router = await createRouter(ssrContext, config);
107
96
 
@@ -115,7 +104,17 @@ async function createApp(ssrContext, config = {}) {
115
104
  // here we inject the router and store to all child components,
116
105
  // making them available everywhere as `this.$router` and `this.$store`.
117
106
  const app = {
118
- head: {"title":"dashboard","meta":[{"charset":"utf-8"},{"name":"viewport","content":"width=device-width, initial-scale=1"},{"hid":"description","name":"description","content":"Rancher Dashboard"}],"link":[{"hid":"icon","rel":"icon","type":"image\u002Fx-icon","href":"\u002Ffavicon.png"}],"style":[],"script":[]},
107
+ head: {
108
+ title: 'dashboard',
109
+ meta: [{ charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, {
110
+ hid: 'description', name: 'description', content: 'Rancher Dashboard'
111
+ }],
112
+ link: [{
113
+ hid: 'icon', rel: 'icon', type: 'image\u002Fx-icon', href: '\u002Ffavicon.png'
114
+ }],
115
+ style: [],
116
+ script: []
117
+ },
119
118
 
120
119
  store,
121
120
  router,
@@ -318,7 +317,7 @@ async function createApp(ssrContext, config = {}) {
318
317
  // Lock enablePreview in context
319
318
  if (process.static && process.client) {
320
319
  app.context.enablePreview = function() {
321
- console.warn('You cannot call enablePreview() outside a plugin.');
320
+ console.warn('You cannot call enablePreview() outside a plugin.'); // eslint-disable-line no-console
322
321
  };
323
322
  }
324
323
 
@@ -0,0 +1,13 @@
1
+ <script>
2
+ export default { middleware: ['unauthenticated'] };
3
+ </script>
4
+
5
+ <template>
6
+ <nuxt />
7
+ </template>
8
+
9
+ <style lang="scss">
10
+ body, #__nuxt, #__layout {
11
+ height: 100%;
12
+ }
13
+ </style>
@@ -35,6 +35,7 @@ export default {
35
35
  :rows="rows"
36
36
  :loading="loading"
37
37
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
38
+ data-testid="app-cluster-repo-list"
38
39
  />
39
40
  </div>
40
41
  </template>
@@ -0,0 +1,48 @@
1
+ <script>
2
+ import ResourceTable from '@shell/components/ResourceTable';
3
+
4
+ export default {
5
+ name: 'ListNamespace',
6
+ components: { ResourceTable },
7
+ props: {
8
+ resource: {
9
+ type: String,
10
+ required: true,
11
+ },
12
+ schema: {
13
+ type: Object,
14
+ required: true,
15
+ },
16
+ rows: {
17
+ type: Array,
18
+ required: true,
19
+ },
20
+ loading: {
21
+ type: Boolean,
22
+ required: false,
23
+ },
24
+ useQueryParamsForSimpleFiltering: {
25
+ type: Boolean,
26
+ default: false
27
+ }
28
+ },
29
+
30
+ $loadingResources() {
31
+ return { loadIndeterminate: true };
32
+ },
33
+ };
34
+ </script>
35
+
36
+ <template>
37
+ <div>
38
+ <ResourceTable
39
+ v-bind="$attrs"
40
+ :rows="rows"
41
+ :groupable="false"
42
+ :schema="schema"
43
+ :loading="loading"
44
+ :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
45
+ v-on="$listeners"
46
+ />
47
+ </div>
48
+ </template>
package/list/workload.vue CHANGED
@@ -1,6 +1,8 @@
1
1
  <script>
2
2
  import ResourceTable from '@shell/components/ResourceTable';
3
- import { WORKLOAD_TYPES, SCHEMA, NODE, POD } from '@shell/config/types';
3
+ import {
4
+ WORKLOAD_TYPES, SCHEMA, NODE, POD, LIST_WORKLOAD_TYPES
5
+ } from '@shell/config/types';
4
6
  import ResourceFetch from '@shell/mixins/resource-fetch';
5
7
 
6
8
  const schema = {
@@ -16,7 +18,7 @@ const schema = {
16
18
  const $loadingResources = ($route, $store) => {
17
19
  const allowedResources = [];
18
20
 
19
- Object.values(WORKLOAD_TYPES).forEach((type) => {
21
+ Object.values(LIST_WORKLOAD_TYPES).forEach((type) => {
20
22
  // You may not have RBAC to see some of the types
21
23
  if ($store.getters['cluster/schemaFor'](type) ) {
22
24
  allowedResources.push(type);
@@ -134,8 +136,8 @@ export default {
134
136
  } else {
135
137
  const type = this.$route.params.resource;
136
138
 
137
- if (type === WORKLOAD_TYPES.JOB) {
138
- // Ignore job (we're fetching this anyway, plus they contain their own state)
139
+ if (type === WORKLOAD_TYPES.JOB || type === POD) {
140
+ // Ignore job and pods (we're fetching this anyway, plus they contain their own state)
139
141
  return;
140
142
  }
141
143
 
package/mixins/chart.js CHANGED
@@ -14,6 +14,8 @@ import { CAPI, CATALOG } from '@shell/config/types';
14
14
  import { isPrerelease } from '@shell/utils/version';
15
15
  import difference from 'lodash/difference';
16
16
  import { LINUX } from '@shell/store/catalog';
17
+ import { clone } from 'utils/object';
18
+ import { merge } from 'lodash';
17
19
 
18
20
  export default {
19
21
  data() {
@@ -391,7 +393,6 @@ export default {
391
393
  */
392
394
 
393
395
  if ( provider ) {
394
- // more.push(provider);
395
396
  try {
396
397
  const crdVersionInfo = await this.$store.dispatch('catalog/getVersionInfo', {
397
398
  repoType: provider.repoType,
@@ -399,6 +400,33 @@ export default {
399
400
  chartName: provider.name,
400
401
  versionName: provider.version
401
402
  });
403
+ let existingCRDApp;
404
+
405
+ // search for an existing crd app to track any non-default values used on the previous install/upgrade
406
+ if (this.mode === _EDIT) {
407
+ const targetNamespace = crdVersionInfo?.chart?.annotations?.[CATALOG_ANNOTATIONS.NAMESPACE];
408
+ const targetName = crdVersionInfo?.chart?.annotations?.[CATALOG_ANNOTATIONS.RELEASE_NAME];
409
+
410
+ if (targetName && targetNamespace) {
411
+ existingCRDApp = await this.$store.dispatch('cluster/find', {
412
+ type: CATALOG.APP,
413
+ id: `${ targetNamespace }/${ targetName }`,
414
+ });
415
+ }
416
+ }
417
+ if (existingCRDApp) {
418
+ // spec.values are any non-default values the user configured
419
+ // the installation form should show these, as well as any default values from the chart
420
+ const existingValues = clone(existingCRDApp.spec?.values || {});
421
+ const defaultValues = clone(existingCRDApp.spec?.chart?.values || {});
422
+
423
+ crdVersionInfo.existingValues = existingValues;
424
+ crdVersionInfo.allValues = merge(defaultValues, existingValues);
425
+ } else {
426
+ // allValues will potentially be updated in the UI - we want to track this separately from values to avoid mutating the chart object in the store
427
+ // this is similar to userValues for the main chart
428
+ crdVersionInfo.allValues = clone(crdVersionInfo.values);
429
+ }
402
430
 
403
431
  out.push(crdVersionInfo);
404
432
  } catch (e) {
@@ -0,0 +1,95 @@
1
+ import Vue from 'vue';
2
+ import { hasFetch, normalizeError, addLifecycleHook } from '../utils/nuxt';
3
+
4
+ const isSsrHydration = vm => vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.fetchKey;
5
+ const nuxtState = window.__NUXT__;
6
+
7
+ export default {
8
+ beforeCreate() {
9
+ if (!hasFetch(this)) {
10
+ return;
11
+ }
12
+
13
+ this._fetchDelay = typeof this.$options.fetchDelay === 'number' ? this.$options.fetchDelay : 200;
14
+
15
+ Vue.util.defineReactive(this, '$fetchState', {
16
+ pending: false,
17
+ error: null,
18
+ timestamp: Date.now()
19
+ });
20
+
21
+ this.$fetch = $fetch.bind(this);
22
+ addLifecycleHook(this, 'created', created);
23
+ addLifecycleHook(this, 'beforeMount', beforeMount);
24
+ }
25
+ };
26
+
27
+ function beforeMount() {
28
+ if (!this._hydrated) {
29
+ return this.$fetch();
30
+ }
31
+ }
32
+
33
+ function created() {
34
+ if (!isSsrHydration(this)) {
35
+ return;
36
+ }
37
+
38
+ // Hydrate component
39
+ this._hydrated = true;
40
+ this._fetchKey = this.$vnode.elm.dataset.fetchKey;
41
+ const data = nuxtState.fetch[this._fetchKey];
42
+
43
+ // If fetch error
44
+ if (data && data._error) {
45
+ this.$fetchState.error = data._error;
46
+
47
+ return;
48
+ }
49
+
50
+ // Merge data
51
+ for (const key in data) {
52
+ Vue.set(this.$data, key, data[key]);
53
+ }
54
+ }
55
+
56
+ function $fetch() {
57
+ if (!this._fetchPromise) {
58
+ this._fetchPromise = $_fetch.call(this)
59
+ .then(() => {
60
+ delete this._fetchPromise;
61
+ });
62
+ }
63
+
64
+ return this._fetchPromise;
65
+ }
66
+
67
+ async function $_fetch() { // eslint-disable-line camelcase
68
+ this.$nuxt.nbFetching++;
69
+ this.$fetchState.pending = true;
70
+ this.$fetchState.error = null;
71
+ this._hydrated = false;
72
+ let error = null;
73
+ const startTime = Date.now();
74
+
75
+ try {
76
+ await this.$options.fetch.call(this);
77
+ } catch (err) {
78
+ if (process.dev) {
79
+ console.error('Error in fetch():', err); // eslint-disable-line no-console
80
+ }
81
+ error = normalizeError(err);
82
+ }
83
+
84
+ const delayLeft = this._fetchDelay - (Date.now() - startTime);
85
+
86
+ if (delayLeft > 0) {
87
+ await new Promise(resolve => setTimeout(resolve, delayLeft));
88
+ }
89
+
90
+ this.$fetchState.error = error;
91
+ this.$fetchState.pending = false;
92
+ this.$fetchState.timestamp = Date.now();
93
+
94
+ this.$nextTick(() => this.$nuxt.nbFetching--);
95
+ }
@@ -1,69 +1,73 @@
1
- import Vue from 'vue'
2
- import { hasFetch, normalizeError, addLifecycleHook, purifyData, createGetCounter } from '../utils'
1
+ import Vue from 'vue';
2
+ import {
3
+ hasFetch, normalizeError, addLifecycleHook, purifyData, createGetCounter
4
+ } from '../../utils/nuxt';
3
5
 
4
6
  async function serverPrefetch() {
5
7
  if (!this._fetchOnServer) {
6
- return
8
+ return;
7
9
  }
8
10
 
9
11
  // Call and await on $fetch
10
12
  try {
11
- await this.$options.fetch.call(this)
13
+ await this.$options.fetch.call(this);
12
14
  } catch (err) {
13
15
  if (process.dev) {
14
- console.error('Error in fetch():', err)
16
+ console.error('Error in fetch():', err); // eslint-disable-line no-console
15
17
  }
16
- this.$fetchState.error = normalizeError(err)
18
+ this.$fetchState.error = normalizeError(err);
17
19
  }
18
- this.$fetchState.pending = false
20
+ this.$fetchState.pending = false;
19
21
 
20
22
  // Define an ssrKey for hydration
21
- this._fetchKey = this._fetchKey || this.$ssrContext.fetchCounters['']++
23
+ this._fetchKey = this._fetchKey || this.$ssrContext.fetchCounters['']++;
22
24
 
23
25
  // Add data-fetch-key on parent element of Component
24
- const attrs = this.$vnode.data.attrs = this.$vnode.data.attrs || {}
25
- attrs['data-fetch-key'] = this._fetchKey
26
+ const attrs = this.$vnode.data.attrs = this.$vnode.data.attrs || {};
27
+
28
+ attrs['data-fetch-key'] = this._fetchKey;
26
29
 
27
30
  // Add to ssrContext for window.__NUXT__.fetch
28
31
 
29
32
  if (this.$ssrContext.nuxt.fetch[this._fetchKey] !== undefined) {
30
- console.warn(`Duplicate fetch key detected (${this._fetchKey}). This may lead to unexpected results.`)
33
+ console.warn(`Duplicate fetch key detected (${ this._fetchKey }). This may lead to unexpected results.`); // eslint-disable-line no-console
31
34
  }
32
35
 
33
36
  this.$ssrContext.nuxt.fetch[this._fetchKey] =
34
- this.$fetchState.error ? { _error: this.$fetchState.error } : purifyData(this._data)
37
+ this.$fetchState.error ? { _error: this.$fetchState.error } : purifyData(this._data);
35
38
  }
36
39
 
37
40
  export default {
38
41
  created() {
39
42
  if (!hasFetch(this)) {
40
- return
43
+ return;
41
44
  }
42
45
 
43
46
  if (typeof this.$options.fetchOnServer === 'function') {
44
- this._fetchOnServer = this.$options.fetchOnServer.call(this) !== false
47
+ this._fetchOnServer = this.$options.fetchOnServer.call(this) !== false;
45
48
  } else {
46
- this._fetchOnServer = this.$options.fetchOnServer !== false
49
+ this._fetchOnServer = this.$options.fetchOnServer !== false;
47
50
  }
48
51
 
49
- const defaultKey = this.$options._scopeId || this.$options.name || ''
50
- const getCounter = createGetCounter(this.$ssrContext.fetchCounters, defaultKey)
52
+ const defaultKey = this.$options._scopeId || this.$options.name || '';
53
+ const getCounter = createGetCounter(this.$ssrContext.fetchCounters, defaultKey);
51
54
 
52
55
  if (typeof this.$options.fetchKey === 'function') {
53
- this._fetchKey = this.$options.fetchKey.call(this, getCounter)
56
+ this._fetchKey = this.$options.fetchKey.call(this, getCounter);
54
57
  } else {
55
- const key = 'string' === typeof this.$options.fetchKey ? this.$options.fetchKey : defaultKey
56
- this._fetchKey = key ? key + ':' + getCounter(key) : String(getCounter(key))
58
+ const key = typeof this.$options.fetchKey === 'string' ? this.$options.fetchKey : defaultKey;
59
+
60
+ this._fetchKey = key ? `${ key }:${ getCounter(key) }` : String(getCounter(key));
57
61
  }
58
62
 
59
63
  // Added for remove vue undefined warning while ssr
60
- this.$fetch = () => {} // issue #8043
64
+ this.$fetch = () => {}; // issue #8043
61
65
  Vue.util.defineReactive(this, '$fetchState', {
62
- pending: true,
63
- error: null,
66
+ pending: true,
67
+ error: null,
64
68
  timestamp: Date.now()
65
- })
69
+ });
66
70
 
67
- addLifecycleHook(this, 'serverPrefetch', serverPrefetch)
71
+ addLifecycleHook(this, 'serverPrefetch', serverPrefetch);
68
72
  }
69
- }
73
+ };
@@ -122,7 +122,7 @@ export default Vue.extend({
122
122
  },
123
123
  validationMessage(): string | undefined {
124
124
  // we want to grab the required rule passed in if we can but if it's not there then we can just grab it from the formRulesGenerator
125
- const requiredRule = this.rules.find((rule: any) => rule?.name === 'required');
125
+ const requiredRule = this.rules.find((rule: any) => rule?.name === 'required') as Function;
126
126
  const ruleMessages = [];
127
127
  const value = this?.value;
128
128
 
@@ -134,7 +134,7 @@ export default Vue.extend({
134
134
  }
135
135
  }
136
136
 
137
- for (const rule of this.rules) {
137
+ for (const rule of this.rules as Function[]) {
138
138
  const message = rule(value);
139
139
 
140
140
  if (!!message && rule.name !== 'required') { // we're catching 'required' above so we can ignore it here
@@ -1,5 +1,6 @@
1
1
  import jsyaml from 'js-yaml';
2
2
  import SteveModel from '@shell/plugins/steve/steve-class';
3
+ import { downloadFile } from '@shell/utils/download';
3
4
 
4
5
  export const ENFORCEMENT_ACTION_VALUES = {
5
6
  DENY: 'deny',
@@ -7,6 +8,23 @@ export const ENFORCEMENT_ACTION_VALUES = {
7
8
  };
8
9
 
9
10
  export default class GateKeeperConstraint extends SteveModel {
11
+ get _availableActions() {
12
+ const out = super._availableActions;
13
+
14
+ const t = this.$rootGetters['i18n/t'];
15
+
16
+ const downloadViolations = {
17
+ action: 'downloadViolations',
18
+ icon: 'icon icon-fw icon-download',
19
+ label: t('gatekeeperConstraint.downloadViolations'),
20
+ total: 1,
21
+ };
22
+
23
+ out.unshift(downloadViolations);
24
+
25
+ return out;
26
+ }
27
+
10
28
  async save() {
11
29
  let constraint;
12
30
  let resourceVersion;
@@ -27,6 +45,25 @@ export default class GateKeeperConstraint extends SteveModel {
27
45
  await constraint.save();
28
46
  }
29
47
 
48
+ async downloadViolations() {
49
+ const Papa = await import(/* webpackChunkName: "csv" */'papaparse');
50
+
51
+ try {
52
+ const violations = (this.violations || []).map((violation) => {
53
+ delete violation.resourceLink;
54
+ delete violation.constraintLink;
55
+
56
+ return violation;
57
+ });
58
+
59
+ const csv = Papa.unparse(violations);
60
+
61
+ downloadFile(`violations-${ this.name }.csv`, csv, 'application/csv');
62
+ } catch (err) {
63
+ this.$dispatch('growl/fromError', { title: 'Error downloading file', err }, { root: true });
64
+ }
65
+ }
66
+
30
67
  cleanForNew() {
31
68
  this.$dispatch(`cleanForNew`, this);
32
69
 
package/models/pod.js CHANGED
@@ -129,6 +129,10 @@ export default class Pod extends WorkloadService {
129
129
  return workloads[0];
130
130
  }
131
131
 
132
+ get ownedByWorkload() {
133
+ return !!this.workloadRef;
134
+ }
135
+
132
136
  get details() {
133
137
  const out = [
134
138
  {
@@ -0,0 +1,16 @@
1
+ import HybridModel from '@shell/plugins/steve/hybrid-class';
2
+ import { GROUP, SERVICE_ACCOUNT, USER } from '@shell/config/types';
3
+
4
+ export default class ClusterRoleBinding extends HybridModel {
5
+ get users() {
6
+ return this.subjects?.filter(({ kind }) => kind?.toLowerCase() === USER);
7
+ }
8
+
9
+ get serviceAccounts() {
10
+ return this.subjects?.filter(({ kind }) => kind?.toLowerCase() === SERVICE_ACCOUNT);
11
+ }
12
+
13
+ get groups() {
14
+ return this.subjects?.filter(({ kind }) => kind?.toLowerCase() === GROUP);
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ import HybridModel from '@shell/plugins/steve/hybrid-class';
2
+ import { GROUP, SERVICE_ACCOUNT, USER } from '@shell/config/types';
3
+
4
+ export default class RoleBinding extends HybridModel {
5
+ get users() {
6
+ return this.subjects.filter(({ kind }) => kind?.toLowerCase() === USER);
7
+ }
8
+
9
+ get serviceAccounts() {
10
+ return this.subjects.filter(({ kind }) => kind?.toLowerCase() === SERVICE_ACCOUNT);
11
+ }
12
+
13
+ get groups() {
14
+ return this.subjects.filter(({ kind }) => kind?.toLowerCase() === GROUP);
15
+ }
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -36,21 +36,17 @@
36
36
  "@babel/preset-typescript": "7.16.7",
37
37
  "@innologica/vue-dropdown-menu": "0.1.3",
38
38
  "@novnc/novnc": "1.2.0",
39
- "@nuxt/types": "2.14.6",
40
39
  "@nuxt/typescript-build": "2.1.0",
41
40
  "@nuxtjs/axios": "5.12.0",
42
41
  "@nuxtjs/eslint-config-typescript": "6.0.1",
43
- "@nuxtjs/eslint-module": "1.2.0",
44
- "@nuxtjs/proxy": "1.3.3",
45
- "@nuxtjs/style-resources": "1.2.1",
46
42
  "@nuxtjs/webpack-profile": "0.1.0",
47
43
  "@popperjs/core": "2.4.4",
48
44
  "@types/node": "16.4.3",
49
45
  "@typescript-eslint/eslint-plugin": "4.33.0",
50
46
  "@typescript-eslint/parser": "4.33.0",
51
- "@vue/cli-plugin-babel": "4.5.15",
52
- "@vue/cli-plugin-typescript": "4.5.15",
53
- "@vue/cli-service": "4.5.15",
47
+ "@vue/cli-plugin-babel": "4.5.18",
48
+ "@vue/cli-plugin-typescript": "4.5.18",
49
+ "@vue/cli-service": "4.5.18",
54
50
  "@vue/test-utils": "1.2.1",
55
51
  "@vue/vue2-jest": "27.0.0",
56
52
  "add": "2.0.6",
@@ -82,7 +78,7 @@
82
78
  "eslint-plugin-import": "2.23.4",
83
79
  "eslint-plugin-jest": "24.4.0",
84
80
  "eslint-plugin-n": "15.2.0",
85
- "eslint-plugin-vue": "7.14.0",
81
+ "eslint-plugin-vue": "9.10.0",
86
82
  "event-target-shim": "5.0.1",
87
83
  "express": "4.17.1",
88
84
  "file-saver": "2.0.2",
@@ -109,7 +105,7 @@
109
105
  "nyc": "15.1.0",
110
106
  "papaparse": "5.3.0",
111
107
  "portal-vue": "2.1.7",
112
- "rancher-icons": "rancher/icons#v2.0.13",
108
+ "rancher-icons": "rancher/icons#v2.0.14",
113
109
  "require-extension-hooks": "0.3.3",
114
110
  "require-extension-hooks-babel": "1.0.0",
115
111
  "require-extension-hooks-vue": "3.0.0",
@@ -125,15 +121,15 @@
125
121
  "typescript": "4.1.6",
126
122
  "url-parse": "1.5.10",
127
123
  "v-tooltip": "2.0.3",
128
- "vue": "2.6.14",
124
+ "vue": "2.7.14",
129
125
  "vue-clipboard2": "0.3.1",
130
126
  "vue-codemirror": "4.0.6",
131
127
  "vue-js-modal": "1.3.35",
132
128
  "vue-resize": "0.4.5",
133
129
  "vue-select": "3.18.3",
134
- "vue-server-renderer": "2.6.14",
130
+ "vue-server-renderer": "2.7.14",
135
131
  "vue-shortkey": "3.1.7",
136
- "vue-template-compiler": "2.6.14",
132
+ "vue-template-compiler": "2.7.14",
137
133
  "vue-virtual-scroll-list": "^2.3.4",
138
134
  "vue2-transitions": "0.3.0",
139
135
  "vuedraggable": "2.24.3",