@rancher/shell 0.1.21 → 0.2.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 (99) hide show
  1. package/assets/styles/global/_button.scss +1 -0
  2. package/assets/translations/en-us.yaml +56 -10
  3. package/assets/translations/zh-hans.yaml +346 -117
  4. package/components/Carousel.vue +25 -9
  5. package/components/HarvesterServiceAddOnConfig.vue +10 -10
  6. package/components/Import.vue +7 -1
  7. package/components/ResourceList/index.vue +34 -14
  8. package/components/ResourceTable.vue +19 -0
  9. package/components/SortableTable/THead.vue +311 -70
  10. package/components/SortableTable/advanced-filtering.js +272 -0
  11. package/components/SortableTable/filtering.js +90 -29
  12. package/components/SortableTable/index.vue +480 -271
  13. package/components/form/MatchExpressions.vue +15 -3
  14. package/components/form/WorkloadPorts.vue +2 -2
  15. package/components/nav/Header.vue +14 -1
  16. package/config/product/settings.js +1 -0
  17. package/config/product/uiplugins.js +1 -0
  18. package/config/uiplugins.js +13 -0
  19. package/creators/app/init +2 -2
  20. package/creators/app/package.json +1 -1
  21. package/creators/pkg/package.json +1 -1
  22. package/detail/cis.cattle.io.clusterscan.vue +6 -2
  23. package/detail/provisioning.cattle.io.cluster.vue +3 -3
  24. package/edit/provisioning.cattle.io.cluster/DrainOptions.vue +0 -1
  25. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +5 -3
  26. package/edit/provisioning.cattle.io.cluster/rke2.vue +25 -24
  27. package/edit/service.vue +1 -1
  28. package/list/node.vue +7 -2
  29. package/mixins/resource-manager.js +5 -0
  30. package/models/cluster.x-k8s.io.machinedeployment.js +8 -0
  31. package/models/management.cattle.io.cluster.js +14 -1
  32. package/nuxt.config.js +113 -108
  33. package/package.json +1 -1
  34. package/pages/c/_cluster/apps/charts/index.vue +1 -1
  35. package/pages/c/_cluster/apps/charts/install.vue +106 -32
  36. package/pages/c/_cluster/settings/performance.vue +11 -0
  37. package/pages/c/_cluster/uiplugins/InstallDialog.vue +16 -2
  38. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +5 -2
  39. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +28 -6
  40. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +1 -1
  41. package/pages/c/_cluster/uiplugins/index.vue +49 -12
  42. package/promptRemove/mixin/roleDeletionCheck.js +15 -1
  43. package/scripts/record-deps.js +3 -3
  44. package/scripts/test-plugins-build.sh +1 -0
  45. package/scripts/typegen.sh +2 -2
  46. package/store/type-map.js +13 -2
  47. package/types/vue-shim.d +20 -0
  48. package/utils/create-yaml.js +30 -6
  49. package/creators/update/yarn-error.log +0 -54
  50. package/rancher-components/BadgeState/BadgeState.spec.ts +0 -12
  51. package/rancher-components/BadgeState/BadgeState.vue +0 -107
  52. package/rancher-components/BadgeState/index.ts +0 -1
  53. package/rancher-components/Banner/Banner.test.ts +0 -13
  54. package/rancher-components/Banner/Banner.vue +0 -163
  55. package/rancher-components/Banner/index.ts +0 -1
  56. package/rancher-components/Card/Card.vue +0 -150
  57. package/rancher-components/Card/index.ts +0 -1
  58. package/rancher-components/Form/Checkbox/Checkbox.test.ts +0 -77
  59. package/rancher-components/Form/Checkbox/Checkbox.vue +0 -395
  60. package/rancher-components/Form/Checkbox/index.ts +0 -1
  61. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +0 -29
  62. package/rancher-components/Form/LabeledInput/LabeledInput.vue +0 -343
  63. package/rancher-components/Form/LabeledInput/index.ts +0 -1
  64. package/rancher-components/Form/Radio/RadioButton.vue +0 -270
  65. package/rancher-components/Form/Radio/RadioGroup.vue +0 -235
  66. package/rancher-components/Form/Radio/index.ts +0 -2
  67. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +0 -168
  68. package/rancher-components/Form/TextArea/index.ts +0 -1
  69. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +0 -107
  70. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +0 -137
  71. package/rancher-components/Form/ToggleSwitch/index.ts +0 -1
  72. package/rancher-components/Form/index.ts +0 -5
  73. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +0 -137
  74. package/rancher-components/LabeledTooltip/index.ts +0 -1
  75. package/rancher-components/components/BadgeState/BadgeState.spec.ts +0 -12
  76. package/rancher-components/components/BadgeState/BadgeState.vue +0 -107
  77. package/rancher-components/components/BadgeState/index.ts +0 -1
  78. package/rancher-components/components/Banner/Banner.test.ts +0 -13
  79. package/rancher-components/components/Banner/Banner.vue +0 -163
  80. package/rancher-components/components/Banner/index.ts +0 -1
  81. package/rancher-components/components/Card/Card.vue +0 -150
  82. package/rancher-components/components/Card/index.ts +0 -1
  83. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +0 -77
  84. package/rancher-components/components/Form/Checkbox/Checkbox.vue +0 -395
  85. package/rancher-components/components/Form/Checkbox/index.ts +0 -1
  86. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +0 -29
  87. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +0 -343
  88. package/rancher-components/components/Form/LabeledInput/index.ts +0 -1
  89. package/rancher-components/components/Form/Radio/RadioButton.vue +0 -270
  90. package/rancher-components/components/Form/Radio/RadioGroup.vue +0 -235
  91. package/rancher-components/components/Form/Radio/index.ts +0 -2
  92. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +0 -168
  93. package/rancher-components/components/Form/TextArea/index.ts +0 -1
  94. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +0 -107
  95. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +0 -137
  96. package/rancher-components/components/Form/ToggleSwitch/index.ts +0 -1
  97. package/rancher-components/components/Form/index.ts +0 -5
  98. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -137
  99. package/rancher-components/components/LabeledTooltip/index.ts +0 -1
