@rancher/shell 3.0.8-rc.8 → 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 (260) 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/brand/suse/dark/rancher-logo.svg +1 -64
  18. package/assets/styles/global/_tooltip.scss +6 -1
  19. package/assets/translations/en-us.yaml +14 -1
  20. package/components/ActionMenuShell.vue +3 -1
  21. package/components/BackLink.vue +8 -0
  22. package/components/BannerGraphic.vue +1 -5
  23. package/components/BrandImage.vue +17 -6
  24. package/components/Cron/CronExpressionEditor.vue +1 -1
  25. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  26. package/components/CruResource.vue +8 -1
  27. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
  28. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
  29. package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
  30. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
  31. package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
  32. package/components/LocaleSelector.vue +2 -2
  33. package/components/ModalManager.vue +11 -1
  34. package/components/Questions/__tests__/Yaml.test.ts +1 -1
  35. package/components/Questions/__tests__/index.test.ts +159 -0
  36. package/components/RelatedResources.vue +5 -0
  37. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  38. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  39. package/components/Resource/Detail/Metadata/index.vue +3 -3
  40. package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
  41. package/components/Resource/Detail/composables.ts +2 -2
  42. package/components/ResourceDetail/Masthead/latest.vue +23 -21
  43. package/components/ResourceDetail/index.vue +3 -0
  44. package/components/ResourceTable.vue +54 -21
  45. package/components/SlideInPanelManager.vue +16 -11
  46. package/components/SortableTable/THead.vue +2 -1
  47. package/components/SortableTable/index.vue +20 -2
  48. package/components/Tabbed/__tests__/index.test.ts +86 -0
  49. package/components/Tabbed/index.vue +37 -2
  50. package/components/__tests__/NamespaceFilter.test.ts +49 -0
  51. package/components/auth/SelectPrincipal.vue +28 -6
  52. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  53. package/components/auth/login/ldap.vue +3 -3
  54. package/components/fleet/FleetSecretSelector.vue +1 -1
  55. package/components/form/KeyValue.vue +1 -1
  56. package/components/form/NameNsDescription.vue +1 -1
  57. package/components/form/NodeScheduling.vue +2 -2
  58. package/components/form/ResourceTabs/composable.ts +2 -2
  59. package/components/form/ResourceTabs/index.vue +0 -2
  60. package/components/form/__tests__/NameNsDescription.test.ts +42 -0
  61. package/components/formatter/InternalExternalIP.vue +4 -1
  62. package/components/formatter/LinkName.vue +5 -0
  63. package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
  64. package/components/nav/Group.vue +25 -7
  65. package/components/nav/Header.vue +1 -1
  66. package/components/nav/NamespaceFilter.vue +1 -0
  67. package/components/nav/Type.vue +17 -6
  68. package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
  69. package/components/nav/__tests__/Type.test.ts +59 -0
  70. package/components/templates/standalone.vue +1 -1
  71. package/composables/cruResource.ts +27 -0
  72. package/composables/focusTrap.ts +3 -1
  73. package/composables/resourceDetail.ts +15 -0
  74. package/composables/useI18n.ts +10 -1
  75. package/composables/useLabeledFormElement.ts +3 -4
  76. package/config/__test__/uiplugins.test.ts +309 -0
  77. package/config/labels-annotations.js +1 -0
  78. package/config/product/explorer.js +3 -1
  79. package/config/product/fleet.js +1 -1
  80. package/config/router/navigation-guards/clusters.js +3 -3
  81. package/config/router/navigation-guards/products.js +1 -1
  82. package/config/router/routes.js +7 -7
  83. package/config/types.js +7 -0
  84. package/config/uiplugins.js +46 -2
  85. package/core/__tests__/extension-manager-impl.test.js +437 -0
  86. package/core/extension-manager-impl.js +21 -25
  87. package/core/plugin-helpers.ts +2 -2
  88. package/core/plugin.ts +9 -1
  89. package/core/plugins-loader.js +2 -2
  90. package/core/types-provisioning.ts +5 -1
  91. package/core/types.ts +35 -0
  92. package/detail/provisioning.cattle.io.cluster.vue +9 -6
  93. package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
  94. package/dialog/MoveNamespaceDialog.vue +20 -4
  95. package/dialog/RollbackWorkloadDialog.vue +2 -5
  96. package/dialog/SearchDialog.vue +1 -0
  97. package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
  98. package/directives/__tests__/clean-tooltip.test.ts +298 -0
  99. package/directives/clean-tooltip.ts +234 -0
  100. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
  101. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +100 -3
  102. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  103. package/edit/configmap.vue +1 -0
  104. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  105. package/edit/fleet.cattle.io.helmop.vue +11 -6
  106. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  107. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  108. package/edit/logging-flow/index.vue +1 -0
  109. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  110. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  111. package/edit/management.cattle.io.project.vue +1 -0
  112. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  113. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  114. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  115. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  116. package/edit/monitoring.coreos.com.route.vue +1 -1
  117. package/edit/namespace.vue +1 -0
  118. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  119. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  120. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  121. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  122. package/edit/node.vue +1 -0
  123. package/edit/persistentvolume/index.vue +27 -22
  124. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  125. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  126. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  127. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  128. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  129. package/edit/persistentvolume/plugins/csi.vue +18 -16
  130. package/edit/persistentvolume/plugins/fc.vue +13 -14
  131. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  132. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  133. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  134. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  135. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  136. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  137. package/edit/persistentvolume/plugins/local.vue +1 -3
  138. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  139. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  140. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  141. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  142. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  143. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  144. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  145. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  146. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  147. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  148. package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
  149. package/edit/provisioning.cattle.io.cluster/rke2.vue +9 -8
  150. package/edit/resources.cattle.io.restore.vue +1 -1
  151. package/edit/secret/index.vue +1 -1
  152. package/edit/service.vue +1 -0
  153. package/edit/serviceaccount.vue +1 -0
  154. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  155. package/edit/workload/Job.vue +2 -2
  156. package/edit/workload/index.vue +2 -1
  157. package/edit/workload/mixins/workload.js +1 -1
  158. package/initialize/App.vue +4 -4
  159. package/initialize/install-plugins.js +19 -5
  160. package/machine-config/azure.vue +1 -1
  161. package/machine-config/components/GCEImage.vue +1 -1
  162. package/mixins/__tests__/brand.spec.ts +2 -2
  163. package/mixins/brand.js +1 -7
  164. package/mixins/create-edit-view/index.js +5 -0
  165. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
  166. package/models/chart.js +70 -74
  167. package/models/management.cattle.io.cluster.js +21 -3
  168. package/models/provisioning.cattle.io.cluster.js +31 -11
  169. package/package.json +11 -10
  170. package/pages/auth/login.vue +4 -6
  171. package/pages/auth/setup.vue +1 -1
  172. package/pages/auth/verify.vue +3 -3
  173. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  174. package/pages/c/_cluster/apps/charts/chart.vue +33 -15
  175. package/pages/c/_cluster/apps/charts/index.vue +122 -24
  176. package/pages/c/_cluster/apps/charts/install.vue +33 -0
  177. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  178. package/pages/c/_cluster/explorer/index.vue +8 -6
  179. package/pages/c/_cluster/fleet/index.vue +4 -7
  180. package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
  181. package/pages/c/_cluster/settings/brand.vue +1 -1
  182. package/pages/c/_cluster/settings/index.vue +5 -0
  183. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  184. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  185. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  186. package/pkg/auto-import.js +3 -3
  187. package/pkg/dynamic-importer.lib.js +1 -1
  188. package/pkg/import.js +1 -1
  189. package/plugins/__tests__/mutations.tests.ts +179 -0
  190. package/plugins/dashboard-client-init.js +3 -0
  191. package/plugins/dashboard-store/getters.js +19 -2
  192. package/plugins/dashboard-store/model-loader.js +1 -1
  193. package/plugins/dashboard-store/mutations.js +23 -2
  194. package/plugins/dashboard-store/resource-class.js +11 -5
  195. package/plugins/i18n.js +8 -0
  196. package/plugins/plugin.js +2 -2
  197. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
  198. package/plugins/steve/steve-class.js +1 -1
  199. package/plugins/steve/steve-pagination-utils.ts +131 -47
  200. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  201. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  202. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
  203. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  204. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  205. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  206. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  207. package/rancher-components/Pill/types.ts +0 -1
  208. package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
  209. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  210. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  211. package/rancher-components/RcIcon/index.ts +1 -0
  212. package/rancher-components/RcIcon/types.ts +160 -0
  213. package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
  214. package/rancher-components/utils/status.test.ts +67 -0
  215. package/rancher-components/utils/status.ts +77 -0
  216. package/scripts/publish-shell.sh +25 -0
  217. package/scripts/typegen.sh +1 -0
  218. package/store/__tests__/catalog.test.ts +1 -1
  219. package/store/__tests__/type-map.test.ts +164 -2
  220. package/store/action-menu.js +8 -0
  221. package/store/auth.js +25 -13
  222. package/store/catalog.js +6 -0
  223. package/store/i18n.js +3 -3
  224. package/store/index.js +8 -6
  225. package/store/notifications.ts +2 -0
  226. package/store/prefs.js +6 -7
  227. package/store/type-map.js +17 -7
  228. package/store/wm.ts +4 -4
  229. package/types/internal-api/shell/modal.d.ts +6 -6
  230. package/types/notifications/index.ts +126 -15
  231. package/types/rancher/index.d.ts +9 -0
  232. package/types/shell/index.d.ts +54 -3
  233. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  234. package/types/store/pagination.types.ts +157 -9
  235. package/types/vue-shim.d.ts +5 -4
  236. package/utils/__tests__/provider.test.ts +98 -0
  237. package/utils/__tests__/router.test.js +238 -0
  238. package/utils/__tests__/selector-typed.test.ts +263 -0
  239. package/utils/cluster.js +4 -1
  240. package/utils/color.js +1 -1
  241. package/utils/dynamic-content/__tests__/info.test.ts +6 -0
  242. package/utils/dynamic-content/info.ts +43 -0
  243. package/utils/favicon.js +4 -4
  244. package/utils/fleet.ts +8 -1
  245. package/utils/pagination-utils.ts +2 -2
  246. package/utils/pagination-wrapper.ts +1 -1
  247. package/utils/provider.ts +14 -0
  248. package/utils/router.js +50 -0
  249. package/utils/selector-typed.ts +6 -2
  250. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  251. package/vue.config.js +3 -3
  252. package/composables/useExtensionManager.ts +0 -17
  253. package/core/plugins.js +0 -38
  254. package/directives/clean-tooltip.js +0 -32
  255. package/plugins/internal-api/index.ts +0 -37
  256. package/plugins/internal-api/shared/base-api.ts +0 -13
  257. package/plugins/internal-api/shell/shell.api.ts +0 -108
  258. package/plugins/nuxt-client-init.js +0 -3
  259. package/types/internal-api/shell/growl.d.ts +0 -25
  260. package/types/internal-api/shell/slideIn.d.ts +0 -15
