@rancher/shell 0.2.1 → 0.2.3

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 (56) hide show
  1. package/assets/translations/en-us.yaml +9 -5
  2. package/assets/translations/zh-hans.yaml +328 -117
  3. package/components/Carousel.vue +25 -9
  4. package/components/Import.vue +7 -1
  5. package/components/SortableTable/index.vue +7 -1
  6. package/components/form/MatchExpressions.vue +15 -3
  7. package/components/nav/Header.vue +14 -1
  8. package/detail/cis.cattle.io.clusterscan.vue +6 -2
  9. package/detail/provisioning.cattle.io.cluster.vue +2 -2
  10. package/edit/provisioning.cattle.io.cluster/ACE.vue +1 -2
  11. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +5 -3
  12. package/list/node.vue +7 -2
  13. package/mixins/resource-manager.js +5 -0
  14. package/models/cluster.x-k8s.io.machinedeployment.js +8 -0
  15. package/models/management.cattle.io.cluster.js +6 -1
  16. package/nuxt.config.js +113 -108
  17. package/package.json +1 -1
  18. package/pages/c/_cluster/apps/charts/index.vue +1 -1
  19. package/pages/c/_cluster/apps/charts/install.vue +24 -38
  20. package/pages/c/_cluster/settings/performance.vue +11 -0
  21. package/pages/c/_cluster/uiplugins/InstallDialog.vue +15 -1
  22. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +28 -6
  23. package/pages/c/_cluster/uiplugins/index.vue +1 -1
  24. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -7
  25. package/scripts/publish-shell.sh +1 -1
  26. package/scripts/test-plugins-build.sh +1 -0
  27. package/scripts/typegen.sh +2 -2
  28. package/store/type-map.js +11 -2
  29. package/types/vue-shim.d +20 -0
  30. package/utils/create-yaml.js +30 -6
  31. package/creators/update/yarn-error.log +0 -54
  32. package/rancher-components/components/BadgeState/BadgeState.spec.ts +0 -12
  33. package/rancher-components/components/BadgeState/BadgeState.vue +0 -107
  34. package/rancher-components/components/BadgeState/index.ts +0 -1
  35. package/rancher-components/components/Banner/Banner.test.ts +0 -13
  36. package/rancher-components/components/Banner/Banner.vue +0 -163
  37. package/rancher-components/components/Banner/index.ts +0 -1
  38. package/rancher-components/components/Card/Card.vue +0 -150
  39. package/rancher-components/components/Card/index.ts +0 -1
  40. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +0 -77
  41. package/rancher-components/components/Form/Checkbox/Checkbox.vue +0 -395
  42. package/rancher-components/components/Form/Checkbox/index.ts +0 -1
  43. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +0 -29
  44. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +0 -343
  45. package/rancher-components/components/Form/LabeledInput/index.ts +0 -1
  46. package/rancher-components/components/Form/Radio/RadioButton.vue +0 -270
  47. package/rancher-components/components/Form/Radio/RadioGroup.vue +0 -235
  48. package/rancher-components/components/Form/Radio/index.ts +0 -2
  49. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +0 -168
  50. package/rancher-components/components/Form/TextArea/index.ts +0 -1
  51. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +0 -107
  52. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +0 -137
  53. package/rancher-components/components/Form/ToggleSwitch/index.ts +0 -1
  54. package/rancher-components/components/Form/index.ts +0 -5
  55. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -137
  56. package/rancher-components/components/LabeledTooltip/index.ts +0 -1
@@ -1,6 +1,9 @@
1
1
  <script>
2
2
  import { get } from '@shell/utils/object';
3
3
  import { BadgeState } from '@components/BadgeState';
4
+ import { mapGetters } from 'vuex';
5
+
6
+ const carouselSeenStorageKey = `carousel-seen`;
4
7
 
5
8
  export default {
6
9
  components: { BadgeState },
@@ -31,16 +34,18 @@ export default {
31
34
  default: 'noopener noreferrer nofollow'
32
35
  },
33
36
  },
