@rancher/shell 3.0.8-rc.9 → 3.0.8

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 (146) hide show
  1. package/apis/impl/apis.ts +61 -0
  2. package/apis/index.ts +40 -0
  3. package/apis/intf/modal.ts +90 -0
  4. package/apis/intf/shell.ts +36 -0
  5. package/apis/intf/slide-in.ts +98 -0
  6. package/apis/intf/system.ts +41 -0
  7. package/apis/shell/__tests__/modal.test.ts +80 -0
  8. package/apis/shell/__tests__/notifications.test.ts +71 -0
  9. package/apis/shell/__tests__/slide-in.test.ts +54 -0
  10. package/apis/shell/__tests__/system.test.ts +129 -0
  11. package/apis/shell/index.ts +38 -0
  12. package/apis/shell/modal.ts +41 -0
  13. package/apis/shell/notifications.ts +65 -0
  14. package/apis/shell/slide-in.ts +33 -0
  15. package/apis/shell/system.ts +65 -0
  16. package/apis/vue-shim.d.ts +11 -0
  17. package/assets/styles/global/_tooltip.scss +6 -1
  18. package/assets/translations/en-us.yaml +5 -0
  19. package/components/ActionMenuShell.vue +3 -1
  20. package/components/CruResource.vue +8 -1
  21. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
  22. package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
  23. package/components/Drawer/ResourceDetailDrawer/index.vue +3 -1
  24. package/components/LocaleSelector.vue +2 -2
  25. package/components/ModalManager.vue +11 -1
  26. package/components/Questions/__tests__/Yaml.test.ts +1 -1
  27. package/components/RelatedResources.vue +5 -0
  28. package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
  29. package/components/ResourceDetail/Masthead/latest.vue +23 -21
  30. package/components/ResourceDetail/index.vue +3 -0
  31. package/components/ResourceTable.vue +54 -21
  32. package/components/SlideInPanelManager.vue +16 -11
  33. package/components/SortableTable/THead.vue +2 -1
  34. package/components/SortableTable/index.vue +20 -2
  35. package/components/Tabbed/index.vue +37 -2
  36. package/components/__tests__/NamespaceFilter.test.ts +49 -0
  37. package/components/auth/SelectPrincipal.vue +4 -0
  38. package/components/auth/login/ldap.vue +3 -3
  39. package/components/fleet/FleetSecretSelector.vue +1 -1
  40. package/components/form/KeyValue.vue +1 -1
  41. package/components/form/NameNsDescription.vue +1 -1
  42. package/components/form/NodeScheduling.vue +2 -2
  43. package/components/form/ResourceTabs/composable.ts +2 -2
  44. package/components/form/ResourceTabs/index.vue +0 -2
  45. package/components/form/__tests__/NameNsDescription.test.ts +42 -0
  46. package/components/formatter/LinkName.vue +5 -0
  47. package/components/nav/Group.vue +25 -7
  48. package/components/nav/Header.vue +1 -1
  49. package/components/nav/NamespaceFilter.vue +1 -0
  50. package/components/nav/Type.vue +17 -6
  51. package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
  52. package/components/nav/__tests__/Type.test.ts +59 -0
  53. package/composables/cruResource.ts +27 -0
  54. package/composables/focusTrap.ts +3 -1
  55. package/composables/resourceDetail.ts +15 -0
  56. package/composables/useLabeledFormElement.ts +3 -4
  57. package/config/product/fleet.js +1 -1
  58. package/config/router/navigation-guards/clusters.js +3 -3
  59. package/config/router/navigation-guards/products.js +1 -1
  60. package/config/router/routes.js +1 -5
  61. package/core/__tests__/extension-manager-impl.test.js +437 -0
  62. package/core/extension-manager-impl.js +6 -27
  63. package/core/plugin-helpers.ts +2 -2
  64. package/core/plugin.ts +9 -1
  65. package/core/plugins-loader.js +2 -2
  66. package/core/types-provisioning.ts +4 -0
  67. package/core/types.ts +35 -0
  68. package/detail/provisioning.cattle.io.cluster.vue +8 -6
  69. package/dialog/DeveloperLoadExtensionDialog.vue +1 -1
  70. package/dialog/MoveNamespaceDialog.vue +20 -4
  71. package/dialog/SearchDialog.vue +1 -0
  72. package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
  73. package/directives/__tests__/clean-tooltip.test.ts +298 -0
  74. package/directives/clean-tooltip.ts +234 -0
  75. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
  76. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +98 -1
  77. package/edit/fleet.cattle.io.helmop.vue +5 -0
  78. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  79. package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
  80. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -8
  81. package/edit/resources.cattle.io.restore.vue +1 -1
  82. package/edit/workload/Job.vue +2 -2
  83. package/edit/workload/index.vue +1 -1
  84. package/initialize/install-plugins.js +4 -5
  85. package/machine-config/azure.vue +1 -1
  86. package/machine-config/components/GCEImage.vue +1 -1
  87. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +16 -0
  88. package/models/chart.js +70 -74
  89. package/models/management.cattle.io.cluster.js +1 -1
  90. package/models/provisioning.cattle.io.cluster.js +11 -3
  91. package/package.json +7 -7
  92. package/pages/auth/login.vue +3 -3
  93. package/pages/auth/setup.vue +1 -1
  94. package/pages/auth/verify.vue +3 -3
  95. package/pages/c/_cluster/apps/charts/index.vue +122 -24
  96. package/pages/c/_cluster/apps/charts/install.vue +33 -0
  97. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  98. package/pages/c/_cluster/fleet/index.vue +4 -7
  99. package/pages/c/_cluster/settings/index.vue +5 -0
  100. package/pkg/auto-import.js +3 -3
  101. package/pkg/dynamic-importer.lib.js +1 -1
  102. package/pkg/import.js +1 -1
  103. package/plugins/__tests__/mutations.tests.ts +179 -0
  104. package/plugins/dashboard-store/getters.js +1 -1
  105. package/plugins/dashboard-store/model-loader.js +1 -1
  106. package/plugins/dashboard-store/mutations.js +23 -2
  107. package/plugins/dashboard-store/resource-class.js +8 -3
  108. package/plugins/plugin.js +2 -2
  109. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +301 -128
  110. package/plugins/steve/steve-class.js +1 -1
  111. package/plugins/steve/steve-pagination-utils.ts +108 -43
  112. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  113. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  114. package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
  115. package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
  116. package/scripts/publish-shell.sh +25 -0
  117. package/store/__tests__/catalog.test.ts +1 -1
  118. package/store/__tests__/type-map.test.ts +164 -2
  119. package/store/auth.js +23 -11
  120. package/store/i18n.js +3 -3
  121. package/store/index.js +5 -3
  122. package/store/notifications.ts +2 -0
  123. package/store/prefs.js +2 -2
  124. package/store/type-map.js +17 -7
  125. package/types/internal-api/shell/modal.d.ts +6 -6
  126. package/types/notifications/index.ts +126 -15
  127. package/types/rancher/index.d.ts +9 -0
  128. package/types/shell/index.d.ts +16 -1
  129. package/types/vue-shim.d.ts +5 -4
  130. package/utils/__tests__/router.test.js +238 -0
  131. package/utils/cluster.js +4 -1
  132. package/utils/fleet.ts +8 -1
  133. package/utils/pagination-utils.ts +2 -2
  134. package/utils/pagination-wrapper.ts +1 -1
  135. package/utils/router.js +50 -0
  136. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  137. package/vue.config.js +3 -3
  138. package/composables/useExtensionManager.ts +0 -17
  139. package/core/__test__/extension-manager-impl.test.js +0 -236
  140. package/core/plugins.js +0 -38
  141. package/directives/clean-tooltip.js +0 -32
  142. package/plugins/internal-api/index.ts +0 -37
  143. package/plugins/internal-api/shared/base-api.ts +0 -13
  144. package/plugins/internal-api/shell/shell.api.ts +0 -108
  145. package/types/internal-api/shell/growl.d.ts +0 -25
  146. package/types/internal-api/shell/slideIn.d.ts +0 -15