@@ -0,0 +1,137 @@
1
+ import { PaginationFilterEquality, PaginationFilterField } from '@shell/types/store/pagination.types';
2
+
3
+ describe('pagination-types', () => {
4
+ describe('class: PaginationFilterField', () => {
5
+ describe('constructor', () => {
6
+ it('should set properties correctly with default values', () => {
7
+ const field = 'testField';
8
+ const value = 'testValue';
9
+ const filterField = new PaginationFilterField({ field, value });
10
+
11
+ expect(filterField.field).toBe(field);
12
+ expect(filterField.value).toBe(value);
13
+ expect(filterField.equals).toBe(true);
14
+ expect(filterField.exact).toBe(true);
15
+ expect(filterField.exists).toBe(false);
16
+ expect(filterField.equality).toBe(PaginationFilterEquality.EQUALS);
17
+ });
18
+
19
+ it('should handle deprecated `equals` and `exact` to set `equality`', () => {
20
+ // equals: true, exact: true
21
+ let ff = new PaginationFilterField({
22
+ field: 'f', value: 'v', equals: true, exact: true
23
+ });
24
+
25
+ expect(ff.equality).toBe(PaginationFilterEquality.EQUALS);
26
+
27
+ // equals: true, exact: false
28
+ ff = new PaginationFilterField({
29
+ field: 'f', value: 'v', equals: true, exact: false
30
+ });
31
+ expect(ff.equality).toBe(PaginationFilterEquality.CONTAINS);
32
+
33
+ // equals: false, exact: true
34
+ ff = new PaginationFilterField({
35
+ field: 'f', value: 'v', equals: false, exact: true
36
+ });
37
+ expect(ff.equality).toBe(PaginationFilterEquality.NOT_EQUALS);
38
+
39
+ // equals: false, exact: false
40
+ ff = new PaginationFilterField({
41
+ field: 'f', value: 'v', equals: false, exact: false
42
+ });
43
+ expect(ff.equality).toBe(PaginationFilterEquality.NOT_CONTAINS);
44
+ });
45
+
46
+ it('should prioritize `equality` over `equals` and `exact`', () => {
47
+ const filterField = new PaginationFilterField({
48
+ field: 'f',
49
+ value: 'v',
50
+ equals: false,
51
+ exact: false,
52
+ equality: PaginationFilterEquality.GREATER_THAN
53
+ });
54
+
55
+ expect(filterField.equality).toBe(PaginationFilterEquality.GREATER_THAN);
56
+ });
57
+
58
+ it('should throw an error if no equality can be determined', () => {
59
+ expect(() => new PaginationFilterField({
60
+ field: 'f',
61
+ value: 'v',
62
+ equals: null,
63
+ exact: null
64
+ })).toThrow('A pagination filter must have either equals or equality set');
65
+ });
66
+
67
+ it('should set `exists` property', () => {
68
+ const filterField = new PaginationFilterField({ field: 'f', exists: true });
69
+
70
+ expect(filterField.exists).toBe(true);
71
+ });
72
+ });
73
+
74
+ describe('safeEquality', () => {
75
+ it('should return EQUALS for equals=true, exact=true', () => {
76
+ const equality = PaginationFilterField.safeEquality({ equals: true, exact: true });
77
+
78
+ expect(equality).toBe(PaginationFilterEquality.EQUALS);
79
+ });
80
+
81
+ it('should return CONTAINS for equals=true, exact=false', () => {
82
+ const equality = PaginationFilterField.safeEquality({ equals: true, exact: false });
83
+
84
+ expect(equality).toBe(PaginationFilterEquality.CONTAINS);
85
+ });
86
+
87
+ it('should return NOT_EQUALS for equals=false, exact=true', () => {
88
+ const equality = PaginationFilterField.safeEquality({ equals: false, exact: true });
89
+
90
+ expect(equality).toBe(PaginationFilterEquality.NOT_EQUALS);
91
+ });
92
+
93
+ it('should return NOT_CONTAINS for equals=false, exact=false', () => {
94
+ const equality = PaginationFilterField.safeEquality({ equals: false, exact: false });
95
+
96
+ expect(equality).toBe(PaginationFilterEquality.NOT_CONTAINS);
97
+ });
98
+
99
+ it('should return equality if it is provided', () => {
100
+ const equality = PaginationFilterField.safeEquality({ equality: PaginationFilterEquality.IN });
101
+
102
+ expect(equality).toBe(PaginationFilterEquality.IN);
103
+ });
104
+
105
+ it('should prioritize equality over equals/exact', () => {
106
+ const equality = PaginationFilterField.safeEquality({
107
+ equals: true,
108
+ exact: false,
109
+ equality: PaginationFilterEquality.LESS_THAN
110
+ });
111
+
112
+ expect(equality).toBe(PaginationFilterEquality.LESS_THAN);
113
+ });
114
+
115
+ it('should return undefined if no equality can be determined', () => {
116
+ const equality = PaginationFilterField.safeEquality({});
117
+
118
+ expect(equality).toBeUndefined();
119
+ });
120
+
121
+ it('should work with an instance of PaginationFilterField', () => {
122
+ const ff = new PaginationFilterField({
123
+ field: 'f',
124
+ value: 'v',
125
+ equals: false,
126
+ exact: false,
127
+ equality: PaginationFilterEquality.GREATER_THAN
128
+ });
129
+
130
+ // safeEquality will prioritize the `equality` property on the instance
131
+ const equality = PaginationFilterField.safeEquality(ff);
132
+
133
+ expect(equality).toBe(PaginationFilterEquality.GREATER_THAN);
134
+ });
135
+ });
136
+ });
137
+ });
@@ -13,6 +13,8 @@ import { KubeLabelSelector } from '@shell/types/kube/kube-api';
13
13
  // The two important / complex params are currently
