@rancher/shell 3.0.7 → 3.0.8-rc.1

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 (83) hide show
  1. package/assets/images/vendor/githubapp.svg +13 -0
  2. package/assets/styles/base/_typography.scss +1 -1
  3. package/assets/styles/themes/_modern.scss +5 -5
  4. package/assets/translations/en-us.yaml +91 -11
  5. package/assets/translations/zh-hans.yaml +0 -4
  6. package/components/Inactivity.vue +222 -106
  7. package/components/InstallHelmCharts.vue +2 -2
  8. package/components/ResourceDetail/index.vue +1 -1
  9. package/components/SortableTable/index.vue +17 -2
  10. package/components/fleet/FleetConfigMapSelector.vue +117 -0
  11. package/components/fleet/FleetSecretSelector.vue +127 -0
  12. package/components/fleet/__tests__/FleetConfigMapSelector.test.ts +125 -0
  13. package/components/fleet/__tests__/FleetSecretSelector.test.ts +82 -0
  14. package/components/form/FileImageSelector.vue +13 -4
  15. package/components/form/FileSelector.vue +11 -2
  16. package/components/form/ResourceLabeledSelect.vue +1 -0
  17. package/components/form/__tests__/ResourceLabeledSelect.test.ts +90 -0
  18. package/components/nav/Header.vue +1 -0
  19. package/config/product/auth.js +1 -0
  20. package/config/query-params.js +1 -0
  21. package/config/settings.ts +8 -1
  22. package/config/types.js +2 -0
  23. package/dialog/AddonConfigConfirmationDialog.vue +45 -1
  24. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +52 -11
  25. package/edit/auth/AuthProviderWarningBanners.vue +14 -1
  26. package/edit/auth/github-app-steps.vue +97 -0
  27. package/edit/auth/github-steps.vue +75 -0
  28. package/edit/auth/github.vue +94 -65
  29. package/edit/fleet.cattle.io.helmop.vue +51 -2
  30. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +15 -5
  31. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +11 -9
  32. package/edit/provisioning.cattle.io.cluster/rke2.vue +56 -9
  33. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +28 -2
  34. package/list/projectsecret.vue +1 -1
  35. package/machine-config/azure.vue +1 -1
  36. package/mixins/chart.js +1 -1
  37. package/models/__tests__/chart.test.ts +17 -9
  38. package/models/__tests__/compliance.cattle.io.clusterscanprofile.spec.js +30 -0
  39. package/models/catalog.cattle.io.app.js +1 -1
  40. package/models/chart.js +3 -1
  41. package/models/compliance.cattle.io.clusterscanprofile.js +1 -1
  42. package/models/management.cattle.io.authconfig.js +1 -0
  43. package/package.json +2 -2
  44. package/pages/auth/login.vue +5 -2
  45. package/pages/auth/verify.vue +1 -1
  46. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +3 -2
  47. package/pages/c/_cluster/apps/charts/chart.vue +2 -2
  48. package/pages/c/_cluster/explorer/EventsTable.vue +89 -3
  49. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  50. package/pages/c/_cluster/settings/performance.vue +12 -25
  51. package/pages/home.vue +313 -12
  52. package/plugins/axios.js +2 -1
  53. package/plugins/dashboard-store/actions.js +1 -1
  54. package/plugins/dashboard-store/resource-class.js +17 -2
  55. package/plugins/steve/steve-pagination-utils.ts +2 -2
  56. package/scripts/extension/publish +1 -1
  57. package/store/auth.js +8 -3
  58. package/store/aws.js +8 -6
  59. package/store/features.js +1 -0
  60. package/store/index.js +9 -3
  61. package/store/prefs.js +6 -0
  62. package/types/kube/kube-api.ts +2 -1
  63. package/types/rancher/index.d.ts +1 -0
  64. package/types/resources/settings.d.ts +29 -7
  65. package/types/shell/index.d.ts +59 -0
  66. package/utils/__tests__/cluster.test.ts +379 -1
  67. package/utils/cluster.js +157 -3
  68. package/utils/dynamic-content/__tests__/config.test.ts +187 -0
  69. package/utils/dynamic-content/__tests__/index.test.ts +390 -0
  70. package/utils/dynamic-content/__tests__/info.test.ts +263 -0
  71. package/utils/dynamic-content/__tests__/new-release.test.ts +216 -0
  72. package/utils/dynamic-content/__tests__/support-notice.test.ts +262 -0
  73. package/utils/dynamic-content/__tests__/util.test.ts +235 -0
  74. package/utils/dynamic-content/config.ts +55 -0
  75. package/utils/dynamic-content/index.ts +273 -0
  76. package/utils/dynamic-content/info.ts +219 -0
  77. package/utils/dynamic-content/new-release.ts +126 -0
  78. package/utils/dynamic-content/support-notice.ts +169 -0
  79. package/utils/dynamic-content/types.d.ts +101 -0
  80. package/utils/dynamic-content/util.ts +122 -0
  81. package/utils/inactivity.ts +104 -0
  82. package/utils/pagination-utils.ts +19 -4
  83. package/utils/release-notes.ts +1 -1