@@ -37,20 +37,35 @@ interface Namespace extends ModelNamespace {
37
37
  }
38
38
  }
39
39
 
40
+ interface NamespaceProjectFilterResult {
41
+ /**
42
+ * True if the ns should be filtered IN. False if filtered OUT.
43
+ */
44
+ [nsName: string]: boolean;
45
+ }
46
+
47
+ /**
48
+ * Helper class, contains namespace / project filter specific functions
49
+ */
40
50
  class NamespaceProjectFilters {
41
51
  /**
42
52
  * User needs all resources.... except if there's some settings which should remove resources in specific circumstances
43
53
  */
44
54
  protected handlePrefAndSettingFilter(args: {
45
55
  allNamespaces: Namespace[],
56
+ /**
57
+ * Reserved / Obscure namespaces are ones used to support clusters and users. By default these are hidden
58
+ */
46
59
  showReservedRancherNamespaces: boolean,
60
+ /**
61
+ * Has product config disabled system projects and namespaces
62
+ */
47
63
  productHidesSystemNamespaces: boolean,
48
- }): PaginationParamFilter[] {
64
+ }): NamespaceProjectFilterResult {
49
65
  const { allNamespaces, showReservedRancherNamespaces, productHidesSystemNamespaces } = args;
50
66
 
51
- // These are AND'd together
52
67
  // Not ns 1 AND ns 2
53
- const filterNamespaces = allNamespaces.reduce((res, ns) => {
68
+ return allNamespaces.reduce((res, ns) => {
54
69
  // Links to ns.isObscure and covers things like `c-`, `user-`, etc (see OBSCURE_NAMESPACE_PREFIX)
55
70
  const hideObscure = showReservedRancherNamespaces ? false : ns.isObscure;
56
71
 
@@ -58,23 +73,11 @@ class NamespaceProjectFilters {
58
73
  const hideSystem = productHidesSystemNamespaces ? ns.isSystem : false;
59
74
 
60
75
  if (hideObscure || hideSystem) {
61
- res.push(ns.name);
76
+ res[ns.name] = false;
62
77
  }
63
78
 
64
79
  return res;
65
- }, [] as String[]);
66
-
67
- if (filterNamespaces.length) {
68
- return [new PaginationParamFilter({
69
- fields: [{
70
- value: filterNamespaces.join(','),
71
- equality: PaginationFilterEquality.NOT_IN,
72
- field: 'metadata.namespace',
73
- }],
74
- })];
75
- }
76
-
77
- return [];
80
+ }, {} as NamespaceProjectFilterResult);
78
81
  }
79
82
 
80
83
  /**
@@ -88,31 +91,88 @@ class NamespaceProjectFilters {
88
91
  allNamespaces: Namespace[],
89
92
  isAllSystem: boolean,
90
93
  isAllUser: boolean,
91
- }) {
92
- const { allNamespaces, isAllSystem } = args;
94
+ }): NamespaceProjectFilterResult {
95
+ const { allNamespaces, isAllSystem, isAllUser } = args;
93
96
  const allSystem = allNamespaces.filter((ns) => ns.isSystem);
94
97
 
95
- // > Neither of these use projectsOrNamespaces to avoid scenarios where the local cluster provides a namespace which has
96
- // > a matching project... which could lead to results in the user project resource being included in the system filter
97
- if (isAllSystem) {
98
- // return resources in system ns 1 OR in system ns 2 ...
99
- // &filter=metadata.namespace=system ns 1,metadata.namespace=system ns 2
100
- return [PaginationParamFilter.createMultipleFields(
101
- allSystem.map(
102
- (ns) => new PaginationFilterField({ field: 'metadata.namespace', value: ns.name })
103
- )
104
- )];
105
- } else { // if isAllUser
106
- // return resources not in system ns 1 AND not in system ns 2 ...
107
- // &filter=metadata.namespace!=system ns 1&filter=metadata.namespace!=system ns 2
108
- return allSystem.map((ns) => PaginationParamFilter.createSingleField({
109
- field: 'metadata.namespace', value: ns.name, equals: false
98
+ return allSystem.reduce((res, ns) => {
99
+ if (isAllSystem) {
100
+ // We want to filter IN system namespaces
101
+ res[ns.name] = true;
102
+ }
103
+
104
+ if (isAllUser) {
105
+ // We want to filter OUT system namespaces
106
+ res[ns.name] = false;
107
+ }
108
+
109
+ return res;
110
+ }, {} as NamespaceProjectFilterResult);
111
+ }
112
+
113
+ /**
114
+ * Combine result `b` into `a` and return result
115
+ */
116
+ protected combineNsProjectFilterResults(a: NamespaceProjectFilterResult, b: NamespaceProjectFilterResult): NamespaceProjectFilterResult {
117
+ // Start with `a`
118
+ const res = { ...a };
119
+
120
+ // Merge entries from `b` into `a` if they don't exist in `a`. This maintains a hierarchy
121
+ // 1. if something has been excluded in `a` ignore requests to include given `b`
122
+ // 2. if something has been included in `a` ignore requests to exclude given `b`
123
+ Object.entries(b).forEach(([ns, include]) => {
124
+ if (res[ns] === undefined) {
125
+ res[ns] = include;
126
+ }
127
+ });
128
+
129
+ return res;
130
+ }
131
+
132
+ /**
133
+ * Convert @NamespaceProjectFilterResult into @PaginationParamFilter
134
+ */
135
+ protected createFiltersFromNamespaceProjectFilterResult(filterResult: NamespaceProjectFilterResult): PaginationParamFilter[] {
136
+ const inList: string[] = [];
137
+ const outList: string[] = [];
138
+
139
+ Object.entries(filterResult).forEach(([ns, include]) => {
140
+ if (include) {
141
+ inList.push(ns);
142
+ } else {
143
+ outList.push(ns);
144
+ }
145
+ });
146
+
147
+ const res: PaginationParamFilter[] = [];
148
+
149
+ // There's no point having both IN and OUT lists together, so prefer the IN list
150
+ if (inList.length) {
151
+ res.push(new PaginationParamFilter({
152
+ fields: [{
153
+ value: inList.join(','),
154
+ equality: PaginationFilterEquality.IN,
155
+ field: 'metadata.namespace',
156
+ }],
157
+ }));
158
+ } else if (outList.length) {
159
+ res.push(new PaginationParamFilter({
160
+ fields: [{
161
+ value: outList.join(','),
162
+ equality: PaginationFilterEquality.NOT_IN,
163
+ field: 'metadata.namespace',
164
+ }],
110
165
  }));
111
166
  }
167
+
168
+ return res;
112
169
  }
113
170
 
114
171
  /**
115
172
  * User needs resources in a set of projects or namespaces
173
+ *
174
+ * Mainly deals with the projectornamespaces filter, also ensures namespace in local cluster matching target project's aren't included
175
+ *
116
176
  */
117
177
  protected handleSelectionFilter(neu: string[], isLocalCluster: boolean) {
118
178
  // User has one or more projects or namespaces. We can pass this straight through to projectsornamespaces
@@ -124,12 +184,12 @@ class NamespaceProjectFilters {
124
184
  ];
125
185
 
126
186
  if (isLocalCluster) {
127
- // > As per `handleSystemOrUserFilter` above, we need to be careful of the local cluster where there's namespaces related to projects with the same id
128
- // > In this case
187
+ // We need to be careful of the local cluster where there's namespaces related to projects with the same id
188
+ // In this case
129
189
  // - We're including resources in the project and it's related namespace (via projectsornamespaces)
130
190
  // - We're also then excluding resources in the related namespace (via below `filter`)
131
191
 
132
- // Exclude resources NOT in projects namespace 1 AND not in projects namespace 2
192
+ // Exclude resources NOT in project's backing namespace 1 AND not in project's backing namespace 2
133
193
  // &filter=metadata.namespace!=pn1&filter=metadata.namespace!=pn2
134
194
  return {
135
195
  projectsOrNamespaces,
@@ -352,24 +412,29 @@ class StevePaginationUtils extends NamespaceProjectFilters {
352
412
  let projectsOrNamespaces: PaginationParamProjectOrNamespace[] = [];
353
413
  // used to return resources in / not in namespaces
354
414
  // &filter=metadata.namespace=abc
355
- let filters: PaginationParamFilter[] = [];
415
+ const filters: PaginationParamFilter[] = [];
416
+ let nsProjectFilterResults = {};
356
417
 
357
418
  if (!showReservedRancherNamespaces || productHidesSystemNamespaces) {
358
- // We need to hide reserved namespaces ('c-', 'user-', etc) OR system namespaces
359
- filters = this.handlePrefAndSettingFilter({
419
+ // We need to hide reserved namespaces ('c-', 'user-', etc) OR system namespaces (given product may hide them)
420
+ nsProjectFilterResults = this.combineNsProjectFilterResults(nsProjectFilterResults, this.handlePrefAndSettingFilter({
360
421
  allNamespaces, showReservedRancherNamespaces, productHidesSystemNamespaces
361
- });
422
+ }));
362
423
  }
363
424
 
364
425
  const isAllSystem = selection[0] === NAMESPACE_FILTER_ALL_SYSTEM;
365
426
  const isAllUser = selection[0] === NAMESPACE_FILTER_ALL_USER;
366
427
 
367
428
  if (selection.length === 1 && (isAllSystem || isAllUser)) {
368
- // Filter by resources either in or not in system namespaces
369
- filters.push(...this.handleSystemOrUserFilter({
429
+ // Filter by resources either in or not in system namespaces (given user selection)
430
+ nsProjectFilterResults = this.combineNsProjectFilterResults(nsProjectFilterResults, this.handleSystemOrUserFilter({
370
431
  allNamespaces, isAllSystem, isAllUser
371
432
  }));
433
+
434
+ filters.push(...this.createFiltersFromNamespaceProjectFilterResult(nsProjectFilterResults));
372
435
  } else {
436
+ filters.push(...this.createFiltersFromNamespaceProjectFilterResult(nsProjectFilterResults));
437
+
373
438
  // User has one or more projects or namespaces
374
439
  const res = this.handleSelectionFilter(selection, isLocalCluster);
375
440
 
@@ -269,7 +269,7 @@ export default defineComponent({
269
269
  class="checkbox-outer-container"
270
270
  data-checkbox-ctrl
271
271
  :class="{
272
- 'v-popper--has-tooltip': hasTooltip,
272
+ 'has-clean-tooltip': hasTooltip,
273
273
  }"
274
274
  >
275
275
  <label
@@ -355,7 +355,7 @@ export default defineComponent({
355
355
  disabled: isDisabled,
356
356
  [status]: status,
357
357
  suffix: hasSuffix,
358
- 'v-popper--has-tooltip': hasTooltip,
358
+ 'has-clean-tooltip': hasTooltip,
359
359
  'compact-input': isCompact,
360
360
  hideArrows,
361
361
  [className]: true
@@ -1,9 +1,7 @@
1
- import { ref, provide, nextTick, defineEmits } from 'vue';
1
+ import { ref, provide, nextTick, EmitFn } from 'vue';
2
2
  import { useDropdownCollection } from './useDropdownCollection';
3
3
  import { RcButtonType } from '@components/RcButton';
4
4
 
5
- const rcDropdownEmits = defineEmits(['update:open']);
6
-
7
5
  /**
8
6
  * Composable that provides the context for a dropdown menu. Includes methods
9
7
  * and state for managing the dropdown's visibility, focus, and keyboard
@@ -13,7 +11,7 @@ const rcDropdownEmits = defineEmits(['update:open']);
13
11
  * @returns Dropdown context methods and state. Used for programmatic
14
12
  * interactions and setting focus.
15
13
  */
16
- export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
14
+ export const useDropdownContext = (emit: EmitFn<['update:open']>) => {
17
15
  const {
18
16
  dropdownItems,
19
17
  firstDropdownItem,
@@ -72,7 +72,7 @@ interface RcItemCardProps {
72
72
  id: string;
73
73
 
74
74
  /** Any object value associated with this card */
75
- value: ItemValue;
75
+ value?: ItemValue;
76
76
 
77
77
  /** Card title, status icons and action menu. Image will be included in the header in small variant too */
78
78
  header: Header;
@@ -8,6 +8,7 @@ SHELL_DIR=$BASE_DIR/shell/
8
8
  CREATORS_DIR=$BASE_DIR/creators/extension
9
9
  FORCE_PUBLISH_TO_NPM="false"
10
10
  DEFAULT_NPM_REGISTRY="https://registry.npmjs.org"
11
+ DUMMY_VERSION="99.99.99"
11
12
 
12
13
  # if TAG doesn't exist, we can exit as it's needed for any type of publish.
13
14
  if [ -z "$TAG" ]; then
@@ -84,6 +85,14 @@ function publish() {
84
85
  fi
85
86
  }
86
87
 
88
+ update_version_in_package_json() {
89
+ local package_json_path="$1"
90
+ local version="$2"
91
+
92
+ sed -i.bak -e "s/\"version\": \"[0-9]*.[0-9]*.[0-9]*\(-alpha\.[0-9]*\|-release[0-9]*.[0-9]*.[0-9]*\|-rc\.[0-9]*\)\{0,1\}\",/\"version\": \"${version}\",/g" "$package_json_path"
93
+ rm "${package_json_path}.bak"
94
+ }
95
+
87
96
  echo "TAG ${TAG}"
88
97
 
89
98
  # let's get the package name and version from the tag
@@ -102,10 +111,26 @@ fi
102
111
  case $PKG_NAME in
103
112
  "shell")
104
113
  echo "Publishing only Shell pkg via tagged release"
114
+
115
+ # with the changes in https://github.com/rancher/dashboard/pull/16166/files#diff-d954ab41ef46f7fdbaaf6d8c2bc715ad2cc823a829317b6ff93a3c94a92811f1
116
+ # with NPM 11.3 --dry--run now does additional checks, one of them is the version number
117
+ # so for dry runs we need to provide a valid version number here (not something published before)
118
+ if [ ${DRY_RUN} == "true" ]; then
119
+ update_version_in_package_json "${SHELL_DIR}/package.json" "${DUMMY_VERSION}"
120
+ fi
121
+
105
122
  publish "Shell" ${SHELL_DIR} ${PKG_V}
106
123
  ;;
107
124
  "creators")
108
125
  echo "Publishing only Creators pkg via tagged release"
126
+
127
+ # with the changes in https://github.com/rancher/dashboard/pull/16166/files#diff-d954ab41ef46f7fdbaaf6d8c2bc715ad2cc823a829317b6ff93a3c94a92811f1
128
+ # with NPM 11.3 --dry--run now does additional checks, one of them is the version number
129
+ # so for dry runs we need to provide a valid version number here (not something published before)
130
+ if [ ${DRY_RUN} == "true" ]; then
131
+ update_version_in_package_json "${CREATORS_DIR}/package.json" "${DUMMY_VERSION}"
132
+ fi
133
+
109
134
  publish "Extension creator" ${CREATORS_DIR} ${PKG_V}
110
135
  ;;
111
136
  *)
@@ -88,7 +88,7 @@ describe('catalog', () => {
88
88
  }
89
89
  },
90
90
  state: {
91
- $plugin: { getDynamic: () => require(`@shell/models/chart`) },
91
+ $extension: { getDynamic: () => require(`@shell/models/chart`) },
92
92
  [catalogStoreName]: { } as { [key: string]: any},
93
93
  },
94
94
  getters: {
@@ -1116,7 +1116,169 @@ describe('type-map', () => {
1116
1116
  });
1117
1117
  });
1118
1118
  });
1119
+
1120
+ describe('activeProducts', () => {
1121
+ // Basic schemas for product filtering tests
1122
+ const productSchemas = {
1123
+ myType: {
1124
+ id: 'mytype',
1125
+ _id: 'mytype',
1126
+ type: SCHEMA,
1127
+ _group: 'mygroup',
1128
+ },
1129
+ anotherType: {
1130
+ id: 'anothertype',
1131
+ _id: 'anothertype',
1132
+ type: SCHEMA,
1133
+ _group: 'anothergroup',
1134
+ },
1135
+ };
1136
+
1137
+ const createProductState = (products) => ({
1138
+ products,
1139
+ schemaGeneration: 1,
1140
+ });
1141
+
1142
+ const createProductRootGetters = (moduleSchemas = [], moduleName = 'cluster') => ({
1143
+ 'prefs/get': () => false,
1144
+ [`${ moduleName }/all`]: (resource) => {
1145
+ if (resource === SCHEMA) {
1146
+ return moduleSchemas;
1147
+ }
1148
+
1149
+ return [];
1150
+ },
1151
+ });
1152
+
1153
+ describe('ifHaveType', () => {
1154
+ it('should show product when matching type exists', () => {
1155
+ const state = createProductState([{
1156
+ name: 'test-product',
1157
+ inStore: 'cluster',
1158
+ ifHaveType: 'mytype',
1159
+ }]);
1160
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1161
+
1162
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1163
+
1164
+ expect(active).toHaveLength(1);
1165
+ expect(active[0].name).toBe('test-product');
1166
+ });
1167
+
1168
+ it('should hide product when matching type does not exist', () => {
1169
+ const state = createProductState([{
1170
+ name: 'test-product',
1171
+ inStore: 'cluster',
1172
+ ifHaveType: 'missingtype',
1173
+ }]);
1174
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1175
+
1176
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1177
+
1178
+ expect(active).toHaveLength(0);
1179
+ });
1180
+ });
1181
+
1182
+ describe('ifNotHaveType', () => {
1183
+ it('should show product when matching type does NOT exist', () => {
1184
+ const state = createProductState([{
1185
+ name: 'test-product',
1186
+ inStore: 'cluster',
1187
+ ifNotHaveType: 'missingtype',
1188
+ }]);
1189
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1190
+
1191
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1192
+
1193
+ expect(active).toHaveLength(1);
1194
+ expect(active[0].name).toBe('test-product');
1195
+ });
1196
+
1197
+ it('should hide product when matching type exists', () => {
1198
+ const state = createProductState([{
1199
+ name: 'test-product',
1200
+ inStore: 'cluster',
1201
+ ifNotHaveType: 'mytype',
1202
+ }]);
1203
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1204
+
1205
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1206
+
1207
+ expect(active).toHaveLength(0);
1208
+ });
1209
+
1210
+ it('should support regex pattern in ifNotHaveType', () => {
1211
+ const state = createProductState([{
1212
+ name: 'test-product',
1213
+ inStore: 'cluster',
1214
+ ifNotHaveType: 'my.*',
1215
+ }]);
1216
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1217
+
1218
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1219
+
1220
+ expect(active).toHaveLength(0);
1221
+ });
1222
+
1223
+ it('should show product when regex pattern does not match any type', () => {
1224
+ const state = createProductState([{
1225
+ name: 'test-product',
1226
+ inStore: 'cluster',
1227
+ ifNotHaveType: 'nomatch.*',
1228
+ }]);
1229
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1230
+
1231
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1232
+
1233
+ expect(active).toHaveLength(1);
1234
+ expect(active[0].name).toBe('test-product');
1235
+ });
1236
+ });
1237
+
1238
+ describe('combined ifHaveType and ifNotHaveType', () => {
1239
+ it('should show product when ifHaveType matches and ifNotHaveType does not match', () => {
1240
+ const state = createProductState([{
1241
+ name: 'test-product',
1242
+ inStore: 'cluster',
1243
+ ifHaveType: 'mytype',
1244
+ ifNotHaveType: 'missingtype',
1245
+ }]);
1246
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1247
+
1248
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1249
+
1250
+ expect(active).toHaveLength(1);
1251
+ expect(active[0].name).toBe('test-product');
1252
+ });
1253
+
1254
+ it('should hide product when ifHaveType matches but ifNotHaveType also matches', () => {
1255
+ const state = createProductState([{
1256
+ name: 'test-product',
1257
+ inStore: 'cluster',
1258
+ ifHaveType: 'mytype',
1259
+ ifNotHaveType: 'anothertype',
1260
+ }]);
1261
+ const rootGetters = createProductRootGetters([productSchemas.myType, productSchemas.anotherType]);
1262
+
1263
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1264
+
1265
+ expect(active).toHaveLength(0);
1266
+ });
1267
+
1268
+ it('should hide product when ifHaveType does not match', () => {
1269
+ const state = createProductState([{
1270
+ name: 'test-product',
1271
+ inStore: 'cluster',
1272
+ ifHaveType: 'missingtype',
1273
+ ifNotHaveType: 'anothermissingtype',
1274
+ }]);
1275
+ const rootGetters = createProductRootGetters([productSchemas.myType]);
1276
+
1277
+ const active = getters.activeProducts(state, {}, {}, rootGetters);
1278
+
1279
+ expect(active).toHaveLength(0);
1280
+ });
1281
+ });
1282
+ });
1119
1283
  });
1120
1284
  });
1121
-
1122
- // getTree - Remove ignored schemas, not-applicable to ns filter
package/store/auth.js CHANGED
@@ -149,12 +149,16 @@ export const actions = {
149
149
  force = true;
150
150
  }
151
151
 
152
- return dispatch('rancher/findAll', {
152
+ const providers = dispatch('rancher/findAll', {
153
153
  type: 'authProvider',
154
154
  opt: {
155
- url: `/v3-public/authProviders`, watch: false, force
155
+ url: `/v1-public/authproviders`,
156
+ watch: false,
157
+ force
156
158
  }
157
159
  }, { root: true });
160
+
161
+ return providers;
158
162
  },
159
163
 
160
164
  getAuthConfigs({ dispatch }) {
@@ -349,13 +353,21 @@ export const actions = {
349
353
  const driver = await dispatch('getAuthProvider', provider);
350
354
 
351
355
  try {
352
- const res = await driver.doAction('login', {
353
- description: 'UI session',
354
- responseType: 'cookie',
355
- ...body
356
- }, { redirectUnauthorized: false });
357
-
358
- return res;
356
+ return await dispatch(
357
+ 'management/request',
358
+ {
359
+ url: `/v1-public/login`,
360
+ method: 'post',
361
+ data: {
362
+ type: driver.type,
363
+ description: 'UI session',
364
+ responseType: 'cookie',
365
+ ...body
366
+ },
367
+ redirectUnauthorized: false,
368
+ },
369
+ { root: true }
370
+ );
359
371
  } catch (err) {
360
372
  if (err._status === 401) {
361
373
  return Promise.reject(LOGIN_ERRORS.CLIENT_UNAUTHORIZED);
@@ -402,14 +414,14 @@ export const actions = {
402
414
  }
403
415
 
404
416
  // Unload plugins - we will load again on login
405
- await rootState.$plugin.logout();
417
+ await rootState.$extension.logout();
406
418
 
407
419
  let logoutAction = '';
408
420
  const data = {};
409
421
 
410
422
  // SLO - Single-sign logout - will logout auth provider from all places where it's logged in
411
423
  if (options.slo) {
412
- logoutAction = '?logoutAll';
424
+ logoutAction = '?all';
413
425
  data.finalRedirectUrl = returnTo({ isSlo: true }, this);
414
426
  }
415
427
 
package/store/i18n.js CHANGED
@@ -285,8 +285,8 @@ export const actions = {
285
285
  return;
286
286
  }
287
287
 
288
- const lastLoad = rootState.$plugin?.lastLoad;
289
- const i18nExt = rootState.$plugin?.getDynamic('l10n', locale);
288
+ const lastLoad = rootState.$extension?.lastLoad;
289
+ const i18nExt = rootState.$extension?.getDynamic('l10n', locale);
290
290
  const reload = lastLoaded < lastLoad;
291
291
 
292
292
  lastLoaded = lastLoad;
@@ -314,7 +314,7 @@ export const actions = {
314
314
 
315
315
  // load all of the default locales from the plugins for fallback
316
316
  if (locale !== DEFAULT_LOCALE) {
317
- const defaultI18nExt = rootState.$plugin?.getDynamic('l10n', DEFAULT_LOCALE);
317
+ const defaultI18nExt = rootState.$extension?.getDynamic('l10n', DEFAULT_LOCALE);
318
318
 
319
319
  if (defaultI18nExt && defaultI18nExt.length) {
320
320
  defaultI18nExt.forEach((fn) => {
package/store/index.js CHANGED
@@ -233,7 +233,7 @@ const updateActiveNamespaceCache = (state, activeNamespaceCache) => {
233
233
  * Are we in the vai enabled world where mgmt clusters are paginated?
234
234
  */
235
235
  const paginateClusters = ({ rootGetters, state }) => {
236
- return paginationUtils.isEnabled({ rootGetters, $plugin: state.$plugin }, { store: 'management', resource: { id: MANAGEMENT.CLUSTER, context: 'side-bar' } });
236
+ return paginationUtils.isEnabled({ rootGetters, $extension: state.$extension }, { store: 'management', resource: { id: MANAGEMENT.CLUSTER, context: 'side-bar' } });
237
237
  };
238
238
 
239
239
  export const state = () => {
@@ -262,6 +262,7 @@ export const state = () => {
262
262
  $router: markRaw({}),
263
263
  $route: markRaw({}),
264
264
  $plugin: markRaw({}),
265
+ $extension: markRaw({}),
265
266
  showWorkspaceSwitcher: true,
266
267
  localCluster: null,
267
268
  };
@@ -775,6 +776,7 @@ export const mutations = {
775
776
  },
776
777
 
777
778
  setPlugin(state, pluginDefinition) {
779
+ state.$extension = markRaw(pluginDefinition || {});
778
780
  state.$plugin = markRaw(pluginDefinition || {});
779
781
  },
780
782
 
@@ -1195,7 +1197,7 @@ export const actions = {
1195
1197
 
1196
1198
  store.dispatch('gcStopIntervals');
1197
1199
 
1198
- Object.values(this.$plugin.getPlugins()).forEach((p) => {
1200
+ Object.values(this.$extension.getPlugins()).forEach((p) => {
1199
1201
  if (p.onLogOut) {
1200
1202
  p.onLogOut(store);
1201
1203
  }
@@ -1254,7 +1256,7 @@ export const actions = {
1254
1256
  dashboardClientInit({ dispatch, commit, rootState }, context) {
1255
1257
  commit('setRouter', context.app.router);
1256
1258
  commit('setRoute', context.route);
1257
- commit('setPlugin', context.app.$plugin);
1259
+ commit('setPlugin', context.app.$extension);
1258
1260
 
1259
1261
  dispatch('management/rehydrateSubscribe');
1260
1262
  dispatch('cluster/rehydrateSubscribe');
@@ -299,6 +299,8 @@ export const actions = {
299
299
 
300
300
  // Show a growl for the notification if necessary
301
301
  dispatch('growl/notification', notification, { root: true });
302
+
303
+ return notification.id;
302
304
  },
303
305
 
304
306
  async fromGrowl( { commit, getters }: any, notification: Notification) {
package/store/prefs.js CHANGED
@@ -233,13 +233,13 @@ export const getters = {
233
233
  }
234
234
  const clusterPref = getters['get'](CLUSTER);
235
235
 
236
- return { name: 'c-cluster-explorer', params: { product: 'explorer', cluster: clusterPref } };
236
+ return { name: 'c-cluster-explorer', params: { cluster: clusterPref } };
237
237
  }
238
238
  case (!!afterLoginRoutePref.match(/.+-dashboard$/)):
239
239
  {
240
240
  const clusterId = afterLoginRoutePref.split('-dashboard')[0];
241
241
 
242
- return { name: 'c-cluster-explorer', params: { product: 'explorer', cluster: clusterId } };
242
+ return { name: 'c-cluster-explorer', params: { cluster: clusterId } };
243
243
  }
244
244
  default:
245
245
  return { name: afterLoginRoutePref };