14
14
  // - `filter` https://github.com/rancher/steve?tab=readme-ov-file#filter
15
15
  // - represented by `PaginationParamFilter extends PaginationParam`
16
+ // - a filter has filter fields which are made up of a field name, equality and value/s
17
+ // - filter=<field><equality><value>
16
18
  // - Examples
17
19
  // - filter=metadata.name=123
18
20
  // - filter=metadata.name=123,metadata.name=456 (name is 123 OR 456)
@@ -45,14 +47,111 @@ export interface PaginationSort {
45
47
  asc: boolean
46
48
  }
47
49
 
50
+ /**
51
+ * Equalities that can be used with a `filter` query param
52
+ *
53
+ * filter=<field><equality><values>
54
+ *
55
+ * For example
56
+ * - filter=a=b
57
+ * - filter=a!=b
58
+ * - filter=a NOT IN (b,c,d)
59
+ */
60
+ export const enum PaginationFilterEquality {
61
+ /**
62
+ * Field is in a collection of values
63
+ */
64
+ IN = ' IN ', // eslint-disable-line no-unused-vars
65
+ /**
66
+ * Field is not in a collection of values
67
+ */
68
+ NOT_IN = ' NOTIN ', // eslint-disable-line no-unused-vars
69
+ /**
70
+ * Field matches a value
71
+ */
72
+ EQUALS= '=', // eslint-disable-line no-unused-vars
73
+ /**
74
+ * Field does not match a value
75
+ */
76
+ NOT_EQUALS= '!=', // eslint-disable-line no-unused-vars
77
+ /**
78
+ * Unknown
79
+ */
80
+ STRICT_EQUALS = '==', // eslint-disable-line no-unused-vars
81
+ /**
82
+ * Field must partially match a value
83
+ */
84
+ CONTAINS= '~', // eslint-disable-line no-unused-vars
85
+ /**
86
+ * Field must not partially match a value
87
+ */
88
+ NOT_CONTAINS= '!~', // eslint-disable-line no-unused-vars
89
+ /**
90
+ * Field must be greater than a value
91
+ */
92
+ GREATER_THAN= 'gt', // eslint-disable-line no-unused-vars
93
+ /**
94
+ * Field must be less than a value
95
+ */
96
+ LESS_THAN= 'lt', // eslint-disable-line no-unused-vars
97
+ }
98
+
99
+ /**
100
+ * Ctor args for a @PaginationFilterField
101
+ */
102
+ type FilterFieldCtorArgs = {
103
+ /**
104
+ * Name of field within the object to filter by for example the x of x=y
105
+ *
106
+ * This can be optional for some (projectsornamespaces)
107
+ */
108
+ field?: string;
109
+ /**
110
+ * Value of field within the object to filter by for example the y of x=y
111
+ *
112
+ * This can be empty if `exists` is true
113
+ */
114
+ value?: string;
115
+ /**
116
+ * Equality field within the object to filter by for example the `=` or `!=` of x=y
117
+ *
118
+ * @deprecated Please use `equality` instead of equals and exact
119
+ */
120
+ equals?: boolean;
121
+ /**
122
+ * Match the field exactly. False for partial matches
123
+ *
124
+ * Value: pod1
125
+ * Exact: true. "p" no, "pod", no, "pod1" yes
126
+ * Exact: false. "p" yes, "pod", yes, "pod1" yes
127
+ *
128
+ * @deprecated Please use `equality` instead of equals and exact
129
+ */
130
+ exact?: boolean,
131
+ /**
132
+ * Check if the field/property exists, regardless of value
133
+ *
134
+ * If this is false it does not flip the expectation, just doesn't add the field
135
+ */
136
+ exists?: boolean,
137
+ /**
138
+ * Equality symbol used to compare the field with the value
139
+ */
140
+ equality?: PaginationFilterEquality
141
+ }
142
+
48
143
  /**
49
144
  * Filter the pagination result by these specific fields
50
145
  *
146
+ * In format of <field><equality><value>
147
+ *
51
148
  * For example
52
149
  *
53
150
  * - metadata.name=test
54
151
  * - metadata.namespace!=system
55
152
  *
153
+ * These are sub items for @PaginationParam, for example filter=<PaginationFilterField>
154
+ *
56
155
  * For more information regarding the API see https://github.com/rancher/steve?tab=readme-ov-file#query-parameters
57
156
  */
