@rancher/shell 3.0.5-rc.5 → 3.0.5-rc.7

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 (361) hide show
  1. package/assets/data/aws-regions.json +1 -0
  2. package/assets/images/key.svg +17 -0
  3. package/assets/styles/base/_spacing.scss +2 -2
  4. package/assets/styles/base/_variables.scss +17 -11
  5. package/assets/styles/global/_form.scss +1 -1
  6. package/assets/styles/global/_labeled-input.scss +1 -1
  7. package/assets/styles/themes/_dark.scss +5 -0
  8. package/assets/styles/themes/_light.scss +11 -2
  9. package/assets/styles/vendor/vue-select.scss +1 -1
  10. package/assets/translations/en-us.yaml +426 -64
  11. package/assets/translations/zh-hans.yaml +3 -4
  12. package/cloud-credential/gcp.vue +9 -1
  13. package/components/AppModal.vue +2 -0
  14. package/components/CodeMirror.vue +2 -2
  15. package/components/ConfigMapSettings/Settings.vue +377 -0
  16. package/components/ConfigMapSettings/index.vue +354 -0
  17. package/components/CruResource.vue +1 -2
  18. package/components/DetailText.vue +61 -11
  19. package/components/Drawer/Chrome.vue +115 -0
  20. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +61 -0
  21. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +48 -0
  22. package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +54 -0
  23. package/components/Drawer/ResourceDetailDrawer/__tests__/YamlTab.test.ts +80 -0
  24. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +106 -0
  25. package/components/Drawer/ResourceDetailDrawer/__tests__/helpers.test.ts +42 -0
  26. package/components/Drawer/ResourceDetailDrawer/composables.ts +53 -0
  27. package/components/Drawer/ResourceDetailDrawer/helpers.ts +10 -0
  28. package/components/Drawer/ResourceDetailDrawer/index.vue +111 -0
  29. package/components/GrowlManager.vue +16 -15
  30. package/components/IconOrSvg.vue +5 -0
  31. package/components/KeyValueView.vue +1 -1
  32. package/components/Loading.vue +1 -1
  33. package/components/LocaleSelector.vue +9 -1
  34. package/components/PaginatedResourceTable.vue +46 -1
  35. package/components/ProgressBarMulti.vue +1 -0
  36. package/components/PromptModal.vue +6 -1
  37. package/components/PromptRestore.vue +22 -44
  38. package/components/RelatedResources.vue +4 -12
  39. package/components/Resource/Detail/Additional.vue +46 -0
  40. package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
  41. package/components/Resource/Detail/Metadata/Annotations/index.vue +5 -0
  42. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +223 -0
  43. package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +47 -256
  44. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +317 -0
  45. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +34 -5
  46. package/components/Resource/Detail/Metadata/KeyValue.vue +32 -22
  47. package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -1
  48. package/components/Resource/Detail/Metadata/Labels/index.vue +4 -0
  49. package/components/Resource/Detail/Metadata/Rectangle.vue +3 -1
  50. package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +1 -1
  51. package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +1 -1
  52. package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +75 -0
  53. package/components/Resource/Detail/Metadata/composables.ts +60 -11
  54. package/components/Resource/Detail/Metadata/index.vue +12 -5
  55. package/components/Resource/Detail/Page.vue +15 -0
  56. package/components/Resource/Detail/ResourceRow.vue +37 -18
  57. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/__tests__/composables.test.ts +29 -0
  58. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/__tests__/index.test.ts +48 -0
  59. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/composables.ts +31 -0
  60. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/index.vue +50 -0
  61. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/__tests__/composables.test.ts +66 -0
  62. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/composables.ts +21 -0
  63. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/index.vue +31 -0
  64. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Basic.vue +45 -0
  65. package/components/Resource/Detail/ResourceTabs/SecretDataTab/BasicAuth.vue +31 -0
  66. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Certificate.vue +31 -0
  67. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Registry.vue +22 -0
  68. package/components/Resource/Detail/ResourceTabs/SecretDataTab/ServiceAccountToken.vue +31 -0
  69. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Ssh.vue +32 -0
  70. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Basic.test.ts +40 -0
  71. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/BasicAuth.test.ts +33 -0
  72. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Certificate.test.ts +33 -0
  73. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Registry.test.ts +27 -0
  74. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/ServiceAccountToken.test.ts +33 -0
  75. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Ssh.test.ts +33 -0
  76. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/auth-types.test.ts +186 -0
  77. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/composables.test.ts +102 -0
  78. package/components/Resource/Detail/ResourceTabs/SecretDataTab/auth-types.ts +109 -0
  79. package/components/Resource/Detail/ResourceTabs/SecretDataTab/composeables.ts +52 -0
  80. package/components/Resource/Detail/ResourceTabs/SecretDataTab/index.vue +71 -0
  81. package/components/Resource/Detail/SpacedRow.vue +1 -1
  82. package/components/Resource/Detail/TitleBar/Title.vue +2 -1
  83. package/components/Resource/Detail/TitleBar/__tests__/Title.test.ts +1 -1
  84. package/components/Resource/Detail/TitleBar/__tests__/Top.test.ts +1 -1
  85. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +63 -0
  86. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
  87. package/components/Resource/Detail/TitleBar/composables.ts +45 -0
  88. package/components/Resource/Detail/TitleBar/index.vue +85 -13
  89. package/components/Resource/Detail/composables.ts +45 -0
  90. package/components/ResourceDetail/Masthead/__tests__/index.test.ts +70 -0
  91. package/components/ResourceDetail/{__tests__/Masthead.test.ts → Masthead/__tests__/legacy.test.ts} +3 -3
  92. package/components/ResourceDetail/Masthead/index.vue +65 -0
  93. package/components/ResourceDetail/Masthead/latest.vue +44 -0
  94. package/components/ResourceDetail/{Masthead.vue → Masthead/legacy.vue} +1 -1
  95. package/components/ResourceDetail/__tests__/index.test.ts +26 -5
  96. package/components/ResourceDetail/index.vue +33 -17
  97. package/components/ResourceDetail/legacy.vue +18 -1
  98. package/components/ResourceList/Masthead.vue +6 -0
  99. package/components/ResourceList/index.vue +1 -0
  100. package/components/ResourceTable.vue +6 -1
  101. package/components/ResourceYaml.vue +15 -2
  102. package/components/RichTranslation.vue +106 -0
  103. package/components/SlideInPanelManager.vue +46 -11
  104. package/components/SortableTable/index.vue +1 -1
  105. package/components/SortableTable/selection.js +0 -1
  106. package/components/StateDot/index.vue +28 -0
  107. package/components/Tabbed/index.vue +17 -16
  108. package/components/Wizard.vue +4 -2
  109. package/components/__tests__/ConfigMapSettings.test.ts +376 -0
  110. package/components/__tests__/GrowlManager.test.ts +0 -25
  111. package/components/__tests__/PromptRestore.test.ts +1 -65
  112. package/components/__tests__/RichTranslation.test.ts +115 -0
  113. package/components/auth/login/ldap.vue +1 -1
  114. package/components/fleet/FleetApplications.vue +0 -7
  115. package/components/fleet/FleetClusterTargets/TargetsList.vue +66 -0
  116. package/components/fleet/FleetClusterTargets/index.vue +455 -0
  117. package/components/fleet/FleetClusters.vue +25 -6
  118. package/components/fleet/FleetGitRepoPaths.vue +476 -0
  119. package/components/fleet/FleetHelmOps.vue +8 -0
  120. package/components/fleet/FleetRepos.vue +1 -6
  121. package/components/fleet/FleetResources.vue +4 -5
  122. package/components/fleet/FleetValuesFrom.vue +295 -0
  123. package/components/fleet/__tests__/FleetClusterTargets.test.ts +1224 -0
  124. package/components/fleet/__tests__/FleetGitRepoPaths.test.ts +265 -0
  125. package/components/fleet/__tests__/FleetOCIStorageSecret.test.ts +13 -13
  126. package/components/fleet/__tests__/FleetValuesFrom.test.ts +300 -0
  127. package/components/fleet/dashboard/ResourceCard.vue +1 -0
  128. package/components/fleet/dashboard/ResourceCardSummary.vue +1 -5
  129. package/components/fleet/dashboard/ResourceDetails.vue +8 -10
  130. package/components/fleet/dashboard/ResourcePanel.vue +17 -9
  131. package/components/form/ArrayList.vue +13 -2
  132. package/components/form/ChangePassword.vue +3 -1
  133. package/components/form/FileImageSelector.vue +1 -1
  134. package/components/form/Footer.vue +10 -4
  135. package/components/form/KeyValue.vue +81 -43
  136. package/components/form/LabeledSelect.vue +56 -16
  137. package/components/form/Labels.vue +90 -17
  138. package/components/form/MatchExpressions.vue +46 -5
  139. package/components/form/NameNsDescription.vue +2 -1
  140. package/components/form/Networking.vue +24 -19
  141. package/components/form/ResourceLabeledSelect.vue +4 -3
  142. package/components/form/ResourceSelector.vue +1 -0
  143. package/components/form/ResourceTabs/index.vue +5 -0
  144. package/components/form/SecretSelector.vue +9 -2
  145. package/components/form/Select.vue +57 -19
  146. package/components/form/SelectOrCreateAuthSecret.vue +6 -3
  147. package/components/form/SimpleSecretSelector.vue +9 -2
  148. package/components/form/Taints.vue +21 -2
  149. package/components/form/UnitInput.vue +8 -0
  150. package/components/form/ValueFromResource.vue +1 -1
  151. package/components/form/__tests__/LabeledSelect.test.ts +8 -4
  152. package/components/form/__tests__/Labels.test.ts +360 -0
  153. package/components/form/__tests__/MatchExpressions.test.ts +16 -13
  154. package/components/form/__tests__/Networking.test.ts +116 -0
  155. package/components/form/__tests__/Select.test.ts +5 -2
  156. package/components/formatter/FleetApplicationSource.vue +1 -1
  157. package/components/formatter/PodImages.vue +1 -1
  158. package/components/formatter/WorkloadHealthScale.vue +1 -1
  159. package/components/formatter/__tests__/LiveDate.test.ts +10 -2
  160. package/components/google/AccountAccess.vue +209 -0
  161. package/components/google/types/gcp.d.ts +136 -0
  162. package/components/google/types/index.d.ts +101 -0
  163. package/components/google/util/__mocks__/gcp.ts +465 -0
  164. package/components/google/util/formatter.ts +82 -0
  165. package/components/google/util/gcp.ts +134 -0
  166. package/components/google/util/index.d.ts +11 -0
  167. package/components/nav/Favorite.vue +1 -1
  168. package/components/nav/Group.vue +71 -45
  169. package/components/nav/Header.vue +5 -1
  170. package/components/nav/NamespaceFilter.vue +13 -1
  171. package/components/nav/NotificationCenter/Notification.vue +510 -0
  172. package/components/nav/NotificationCenter/NotificationHeader.vue +112 -0
  173. package/components/nav/NotificationCenter/index.vue +148 -0
  174. package/composables/drawer.ts +26 -0
  175. package/composables/resources.test.ts +63 -0
  176. package/composables/resources.ts +38 -0
  177. package/composables/useIsNewDetailPageEnabled.ts +17 -0
  178. package/config/labels-annotations.js +8 -0
  179. package/config/pagination-table-headers.js +8 -1
  180. package/config/product/auth.js +16 -1
  181. package/config/product/{cis.js → compliance.js} +23 -26
  182. package/config/product/explorer.js +32 -3
  183. package/config/product/fleet.js +7 -0
  184. package/config/product/manager.js +0 -1
  185. package/config/product/settings.js +22 -11
  186. package/config/query-params.js +13 -0
  187. package/config/roles.ts +1 -1
  188. package/config/router/navigation-guards/authentication.js +51 -2
  189. package/config/router/routes.js +47 -31
  190. package/config/settings.ts +21 -3
  191. package/config/store.js +2 -0
  192. package/config/system-namespaces.js +1 -1
  193. package/config/table-headers.js +32 -3
  194. package/config/types.js +16 -7
  195. package/config/version.js +1 -1
  196. package/core/plugin.ts +32 -7
  197. package/core/types.ts +18 -1
  198. package/detail/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +22 -18
  199. package/detail/management.cattle.io.fleetworkspace.vue +18 -27
  200. package/detail/management.cattle.io.oidcclient.vue +369 -0
  201. package/detail/node.vue +2 -2
  202. package/detail/pod.vue +2 -2
  203. package/detail/provisioning.cattle.io.cluster.vue +3 -47
  204. package/detail/service.vue +10 -1
  205. package/detail/workload/index.vue +8 -2
  206. package/dialog/ExtensionCatalogUninstallDialog.vue +7 -4
  207. package/dialog/GenericPrompt.vue +1 -1
  208. package/dialog/ImportDialog.vue +8 -8
  209. package/dialog/OidcClientSecretDialog.vue +117 -0
  210. package/dialog/RotateEncryptionKeyDialog.vue +10 -30
  211. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +3 -3
  212. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +5 -2
  213. package/edit/auth/ldap/__tests__/config.test.ts +14 -0
  214. package/edit/auth/ldap/config.vue +24 -0
  215. package/edit/autoscaling.horizontalpodautoscaler/index.vue +4 -1
  216. package/edit/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +30 -31
  217. package/edit/{cis.cattle.io.clusterscanbenchmark.vue → compliance.cattle.io.clusterscanbenchmark.vue} +4 -4
  218. package/edit/{cis.cattle.io.clusterscanprofile.vue → compliance.cattle.io.clusterscanprofile.vue} +5 -5
  219. package/edit/configmap.vue +8 -2
  220. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  221. package/edit/fleet.cattle.io.gitrepo.vue +44 -222
  222. package/edit/fleet.cattle.io.helmop.vue +44 -269
  223. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  224. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  225. package/edit/logging-flow/index.vue +1 -0
  226. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  227. package/edit/management.cattle.io.fleetworkspace.vue +1 -0
  228. package/edit/management.cattle.io.oidcclient.vue +162 -0
  229. package/edit/management.cattle.io.project.vue +4 -1
  230. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
  231. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +5 -0
  232. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  233. package/edit/monitoring.coreos.com.receiver/auth.vue +30 -30
  234. package/edit/monitoring.coreos.com.receiver/index.vue +1 -0
  235. package/edit/monitoring.coreos.com.receiver/types/email.vue +1 -1
  236. package/edit/monitoring.coreos.com.route.vue +1 -0
  237. package/edit/namespace.vue +1 -0
  238. package/edit/networking.istio.io.destinationrule/index.vue +4 -1
  239. package/edit/networking.k8s.io.ingress/Certificate.vue +12 -12
  240. package/edit/networking.k8s.io.ingress/__tests__/Certificate.test.ts +165 -0
  241. package/edit/networking.k8s.io.ingress/index.vue +4 -1
  242. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +7 -2
  243. package/edit/networking.k8s.io.networkpolicy/index.vue +6 -2
  244. package/edit/node.vue +1 -0
  245. package/edit/persistentvolume/index.vue +4 -1
  246. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +3 -2
  247. package/edit/provisioning.cattle.io.cluster/rke2.vue +516 -426
  248. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +48 -39
  249. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +5 -0
  250. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +2 -2
  251. package/edit/resources.cattle.io.restore.vue +1 -1
  252. package/edit/secret/basic.vue +1 -0
  253. package/edit/secret/index.vue +127 -15
  254. package/edit/service.vue +4 -1
  255. package/edit/serviceaccount.vue +4 -1
  256. package/edit/storage.k8s.io.storageclass/index.vue +4 -1
  257. package/edit/workload/index.vue +5 -0
  258. package/list/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +2 -2
  259. package/list/management.cattle.io.oidcclient.vue +108 -0
  260. package/list/node.vue +2 -0
  261. package/list/projectsecret.vue +345 -0
  262. package/list/secret.vue +109 -0
  263. package/machine-config/amazonec2.vue +3 -24
  264. package/machine-config/components/GCEImage.vue +374 -0
  265. package/machine-config/google.vue +617 -0
  266. package/mixins/__tests__/brand.spec.ts +170 -0
  267. package/mixins/brand.js +16 -17
  268. package/mixins/create-edit-view/impl.js +10 -1
  269. package/mixins/create-edit-view/index.js +5 -0
  270. package/mixins/resource-fetch-api-pagination.js +24 -8
  271. package/mixins/resource-fetch.js +3 -1
  272. package/mixins/vue-select-overrides.js +1 -0
  273. package/models/cluster.x-k8s.io.machinedeployment.js +11 -2
  274. package/models/{cis.cattle.io.clusterscan.js → compliance.cattle.io.clusterscan.js} +8 -8
  275. package/models/{cis.cattle.io.clusterscanbenchmark.js → compliance.cattle.io.clusterscanbenchmark.js} +1 -1
  276. package/models/{cis.cattle.io.clusterscanprofile.js → compliance.cattle.io.clusterscanprofile.js} +5 -5
  277. package/models/{cis.cattle.io.clusterscanreport.js → compliance.cattle.io.clusterscanreport.js} +1 -1
  278. package/models/fleet-application.js +8 -79
  279. package/models/fleet.cattle.io.cluster.js +13 -2
  280. package/models/fleet.cattle.io.gitrepo.js +2 -2
  281. package/models/fleet.cattle.io.helmop.js +9 -39
  282. package/models/management.cattle.io.fleetworkspace.js +2 -1
  283. package/models/management.cattle.io.oidcclient.js +18 -0
  284. package/models/management.cattle.io.registration.js +3 -0
  285. package/models/provisioning.cattle.io.cluster.js +29 -33
  286. package/models/secret.js +157 -2
  287. package/models/service.js +4 -0
  288. package/models/workload.js +5 -0
  289. package/package.json +2 -2
  290. package/pages/about.vue +4 -58
  291. package/pages/auth/login.vue +1 -1
  292. package/pages/c/_cluster/apps/charts/AddRepoLink.vue +0 -1
  293. package/pages/c/_cluster/apps/charts/index.vue +296 -81
  294. package/pages/c/_cluster/auth/user.retention/index.vue +87 -78
  295. package/pages/c/_cluster/explorer/index.vue +3 -3
  296. package/pages/c/_cluster/explorer/projectsecret.vue +34 -0
  297. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -1
  298. package/pages/c/_cluster/fleet/application/create.vue +3 -2
  299. package/pages/c/_cluster/fleet/index.vue +94 -57
  300. package/pages/c/_cluster/fleet/settings/index.vue +229 -0
  301. package/pages/c/_cluster/longhorn/index.vue +5 -2
  302. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +16 -1
  303. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +2 -2
  304. package/pages/explorer/resource/detail/configmap.vue +30 -7
  305. package/pages/explorer/resource/detail/projectsecret.vue +9 -0
  306. package/pages/explorer/resource/detail/secret.vue +63 -0
  307. package/pages/home.vue +9 -55
  308. package/pages/support/index.vue +4 -6
  309. package/plugins/dashboard-store/__tests__/normalize.test.ts +223 -0
  310. package/plugins/dashboard-store/__tests__/resource-class.test.ts +191 -0
  311. package/plugins/dashboard-store/__tests__/utils/normalize-usecases.ts +1526 -0
  312. package/plugins/dashboard-store/actions.js +19 -5
  313. package/plugins/dashboard-store/getters.js +4 -0
  314. package/plugins/dashboard-store/normalize.js +29 -17
  315. package/plugins/dashboard-store/resource-class.js +68 -19
  316. package/plugins/steve/steve-pagination-utils.ts +38 -19
  317. package/plugins/steve/subscribe.js +6 -1
  318. package/rancher-components/Banner/Banner.vue +13 -0
  319. package/rancher-components/Form/Checkbox/Checkbox.vue +9 -4
  320. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  321. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -0
  322. package/rancher-components/RcItemCard/RcItemCard.vue +8 -3
  323. package/store/auth.js +2 -0
  324. package/store/catalog.js +23 -1
  325. package/store/growl.js +97 -8
  326. package/store/index.js +6 -0
  327. package/store/notifications.ts +426 -0
  328. package/store/prefs.js +0 -1
  329. package/store/type-map.js +19 -16
  330. package/store/uiplugins.ts +15 -1
  331. package/types/fleet.d.ts +24 -0
  332. package/types/kube/kube-api.ts +12 -0
  333. package/types/notifications/index.ts +74 -0
  334. package/types/shell/index.d.ts +661 -589
  335. package/types/store/dashboard-store.types.ts +16 -0
  336. package/types/store/pagination.types.ts +16 -6
  337. package/utils/__tests__/create-yaml.test.ts +235 -0
  338. package/utils/__tests__/fleet.test.ts +148 -0
  339. package/utils/__tests__/object.test.ts +54 -1
  340. package/utils/__tests__/string.test.ts +273 -1
  341. package/utils/__tests__/time.test.ts +31 -0
  342. package/utils/auth.js +9 -2
  343. package/utils/create-yaml.js +103 -9
  344. package/utils/crypto/encryption.ts +103 -0
  345. package/utils/cspAdaptor.ts +51 -0
  346. package/utils/fleet.ts +54 -65
  347. package/utils/object.js +36 -0
  348. package/utils/pagination-utils.ts +19 -1
  349. package/utils/release-notes.ts +48 -0
  350. package/utils/selector-typed.ts +7 -2
  351. package/utils/string.js +24 -0
  352. package/utils/{time.js → time.ts} +25 -6
  353. package/utils/uiplugins.ts +22 -0
  354. package/utils/validators/formRules/index.ts +3 -0
  355. package/components/Resource/Detail/TitleBar/composable.ts +0 -31
  356. package/config/product/legacy.js +0 -62
  357. package/models/etcdbackup.js +0 -45
  358. package/pages/c/_cluster/legacy/pages/_page.vue +0 -29
  359. package/pages/c/_cluster/legacy/project/_page.vue +0 -57
  360. package/pages/c/_cluster/legacy/project/index.vue +0 -32
  361. package/pages/c/_cluster/legacy/project/pipelines.vue +0 -96
