@rancher/shell 3.0.12-rc.5 → 3.0.12-rc.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 (89) hide show
  1. package/apis/intf/resources-api/resource-base.ts +42 -2
  2. package/apis/intf/resources-api/resource-instance.ts +101 -0
  3. package/apis/intf/resources-api/resources-api.ts +177 -23
  4. package/apis/intf/resources.ts +8 -6
  5. package/apis/resources/__tests__/resources-api-class.test.ts +309 -28
  6. package/apis/resources/resources-api-class.ts +232 -43
  7. package/assets/images/providers/traefik.png +0 -0
  8. package/assets/translations/en-us.yaml +10 -4
  9. package/chart/__tests__/rancher-monitoring-dashboards-index.test.ts +269 -0
  10. package/chart/rancher-monitoring-dashboards/index.vue +155 -0
  11. package/cloud-credential/__tests__/generic.test.ts +132 -0
  12. package/cloud-credential/generic.vue +33 -3
  13. package/components/EtcdInfoBanner.vue +2 -12
  14. package/components/GrafanaDashboard.vue +2 -8
  15. package/components/Resource/Detail/Masthead/__tests__/index.test.ts +68 -14
  16. package/components/Resource/Detail/Masthead/index.vue +8 -3
  17. package/components/form/Security.vue +1 -1
  18. package/components/formatter/Translate.vue +22 -1
  19. package/components/nav/Group.vue +5 -10
  20. package/components/nav/TopLevelMenu.vue +1 -30
  21. package/components/nav/__tests__/Group.test.ts +61 -0
  22. package/config/labels-annotations.js +1 -0
  23. package/config/table-headers.js +5 -2
  24. package/core/__tests__/plugin-products-apply.test.ts +787 -0
  25. package/core/__tests__/plugin-products-extend.test.ts +189 -0
  26. package/core/__tests__/plugin-products-helpers.test.ts +81 -78
  27. package/core/__tests__/plugin-products-new.test.ts +389 -0
  28. package/core/__tests__/plugin-products-scenarios.test.ts +980 -0
  29. package/core/__tests__/plugin-products-side-menu.test.ts +1935 -0
  30. package/core/plugin-products-base.ts +201 -93
  31. package/core/plugin-products-extending.ts +1 -1
  32. package/core/plugin-products-external.ts +380 -0
  33. package/core/plugin-products-helpers.ts +28 -24
  34. package/core/plugin-products-internal.ts +207 -0
  35. package/core/plugin-products-top-level.ts +10 -5
  36. package/core/plugin-products-type-guards.ts +17 -6
  37. package/core/plugin-products.ts +5 -7
  38. package/core/plugin-types.ts +1 -389
  39. package/core/plugin.ts +10 -11
  40. package/core/types.ts +6 -202
  41. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +52 -0
  42. package/detail/pod.vue +1 -1
  43. package/detail/provisioning.cattle.io.cluster.vue +0 -2
  44. package/edit/auth/AuthProviderWarningBanners.vue +12 -0
  45. package/edit/auth/__tests__/AuthProviderWarningBanners.test.ts +10 -1
  46. package/edit/auth/__tests__/azuread.test.ts +1 -0
  47. package/edit/auth/__tests__/github.test.ts +1 -0
  48. package/edit/auth/__tests__/oidc.test.ts +1 -0
  49. package/edit/auth/__tests__/saml.test.ts +1 -0
  50. package/edit/auth/ldap/__tests__/index.test.ts +1 -0
  51. package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
  52. package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -1
  53. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +2 -2
  54. package/list/management.cattle.io.user.vue +24 -5
  55. package/list/utils/management.cattle.io.cluster.utils.ts +1 -1
  56. package/machine-config/__tests__/generic.test.ts +163 -0
  57. package/machine-config/components/EC2Networking.vue +31 -7
  58. package/machine-config/components/__tests__/EC2Networking.test.ts +38 -15
  59. package/machine-config/generic.vue +32 -5
  60. package/mixins/resource-fetch.js +1 -1
  61. package/models/__tests__/rke-machine.cattle.io.vmwarevspheremachinetemplate.test.ts +22 -0
  62. package/models/pod.js +12 -10
  63. package/models/rke-machine.cattle.io.vmwarevspheremachinetemplate.js +9 -0
  64. package/package.json +1 -1
  65. package/pages/auth/login.vue +1 -1
  66. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +110 -0
  67. package/pages/c/_cluster/apps/charts/install.vue +29 -0
  68. package/pages/c/_cluster/auth/config/index.vue +11 -4
  69. package/pages/c/_cluster/monitoring/index.vue +6 -1
  70. package/plugins/dashboard-store/resource-class.js +10 -3
  71. package/plugins/steve/__tests__/steve-class-resource-api.test.ts +147 -0
  72. package/plugins/steve/steve-class.js +43 -0
  73. package/plugins/steve/subscribe.js +11 -0
  74. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +115 -0
  75. package/rancher-components/Form/LabeledInput/LabeledInput.vue +83 -3
  76. package/store/__tests__/auth.test.ts +18 -0
  77. package/store/__tests__/notifications.test.ts +466 -1
  78. package/store/__tests__/ui-context.test.ts +255 -0
  79. package/store/auth.js +11 -1
  80. package/store/features.js +1 -0
  81. package/store/plugins.js +6 -0
  82. package/types/rancher/steve.api.ts +2 -2
  83. package/types/shell/index.d.ts +58 -0
  84. package/types/store/dashboard-store.types.ts +2 -2
  85. package/types/store/type-map.ts +262 -1
  86. package/utils/async.ts +2 -0
  87. package/utils/grafana.js +2 -17
  88. package/utils/monitoring.js +38 -1
  89. package/core/__tests__/plugin-products.test.ts +0 -4694