58
157
  export class PaginationFilterField {
@@ -70,6 +169,8 @@ export class PaginationFilterField {
70
169
  value?: string;
71
170
  /**
72
171
  * Equality field within the object to filter by for example the `=` or `!=` of x=y
172
+ *
173
+ * @deprecated Please use `equality` instead of equals and exact
73
174
  */
74
175
  equals?: boolean;
75
176
  /**
@@ -78,9 +179,14 @@ export class PaginationFilterField {
78
179
  * Value: pod1
79
180
  * Exact: true. "p" no, "pod", no, "pod1" yes
80
181
  * Exact: false. "p" yes, "pod", yes, "pod1" yes
182
+ *
183
+ * @deprecated Please use `equality` instead of equals and exact
81
184
  */
82
185
  exact?: boolean;
83
-
186
+ /**
187
+ * Equality symbol used to compare the field with the value
188
+ */
189
+ equality?: PaginationFilterEquality;
84
190
  /**
85
191
  * Check if the field/property exists, regardless of value
86
192
  *
@@ -88,17 +194,51 @@ export class PaginationFilterField {
88
194
  */
89
195
  exists?: boolean;
90
196
 
91
- constructor(
92
- {
93
- field, value = '', equals = true, exact = true, exists = false
94
- }:
95
- { field?: string; value?: string; equals?: boolean; exact?: boolean; exists?:boolean;}
96
- ) {
197
+ constructor(args: FilterFieldCtorArgs) {
198
+ const {
199
+ field, value = '', equals = true, exact = true, equality = undefined, exists = false
200
+ } = args;
201
+
97
202
  this.field = field;
98
203
  this.value = value;
99
204
  this.equals = equals;
100
205
  this.exact = exact;
101
206
  this.exists = exists;
207
+
208
+ const _equality = PaginationFilterField.safeEquality({
209
+ field, value, equals, exact, equality, exists
210
+ });
211
+
212
+ if (_equality) {
213
+ this.equality = _equality;
214
+ } else {
215
+ throw new Error('A pagination filter must have either equals or equality set');
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Determine equality for this field.
221
+ *
222
+ * Mainly to ensure legacy objects using deprecated fields instead of new equality field fall back on something sensible
223
+ */
224
+ static safeEquality(args: FilterFieldCtorArgs | PaginationFilterField): PaginationFilterEquality | undefined {
225
+ if (args.equality) {
226
+ return args.equality;
227
+ }
228
+
229
+ if (args.equals === true) {
230
+ if (args.exact === true) {
231
+ return PaginationFilterEquality.EQUALS;
232
+ } else {
233
+ return PaginationFilterEquality.CONTAINS;
234
+ }
235
+ } else if (args.equals === false) {
236
+ if (args.exact === true) {
237
+ return PaginationFilterEquality.NOT_EQUALS;
238
+ } else {
239
+ return PaginationFilterEquality.NOT_CONTAINS;
240
+ }
241
+ }
102
242
  }
103
243
  }
104
244
 
@@ -202,7 +342,15 @@ export abstract class PaginationParam {
202
342
  }
203
343
 
204
344
  /**
205
- * This is a convenience class for the `filter` param which works some magic, adds defaults and converts to the required PaginationParam format
345
+ * This is a convenience class for the `filter` param which works some magic, adds defaults and converts to the required PaginationParam format.
346
+ *
347
+ * for example
348
+ *
349
+ * - filter=???
350
+ *
351
+ * including `fields` this could be
352
+ *
353
+ * - filter=a=b
206
354
  *
207
355
  * See description for {@link PaginationParam} for how multiple of these can be combined together to AND or OR together
208
356
  *
@@ -238,7 +386,7 @@ export class PaginationParamFilter extends PaginationParam {
238
386
  /**
239
387
  * Convenience method when you just want an instance of {@link PaginationParamFilter} with a simple `filter=x=y` param
240
388
  */
241
- static createSingleField(field: { field?: string; value?: string; equals?: boolean; exact?: boolean, exists?: boolean }): PaginationParam {
389
+ static createSingleField(field: FilterFieldCtorArgs): PaginationParam {
242
390
  return new PaginationParamFilter({ fields: [new PaginationFilterField(field)] });
243
391
  }
244
392
 
@@ -1,7 +1,9 @@
1
1
  /* eslint-disable */
2
- import type ShellApi from '@shell/plugins/internal-api/shell/shell.api';
3
2
  import { VuexStore } from '@shell/types/store/vuex';
4
3
 
4
+ // Include the types for the APIs
5
+ /// <reference path="../apis/vue-shim.d.ts" />
6
+
5
7
  export {};
6
8
 
7
9
  declare module 'vue' {
@@ -14,7 +16,6 @@ declare module 'vue' {
14
16
  (key: string, args?: Record<string, any>, raw?: boolean): string;
15
17
  (options: { k: string; raw?: boolean; tag?: string | Record<string, any>; escapehtml?: boolean }): string;
16
18
  },
17
- $store: VuexStore,
18
- $shell: ShellApi,
19
+ $store: VuexStore
19
20
  }
20
- }
21
+ }
@@ -0,0 +1,98 @@
1
+ import { getHostedProviders, isHostedProvider } from '../provider';
2
+ import { ClusterProvisionerContext, IClusterProvisioner } from '@shell/core/types';
3
+
4
+ const DEFAULT_CONTEXT = {
5
+ dispatch: {},
6
+ getters: {},
7
+ axios: {},
8
+ t: (args: any) => args.join(' '),
9
+ };
10
+
11
+ const MOCK_PROVIDERS: IClusterProvisioner[] = [
12
+ { id: 'AKS', group: 'hosted' } as IClusterProvisioner,
13
+ { id: 'EKS', group: 'hosted' } as IClusterProvisioner,
14
+ { id: 'GKE', group: 'hosted' } as IClusterProvisioner,
15
+ { id: 'alibaba', group: 'hosted' } as IClusterProvisioner,
16
+ { id: 'other', group: 'other' } as IClusterProvisioner,
17
+ ];
18
+
19
+ describe('utils/provider', () => {
20
+ describe('getHostedProviders', () => {
21
+ it('should return an empty array when context.$extension is undefined', () => {
22
+ const context = { ...DEFAULT_CONTEXT } as ClusterProvisionerContext;
23
+ const result = getHostedProviders(context);
24
+
25
+ expect(result).toStrictEqual([]);
26
+ });
27
+
28
+ it('should return hosted providers when context.$extension is defined', () => {
29
+ const context = {
30
+ ...DEFAULT_CONTEXT,
31
+ $extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
32
+ } as unknown as ClusterProvisionerContext;
33
+
34
+ const result = getHostedProviders(context);
35
+
36
+ expect(result).toStrictEqual([
37
+ { id: 'AKS', group: 'hosted' },
38
+ { id: 'EKS', group: 'hosted' },
39
+ { id: 'GKE', group: 'hosted' },
40
+ { id: 'alibaba', group: 'hosted' },
41
+ ]);
42
+ expect(context.$extension.getProviders).toHaveBeenCalledWith(context);
43
+ });
44
+
45
+ it('should return an empty array if getProviders returns null', () => {
46
+ const context = {
47
+ ...DEFAULT_CONTEXT,
48
+ $extension: { getProviders: jest.fn().mockReturnValue(null) }
49
+ } as unknown as ClusterProvisionerContext;
50
+
51
+ const result = getHostedProviders(context);
52
+
53
+ expect(result).toStrictEqual([]);
54
+ });
55
+
56
+ it('should return an empty array if getProviders returns undefined', () => {
57
+ const context = {
58
+ ...DEFAULT_CONTEXT,
59
+ $extension: { getProviders: jest.fn().mockReturnValue(undefined) }
60
+ } as unknown as ClusterProvisionerContext;
61
+
62
+ const result = getHostedProviders(context);
63
+
64
+ expect(result).toStrictEqual([]);
65
+ });
66
+ });
67
+
68
+ describe('isHostedProvider', () => {
69
+ it('should return false if provisioner is not provided', () => {
70
+ const context = {
71
+ ...DEFAULT_CONTEXT,
72
+ $extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
73
+ } as ClusterProvisionerContext;
74
+
75
+ expect(isHostedProvider(context, '')).toBe(false);
76
+ expect(isHostedProvider(context, undefined as any)).toBe(false);
77
+ expect(isHostedProvider(context, null as any)).toBe(false);
78
+ });
79
+
80
+ it('should return true only if provisioner is in the list of hosted providers', () => {
81
+ const context = {
82
+ ...DEFAULT_CONTEXT,
83
+ $extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
84
+ } as ClusterProvisionerContext;
85
+
86
+ expect(isHostedProvider(context, 'AKS')).toBe(true);
87
+ expect(isHostedProvider(context, 'eks')).toBe(true);
88
+ expect(isHostedProvider(context, 'different')).toBe(false); // case-insensitive check
89
+ expect(isHostedProvider(context, 'other')).toBe(false); // case-insensitive check
90
+ });
91
+
92
+ it('should return false if there are no hosted providers', () => {
93
+ const context = { ...DEFAULT_CONTEXT, $extension: { getProviders: jest.fn().mockReturnValue([]) } } as ClusterProvisionerContext;
94
+
95
+ expect(isHostedProvider(context, 'prov1')).toBe(false);
96
+ });
97
+ });
98
+ });