@@ -36,6 +36,35 @@ export default defineComponent({
36
36
  default: null,
37
37
  },
38
38
 
39
+ groupTooltip: {
40
+ type: String,
41
+ default: 'resourceTable.groupBy.namespace',
42
+ },
43
+
44
+ /**
45
+ * Field to group rows by, row[groupBy] must be something that can be a map key (or also use groupSort)
46
+ */
47
+ groupBy: {
48
+ type: String,
49
+ default: null,
50
+ },
51
+
52
+ /**
53
+ * Field to order groups by, defaults to groupBy
54
+ */
55
+ groupSort: {
56
+ type: String,
57
+ default: null
58
+ },
59
+
60
+ /**
61
+ * Override any product based group options
62
+ */
63
+ groupOptions: {
64
+ type: Array,
65
+ default: null
66
+ },
67
+
39
68
  groupable: {
40
69
  type: Boolean,
41
70
  default: null, // Null: auto based on namespaced and type custom groupings
@@ -58,6 +87,14 @@ export default defineComponent({
58
87
  default: null,
59
88
  },
60
89
 
90
+ /**
91
+ * Use this store instead of the store `inStore` getters
92
+ */
93
+ overrideInStore: {
94
+ type: String,
95
+ default: undefined,
96
+ },
97
+
61
98
  /**
62
99
  * Information may be required from resources other than the primary one shown per row
63
100
  *
@@ -79,7 +116,7 @@ export default defineComponent({
79
116
 
80
117
  async fetch() {
81
118
  const promises = [
82
- this.$fetchType(this.resource, [], this.inStore),
119
+ this.$fetchType(this.resource, [], this.overrideInStore || this.inStore),
83
120
  ];
84
121
 
85
122
  if (this.fetchSecondaryResources) {
@@ -115,13 +152,21 @@ export default defineComponent({
115
152
  :rows="rows"
116
153
  :alt-loading="canPaginate && !isFirstLoad"
117
154
  :loading="loading"
155
+
156
+ :group-by="groupBy"
157
+ :group-sort="groupSort"
118
158
  :groupable="groupable"
159
+ :groupTooltip="groupTooltip"
160
+ :groupOptions="groupOptions"
161
+
162
+ :override-in-store="overrideInStore"
119
163
 
120
164
  :headers="safeHeaders"
121
165
  :namespaced="namespaced"
122
166
 
123
167
  :external-pagination-enabled="canPaginate"
124
168
  :external-pagination-result="paginationResult"
169
+
125
170
  @pagination-changed="paginationChanged"
126
171
  >
127
172
  <!-- Pass down templates provided by the caller -->
@@ -122,6 +122,7 @@ function toPercent(value, min, max) {
122
122
  v-trim-whitespace
123
123
  :class="{progress: true, multi: pieces.length > 1}"
124
124
  :aria-label="ariaLabelText"
125
+ role="progressbar"
125
126
  >
126
127
  <div
127
128
  v-for="(piece, idx) of pieces"
@@ -92,7 +92,12 @@ export default {
92
92
  }
93
93
 
94
94
  this.errors = [];
95
- this.$store.commit('action-menu/togglePromptModal', data);
95
+
96
+ // Guard against events that can be implicitly passed by components
97
+ const modalData = data instanceof Event ? undefined : data;
98
+
99
+ this.$store.commit('action-menu/togglePromptModal', modalData);
100
+
96
101
  if (this.backgroundClosing) {
97
102
  this.backgroundClosing();
98
103
  }
@@ -7,7 +7,7 @@ import Date from '@shell/components/formatter/Date.vue';
7
7
  import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
8
8
  import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
9
9
  import { exceptionToErrorsArray } from '@shell/utils/error';
10
- import { CAPI, NORMAN, SNAPSHOT } from '@shell/config/types';
10
+ import { CAPI, SNAPSHOT } from '@shell/config/types';
11
11
  import { set } from '@shell/utils/object';
12
12
  import ChildHook, { BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
13
13
  import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
@@ -47,14 +47,13 @@ export default {
47
47
  },
48
48
 
49
49
  computed: {
50
- // toRestore can be a provisioning.cattle.io.cluster or a rke.cattle.io.etcdsnapshot or an etcdBackup resource
50
+ // toRestore can be a provisioning.cattle.io.cluster or a rke.cattle.io.etcdsnapshot resource
51
51
  ...mapState('action-menu', ['showPromptRestore', 'toRestore']),
52
52
  ...mapGetters({ t: 'i18n/t' }),
53
53
 
54
54
  // Was the dialog opened to restore a specific snapshot, or opened on a cluster to choose
55
55
  isCluster() {
56
- const isSnapshot = this.toRestore[0]?.type.toLowerCase() === NORMAN.ETCD_BACKUP ||
57
- this.toRestore[0]?.type.toLowerCase() === SNAPSHOT;
56
+ const isSnapshot = this.toRestore[0]?.type.toLowerCase() === SNAPSHOT;
58
57
 
59
58
  return !isSnapshot;
60
59
  },
@@ -79,9 +78,7 @@ export default {
79
78
  }
80
79
  },
81
80
  restoreModeOptions() {
82
- const etcdOption = this.isRke2 ? 'none' : 'etcd';
83
-
84
- return [etcdOption, 'kubernetesVersion', 'all'];
81
+ return ['none', 'kubernetesVersion', 'all'];
85
82
  }
86
83
  },
87
84
 
@@ -112,20 +109,12 @@ export default {
112
109
  }
113
110
 
114
111
  const cluster = this.toRestore?.[0];
115
- let promise;
116
-
117
- if (!cluster?.isRke2) {
118
- promise = this.$store.dispatch('rancher/findAll', { type: NORMAN.ETCD_BACKUP }).then((snapshots) => {
119
- return snapshots.filter((s) => s.state === STATES_ENUM.ACTIVE && s.clusterId === cluster.metadata.name);
120
- });
121
- } else {
122
- promise = this.$store.dispatch('management/findAll', { type: SNAPSHOT }).then((snapshots) => {
123
- const toRestoreClusterName = cluster?.clusterName || cluster?.metadata?.name;
112
+ const promise = this.$store.dispatch('management/findAll', { type: SNAPSHOT }).then((snapshots) => {
113
+ const toRestoreClusterName = cluster?.clusterName || cluster?.metadata?.name;
124
114
 
125
- return snapshots.filter((s) => s?.snapshotFile?.status === STATES_ENUM.SUCCESSFUL && s.clusterName === toRestoreClusterName
126
- );
127
- });
128
- }
115
+ return snapshots.filter((s) => s?.snapshotFile?.status === STATES_ENUM.SUCCESSFUL && s.clusterName === toRestoreClusterName
116
+ );
117
+ });
129
118
 
130
119
  // Map of snapshots by name
131
120
  const allSnapshots = await promise.then((snapshots) => {
@@ -154,30 +143,19 @@ export default {
154
143
 
155
144
  async apply(buttonDone) {
156
145
  try {
157
- if ( this.isRke2 ) {
158
- const cluster = this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, this.snapshot.clusterId);
159
-
160
- await this.applyHooks(BEFORE_SAVE_HOOKS);
161
-
162
- const now = cluster.spec?.rkeConfig?.etcdSnapshotRestore?.generation || 0;
163
-
164
- set(cluster, 'spec.rkeConfig.etcdSnapshotRestore', {
165
- generation: now + 1,
166
- name: this.snapshot.name,
167
- restoreRKEConfig: this.restoreMode,
168
- });
169
-
170
- await cluster.save();
171
- } else {
172
- await this.$store.dispatch('rancher/request', {
173
- url: `/v3/clusters/${ escape(this.snapshot.clusterId) }?action=restoreFromEtcdBackup`,
174
- method: 'post',
175
- data: {
176
- etcdBackupId: this.snapshot.id,
177
- restoreRkeConfig: this.restoreMode,
178
- },
179
- });
180
- }
146
+ const cluster = this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, this.snapshot.clusterId);
147
+
148
+ await this.applyHooks(BEFORE_SAVE_HOOKS);
149
+
150
+ const now = cluster.spec?.rkeConfig?.etcdSnapshotRestore?.generation || 0;
151
+
152
+ set(cluster, 'spec.rkeConfig.etcdSnapshotRestore', {
153
+ generation: now + 1,
154
+ name: this.snapshot.name,
155
+ restoreRKEConfig: this.restoreMode,
156
+ });
157
+
158
+ await cluster.save();
181
159
 
182
160
  this.$store.dispatch('growl/success', {
183
161
  title: this.t('promptRestore.notification.title'),
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import ResourceTable from '@shell/components/ResourceTable';
3
- import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
3
+ import { STATES_ENUM, colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
4
4
  import { NAME, NAMESPACE, STATE, TYPE } from '@shell/config/table-headers';
5
5
  import { sortableNumericSuffix } from '@shell/utils/sort';
6
6
  import { NAME as EXPLORER } from '@shell/config/product/explorer';
@@ -70,9 +70,9 @@ export default {
70
70
  const out = [];
71
71
 
72
72
  for ( const r of this.filteredRelationships) {
73
- const state = r.state || 'active';
74
- const stateColor = colorForState(state, r.error, r.transitioning);
75
73
  const type = r[`${ this.direction }Type`];
74
+ const state = r.state || this.$store.getters[`${ inStore }/byId`](type, r[`${ this.direction }Id`])?.state || STATES_ENUM.MISSING;
75
+ const stateColor = colorForState(state, r.error, r.transitioning);
76
76
  const schema = this.$store.getters[`${ inStore }/schemaFor`](type);
77
77
 
78
78
  let name = r[`${ this.direction }Id`];
@@ -104,7 +104,6 @@ export default {
104
104
 
105
105
  out.push({
106
106
  type,
107
- real: this.$store.getters[`${ inStore }/byId`](type, r[`${ this.direction }Id`]),
108
107
  id: r[`${ this.direction }Id`],
109
108
  state,
110
109
  metadata: { namespace, name },
@@ -174,14 +173,7 @@ export default {
174
173
  :groupable="false"
175
174
  >
176
175
  <template #cell:state="{row}">
177
- <BadgeState
178
- v-if="row.real"
179
- :value="row.real"
180
- />
181
- <BadgeState
182
- v-else
183
- :value="row"
184
- />
176
+ <BadgeState :value="row" />
185
177
  </template>
186
178
  </ResourceTable>
187
179
  </template>
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ import { computed } from 'vue';
3
+
4
+ export interface Props {
5
+ items: string[];
6
+ }
7
+ </script>
8
+
9
+ <script setup lang="ts">
10
+
11
+ const { items } = defineProps<Props>();
12
+
13
+ const first = computed(() => items[0]);
14
+ const tooltipValue = computed(() => {
15
+ let rows = '';
16
+
17
+ items.forEach((item) => {
18
+ rows += `&#8226; ${ item }<br>`;
19
+ });
20
+
21
+ return rows;
22
+ });
23
+ </script>
24
+
25
+ <template>
26
+ <div class="additional">
27
+ <div class="initial">
28
+ {{ first }}
29
+ </div>
30
+ <div
31
+ v-if="items.length > 1"
32
+ v-clean-tooltip.bottom="tooltipValue"
33
+ class="more text-muted"
34
+ >
35
+ {{ t('generic.plusMore', {n: items.length-1}) }}
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <style lang="scss" scoped>
41
+ .more {
42
+ margin-top: 4px;
43
+ cursor: help;
44
+ font-size: 0.8em;
45
+ }
46
+ </style>
@@ -3,7 +3,7 @@ import Annotations from '@shell/components/Resource/Detail/Metadata/Annotations/
3
3
  import { createStore } from 'vuex';
4
4
 
5
5
  describe('component: Metadata/Annotations', () => {
6
- it('shoulder render KeyValue with the appropriate props', async() => {
6
+ it('should render KeyValue with the appropriate props', async() => {
7
7
  const annotations = [{ key: 'key', value: 'value' }];
8
8
  const wrapper = mount(Annotations, {
9
9
  props: { annotations },
@@ -7,12 +7,15 @@ export type Annotation = Row;
7
7
 
8
8
  export interface AnnotationsProps {
9
9
  annotations: Annotation[];
10
+
11
+ onShowConfiguration?: (returnFocusSelector: string) => void;
10
12
  }
11
13
 
12
14
  </script>
13
15
 
14
16
  <script setup lang="ts">
15
17
  const { annotations } = defineProps<AnnotationsProps>();
18
+ const emit = defineEmits(['show-configuration']);
16
19
  const store = useStore();
17
20
  const i18n = useI18n(store);
18
21
  </script>
@@ -22,5 +25,7 @@ const i18n = useI18n(store);
22
25
  :propertyName="i18n.t('component.resource.detail.metadata.annotations.title')"
23
26
  :rows="annotations"
24
27
  :outline="true"
28
+
29
+ @show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector)"
25
30
  />
26
31
  </template>
@@ -0,0 +1,223 @@
1
+ import {
2
+ useNamespace, useWorkspace, useLiveDate, useCreatedBy, useProject,
3
+ useResourceDetails
4
+ } from '@shell/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields';
5
+ import { NAMESPACE, FLEET } from '@shell/config/types';
6
+ import { NAME as FLEET_NAME } from '@shell/config/product/fleet';
7
+
8
+ const mockStore = {
9
+ getters: {
10
+ productId: 'PRODUCT_ID', clusterId: 'CLUSTER_ID', 'type-map/optionsFor': jest.fn()
11
+ }
12
+ };
13
+ const mockRoute = { params: { cluster: 'CLUSTER', namespace: 'NAMESPACE' } };
14
+ const mockDrawer = { openResourceDetailDrawer: jest.fn() };
15
+
16
+ jest.mock('vuex', () => ({ useStore: () => mockStore }));
17
+ jest.mock('vue-router', () => ({ useRoute: () => mockRoute }));
18
+ jest.mock('@shell/components/Drawer/ResourceDetailDrawer/composables', () => ({ useResourceDetailDrawer: () => mockDrawer }));
19
+
20
+ describe('composables: IdentifyingFields', () => {
21
+ describe('useNamespace', () => {
22
+ it('should return undefined if namespace is falsy', () => {
23
+ const resource = {};
24
+ const result = useNamespace(resource);
25
+
26
+ expect(result).toBeUndefined();
27
+ });
28
+
29
+ it('should return undefined if namespaces is truthy', () => {
30
+ const resource = { namespaces: [] };
31
+ const result = useNamespace(resource);
32
+
33
+ expect(result).toBeUndefined();
34
+ });
35
+
36
+ it('should return a valid namespace row with namespaceLocation', () => {
37
+ const resource = { namespace: 'NAMESPACE', namespaceLocation: 'NAMESPACE_LOCATION' };
38
+ const result = useNamespace(resource);
39
+
40
+ expect(result?.value.to).toStrictEqual(resource.namespaceLocation);
41
+ expect(result?.value.value).toStrictEqual(resource.namespace);
42
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.namespace');
43
+ expect(result?.value.valueDataTestid).toStrictEqual('masthead-subheader-namespace');
44
+ });
45
+
46
+ it('should return a valid namespace row with computed `to`', () => {
47
+ const resource = { namespace: 'NAMESPACE' };
48
+ const result = useNamespace(resource);
49
+
50
+ expect(result?.value.to).toStrictEqual({
51
+ name: `c-cluster-product-resource-id`,
52
+ params: {
53
+ product: 'PRODUCT_ID',
54
+ cluster: 'CLUSTER_ID',
55
+ resource: NAMESPACE,
56
+ id: resource.namespace
57
+ }
58
+ });
59
+ expect(result?.value.value).toStrictEqual(resource.namespace);
60
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.namespace');
61
+ expect(result?.value.valueDataTestid).toStrictEqual('masthead-subheader-namespace');
62
+ });
63
+ });
64
+
65
+ describe('useWorkspace', () => {
66
+ it('should return undefined if productId is not fleet', () => {
67
+ const resource = { metadata: { namespace: true } };
68
+ const result = useWorkspace(resource);
69
+
70
+ expect(result).toBeUndefined();
71
+ });
72
+
73
+ it('should return undefined if productId is fleet and metadata namespace is falsy', () => {
74
+ mockStore.getters.productId = FLEET_NAME;
75
+ const resource = { };
76
+ const result = useWorkspace(resource);
77
+
78
+ expect(result).toBeUndefined();
79
+ });
80
+
81
+ it('should return a valid workspace row', () => {
82
+ mockStore.getters.productId = FLEET_NAME;
83
+ const resource = { namespace: 'NAMESPACE', metadata: { namespace: true } };
84
+ const result = useWorkspace(resource);
85
+
86
+ expect(result?.value.to).toStrictEqual({
87
+ name: `c-cluster-product-resource-id`,
88
+ params: {
89
+ product: FLEET_NAME,
90
+ cluster: 'CLUSTER_ID',
91
+ resource: FLEET.WORKSPACE,
92
+ id: mockRoute.params.namespace
93
+ }
94
+ });
95
+ expect(result?.value.value).toStrictEqual(resource.namespace);
96
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.workspace');
97
+ });
98
+ });
99
+
100
+ describe('useLiveDate', () => {
101
+ it('should return undefined if showAge is false', () => {
102
+ mockStore.getters[`type-map/optionsFor`].mockReturnValue({ showAge: false });
103
+
104
+ const resource = { };
105
+ const result = useLiveDate(resource);
106
+
107
+ expect(result).toBeUndefined();
108
+ });
109
+
110
+ it('should return a valid liveDate row', () => {
111
+ mockStore.getters[`type-map/optionsFor`].mockReturnValue({ showAge: true });
112
+
113
+ const resource = { creationTimestamp: 'CREATION_TIMESTAMP' };
114
+ const result = useLiveDate(resource);
115
+
116
+ expect(result?.value.valueOverride).toStrictEqual({
117
+ component: 'LiveDate',
118
+ props: { value: resource.creationTimestamp }
119
+ });
120
+ expect(result?.value.value).toStrictEqual(resource.creationTimestamp);
121
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.age');
122
+ });
123
+ });
124
+
125
+ describe('useCreatedBy', () => {
126
+ it('should return undefined if showCreatedBy is falsy', () => {
127
+ const resource = {};
128
+ const result = useCreatedBy(resource);
129
+
130
+ expect(result).toBeUndefined();
131
+ });
132
+
133
+ it('should return a valid createdBy row', () => {
134
+ mockStore.getters[`type-map/optionsFor`].mockReturnValue({ showAge: true });
135
+
136
+ const resource = { showCreatedBy: true, createdBy: { displayName: 'CREATED_BY' } };
137
+ const result = useCreatedBy(resource);
138
+
139
+ expect(result?.value.to).toBeUndefined();
140
+ expect(result?.value.value).toStrictEqual(resource.createdBy.displayName);
141
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.createdBy');
142
+ expect(result?.value.dataTestid).toStrictEqual('masthead-subheader-createdBy');
143
+ expect(result?.value.valueDataTestid).toStrictEqual('masthead-subheader-createdBy_plain-text');
144
+ });
145
+
146
+ it('should return a valid createdBy row with createdBy.location', () => {
147
+ mockStore.getters[`type-map/optionsFor`].mockReturnValue({ showAge: true });
148
+
149
+ const resource = { showCreatedBy: true, createdBy: { displayName: 'CREATED_BY', location: 'LOCATION' } };
150
+ const result = useCreatedBy(resource);
151
+
152
+ expect(result?.value.to).toStrictEqual(resource.createdBy.location);
153
+ expect(result?.value.value).toStrictEqual(resource.createdBy.displayName);
154
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.createdBy');
155
+ expect(result?.value.dataTestid).toStrictEqual('masthead-subheader-createdBy');
156
+ expect(result?.value.valueDataTestid).toStrictEqual('masthead-subheader-createdBy-link');
157
+ });
158
+ });
159
+
160
+ describe('useProject', () => {
161
+ it('should return undefined if type is not namespace', () => {
162
+ const resource = { type: 'anything' };
163
+ const result = useProject(resource);
164
+
165
+ expect(result).toBeUndefined();
166
+ });
167
+
168
+ it('should return undefined if project is falsy', () => {
169
+ const resource = { type: NAMESPACE };
170
+ const result = useProject(resource);
171
+
172
+ expect(result).toBeUndefined();
173
+ });
174
+
175
+ it('should return a valid project row', () => {
176
+ const resource = { type: NAMESPACE, project: { nameDisplay: 'PROJECT', detailLocation: 'LOCATION' } };
177
+ const result = useProject(resource);
178
+
179
+ expect(result?.value.to).toStrictEqual(resource.project.detailLocation);
180
+ expect(result?.value.value).toStrictEqual(resource.project.nameDisplay);
181
+ expect(result?.value.label).toStrictEqual('component.resource.detail.metadata.identifyingInformation.project');
182
+ });
183
+ });
184
+
185
+ describe('useResourceDetails', () => {
186
+ it('should return undefined if details is falsy', () => {
187
+ const resource = { };
188
+ const result = useResourceDetails(resource);
189
+
190
+ expect(result).toBeUndefined();
191
+ });
192
+
193
+ it('should return valid resourceDetail without valueOverride', () => {
194
+ const resource = { details: [{ label: 'LABEL', content: 'CONTENT' }] };
195
+ const result = useResourceDetails(resource);
196
+
197
+ expect(result?.value[0].label).toStrictEqual(resource.details[0].label);
198
+ expect(result?.value[0].value).toStrictEqual(resource.details[0].content);
199
+ expect(result?.value[0].valueOverride).toBeUndefined();
200
+ });
201
+
202
+ it('should omit separator details', () => {
203
+ const resource = { details: [{ separator: true }] };
204
+ const result = useResourceDetails(resource);
205
+
206
+ expect(result?.value).toHaveLength(0);
207
+ });
208
+
209
+ it('should return valid resourceDetail with valueOverride', () => {
210
+ const resource = {
211
+ details: [{
212
+ label: 'LABEL', content: 'CONTENT', formatter: 'FORMATTER', formatterOpts: { key: 'value' }
213
+ }]
214
+ };
215
+ const result = useResourceDetails(resource);
216
+
217
+ expect(result?.value[0].label).toStrictEqual(resource.details[0].label);
218
+ expect(result?.value[0].value).toStrictEqual(resource.details[0].content);
219
+ expect(result?.value[0].valueOverride?.component).toStrictEqual(resource.details[0].formatter);
220
+ expect(result?.value[0].valueOverride?.props).toStrictEqual({ value: resource.details[0].content, ...resource.details[0].formatterOpts });
221
+ });
222
+ });
223
+ });