37
+
34
38
  data() {
35
39
  return {
36
- slider: this.sliders,
37
- activeItemId: 0,
38
- autoScroll: true
40
+ slider: this.sliders,
41
+ activeItemId: 0,
42
+ autoScroll: true,
43
+ autoScrollSlideInterval: null,
39
44
  };
40
45
  },
41
46
 
42
47
  computed: {
43
-
48
+ ...mapGetters(['clusterId']),
44
49
  trackStyle() {
45
50
  const sliderItem = this.activeItemId * 100 / this.slider.length;
46
51
  const width = 60 * this.slider.length;
@@ -77,9 +82,6 @@ export default {
77
82
  this.slidePosition();
78
83
  },
79
84
 
80
- timer() {
81
- setInterval(this.autoScrollSlide, 2000);
82
- },
83
85
  autoScrollSlide() {
84
86
  if (this.activeItemId < this.slider.length && this.autoScroll ) {
85
87
  this.activeItemId++;
@@ -103,9 +105,23 @@ export default {
103
105
  }
104
106
  },
105
107
 
108
+ beforeDestroy() {
109
+ if (this.autoScrollSlideInterval) {
110
+ clearInterval(this.autoScrollSlideInterval);
111
+ }
112
+ },
113
+
106
114
  mounted() {
107
- this.timer();
108
- }
115
+ const lastSeenCluster = sessionStorage.getItem(carouselSeenStorageKey);
116
+
117
+ if (lastSeenCluster !== this.clusterId) {
118
+ // Session storage lasts until tab/window closed (retained on refresh)
119
+ sessionStorage.setItem(carouselSeenStorageKey, this.clusterId);
120
+
121
+ this.autoScrollSlideInterval = setInterval(this.autoScrollSlide, 5000);
122
+ }
123
+ },
124
+
109
125
  };
110
126
 
111
127
  </script>
@@ -27,6 +27,13 @@ export default {
27
27
  SortableTable
28
28
  },
29
29
 
30
+ props: {
31
+ defaultNamespace: {
32
+ type: String,
33
+ default: 'default'
34
+ },
35
+ },
36
+
30
37
  async fetch() {
31
38
  this.allNamespaces = await this.$store.dispatch('cluster/findAll', { type: NAMESPACE, opt: { url: 'namespaces' } });
32
39
  },
@@ -34,7 +41,6 @@ export default {
34
41
  data() {
35
42
  return {
36
43
  currentYaml: '',
37
- defaultNamespace: 'default',
38
44
  allNamespaces: null,
39
45
  errors: null,
40
46
  rows: null,
@@ -716,7 +716,11 @@ export default {
716
716
  }
717
717
 
718
718
  if (isLabel) {
719
- return row.metadata.labels[col.label];
719
+ if (row.metadata?.labels && row.metadata?.labels[col.label]) {
720
+ return row.metadata?.labels[col.label];
721
+ }
722
+
723
+ return '';
720
724
  }
721
725
 
722
726
  // Use to debug table columns using expensive value getters
@@ -1181,6 +1185,8 @@ export default {
1181
1185
  :full-colspan="fullColspan"
1182
1186
  :row="row.row"
1183
1187
  :sub-matches="subMatches"
1188
+ :onRowMouseEnter="onRowMouseEnter"
1189
+ :onRowMouseLeave="onRowMouseLeave"
1184
1190
  >
1185
1191
  <tr
1186
1192
  v-if="row.row.stateDescription"
@@ -5,9 +5,10 @@ import { mapGetters } from 'vuex';
5
5
  import { isArray, removeObject } from '@shell/utils/array';
6
6
  import { clone } from '@shell/utils/object';
7
7
  import { convert, simplify } from '@shell/utils/selector';
8
+ import LabeledSelect from '@shell/components/form/LabeledSelect';
8
9
 
9
10
  export default {
10
- components: { Select },
11
+ components: { Select, LabeledSelect },
11
12
  props: {
12
13
  // Array of actual match expressions
13
14
  // or k8s selector Object of {matchExpressions, matchLabels}
@@ -38,6 +39,12 @@ export default {
38
39
  showRemove: {
39
40
  type: Boolean,
40
41
  default: true
42
+ },
43
+
44
+ // if options are passed for keys, then the key's input will become a select
45
+ keysSelectOptions: {
46
+ type: Array,
47
+ default: () => []
41
48
  }
42
49
  },
43
50
 
@@ -108,6 +115,10 @@ export default {
108
115
  return POD;
109
116
  },
110
117
 
118
+ hasKeySelectOptions() {
119
+ return !!this.keysSelectOptions?.length;
120
+ },
121
+
111
122
  ...mapGetters({ t: 'i18n/t' })
112
123
  },
113
124
 
@@ -194,11 +205,12 @@ export default {
194
205
  <div v-if="isView">
195
206
  {{ row.key }}
196
207
  </div>
197
- <input
208
+ <input v-else-if="!hasKeySelectOptions" v-model="row.key" :mode="mode" @input="update" />
209
+ <LabeledSelect
198
210
  v-else
199
211
  v-model="row.key"
200
212
  :mode="mode"
201
- @input="update"
213
+ :options="keysSelectOptions"
202
214
  />
203
215
  </div>
204
216
  <div
@@ -109,6 +109,19 @@ export default {
109
109
  return !this.featureRancherDesktop;
110
110
  },
111
111
 
112
+ showFilter() {
113
+ // Some products won't have a current cluster
114
+ const validClusterOrProduct = this.currentCluster ||
115
+ (this.currentProduct && this.currentProduct.customNamespaceFilter) ||
116
+ (this.currentProduct && this.currentProduct.showWorkspaceSwitcher);
117
+ // Don't show if the header is in 'simple' mode
118
+ const notSimple = !this.simple;
119
+ // One of these must be enabled, otherwise t here's no component to show
120
+ const validFilterSettings = this.currentProduct.showNamespaceFilter || this.currentProduct.showWorkspaceSwitcher;
121
+
122
+ return validClusterOrProduct && notSimple && validFilterSettings;
123
+ },
124
+
112
125
  featureRancherDesktop() {
113
126
  return this.$config.rancherEnv === 'desktop';
114
127
  },
@@ -332,7 +345,7 @@ export default {
332
345
  <component :is="navHeaderRight" />
333
346
 
334
347
  <div
335
- v-if="(currentCluster || (currentProduct && currentProduct.customNamespaceFilter)) && !simple && (currentProduct.showNamespaceFilter || currentProduct.showWorkspaceSwitcher)"
348
+ v-if="showFilter"
336
349
  class="top"
337
350
  >
338
351
  <NamespaceFilter v-if="clusterReady && currentProduct && (currentProduct.showNamespaceFilter || isExplorer)" />
@@ -290,8 +290,12 @@ export default {
290
290
  :headers="reportCheckHeaders"
291
291
  key-field="id"
292
292
  >
293
- <template #sub-row="{row, fullColspan}">
294
- <tr class="sub-row">
293
+ <template #sub-row="{row, fullColspan, onRowMouseEnter, onRowMouseLeave}">
294
+ <tr
295
+ class="sub-row"
296
+ @mouseenter="onRowMouseEnter"
297
+ @mouseleave="onRowMouseLeave"
298
+ >
295
299
  <td :colspan="fullColspan">
296
300
  <Banner v-if="(row.state==='fail' || row.state==='warn')&& row.remediation" class="sub-banner" :label="remediationDisplay(row)" color="warning" />
297
301
  <SortableTable
@@ -631,11 +631,11 @@ export default {
631
631
  </div>
632
632
  </div>
633
633
  <div v-if="group.ref" class="right mr-45">
634
- <template v-if="value.hasLink('update')">
634
+ <template v-if="value.hasLink('update') && group.ref.showScalePool">
635
635
  <button v-tooltip="t('node.list.scaleDown')" :disabled="!group.ref.canScaleDownPool()" type="button" class="btn btn-sm role-secondary" @click="group.ref.scalePool(-1)">
636
636
  <i class="icon icon-sm icon-minus" />
637
637
  </button>
638
- <button v-tooltip="t('node.list.scaleUp')" type="button" class="btn btn-sm role-secondary ml-10" @click="group.ref.scalePool(1)">
638
+ <button v-tooltip="t('node.list.scaleUp')" :disabled="!group.ref.canScaleUpPool()" type="button" class="btn btn-sm role-secondary ml-10" @click="group.ref.scalePool(1)">
639
639
  <i class="icon icon-sm icon-plus" />
640
640
  </button>
641
641
  </template>
@@ -4,7 +4,6 @@ import { LabeledInput } from '@components/Form/LabeledInput';
4
4
  import FileSelector, { createOnSelected } from '@shell/components/form/FileSelector';
5
5
  import { set } from '@shell/utils/object';
6
6
  import isEmpty from 'lodash/isEmpty';
7
- import { _CREATE } from '@shell/config/query-params';
8
7
 
9
8
  export default {
10
9
  components: {
@@ -24,7 +23,7 @@ export default {
24
23
  },
25
24
 
26
25
  data() {
27
- if ( isEmpty(this.value?.spec?.localClusterAuthEndpoint) && this.mode === _CREATE ) {
26
+ if ( isEmpty(this.value?.spec?.localClusterAuthEndpoint) ) {
28
27
  set(this.value, 'spec.localClusterAuthEndpoint', {
29
28
  enabled: false,
30
29
  caCerts: '',
@@ -35,9 +35,10 @@ export default {
35
35
  default: () => ({})
36
36
  },
37
37
 
38
+ // no credentials are required for elemental machine pools
38
39
  credentialId: {
39
- type: String,
40
- required: true,
40
+ type: String,
41
+ default: null
41
42
  },
42
43
 
43
44
  mode: {
@@ -219,7 +220,8 @@ export default {
219
220
  :machine-pools="machinePools"
220
221
  @error="e=>errors = e"
221
222
  />
222
- <Banner v-else color="info" label="You do not have access to see this machine pool's configuration." />
223
+ <Banner v-else-if="value.configMissing" color="error" label-key="cluster.machinePool.configNotFound" />
224
+ <Banner v-else color="info" label-key="cluster.machinePool.noAccessBanner" />
223
225
 
224
226
  <AdvancedSection :mode="mode" class="advanced">
225
227
  <portal-target :name="'advanced-' + uuid" multiple />
package/list/node.vue CHANGED
@@ -153,8 +153,13 @@ export default {
153
153
  :loading="loading"
154
154
  v-on="$listeners"
155
155
  >
156
- <template #sub-row="{fullColspan, row}">
157
- <tr class="taints sub-row" :class="{'empty-taints': !row.spec.taints || !row.spec.taints.length}">
156
+ <template #sub-row="{fullColspan, row, onRowMouseEnter, onRowMouseLeave}">
157
+ <tr
158
+ class="taints sub-row"
159
+ :class="{'empty-taints': !row.spec.taints || !row.spec.taints.length}"
160
+ @mouseenter="onRowMouseEnter"
161
+ @mouseleave="onRowMouseLeave"
162
+ >
158
163
  <template v-if="row.spec.taints && row.spec.taints.length">
159
164
  <td>&nbsp;</td>
160
165
  <td>&nbsp;</td>
@@ -74,6 +74,11 @@ export default {
74
74
  // - id param = this.$store.getters['cluster/keyFieldForType'](type)
75
75
  // - id value = new dashboard-store getter, overwritten by steve store getter
76
76
  requestData.forEach((item) => {
77
+ // if there's already a prop type, don't overwrite it without storing it first...
78
+ // only do this operation once in multiple apply's because the requestData is the same!
79
+ if (item.type && !item._type) {
80
+ item._type = item.type;
81
+ }
77
82
  item.type = type;
78
83
  item.id = `${ item.metadata.namespace }/${ item.metadata.name }`;
79
84
  });
@@ -159,6 +159,14 @@ export default class CapiMachineDeployment extends SteveModel {
159
159
  return notOnlyOfRole(this, this.cluster.machines);
160
160
  }
161
161
 
162
+ canScaleUpPool() {
163
+ return true;
164
+ }
165
+
166
+ get showScalePool() {
167
+ return this.canScaleDownPool() || this.canScaleUpPool();
168
+ }
169
+
162
170
  get stateParts() {
163
171
  const out = [
164
172
  {
@@ -432,7 +432,12 @@ export default class MgmtCluster extends HybridModel {
432
432
  }
433
433
 
434
434
  get provClusterId() {
435
- const verb = this.isLocal ? 'to' : 'from';
435
+ const isRKE1 = !!this.spec?.rancherKubernetesEngineConfig;
436
+ // Note: RKE1 provisioning cluster IDs are in a different format. For example,
437
+ // RKE2 cluster IDs include the name - fleet-default/cluster-name - whereas an RKE1
438
+ // cluster has the less human readable management cluster ID in it: fleet-default/c-khk48
439
+
440
+ const verb = this.isLocal || isRKE1 ? 'to' : 'from';
436
441
  const from = `${ verb }Type`;
437
442
  const id = `${ verb }Id`;
438
443
 
package/nuxt.config.js CHANGED
@@ -10,6 +10,29 @@ import { trimWhitespaceSsr as trimWhitespace } from './plugins/trim-whitespace';
10
10
 
11
11
  const createProxyMiddleware = require('http-proxy-middleware');
12
12
 
13
+ // Global variables
14
+ let api = process.env.API || 'http://localhost:8989';
15
+
16
+ if ( !api.startsWith('http') ) {
17
+ api = `https://${ api }`;
18
+ }
19
+
20
+ // needed for proxies
21
+ export const API_PATH = api;
22
+
23
+ const dev = (process.env.NODE_ENV !== 'production');
24
+ const devPorts = dev || process.env.DEV_PORTS === 'true';
25
+ const version = process.env.VERSION ||
26
+ process.env.DRONE_TAG ||
27
+ process.env.DRONE_VERSION ||
28
+ require('./package.json').version;
29
+
30
+ const prime = process.env.PRIME;
31
+
32
+ const pl = process.env.PL || STANDARD;
33
+ const commit = process.env.COMMIT || 'head';
34
+ const perfTest = (process.env.PERF_TEST === 'true'); // Enable performance testing when in dev
35
+
13
36
  // ===============================================================================================
14
37
  // Nuxt configuration
15
38
  // ===============================================================================================
@@ -195,25 +218,6 @@ export default function(dir, _appConfig) {
195
218
  require('events').EventEmitter.defaultMaxListeners = 20;
196
219
  require('dotenv').config();
197
220
 
198
- const version = process.env.VERSION ||
199
- process.env.DRONE_TAG ||
200
- process.env.DRONE_VERSION ||
201
- require('./package.json').version;
202
-
203
- const prime = process.env.PRIME;
204
-
205
- const dev = (process.env.NODE_ENV !== 'production');
206
- const devPorts = dev || process.env.DEV_PORTS === 'true';
207
- const pl = process.env.PL || STANDARD;
208
- const commit = process.env.COMMIT || 'head';
209
- const perfTest = (process.env.PERF_TEST === 'true'); // Enable performance testing when in dev
210
-
211
- let api = process.env.API || 'http://localhost:8989';
212
-
213
- if ( !api.startsWith('http') ) {
214
- api = `https://${ api }`;
215
- }
216
-
217
221
  let routerBasePath = '/';
218
222
  let resourceBase = '';
219
223
  let outputDir = 'dist';
@@ -587,6 +591,7 @@ export default function(dir, _appConfig) {
587
591
 
588
592
  // Proxy: https://github.com/nuxt-community/proxy-module#options
589
593
  proxy: {
594
+ ...appConfig.proxies,
590
595
  '/k8s': proxyWsOpts(api), // Straight to a remote cluster (/k8s/clusters/<id>/)
591
596
  '/pp': proxyWsOpts(api), // For (epinio) standalone API
592
597
  '/api': proxyWsOpts(api), // Management k8s API
@@ -637,114 +642,114 @@ export default function(dir, _appConfig) {
637
642
  };
638
643
 
639
644
  return config;
645
+ }
640
646
 
641
- // ===============================================================================================
642
- // Functions for the request proxying used in dev
643
- // ===============================================================================================
644
-
645
- function proxyMetaOpts(target) {
646
- return {
647
- target,
648
- followRedirects: true,
649
- secure: !dev,
650
- onProxyReq,
651
- onProxyReqWs,
652
- onError,
653
- onProxyRes,
654
- };
655
- }
656
-
657
- function proxyOpts(target) {
658
- return {
659
- target,
660
- secure: !devPorts,
661
- onProxyReq,
662
- onProxyReqWs,
663
- onError,
664
- onProxyRes,
665
- };
666
- }
647
+ // ===============================================================================================
648
+ // Functions for the request proxying used in dev
649
+ // ===============================================================================================
667
650
 
668
- // Intercept the /rancherversion API call wnad modify the 'RancherPrime' value
669
- // if configured to do so by the environment variable PRIME
670
- function proxyPrimeOpts(target) {
671
- const opts = proxyOpts(target);
651
+ export function proxyMetaOpts(target) {
652
+ return {
653
+ target,
654
+ followRedirects: true,
655
+ secure: !dev,
656
+ onProxyReq,
657
+ onProxyReqWs,
658
+ onError,
659
+ onProxyRes,
660
+ };
661
+ }
672
662
 
673
- // Don't intercept if the PRIME environment variable is not set
674
- if (!prime?.length) {
675
- return opts;
676
- }
663
+ export function proxyOpts(target) {
664
+ return {
665
+ target,
666
+ secure: !devPorts,
667
+ onProxyReq,
668
+ onProxyReqWs,
669
+ onError,
670
+ onProxyRes,
671
+ };
672
+ }
677
673
 
678
- opts.onProxyRes = (proxyRes, req, res) => {
679
- const _end = res.end;
680
- let body = '';
674
+ // Intercept the /rancherversion API call wnad modify the 'RancherPrime' value
675
+ // if configured to do so by the environment variable PRIME
676
+ export function proxyPrimeOpts(target) {
677
+ const opts = proxyOpts(target);
681
678
 
682
- proxyRes.on( 'data', (data) => {
683
- data = data.toString('utf-8');
684
- body += data;
685
- });
679
+ // Don't intercept if the PRIME environment variable is not set
680
+ if (!prime?.length) {
681
+ return opts;
682
+ }
686
683
 
687
- res.write = () => {};
684
+ opts.onProxyRes = (proxyRes, req, res) => {
685
+ const _end = res.end;
686
+ let body = '';
688
687
 
689
- res.end = () => {
690
- let output = body;
688
+ proxyRes.on( 'data', (data) => {
689
+ data = data.toString('utf-8');
690
+ body += data;
691
+ });
691
692
 
692
- try {
693
- const out = JSON.parse(body);
693
+ res.write = () => {};
694
694
 
695
- out.RancherPrime = prime;
696
- output = JSON.stringify(out);
697
- } catch (err) {}
695
+ res.end = () => {
696
+ let output = body;
698
697
 
699
- res.setHeader('content-length', output.length );
700
- res.setHeader('content-type', 'application/json' );
701
- res.setHeader('transfer-encoding', '');
702
- res.setHeader('cache-control', 'no-cache');
703
- res.writeHead(proxyRes.statusCode);
704
- _end.apply(res, [output]);
705
- };
698
+ try {
699
+ const out = JSON.parse(body);
700
+
701
+ out.RancherPrime = prime;
702
+ output = JSON.stringify(out);
703
+ } catch (err) {}
704
+
705
+ res.setHeader('content-length', output.length );
706
+ res.setHeader('content-type', 'application/json' );
707
+ res.setHeader('transfer-encoding', '');
708
+ res.setHeader('cache-control', 'no-cache');
709
+ res.writeHead(proxyRes.statusCode);
710
+ _end.apply(res, [output]);
706
711
  };
712
+ };
707
713
 
708
- return opts;
709
- }
710
-
711
- function onProxyRes(proxyRes, req, res) {
712
- if (devPorts) {
713
- proxyRes.headers['X-Frame-Options'] = 'ALLOWALL';
714
- }
715
- }
714
+ return opts;
715
+ }
716
716
 
717
- function proxyWsOpts(target) {
718
- return {
719
- ...proxyOpts(target),
720
- ws: true,
721
- changeOrigin: true,
722
- };
717
+ export function onProxyRes(proxyRes, req, res) {
718
+ if (devPorts) {
719
+ proxyRes.headers['X-Frame-Options'] = 'ALLOWALL';
723
720
  }
721
+ }
724
722
 
725
- function onProxyReq(proxyReq, req) {
726
- if (!(proxyReq._currentRequest && proxyReq._currentRequest._headerSent)) {
727
- proxyReq.setHeader('x-api-host', req.headers['host']);
728
- proxyReq.setHeader('x-forwarded-proto', 'https');
729
- // console.log(proxyReq.getHeaders());
730
- }
731
- }
723
+ export function proxyWsOpts(target) {
724
+ return {
725
+ ...proxyOpts(target),
726
+ ws: true,
727
+ changeOrigin: true,
728
+ };
729
+ }
732
730
 
733
- function onProxyReqWs(proxyReq, req, socket, options, head) {
734
- req.headers.origin = options.target.href;
735
- proxyReq.setHeader('origin', options.target.href);
731
+ export function onProxyReq(proxyReq, req) {
732
+ if (!(proxyReq._currentRequest && proxyReq._currentRequest._headerSent)) {
736
733
  proxyReq.setHeader('x-api-host', req.headers['host']);
737
734
  proxyReq.setHeader('x-forwarded-proto', 'https');
738
735
  // console.log(proxyReq.getHeaders());
739
-
740
- socket.on('error', (err) => {
741
- console.error('Proxy WS Error:', err); // eslint-disable-line no-console
742
- });
743
736
  }
737
+ }
744
738
 
745
- function onError(err, req, res) {
746
- res.statusCode = 598;
747
- console.error('Proxy Error:', err); // eslint-disable-line no-console
748
- res.write(JSON.stringify(err));
749
- }
739
+ export function onProxyReqWs(proxyReq, req, socket, options, head) {
740
+ req.headers.origin = options.target.href;
741
+ proxyReq.setHeader('origin', options.target.href);
742
+ proxyReq.setHeader('x-api-host', req.headers['host']);
743
+ proxyReq.setHeader('x-forwarded-proto', 'https');
744
+ // console.log(proxyReq.getHeaders());
745
+
746
+ socket.on('error', (err) => {
747
+ console.error('Proxy WS Error:', err); // eslint-disable-line no-console
748
+ });
749
+ }
750
+
751
+ export function onError(err, req, res) {
752
+ res.statusCode = 598;
753
+ console.error('Proxy Error:', err); // eslint-disable-line no-console
754
+ res.write(JSON.stringify(err));
750
755
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -353,7 +353,7 @@ export default {
353
353
  </div>
354
354
  </header>
355
355
  <div v-if="showCarousel">
356
- <h3>Featured Charts</h3>
356
+ <h3>{{ t('catalog.charts.featuredCharts') }}</h3>
357
357
  <Carousel
358
358
  :sliders="getFeaturedCharts"
359
359
  @clicked="(row) => selectChart(row)"