@@ -1,5 +1,7 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import Masthead from '@shell/components/Resource/Detail/Masthead/index.vue';
3
+ import TitleBar from '@shell/components/Resource/Detail/TitleBar/index.vue';
4
+ import Metadata from '@shell/components/Resource/Detail/Metadata/index.vue';
3
5
  import Cards from '@shell/components/Resource/Detail/Cards.vue';
4
6
 
5
7
  jest.mock('@shell/utils/clipboard', () => ({ copyTextToClipboard: jest.fn() }));
@@ -19,16 +21,18 @@ describe('component: Masthead/index', () => {
19
21
  metadataProps: { items: [] }
20
22
  };
21
23
 
24
+ const globalStubs = {
25
+ stubs: {
26
+ TitleBar: true,
27
+ Metadata: true,
28
+ Cards: true
29
+ }
30
+ };
31
+
22
32
  it('should render the Cards component', () => {
23
33
  const wrapper = mount(Masthead, {
24
34
  props: defaultProps,
25
- global: {
26
- stubs: {
27
- TitleBar: true,
28
- Metadata: true,
29
- Cards: true
30
- }
31
- }
35
+ global: globalStubs
32
36
  });
33
37
 
34
38
  expect(wrapper.findComponent(Cards).exists()).toBe(true);
@@ -37,17 +41,67 @@ describe('component: Masthead/index', () => {
37
41
  it('should pass the resource from titleBarProps to Cards', () => {
38
42
  const wrapper = mount(Masthead, {
39
43
  props: defaultProps,
40
- global: {
41
- stubs: {
42
- TitleBar: true,
43
- Metadata: true,
44
- Cards: true
45
- }
46
- }
44
+ global: globalStubs
47
45
  });
48
46
 
49
47
  const cardsComponent = wrapper.findComponent(Cards);
50
48
 
51
49
  expect(cardsComponent.props('resource')).toStrictEqual(mockResource);
52
50
  });
51
+
52
+ it('should render TitleBar when titleBarProps is provided', () => {
53
+ const wrapper = mount(Masthead, {
54
+ props: defaultProps,
55
+ global: globalStubs
56
+ });
57
+
58
+ expect(wrapper.findComponent(TitleBar).exists()).toBe(true);
59
+ });
60
+
61
+ it('should render Metadata when metadataProps is provided', () => {
62
+ const wrapper = mount(Masthead, {
63
+ props: defaultProps,
64
+ global: globalStubs
65
+ });
66
+
67
+ expect(wrapper.findComponent(Metadata).exists()).toBe(true);
68
+ });
69
+
70
+ it('should not render TitleBar when titleBarProps is undefined', () => {
71
+ const wrapper = mount(Masthead, {
72
+ props: { titleBarProps: undefined, metadataProps: { items: [] } },
73
+ global: globalStubs
74
+ });
75
+
76
+ expect(wrapper.findComponent(TitleBar).exists()).toBe(false);
77
+ });
78
+
79
+ it('should not render Metadata when metadataProps is undefined', () => {
80
+ const wrapper = mount(Masthead, {
81
+ props: { titleBarProps: defaultProps.titleBarProps, metadataProps: undefined },
82
+ global: globalStubs
83
+ });
84
+
85
+ expect(wrapper.findComponent(Metadata).exists()).toBe(false);
86
+ });
87
+
88
+ it('should not render Cards when titleBarProps is undefined', () => {
89
+ const wrapper = mount(Masthead, {
90
+ props: { titleBarProps: undefined, metadataProps: undefined },
91
+ global: globalStubs
92
+ });
93
+
94
+ expect(wrapper.findComponent(Cards).exists()).toBe(false);
95
+ });
96
+
97
+ it('should not render any children when both props are undefined', () => {
98
+ const wrapper = mount(Masthead, {
99
+ props: { titleBarProps: undefined, metadataProps: undefined },
100
+ global: globalStubs
101
+ });
102
+
103
+ expect(wrapper.findComponent(TitleBar).exists()).toBe(false);
104
+ expect(wrapper.findComponent(Metadata).exists()).toBe(false);
105
+ expect(wrapper.findComponent(Cards).exists()).toBe(false);
106
+ });
53
107
  });
@@ -4,8 +4,8 @@ import Metadata, { MetadataProps } from '@shell/components/Resource/Detail/Metad
4
4
  import Cards from '@shell/components/Resource/Detail/Cards.vue';
5
5
 
6
6
  export interface MastheadProps {
7
- titleBarProps: TitleBarProps;
8
- metadataProps: MetadataProps;
7
+ titleBarProps?: TitleBarProps;
8
+ metadataProps?: MetadataProps;
9
9
  }
10
10
  </script>
11
11
 
@@ -15,7 +15,10 @@ const props = defineProps<MastheadProps>();
15
15
  </script>
16
16
  <template>
17
17
  <div class="masthead">
18
- <TitleBar v-bind="props.titleBarProps">
18
+ <TitleBar
19
+ v-if="props.titleBarProps"
20
+ v-bind="props.titleBarProps"
21
+ >
19
22
  <template
20
23
  v-if="$slots['additional-actions']"
21
24
  #additional-actions
@@ -24,10 +27,12 @@ const props = defineProps<MastheadProps>();
24
27
  </template>
25
28
  </TitleBar>
26
29
  <Metadata
30
+ v-if="props.metadataProps"
27
31
  class="metadata-section"
28
32
  v-bind="props.metadataProps"
29
33
  />
30
34
  <Cards
35
+ v-if="props.titleBarProps"
31
36
  class="cards-section"
32
37
  :resource="props.titleBarProps.resource"
33
38
  />
@@ -285,7 +285,7 @@ export default {
285
285
  </legend>
286
286
  <LabeledInput
287
287
  v-model:value.number="securityContext.runAsUser"
288
- type="number"
288
+ type="integer"
289
289
  min="0"
290
290
  :label="t('workload.container.security.runAsUser.label')"
291
291
  :mode="mode"
@@ -1,4 +1,6 @@
1
1
  <script>
2
+ import { get } from '@shell/utils/object';
3
+
2
4
  export default {
3
5
  props: {
4
6
  row: {
@@ -6,6 +8,11 @@ export default {
6
8
  required: true,
7
9
  },
8
10
 
11
+ fallbackPath: {
12
+ type: String,
13
+ default: '',
14
+ },
15
+
9
16
  prefix: {
10
17
  type: String,
11
18
  default: '',
@@ -18,8 +25,22 @@ export default {
18
25
  },
19
26
 
20
27
  computed: {
28
+ l10nId() {
29
+ return `${ this.prefix ? `${ this.prefix }.` : '' }${ this.value || this.row.id }`;
30
+ },
31
+
32
+ l10nFallback() {
33
+ const fallback = this.value;
34
+
35
+ if (this.fallbackPath) {
36
+ return get(this.row, this.fallbackPath) || fallback;
37
+ }
38
+
39
+ return fallback;
40
+ },
41
+
21
42
  text() {
22
- return this.$store.getters['i18n/withFallback'](`${ this.prefix }.${ this.value || this.row.id }`, null, this.value);
43
+ return this.$store.getters['i18n/withFallback'](this.l10nId, null, this.l10nFallback);
23
44
  },
24
45
  },
25
46
  };
@@ -384,14 +384,12 @@ export default {
384
384
  user-select: none;
385
385
  text-transform: none;
386
386
  font-size: 14px;
387
+ height: 100%;
388
+ padding: 8px 0 8px 16px;
389
+ display: inline-flex;
390
+ align-items: center;
387
391
  }
388
392
 
389
- > H6 {
390
- text-transform: none;
391
- height: 100%;
392
- padding: 8px 0 8px 16px;
393
- }
394
-
395
393
  > A {
396
394
  display: block;
397
395
  box-sizing:border-box;
@@ -403,10 +401,6 @@ export default {
403
401
  &:focus{
404
402
  outline:none;
405
403
  }
406
- > H6 {
407
- text-transform: none;
408
- padding: 8px 0 8px 16px;
409
- }
410
404
  }
411
405
  }
412
406
 
@@ -574,6 +568,7 @@ export default {
574
568
  padding-left: 24px;
575
569
  display: flex;
576
570
  justify-content: space-between;
571
+ align-items: center;
577
572
  }
578
573
 
579
574
  A:focus {
@@ -955,19 +955,6 @@ export default {
955
955
  <div
956
956
  class="footer"
957
957
  >
958
- <div
959
- v-if="canEditSettings"
960
- class="support"
961
- @click="hide()"
962
- >
963
- <router-link
964
- :to="{name: 'support'}"
965
- role="link"
966
- :aria-label="t('nav.ariaLabel.support')"
967
- >
968
- {{ t('nav.support', {hasSupport}) }}
969
- </router-link>
970
- </div>
971
958
  <div
972
959
  class="version"
973
960
  :class="{'version-small': largeAboutText}"
@@ -1574,10 +1561,6 @@ export default {
1574
1561
  margin: 20px 10px;
1575
1562
  width: 50px;
1576
1563
 
1577
- .support {
1578
- display: none;
1579
- }
1580
-
1581
1564
  .version{
1582
1565
  text-align: center;
1583
1566
 
@@ -1597,19 +1580,7 @@ export default {
1597
1580
  > * {
1598
1581
  flex: 1;
1599
1582
  color: var(--link);
1600
-
1601
- &:first-child {
1602
- text-align: left;
1603
- }
1604
- &:last-child {
1605
- text-align: right;
1606
- }
1607
- text-align: center;
1608
- }
1609
-
1610
- .support a:focus-visible {
1611
- @include focus-outline;
1612
- outline-offset: 4px;
1583
+ text-align: left;
1613
1584
  }
1614
1585
 
1615
1586
  .version {
@@ -64,4 +64,65 @@ describe('component: Group', () => {
64
64
 
65
65
  expect((wrapper.vm as any).hasActiveRoute()).toBe(true);
66
66
  });
67
+
68
+ describe('group header label', () => {
69
+ const mountGroup = (group: any) => shallowMount(Group as any, {
70
+ props: {
71
+ group, canCollapse: true, idPrefix: ''
72
+ },
73
+ global: {
74
+ stubs: { 'router-link': { template: '<a><slot /></a>' } },
75
+ mocks: {
76
+ $route: {
77
+ params: {}, path: '/test/route', fullPath: '/test/route', matched: []
78
+ },
79
+ $router: {
80
+ resolve: jest.fn().mockReturnValue({ path: '/test/route', fullPath: '/test/route' }),
81
+ getRoutes: jest.fn().mockReturnValue([])
82
+ },
83
+ t: (key: string) => key
84
+ }
85
+ }
86
+ });
87
+
88
+ it('renders the label in an h6 for a non-linked group header', () => {
89
+ const group = {
90
+ name: 'test',
91
+ label: 'My Group',
92
+ children: [
93
+ { route: { name: 'child-route', params: {} } }
94
+ ]
95
+ };
96
+
97
+ const wrapper = mountGroup(group);
98
+ const header = wrapper.find('.header');
99
+ const h6 = header.find('h6');
100
+
101
+ // Non-linked header: the label sits in a bare h6, not wrapped in a router-link
102
+ expect(header.find('a').exists()).toBe(false);
103
+ expect(h6.exists()).toBe(true);
104
+ expect(h6.find('span').html()).toContain('My Group');
105
+ });
106
+
107
+ it('renders the label in an h6 wrapped in a router-link for a group header with overview', () => {
108
+ const group = {
109
+ name: 'test',
110
+ label: 'My Group',
111
+ children: [
112
+ {
113
+ route: { name: 'overview-route' }, overview: true, exact: true
114
+ }
115
+ ]
116
+ };
117
+
118
+ const wrapper = mountGroup(group);
119
+ const link = wrapper.find('.header a');
120
+ const h6 = link.find('h6');
121
+
122
+ // Linked header: the same h6 label markup is wrapped in a router-link
123
+ expect(link.exists()).toBe(true);
124
+ expect(h6.exists()).toBe(true);
125
+ expect(h6.find('span').html()).toContain('My Group');
126
+ });
127
+ });
67
128
  });
@@ -20,6 +20,7 @@ export const IMPORTED_CLUSTER_VERSION_MANAGEMENT = 'rancher.io/imported-cluster-
20
20
  export const UI_PROJECT_SECRET = 'management.cattle.io/project-scoped-secret';
21
21
  export const UI_PROJECT_SECRET_COPY = 'management.cattle.io/project-scoped-secret-copy';
22
22
  export const SERVICE_LINKS = 'ui.rancher/service-links';
23
+ export const NODE_DRIVER_FIELD_HINTS = 'io.cattle.nodedriver/ui-field-hints';
23
24
 
24
25
  export const KUBERNETES = {
25
26
  SERVICE_ACCOUNT_UID: 'kubernetes.io/service-account.uid',
@@ -1072,11 +1072,14 @@ export const ROLE = {
1072
1072
  export const FEATURE_DESCRIPTION = {
1073
1073
  name: 'description',
1074
1074
  labelKey: 'tableHeaders.description',
1075
- value: 'status.description',
1075
+ value: 'id',
1076
1076
  align: 'left',
1077
1077
  sort: ['status.description'],
1078
1078
  formatter: 'Translate',
1079
- formatterOpts: { prefix: 'featureFlags.description' },
1079
+ formatterOpts: {
1080
+ prefix: 'featureFlags.description',
1081
+ fallbackPath: 'status.description'
1082
+ },
1080
1083
  };
1081
1084
 
1082
1085
  export const STATE_NORMAN = {