@@ -0,0 +1,127 @@
1
+ <script lang="ts" setup>
2
+ import { ref, computed, defineProps, defineEmits } from 'vue';
3
+ import { _EDIT } from '@shell/config/query-params';
4
+ import { TYPES } from '@shell/models/secret';
5
+ import { SECRET } from '@shell/config/types';
6
+ import { PaginationParamFilter } from '@shell/types/store/pagination.types';
7
+ import ResourceLabeledSelect from '@shell/components/form/ResourceLabeledSelect.vue';
8
+
9
+ interface Secret {
10
+ id?: string;
11
+ name: string;
12
+ namespace: string;
13
+ _type: string;
14
+ }
15
+
16
+ const props = defineProps({
17
+ value: {
18
+ type: Object,
19
+ required: true,
20
+ },
21
+ namespace: {
22
+ type: String,
23
+ required: true,
24
+ },
25
+ inStore: {
26
+ type: String,
27
+ default: 'management',
28
+ },
29
+ mode: {
30
+ type: String,
31
+ default: _EDIT
32
+ },
33
+ label: {
34
+ type: String,
35
+ default: '',
36
+ },
37
+ });
38
+
39
+ const emit = defineEmits(['update:value']);
40
+
41
+ const types = computed<string[]>(() => Object.values(TYPES));
42
+
43
+ const secrets = ref<Secret[]>([]);
44
+
45
+ const allSecretsSettings = {
46
+ updateResources: (secretsList: Secret[]) => {
47
+ const allSecretsInNamespace = secretsList.filter((secret) => types.value.includes(secret._type) && secret.namespace === props.namespace);
48
+ const mappedSecrets = mapSecrets(allSecretsInNamespace.sort((a, b) => a.name.localeCompare(b.name)));
49
+
50
+ secrets.value = allSecretsInNamespace;
51
+
52
+ return mappedSecrets;
53
+ }
54
+ };
55
+
56
+ const paginateSecretsSetting = {
57
+ requestSettings: paginatePageOptions,
58
+ updateResources: (secretsList: Secret[]) => {
59
+ const mappedSecrets = mapSecrets(secretsList);
60
+
61
+ secrets.value = secretsList;
62
+
63
+ return mappedSecrets;
64
+ }
65
+ };
66
+
67
+ function mapSecrets(secretsList: Secret[]) {
68
+ return secretsList.reduce<{ label: string; value: string }[]>((res, s) => {
69
+ if (s.id) {
70
+ res.push({ label: s.name, value: s.name });
71
+ } else {
72
+ res.push(s as any);
73
+ }
74
+
75
+ return res;
76
+ }, []);
77
+ }
78
+
79
+ function update(value: any) {
80
+ emit('update:value', value);
81
+ }
82
+
83
+ function paginatePageOptions(opts: any) {
84
+ const { opts: { filter } } = opts;
85
+
86
+ const filters = !!filter ? [PaginationParamFilter.createSingleField({
87
+ field: 'metadata.name', value: filter, exact: false, equals: true
88
+ })] : [];
89
+
90
+ filters.push(
91
+ PaginationParamFilter.createSingleField({ field: 'metadata.namespace', value: props.namespace }),
92
+ PaginationParamFilter.createMultipleFields(types.value.map((t) => ({
93
+ field: 'metadata.fields.1',
94
+ equals: true,
95
+ exact: true,
96
+ value: t
97
+ })))
98
+ );
99
+
100
+ return {
101
+ ...opts,
102
+ filters,
103
+ groupByNamespace: false,
104
+ classify: true,
105
+ sort: [{ asc: true, field: 'metadata.name' }],
106
+ };
107
+ }
108
+ </script>
109
+
110
+ <template>
111
+ <ResourceLabeledSelect
112
+ :key="namespace"
113
+ :value="value"
114
+ :label="label || t('fleet.secrets.label')"
115
+ :mode="mode"
116
+ :resource-type="SECRET"
117
+ :loading="$fetchState.pending"
118
+ :in-store="inStore"
119
+ :paginated-resource-settings="paginateSecretsSetting"
120
+ :all-resources-settings="allSecretsSettings"
121
+ :multiple="true"
122
+ @update:value="update"
123
+ />
124
+ </template>
125
+
126
+ <style lang="scss" scoped>
127
+ </style>
@@ -0,0 +1,125 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { _EDIT } from '@shell/config/query-params';
3
+ import FleetConfigMapSelector from '@shell/components/fleet/FleetConfigMapSelector.vue';
4
+ import ResourceLabeledSelect from '@shell/components/form/ResourceLabeledSelect.vue';
5
+
6
+ describe('fleetConfigMapSelector.vue', () => {
7
+ const defaultProps = {
8
+ value: {},
9
+ namespace: 'fleet-default',
10
+ inStore: 'management',
11
+ mode: _EDIT,
12
+ label: 'Config Map',
13
+ };
14
+
15
+ const global = {
16
+ stubs: { ResourceLabeledSelect },
17
+ mocks: {
18
+ $fetchState: { pending: false },
19
+ $store: { getters: { 'management/all': () => [] } },
20
+ },
21
+ };
22
+
23
+ it('should emit update:value when update is called', async() => {
24
+ const wrapper = shallowMount(FleetConfigMapSelector, {
25
+ props: defaultProps,
26
+ global,
27
+ });
28
+
29
+ const vm = wrapper.vm as any;
30
+
31
+ await vm.update('cm1');
32
+
33
+ expect(wrapper.emitted('update:value')).toBeTruthy();
34
+ expect(wrapper.emitted('update:value')?.[0]).toStrictEqual(['cm1']);
35
+ });
36
+
37
+ it('should correctly map configMaps', () => {
38
+ const wrapper = shallowMount(FleetConfigMapSelector, {
39
+ props: defaultProps,
40
+ global
41
+ });
42
+
43
+ const configMapsList = [
44
+ {
45
+ id: '1', name: 'cm1', namespace: 'fleet-default'
46
+ },
47
+ { name: 'cm2', namespace: 'fleet-default' }
48
+ ];
49
+
50
+ const vm = wrapper.vm as any;
51
+ const result = vm.mapConfigMaps(configMapsList);
52
+
53
+ expect(result).toStrictEqual([
54
+ { label: 'cm1', value: 'cm1' },
55
+ { name: 'cm2', namespace: 'fleet-default' }
56
+ ]);
57
+ });
58
+
59
+ it('should return correct filter options from paginatePageOptions', () => {
60
+ const wrapper = shallowMount(FleetConfigMapSelector, {
61
+ props: defaultProps,
62
+ global
63
+ });
64
+
65
+ const opts = { opts: { filter: 'test' } };
66
+
67
+ const vm = wrapper.vm as any;
68
+ const result = vm.paginatePageOptions(opts);
69
+
70
+ expect(result.filters).toHaveLength(2);
71
+ expect(result.groupByNamespace).toStrictEqual(false);
72
+ expect(result.classify).toStrictEqual(true);
73
+ expect(result.sort).toStrictEqual([{ asc: true, field: 'metadata.name' }]);
74
+ });
75
+
76
+ it('should correctly filter and map configMaps in allConfigMapsSettings.updateResources', () => {
77
+ const wrapper = shallowMount(FleetConfigMapSelector, {
78
+ props: defaultProps,
79
+ global
80
+ });
81
+
82
+ const configMapsList = [
83
+ {
84
+ id: '1', name: 'cm1', namespace: 'fleet-default'
85
+ },
86
+ {
87
+ id: '2', name: 'cm2', namespace: 'other'
88
+ }
89
+ ];
90
+
91
+ const vm = wrapper.vm as any;
92
+
93
+ const result = vm.allConfigMapsSettings.updateResources(configMapsList);
94
+
95
+ expect(result).toStrictEqual([{ label: 'cm1', value: 'cm1' }]);
96
+ expect(vm.configMaps).toStrictEqual([{
97
+ id: '1', name: 'cm1', namespace: 'fleet-default'
98
+ }]);
99
+ });
100
+
101
+ it('should correctly map configMaps in paginateConfigMapsSetting.updateResources', () => {
102
+ const wrapper = shallowMount(FleetConfigMapSelector, {
103
+ props: defaultProps,
104
+ global
105
+ });
106
+
107
+ const configMapsList = [
108
+ {
109
+ id: '1', name: 'cm1', namespace: 'fleet-default'
110
+ },
111
+ {
112
+ id: '2', name: 'cm2', namespace: 'fleet-default'
113
+ }
114
+ ];
115
+
116
+ const vm = wrapper.vm as any;
117
+ const result = vm.paginateConfigMapsSetting.updateResources(configMapsList);
118
+
119
+ expect(result).toStrictEqual([
120
+ { label: 'cm1', value: 'cm1' },
121
+ { label: 'cm2', value: 'cm2' }
122
+ ]);
123
+ expect(vm.configMaps).toStrictEqual(configMapsList);
124
+ });
125
+ });
@@ -0,0 +1,82 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import FleetSecretSelector from '@shell/components/fleet/FleetSecretSelector.vue';
3
+ import { _EDIT } from '@shell/config/query-params';
4
+
5
+ describe('component: FleetSecretSelector.vue', () => {
6
+ const secretsMock = [
7
+ {
8
+ id: '1', name: 'secret1', namespace: 'fleet-default', _type: 'Opaque'
9
+ },
10
+ {
11
+ id: '2', name: 'secret2', namespace: 'fleet-default', _type: 'Opaque'
12
+ },
13
+ {
14
+ id: '3', name: 'secret3', namespace: 'other', _type: 'Opaque'
15
+ },
16
+ ];
17
+
18
+ const props = {
19
+ value: {},
20
+ namespace: 'fleet-default',
21
+ inStore: 'management',
22
+ mode: _EDIT,
23
+ };
24
+
25
+ const global = { mocks: { $fetchState: { pending: false, error: false } } };
26
+
27
+ it('should emit update:value when update is called', async() => {
28
+ const wrapper = shallowMount(FleetSecretSelector, { props, global });
29
+
30
+ await (wrapper.vm as any).update('secret1');
31
+
32
+ expect(wrapper.emitted('update:value')).toBeTruthy();
33
+ expect(wrapper.emitted('update:value')?.[0]).toStrictEqual(['secret1']);
34
+ });
35
+
36
+ it('should correctly map secrets', () => {
37
+ const wrapper = shallowMount(FleetSecretSelector, { props, global });
38
+ const mapped = (wrapper.vm as any).mapSecrets(secretsMock);
39
+
40
+ expect(mapped).toStrictEqual([
41
+ { label: 'secret1', value: 'secret1' },
42
+ { label: 'secret2', value: 'secret2' },
43
+ { label: 'secret3', value: 'secret3' }
44
+ ]);
45
+ });
46
+
47
+ it('should filter and sort secrets by namespace and type', () => {
48
+ const wrapper = shallowMount(FleetSecretSelector, { props, global });
49
+
50
+ const result = (wrapper.vm as any).allSecretsSettings.updateResources(secretsMock);
51
+
52
+ expect(result).toStrictEqual([
53
+ { label: 'secret1', value: 'secret1' },
54
+ { label: 'secret2', value: 'secret2' }
55
+ ]);
56
+ expect((wrapper.vm as any).secrets).toStrictEqual([
57
+ {
58
+ id: '1', name: 'secret1', namespace: 'fleet-default', _type: 'Opaque'
59
+ },
60
+ {
61
+ id: '2', name: 'secret2', namespace: 'fleet-default', _type: 'Opaque'
62
+ }
63
+ ]);
64
+ });
65
+
66
+ it('should return correct filter structure from paginatePageOptions', () => {
67
+ const wrapper = shallowMount(FleetSecretSelector, { props, global });
68
+
69
+ const opts = { opts: { filter: 'secret' } };
70
+ const result = (wrapper.vm as any).paginatePageOptions(opts);
71
+
72
+ expect(result.filters).toStrictEqual(
73
+ expect.arrayContaining([
74
+ expect.objectContaining({ fields: expect.arrayContaining([expect.objectContaining({ field: 'metadata.name' })]) }),
75
+ expect.objectContaining({ fields: expect.arrayContaining([expect.objectContaining({ field: 'metadata.namespace' })]) }),
76
+ expect.objectContaining({ fields: expect.arrayContaining([expect.objectContaining({ field: 'metadata.fields.1' })]) }),
77
+ ])
78
+ );
79
+
80
+ expect(result.sort).toStrictEqual([{ asc: true, field: 'metadata.name' }]);
81
+ });
82
+ });
@@ -7,7 +7,8 @@ export default {
7
7
  emits: ['update:value', 'error'],
8
8
 
9
9
  components: { FileSelector, LazyImage },
10
- props: {
10
+
11
+ props: {
11
12
  value: {
12
13
  type: String,
13
14
  default: null,
@@ -36,12 +37,20 @@ export default {
36
37
  accept: {
37
38
  type: String,
38
39
  default: 'image/*'
39
- }
40
+ },
41
+
42
+ class: {
43
+ type: [String, Array],
44
+ default: 'role-primary',
45
+ },
40
46
  },
41
47
  computed: {
42
48
  isView() {
43
49
  return this.mode === _VIEW;
44
- }
50
+ },
51
+ customClass() {
52
+ return [...(Array.isArray(this.class) ? this.class : [this.class])];
53
+ },
45
54
  },
46
55
  methods: {
47
56
  /**
@@ -62,7 +71,7 @@ export default {
62
71
  <FileSelector
63
72
  v-if="!value && !isView"
64
73
  :value="value"
65
- class="btn role-primary"
74
+ :class="customClass"
66
75
  :mode="mode"
67
76
  :read-as-data-url="true"
68
77
  :byte-limit="byteLimit"
@@ -67,12 +67,21 @@ export default {
67
67
  default: '*'
68
68
  },
69
69
 
70
+ class: {
71
+ type: [String, Array],
72
+ default: () => [],
73
+ }
74
+
70
75
  },
71
76
 
72
77
  computed: {
73
78
  isView() {
74
79
  return this.mode === _VIEW;
75
- }
80
+ },
81
+
82
+ customClass() {
83
+ return ['file-selector', 'btn', ...(Array.isArray(this.class) ? this.class : [this.class])];
84
+ },
76
85
  },
77
86
 
78
87
  methods: {
@@ -151,7 +160,7 @@ export default {
151
160
  :aria-label="label"
152
161
  type="button"
153
162
  role="button"
154
- class="file-selector btn"
163
+ :class="customClass"
155
164
  data-testid="file-selector__uploader-button"
156
165
  @click="selectFile"
157
166
  >
@@ -163,6 +163,7 @@ export default defineComponent({
163
163
  :loading="$fetchState.pending"
164
164
  :options="allOfType"
165
165
  :paginate="paginateType"
166
+ :multiple="$attrs.multiple || false"
166
167
  @update:value="$emit('update:value', $event)"
167
168
  />
168
169
  </template>
@@ -0,0 +1,90 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import ResourceLabeledSelect from '@shell/components/form/ResourceLabeledSelect.vue';
3
+ import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
4
+ import { RESOURCE_LABEL_SELECT_MODE } from '@shell/types/components/resourceLabeledSelect';
5
+
6
+ const mockStore = {
7
+ getters: {
8
+ currentStore: jest.fn().mockReturnValue('cluster'),
9
+ 'cluster/paginationEnabled': jest.fn().mockReturnValue(true),
10
+ 'cluster/all': jest.fn().mockReturnValue([{ id: 'foo', name: 'Foo' }]),
11
+ },
12
+ dispatch: jest.fn().mockResolvedValue(undefined),
13
+ };
14
+
15
+ const requiredSetup = () => {
16
+ return {
17
+ global: {
18
+ components: { LabeledSelect },
19
+ mocks: { $store: mockStore, $fetchState: {} }
20
+ }
21
+ };
22
+ };
23
+
24
+ describe('component: ResourceLabeledSelect.vue', () => {
25
+ it('should render LabeledSelect', async() => {
26
+ const wrapper = shallowMount(ResourceLabeledSelect, {
27
+ ...requiredSetup(),
28
+ props: { resourceType: 'testResource' }
29
+ });
30
+
31
+ expect(wrapper.findComponent(LabeledSelect).exists()).toBe(true);
32
+ });
33
+
34
+ it('should call paginateType with overrideRequest if provided', async() => {
35
+ const overrideRequest = jest.fn().mockResolvedValue({ page: [{ id: 'bar', name: 'Bar' }], total: 1 });
36
+ const wrapper = shallowMount(ResourceLabeledSelect, {
37
+ ...requiredSetup(),
38
+ props: {
39
+ resourceType: 'testResource',
40
+ paginateMode: RESOURCE_LABEL_SELECT_MODE.DYNAMIC,
41
+ paginatedResourceSettings: { overrideRequest }
42
+ }
43
+ });
44
+
45
+ const result = await wrapper.vm.paginateType({
46
+ filter: 'bar',
47
+ page: 1,
48
+ pageSize: 10,
49
+ pageContent: [],
50
+ resetPage: false
51
+ });
52
+
53
+ expect(overrideRequest).toHaveBeenCalledWith({
54
+ filter: 'bar',
55
+ page: 1,
56
+ pageSize: 10,
57
+ pageContent: [],
58
+ resetPage: false
59
+ });
60
+ expect(result.page[0].name).toBe('Bar');
61
+ });
62
+
63
+ it('should emit update:value when LabeledSelect emits update:value', async() => {
64
+ const wrapper = shallowMount(ResourceLabeledSelect, {
65
+ ...requiredSetup(),
66
+ props: { resourceType: 'testResource' }
67
+ });
68
+
69
+ wrapper.findComponent(LabeledSelect).vm.$emit('update:value', 'baz');
70
+
71
+ expect(wrapper.emitted('update:value')).toBeTruthy();
72
+ expect(wrapper.emitted('update:value')?.[0]).toStrictEqual(['baz']);
73
+ });
74
+
75
+ it('should pass correct props and attrs to LabeledSelect', async() => {
76
+ const wrapper = shallowMount(ResourceLabeledSelect, {
77
+ ...requiredSetup(),
78
+ props: {
79
+ resourceType: 'testResource',
80
+ allResourcesSettings: { labelSelectOptions: { placeholder: 'Select a resource' } }
81
+ },
82
+ attrs: { multiple: true }
83
+ });
84
+
85
+ const labeledSelect = wrapper.findComponent(LabeledSelect);
86
+
87
+ expect(labeledSelect.attributes('placeholder')).toBe('Select a resource');
88
+ expect(labeledSelect.attributes('multiple')).toBe('true');
89
+ });
90
+ });
@@ -842,6 +842,7 @@ export default {
842
842
  .side-menu-logo {
843
843
  align-items: center;
844
844
  display: flex;
845
+ height: 55px;
845
846
  margin-right: 8px;
846
847
  max-width: 200px;
847
848
  padding: 12px 0;
@@ -177,6 +177,7 @@ export function init(store) {
177
177
  });
178
178
 
179
179
  componentForType(`${ MANAGEMENT.AUTH_CONFIG }/github`, 'auth/github');
180
+ componentForType(`${ MANAGEMENT.AUTH_CONFIG }/githubapp`, 'auth/github');
180
181
  componentForType(`${ MANAGEMENT.AUTH_CONFIG }/openldap`, 'auth/ldap/index');
181
182
  componentForType(`${ MANAGEMENT.AUTH_CONFIG }/freeipa`, 'auth/ldap/index');
182
183
  componentForType(`${ MANAGEMENT.AUTH_CONFIG }/activedirectory`, 'auth/ldap/index');
@@ -8,6 +8,7 @@ export const STEP = 'step';
8
8
  export const LOGGED_OUT = 'logged-out';
9
9
  export const IS_SSO = 'is-sso';
10
10
  export const IS_SLO = 'is-slo';
11
+ export const IS_SESSION_IDLE = 'is-session-idle';
11
12
  export const UPGRADED = 'upgraded';
12
13
  export const TIMED_OUT = 'timed-out';
13
14
  export const AUTH_TEST = 'test';
@@ -52,6 +52,7 @@ export const SETTING = {
52
52
  RKE_METADATA_CONFIG: 'rke-metadata-config',
53
53
  EULA_AGREED: 'eula-agreed',
54
54
  AUTH_USER_INFO_MAX_AGE_SECONDS: 'auth-user-info-max-age-seconds',
55
+ AUTH_USER_SESSION_IDLE_TTL_MINUTES: 'auth-user-session-idle-ttl-minutes',
55
56
  AUTH_USER_SESSION_TTL_MINUTES: 'auth-user-session-ttl-minutes',
56
57
  AUTH_USER_INFO_RESYNC_CRON: 'auth-user-info-resync-cron',
57
58
  AUTH_LOCAL_VALIDATE_DESC: 'auth-password-requirements-description',
@@ -109,7 +110,12 @@ export const SETTING = {
109
110
  SYSTEM_AGENT_UPGRADER_INSTALL_CONCURRENCY: 'system-agent-upgrader-install-concurrency',
110
111
  IMPORTED_CLUSTER_VERSION_MANAGEMENT: 'imported-cluster-version-management',
111
112
  CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS: 'cluster-agent-default-priority-class',
112
- CLUSTER_AGENT_DEFAULT_POD_DISTRIBUTION_BUDGET: 'cluster-agent-default-pod-disruption-budget'
113
+ CLUSTER_AGENT_DEFAULT_POD_DISTRIBUTION_BUDGET: 'cluster-agent-default-pod-disruption-budget',
114
+ /**
115
+ * Dynamic Content settings
116
+ */
117
+ DYNAMIC_CONTENT_ENABLED: 'ui-content-enabled',
118
+ DYNAMIC_CONTENT_ENDPOINT: 'ui-content-endpoint',
113
119
  } as const;
114
120
 
115
121
  // These are the settings that are allowed to be edited via the UI
@@ -140,6 +146,7 @@ export const ALLOWED_SETTINGS: GlobalSetting = {
140
146
  },
141
147
  [SETTING.INGRESS_IP_DOMAIN]: {},
142
148
  [SETTING.AUTH_USER_INFO_MAX_AGE_SECONDS]: {},
149
+ [SETTING.AUTH_USER_SESSION_IDLE_TTL_MINUTES]: {},
143
150
  [SETTING.AUTH_USER_SESSION_TTL_MINUTES]: {},
144
151
  [SETTING.AUTH_TOKEN_MAX_TTL_MINUTES]: {},
145
152
  [SETTING.KUBECONFIG_GENERATE_TOKEN]: { kind: 'boolean' },
package/config/types.js CHANGED
@@ -222,6 +222,8 @@ export const MANAGEMENT = {
222
222
  OIDC_CLIENT: 'management.cattle.io.oidcclient'
223
223
  };
224
224
 
225
+ export const EXT = { USER_ACTIVITY: 'ext.cattle.io.useractivity' };
226
+
225
227
  export const CAPI = {
226
228
  CAPI_CLUSTER: 'cluster.x-k8s.io.cluster',
227
229
  MACHINE_DEPLOYMENT: 'cluster.x-k8s.io.machinedeployment',
@@ -1,6 +1,10 @@
1
1
  <script>
2
2
  import AsyncButton from '@shell/components/AsyncButton';
3
3
  import { Card } from '@components/Card';
4
+ import { mapGetters } from 'vuex';
5
+
6
+ import { labelForAddon } from '@shell/utils/cluster';
7
+ import { resourceNames } from '@shell/utils/string';
4
8
 
5
9
  export default {
6
10
  emits: ['close'],
@@ -17,11 +21,45 @@ export default {
17
21
  registerBackgroundClosing: {
18
22
  type: Function,
19
23
  required: true
24
+ },
25
+ /**
26
+ * The names of the addons that have configuration conflicts.
27
+ */
28
+ addonNames: {
29
+ type: Array,
30
+ default: () => []
31
+ },
32
+ /**
33
+ * The Kubernetes version the user is upgrading from.
34
+ */
35
+ previousKubeVersion: {
36
+ type: String,
37
+ default: ''
38
+ },
39
+ /**
40
+ * The Kubernetes version the user is upgrading to.
41
+ */
42
+ newKubeVersion: {
43
+ type: String,
44
+ default: ''
20
45
  }
21
46
  },
22
47
  created() {
23
48
  this.registerBackgroundClosing(this.closing);
24
49
  },
50
+ computed: {
51
+ ...mapGetters({ t: 'i18n/t' }),
52
+
53
+ formattedAddons() {
54
+ if (!this.addonNames || this.addonNames.length === 0) {
55
+ return '';
56
+ }
57
+
58
+ const translatedNames = this.addonNames.map((name) => labelForAddon(this.$store, name, true));
59
+
60
+ return resourceNames(translatedNames, null, this.t, false);
61
+ }
62
+ },
25
63
  methods: {
26
64
  continue(value) {
27
65
  if (this.resources[0]) {
@@ -59,7 +97,13 @@ export default {
59
97
 
60
98
  <template #body>
61
99
  <slot name="body">
62
- {{ t('addonConfigConfirmation.body') }}
100
+ <span
101
+ v-clean-html="t('addonConfigConfirmation.body', {
102
+ addons: formattedAddons,
103
+ previousKubeVersion,
104
+ newKubeVersion
105
+ }, true)"
106
+ />
63
107
  </slot>
64
108
  </template>
65
109