@@ -24,6 +24,7 @@ export default {
24
24
 
25
25
  data() {
26
26
  return {
27
+ currentVersion: '',
27
28
  defaultRegistrySetting: null,
28
29
  plugin: undefined,
29
30
  busy: false,
@@ -43,7 +44,16 @@ export default {
43
44
  return [];
44
45
  }
45
46
 
46
- return this.plugin.versions.map((version) => {
47
+ // Don't allow update/rollback to curent version
48
+ const versions = this.plugin.versions.filter((v) => {
49
+ if (this.currentVersion) {
50
+ return v.version !== this.currentVersion;
51
+ }
52
+
53
+ return true;
54
+ });
55
+
56
+ return versions.map((version) => {
47
57
  return {
48
58
  label: version.version,
49
59
  value: version.version,
@@ -65,6 +75,8 @@ export default {
65
75
  this.version = plugin.displayVersion;
66
76
 
67
77
  if (mode === 'update') {
78
+ this.currentVersion = plugin.displayVersion;
79
+
68
80
  // Update to latest version, so take the first version
69
81
  if (plugin.versions.length > 0) {
70
82
  this.version = plugin.versions[0].version;
@@ -73,6 +85,8 @@ export default {
73
85
  // Find the newest version once we remove the current version
74
86
  const versionNames = plugin.versions.filter(v => v.version !== plugin.displayVersion);
75
87
 
88
+ this.currentVersion = plugin.displayVersion;
89
+
76
90
  if (versionNames.length > 0) {
77
91
  this.version = versionNames[0].version;
78
92
  }
@@ -208,7 +222,7 @@ export default {
208
222
  >
209
223
  <div v-if="plugin" class="plugin-install-dialog">
210
224
  <h4 class="mt-10">
211
- {{ t(`plugins.${ mode }.title`, { name: plugin.name }) }}
225
+ {{ t(`plugins.${ mode }.title`, { name: plugin.label }) }}
212
226
  </h4>
213
227
  <div class="custom mt-10">
214
228
  <div class="dialog-panel">
@@ -117,8 +117,11 @@ export default {
117
117
  </div>
118
118
  <div>
119
119
  <Banner v-if="info.error" color="error" :label="info.error" class="mt-10" />
120
- <Banner v-if="!info.certified" color="warning" :label="t('plugins.descriptions.third-party')" class="mt-10" />
121
- <Banner v-if="info.experimental" color="warning" :label="t('plugins.descriptions.experimental')" class="mt-10" />
120
+ <Banner v-if="info.builtin" color="warning" :label="t('plugins.descriptions.built-in')" class="mt-10" />
121
+ <template v-else>
122
+ <Banner v-if="!info.certified" color="warning" :label="t('plugins.descriptions.third-party')" class="mt-10" />
123
+ <Banner v-if="info.experimental" color="warning" :label="t('plugins.descriptions.experimental')" class="mt-10" />
124
+ </template>
122
125
  </div>
123
126
 
124
127
  <h3 v-if="info.versions.length">
@@ -7,6 +7,7 @@ import {
7
7
  UI_PLUGIN_CHARTS,
8
8
  UI_PLUGINS_REPO_NAME,
9
9
  UI_PLUGINS_REPO_URL,
10
+ UI_PLUGIN_OPERATOR_CRD_CHART_NAME,
10
11
  } from '@shell/config/uiplugins';
11
12
 
12
13
  export default {
@@ -21,13 +22,23 @@ export default {
21
22
 
22
23
  this.defaultRepo = repos.find(r => r.name === UI_PLUGINS_REPO_NAME && r.spec.gitRepo === UI_PLUGINS_REPO_URL);
23
24
  }
25
+
26
+ if (this.$store.getters['management/schemaFor'](UI_PLUGIN)) {
27
+ const plugins = await this.$store.dispatch('management/findAll', { type: UI_PLUGIN });
28
+
29
+ // Are there any plugins installed?
30
+ this.hasPluginsInstalled = (plugins || []).length > 0;
31
+ this.removeCRD = !this.hasPluginsInstalled;
32
+ }
24
33
  },
25
34
 
26
35
  data() {
27
36
  return {
28
- errors: [],
29
- defaultRepo: undefined,
30
- removeRepo: false,
37
+ errors: [],
38
+ defaultRepo: undefined,
39
+ removeRepo: false,
40
+ removeCRD: true,
41
+ hasPluginsInstalled: false,
31
42
  };
32
43
  },
33
44
 
@@ -42,8 +53,8 @@ export default {
42
53
  return found.remove();
43
54
  }
44
55
 
45
- // TODO - Return rejected promise - error
46
- return null;
56
+ // Return rejected promise - could not find the required chart
57
+ return Promise.reject(new Error(`Could not find chart §{ name }`));
47
58
  },
48
59
 
49
60
  showDialog() {
@@ -55,7 +66,12 @@ export default {
55
66
  this.errors = [];
56
67
 
57
68
  // Remove the charts in the reverse order that we install them in
58
- const uninstall = [...UI_PLUGIN_CHARTS].reverse();
69
+ let uninstall = [...UI_PLUGIN_CHARTS].reverse();
70
+
71
+ if (!this.removeCRD) {
72
+ // User does not want to uninstall the CRD, so remove the chart
73
+ uninstall = uninstall.filter(chart => chart !== UI_PLUGIN_OPERATOR_CRD_CHART_NAME);
74
+ }
59
75
 
60
76
  for (let i = 0; i < uninstall.length; i++) {
61
77
  const chart = uninstall[i];
@@ -103,6 +119,12 @@ export default {
103
119
  {{ t('plugins.setup.remove.registry.prompt') }}
104
120
  </div>
105
121
  </div>
122
+ <div v-if="hasPluginsInstalled" class="mt-20">
123
+ <Checkbox v-model="removeCRD" :primary="true" label-key="plugins.setup.remove.crd.title" />
124
+ <div class="checkbox-info">
125
+ {{ t('plugins.setup.remove.crd.prompt') }}
126
+ </div>
127
+ </div>
106
128
  </template>
107
129
  </Dialog>
108
130
  </template>
@@ -69,7 +69,7 @@ export default {
69
69
  >
70
70
  <div v-if="plugin" class="plugin-install-dialog">
71
71
  <h4 class="mt-10">
72
- {{ t('plugins.uninstall.title', { name: plugin.name }) }}
72
+ {{ t('plugins.uninstall.title', { name: plugin.label }) }}
73
73
  </h4>
74
74
  <div class="mt-10 dialog-panel">
75
75
  <div class="dialog-info">
@@ -6,7 +6,7 @@ import { sortBy } from '@shell/utils/sort';
6
6
  import { allHash } from '@shell/utils/promise';
7
7
  import { CATALOG, UI_PLUGIN, SERVICE } from '@shell/config/types';
8
8
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
9
-
9
+ import { NAME as APP_PRODUCT } from '@shell/config/product/apps';
10
10
  import ActionMenu from '@shell/components/ActionMenu';
11
11
  import Tabbed from '@shell/components/Tabbed/index.vue';
12
12
  import Tab from '@shell/components/Tabbed/Tab.vue';
@@ -18,7 +18,14 @@ import DeveloperInstallDialog from './DeveloperInstallDialog.vue';
18
18
  import PluginInfoPanel from './PluginInfoPanel.vue';
19
19
  import SetupUIPlugins from './SetupUIPlugins';
20
20
  import RemoveUIPlugins from './RemoveUIPlugins';
21
- import { isUIPlugin, uiPluginHasAnnotation, isSupportedChartVersion, UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
21
+ import {
22
+ isUIPlugin,
23
+ uiPluginAnnotation,
24
+ uiPluginHasAnnotation,
25
+ isSupportedChartVersion,
26
+ UI_PLUGIN_NAMESPACE,
27
+ UI_PLUGIN_CHART_ANNOTATIONS
28
+ } from '@shell/config/uiplugins';
22
29
 
23
30
  const MAX_DESCRIPTION_LENGTH = 200;
24
31
 
@@ -100,17 +107,25 @@ export default {
100
107
  menuActions() {
101
108
  const menuActions = [];
102
109
 
110
+ // Add link to go to the Repos view of the local cluster
111
+ menuActions.push({
112
+ action: 'manageRepos',
113
+ label: this.t('plugins.manageRepos'),
114
+ enabled: true
115
+ });
116
+
103
117
  // Only show Developer Load action if the user has this enabled in preferences
104
118
  if (this.pluginDeveloper) {
119
+ menuActions.push( { divider: true });
105
120
  menuActions.push({
106
121
  action: 'devLoad',
107
122
  label: this.t('plugins.developer.label'),
108
123
  enabled: true
109
124
  });
110
- menuActions.push( { divider: true });
111
125
  }
112
126
 
113
127
  if (this.hasService) {
128
+ menuActions.push( { divider: true });
114
129
  menuActions.push({
115
130
  action: 'removePluginSupport',
116
131
  label: this.t('plugins.setup.remove.label'),
@@ -156,8 +171,11 @@ export default {
156
171
  all = all.filter(c => !uiPluginHasAnnotation(c, CATALOG_ANNOTATIONS.HIDDEN, 'true'));
157
172
 
158
173
  all = all.map((chart) => {
174
+ // Label can be overridden by chart annotation
175
+ const label = uiPluginAnnotation(UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME) || chart.chartNameDisplay;
159
176
  const item = {
160
177
  name: chart.chartNameDisplay,
178
+ label,
161
179
  description: chart.chartDescription,
162
180
  id: chart.id,
163
181
  versions: [],
@@ -197,7 +215,9 @@ export default {
197
215
  // A pluign is loaded, but there is no chart, so add an item so that it shows up
198
216
  const item = {
199
217
  name: p.name,
218
+ label: p.name,
200
219
  description: p.metadata?.description,
220
+ icon: p.metadata?.icon,
201
221
  id: p.id,
202
222
  versions: [],
203
223
  displayVersion: p.metadata?.version || '-',
@@ -229,6 +249,7 @@ export default {
229
249
  // No chart, so add a card for the plugin based on its Custom resource being present
230
250
  const item = {
231
251
  name: p.name,
252
+ label: p.name,
232
253
  description: p.description || '-',
233
254
  id: `${ p.name }-${ p.version }`,
234
255
  versions: [],
@@ -317,11 +338,11 @@ export default {
317
338
 
318
339
  plugins(neu, old) {
319
340
  const installed = this.$store.getters['uiplugins/plugins'];
320
-
341
+ const shouldHaveLoaded = (installed || []).filter(p => !this.uiErrors[p.name] && !p.builtin);
321
342
  let changes = 0;
322
343
 
323
344
  // Did the user remove an extension
324
- if (neu?.length < installed.length) {
345
+ if (neu?.length < shouldHaveLoaded.length) {
325
346
  changes++;
326
347
  }
327
348
 
@@ -329,7 +350,9 @@ export default {
329
350
  const existing = installed.find(p => !p.removed && p.name === plugin.name && p.version === plugin.version);
330
351
 
331
352
  if (!existing && plugin.isCached) {
332
- changes++;
353
+ if (!this.uiErrors[plugin.name]) {
354
+ changes++;
355
+ }
333
356
 
334
357
  this.updatePluginInstallStatus(plugin.name, false);
335
358
  }
@@ -441,6 +464,17 @@ export default {
441
464
 
442
465
  reload() {
443
466
  this.$router.go();
467
+ },
468
+
469
+ manageRepos() {
470
+ this.$router.push({
471
+ name: 'c-cluster-product-resource',
472
+ params: {
473
+ cluster: 'local',
474
+ product: APP_PRODUCT,
475
+ resource: CATALOG.CLUSTER_REPO
476
+ }
477
+ });
444
478
  }
445
479
  }
446
480
  };
@@ -479,6 +513,7 @@ export default {
479
513
  @close="setMenu(false)"
480
514
  @devLoad="showDeveloperLoaddDialog"
481
515
  @removePluginSupport="removePluginSupport"
516
+ @manageRepos="manageRepos"
482
517
  />
483
518
  </div>
484
519
 
@@ -528,14 +563,11 @@ export default {
528
563
  </div>
529
564
  <div class="plugin-metadata">
530
565
  <div class="plugin-name">
531
- {{ plugin.name }}
566
+ {{ plugin.label }}
532
567
  </div>
533
568
  <div>{{ plugin.description }}</div>
534
- <div v-if="plugin.builtin" class="plugin-builtin">
535
- {{ t('plugins.labels.builtin') }}
536
- </div>
537
569
  <div class="plugin-version">
538
- <span v-if="plugin.installing === 'uninstall'" class="plugin-installing">
570
+ <span v-if="plugin.installing" class="plugin-installing">
539
571
  -
540
572
  </span>
541
573
  <span v-else>
@@ -543,7 +575,12 @@ export default {
543
575
  <span v-if="plugin.upgrade" v-tooltip="t('plugins.upgradeAvailable')"> -> {{ plugin.upgrade }}</span>
544
576
  </span>
545
577
  </div>
546
- <div class="plugin-badges">
578
+ <div v-if="plugin.builtin" class="plugin-badges">
579
+ <div class="plugin-builtin">
580
+ {{ t('plugins.labels.builtin') }}
581
+ </div>
582
+ </div>
583
+ <div v-else class="plugin-badges">
547
584
  <div v-if="!plugin.certified" v-tooltip="t('plugins.descriptions.third-party')">
548
585
  {{ t('plugins.labels.third-party') }}
549
586
  </div>
@@ -66,12 +66,26 @@ export default {
66
66
  method: 'get',
67
67
  }, { root: true });
68
68
 
69
+ // We need to fetch the users here in order to get an accurate count when selecting global roles.
70
+ const users = await this.$store.dispatch('management/request', {
71
+ url: `/v1/${ MANAGEMENT.USER }`,
72
+ method: 'get',
73
+ }, { root: true });
74
+
75
+ const userMap = users.data?.reduce((map, user) => {
76
+ if ( user.username ) {
77
+ map[user.id] = user;
78
+ }
79
+
80
+ return map;
81
+ }, {});
82
+
69
83
  if (request.data && request.data.length) {
70
84
  rolesToRemove.forEach((toRemove) => {
71
85
  const usedRoles = request.data.filter(item => item[propToMatch] === toRemove.id);
72
86
 
73
87
  if (usedRoles.length) {
74
- const uniqueUsers = [...new Set(usedRoles.map(item => item.userName))];
88
+ const uniqueUsers = [...new Set(usedRoles.map(item => item.userName).filter(user => userMap[user]))];
75
89
 
76
90
  if (uniqueUsers.length) {
77
91
  numberOfRolesWithBinds++;
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
4
  // Script lives in shell/scripts, so work out top-level dir from there
5
- const topDir = path.resolve(__dirname, '..', '..')
5
+ const topDir = path.resolve(__dirname, '..', '..');
6
6
  const dir = process.cwd();
7
7
 
8
8
  // Read the package.json file
@@ -17,10 +17,10 @@ if (mainPkg._requires) {
17
17
  // Map each one to the same version as the main package
18
18
  const out = {};
19
19
 
20
- mainPkg._requires.forEach(name => {
20
+ mainPkg._requires.forEach((name) => {
21
21
  let ver = topPkg.dependencies?.[name] || topPkg.devDependencies?.[name];
22
22
 
23
- if (name === '@rancher/components') {
23
+ if (name === '@rancher/components') {
24
24
  const componentsPkgFile = path.join(topDir, 'pkg', 'rancher-components', 'package.json');
25
25
  const componentsPkg = JSON.parse(fs.readFileSync(componentsPkgFile));
26
26
 
@@ -80,6 +80,7 @@ rm ${SHELL_DIR}/package.json.bak
80
80
 
81
81
  # Publish shell
82
82
  echo "Publishing shell packages to local registry"
83
+ yarn install
83
84
  ${SHELL_DIR}/scripts/publish-shell.sh
84
85
 
85
86
  if [ "${SKIP_STANDALONE}" == "false" ]; then
@@ -46,8 +46,8 @@ echo "// Auto-generated type definitions for shell" > ${INDEX}
46
46
  echo "// Do not modify this file as changes will get overwritten" >> ${INDEX}
47
47
 
48
48
  # Copy in the vue shim type definitions
49
- if [ -f "$BASE_DIR/vue-shim.d.ts" ]; then
50
- cat "$BASE_DIR/vue-shim.d.ts" >> ${INDEX}
49
+ if [ -f "$BASE_DIR/shell/types/vue-shim.d" ]; then
50
+ cat "$BASE_DIR/shell/types/vue-shim.d" >> ${INDEX}
51
51
  fi
52
52
 
53
53
  function processDir() {
package/store/type-map.js CHANGED
@@ -121,7 +121,13 @@
121
121
  // continueOnMatch
122
122
  // )
123
123
  import { AGE, NAME, NAMESPACE as NAMESPACE_COL, STATE } from '@shell/config/table-headers';
124
- import { COUNT, SCHEMA, MANAGEMENT, NAMESPACE } from '@shell/config/types';
124
+ import {
125
+ CATALOG,
126
+ COUNT,
127
+ SCHEMA,
128
+ MANAGEMENT,
129
+ NAMESPACE
130
+ } from '@shell/config/types';
125
131
  import { VIEW_IN_API, EXPANDED_GROUPS, FAVORITE_TYPES } from '@shell/store/prefs';
126
132
  import {
127
133
  addObject, findBy, insertAt, isArray, removeObject, filterBy
@@ -218,6 +224,8 @@ export function DSL(store, product, module = 'type-map') {
218
224
  headers.forEach((header) => {
219
225
  // If on the client, then use the value getter if there is one
220
226
  if (header.getValue) {
227
+ // we need to store the .value prop for the advanced filtering
228
+ header.valueProp = header.value;
221
229
  header.value = header.getValue;
222
230
  }
223
231
 
@@ -1760,8 +1768,11 @@ function ifHave(getters, option) {
1760
1768
  export function isAdminUser(getters) {
1761
1769
  const canEditSettings = (getters['management/schemaFor'](MANAGEMENT.SETTING)?.resourceMethods || []).includes('PUT');
1762
1770
  const canEditFeatureFlags = (getters['management/schemaFor'](MANAGEMENT.FEATURE)?.resourceMethods || []).includes('PUT');
1771
+ const canInstallApps = (getters['management/schemaFor'](CATALOG.APP)?.resourceMethods || []).includes('PUT');
1772
+ const canAddRepos = (getters['management/schemaFor'](CATALOG.CLUSTER_REPO)?.resourceMethods || []).includes('PUT');
1773
+ const canPutHelmOperations = (getters['management/schemaFor'](CATALOG.OPERATION)?.resourceMethods || []).includes('PUT');
1763
1774
 
1764
- return canEditSettings && canEditFeatureFlags;
1775
+ return canEditSettings && canEditFeatureFlags && canInstallApps && canAddRepos && canPutHelmOperations;
1765
1776
  }
1766
1777
 
1767
1778
  // Is V1 Istio installed?
@@ -0,0 +1,20 @@
1
+ declare module '*.vue' {
2
+ import Vue from 'vue';
3
+ export default Vue;
4
+ }
5
+
6
+ // This is required to keep typescript from complaining. It is required for
7
+ // our i18n plugin. For more info see:
8
+ // https://v2.vuejs.org/v2/guide/typescript.html?redirect=true#Augmenting-Types-for-Use-with-Plugins
9
+ declare module 'vue/types/vue' {
10
+ // eslint-disable-next-line no-unused-vars
11
+ interface Vue {
12
+ /**
13
+ * Lookup a given string with the given arguments
14
+ * @param raw if set, do not do HTML escaping.
15
+ */
16
+ t: (key: string, args?: Record<string, any>, raw?: boolean) => string,
17
+ }
18
+ }
19
+
20
+ declare module 'js-yaml';
@@ -1,7 +1,7 @@
1
1
  import { indent as _indent } from '@shell/utils/string';
2
2
  import { addObject, findBy, removeObject, removeObjects } from '@shell/utils/array';
3
3
  import jsyaml from 'js-yaml';
4
- import { cleanUp } from '@shell/utils/object';
4
+ import { cleanUp, isEmpty } from '@shell/utils/object';
5
5
 
6
6
  export const SIMPLE_TYPES = [
7
7
  'string',
@@ -114,7 +114,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
114
114
  }
115
115
  }
116
116
 
117
- // Mark any fields that are passed in as data as regular so they're not commented out
117
+ // Include all fields in schema's resourceFields as comments
118
118
  const commentFields = Object.keys(schema.resourceFields || {});
119
119
 
120
120
  commentFields.forEach((key) => {
@@ -123,12 +123,14 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
123
123
  }
124
124
  });
125
125
 
126
+ // add any fields defined in data as uncommented fields in yaml
126
127
  for ( const key in data ) {
127
128
  if ( typeof data[key] !== 'undefined' ) {
128
129
  addObject(regularFields, key);
129
130
  }
130
131
  }
131
132
 
133
+ // ACTIVELY_REMOVE are fields that should be removed even if they are defined in data
132
134
  for ( const entry of ACTIVELY_REMOVE ) {
133
135
  const parts = entry.split(/\./);
134
136
  const key = parts[parts.length - 1];
@@ -139,6 +141,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
139
141
  }
140
142
  }
141
143
 
144
+ // NEVER_ADD are fields that should not be added as comments, but may added as regular fields if already defined in data
142
145
  for ( const entry of NEVER_ADD ) {
143
146
  const parts = entry.split(/\./);
144
147
  const key = parts[parts.length - 1];
@@ -149,6 +152,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
149
152
  }
150
153
  }
151
154
 
155
+ // do not include commented fields if already defined in data
152
156
  removeObjects(commentFields, regularFields);
153
157
 
154
158
  const regular = regularFields.map(k => stringifyField(k));
@@ -183,6 +187,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
183
187
  out = 'type:';
184
188
  }
185
189
 
190
+ // if a key on data is not listed in the schema's resourceFields, just convert it to yaml, add indents where needed, and return
186
191
  if ( !field ) {
187
192
  if (data[key]) {
188
193
  try {
@@ -209,7 +214,9 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
209
214
  const arrayOf = typeRef('array', type);
210
215
  const referenceTo = typeRef('reference', type);
211
216
 
217
+ // type == map[mapOf]
212
218
  if ( mapOf ) {
219
+ // if key is defined in data, convert the value to yaml, add newline+indent and add to output yaml string
213
220
  if (data[key]) {
214
221
  try {
215
222
  const cleaned = cleanUp(data);
@@ -224,17 +231,20 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
224
231
  if ( SIMPLE_TYPES.includes(mapOf) ) {
225
232
  out += `\n# key: ${ mapOf }`;
226
233
  } else {
234
+ // If not a simple type ie some sort of object/array, recusively build out commented fields (note data = null here) per the type's (mapOf's) schema
227
235
  const chunk = createYaml(schemas, mapOf, null, processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
228
- let indented = indent(chunk, 2);
236
+ let indented = indent(chunk);
229
237
 
238
+ // convert "# foo" to "#foo"
230
239
  indented = indented.replace(/^(#)?\s\s\s\s/, '$1');
231
240
 
232
- out += `\n ${ indented }`;
241
+ out += `\n${ indented }`;
233
242
  }
234
243
 
235
244
  return out;
236
245
  }
237
246
 
247
+ // type == array[arrayOf]
238
248
  if ( arrayOf ) {
239
249
  if (data[key]) {
240
250
  try {
@@ -256,6 +266,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
256
266
  const chunk = createYaml(schemas, arrayOf, null, false, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
257
267
  let indented = indent(chunk, 2);
258
268
 
269
+ // turn "# foo" into "# - foo"
259
270
  indented = indented.replace(/^(#)?\s*\s\s([^\s])/, '$1 - $2');
260
271
 
261
272
  out += `\n${ indented }`;
@@ -303,8 +314,21 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
303
314
 
304
315
  const subDef = findBy(schemas, 'id', type);
305
316
 
306
- if ( subDef ) {
307
- const chunk = createYaml(schemas, type, data[key], processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
317
+ if ( subDef) {
318
+ let chunk;
319
+
320
+ if (subDef?.resourceFields && !isEmpty(subDef?.resourceFields)) {
321
+ chunk = createYaml(schemas, type, data[key], processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
322
+ } else if (data[key]) {
323
+ // if there are no fields defined on the schema but there are in the data, just format data as yaml and add to output yaml
324
+ try {
325
+ const parsed = jsyaml.dump(data[key]);
326
+
327
+ chunk = parsed.trim();
328
+ } catch (e) {
329
+ console.error(`Error: Unale to parse data for yaml of type: ${ type }`, e); // eslint-disable-line no-console
330
+ }
331
+ }
308
332
 
309
333
  out += `\n${ indent(chunk) }`;
310
334
  } else {
@@ -1,54 +0,0 @@
1
- Arguments:
2
- /usr/local/bin/node /usr/local/Cellar/yarn/1.22.11/libexec/bin/yarn.js add @rancher/pkg@0.0.0
3
-
4
- PATH:
5
- /Users/nwm/.gem/ruby/3.1.2/bin:/Users/nwm/.rubies/ruby-3.1.2/lib/ruby/gems/3.1.0/bin:/Users/nwm/.rubies/ruby-3.1.2/bin:/Users/nwm/.deno/bin:/usr/local/sbin:/opt/local/bin:/opt/local/sbin:/Users/nwm/.rd/bin:/Users/nwm/go/bin:/usr/local/bin:/Users/nwm/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/usr/local/MacGPG2/bin:/Library/Apple/usr/bin:/Users/nwm/.deno/bin:/usr/local/sbin:/Users/nwm/google-cloud-sdk/bin:/opt/local/bin:/opt/local/sbin:/Users/nwm/.rd/bin:/Users/nwm/go/bin:/Users/nwm/bin:/Applications/Utilities/kdiff3.app/Contents/MacOS/:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/Applications/Utilities/kdiff3.app/Contents/MacOS/:/Applications/Visual Studio Code.app/Contents/Resources/app/bin
6
-
7
- Yarn version:
8
- 1.22.11
9
-
10
- Node version:
11
- 16.16.0
12
-
13
- Platform:
14
- darwin x64
15
-
16
- Trace:
17
- Error: https://registry.yarnpkg.com/@rancher%2fpkg: Not found
18
- at Request.params.callback [as _callback] (/usr/local/Cellar/yarn/1.22.11/libexec/lib/cli.js:66992:18)
19
- at Request.self.callback (/usr/local/Cellar/yarn/1.22.11/libexec/lib/cli.js:140763:22)
20
- at Request.emit (node:events:527:28)
21
- at Request.<anonymous> (/usr/local/Cellar/yarn/1.22.11/libexec/lib/cli.js:141735:10)
22
- at Request.emit (node:events:527:28)
23
- at IncomingMessage.<anonymous> (/usr/local/Cellar/yarn/1.22.11/libexec/lib/cli.js:141657:12)
24
- at Object.onceWrapper (node:events:641:28)
25
- at IncomingMessage.emit (node:events:539:35)
26
- at endReadableNT (node:internal/streams/readable:1345:12)
27
- at processTicksAndRejections (node:internal/process/task_queues:83:21)
28
-
29
- npm manifest:
30
- {
31
- "name": "@rancher/create-app",
32
- "description": "Rancher UI Upgrade helper",
33
- "version": "0.0.0",
34
- "license": "Apache-2.0",
35
- "author": "SUSE",
36
- "private": false,
37
- "bin": "./init",
38
- "files": [
39
- "*.*",
40
- "init"
41
- ],
42
- "engines": {
43
- "node": ">=12"
44
- },
45
- "dependencies": {
46
- "fs-extra": "^10.0.0"
47
- }
48
- }
49
-
50
- yarn manifest:
51
- No manifest
52
-
53
- Lockfile:
54
- No lockfile
@@ -1,12 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
- import { BadgeState } from './index';
3
-
4
- describe('BadgeState.vue', () => {
5
- it('renders props.msg when passed', () => {
6
- const label = 'Hello, World!';
7
-
8
- const wrapper = shallowMount(BadgeState, { propsData: { label } });
9
-
10
- expect(wrapper.find('span').text()).toMatch(label);
11
- });
12
- });