dashboard-shell-shell 3.0.2-test.20250913 → 3.0.5-test.2

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 (628) hide show
  1. package/assets/data/aws-regions.json +3 -0
  2. package/assets/icons/demo.css:Zone.Identifier +0 -0
  3. package/assets/icons/demo_index.html:Zone.Identifier +0 -0
  4. package/assets/icons/iconfont.css:Zone.Identifier +0 -0
  5. package/assets/icons/iconfont.js:Zone.Identifier +0 -0
  6. package/assets/icons/iconfont.json:Zone.Identifier +0 -0
  7. package/assets/icons/iconfont.ttf:Zone.Identifier +0 -0
  8. package/assets/icons/iconfont.woff2:Zone.Identifier +0 -0
  9. package/assets/icons/iconfont.woff:Zone.Identifier +0 -0
  10. package/assets/images/icons/document.svg +3 -0
  11. package/assets/images/key.svg +17 -0
  12. package/assets/images/providers/sks.svg +1 -0
  13. package/assets/images/vendor/cognito.svg +1 -0
  14. package/assets/styles/app.scss +3 -0
  15. package/assets/styles/base/_basic.scss +10 -0
  16. package/assets/styles/base/_spacing.scss +29 -0
  17. package/assets/styles/base/_variables.scss +16 -10
  18. package/assets/styles/global/_labeled-input.scss +1 -1
  19. package/assets/styles/global/_layout.scss +1 -1
  20. package/assets/styles/themes/_dark.scss +30 -0
  21. package/assets/styles/themes/_light.scss +80 -2
  22. package/assets/translations/en-us.yaml +822 -105
  23. package/assets/translations/zh-hans.yaml +13 -3
  24. package/chart/__tests__/S3.test.ts +2 -1
  25. package/chart/monitoring/index.vue +1 -1
  26. package/cloud-credential/gcp.vue +9 -1
  27. package/components/ActionMenuShell.vue +3 -7
  28. package/components/AppModal.vue +9 -28
  29. package/components/AsyncButton.vue +2 -0
  30. package/components/BrandImage.vue +0 -21
  31. package/components/Certificates.vue +5 -0
  32. package/components/CodeMirror.vue +3 -3
  33. package/components/CommunityLinks.vue +3 -58
  34. package/components/ConfigMapSettings/Settings.vue +377 -0
  35. package/components/ConfigMapSettings/index.vue +354 -0
  36. package/components/CruResource.vue +103 -16
  37. package/components/DetailText.vue +61 -11
  38. package/components/Drawer/Chrome.vue +115 -0
  39. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +61 -0
  40. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +48 -0
  41. package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +54 -0
  42. package/components/Drawer/ResourceDetailDrawer/__tests__/YamlTab.test.ts +80 -0
  43. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +106 -0
  44. package/components/Drawer/ResourceDetailDrawer/__tests__/helpers.test.ts +42 -0
  45. package/components/Drawer/ResourceDetailDrawer/composables.ts +53 -0
  46. package/components/Drawer/ResourceDetailDrawer/helpers.ts +10 -0
  47. package/components/Drawer/ResourceDetailDrawer/index.vue +123 -0
  48. package/components/ExplorerProjectsNamespaces.vue +46 -29
  49. package/components/FilterPanel.vue +156 -0
  50. package/components/FixedBanner.vue +19 -5
  51. package/components/{fleet/ForceDirectedTreeChart/index.vue → ForceDirectedTreeChart.vue} +47 -41
  52. package/components/GrowlManager.vue +16 -15
  53. package/components/IconOrSvg.vue +19 -35
  54. package/components/KeyValueView.vue +1 -1
  55. package/components/LandingPagePreference.vue +2 -0
  56. package/components/Loading.vue +1 -1
  57. package/components/LocaleSelector.vue +10 -2
  58. package/components/PaginatedResourceTable.vue +53 -1
  59. package/components/ProgressBarMulti.vue +1 -0
  60. package/components/PromptModal.vue +38 -7
  61. package/components/PromptRemove.vue +5 -1
  62. package/components/PromptRestore.vue +22 -44
  63. package/components/RelatedResources.vue +4 -12
  64. package/components/Resource/Detail/Additional.vue +46 -0
  65. package/components/Resource/Detail/Card/PodsCard/Bubble.vue +13 -0
  66. package/components/Resource/Detail/Card/PodsCard/composable.ts +30 -0
  67. package/components/Resource/Detail/Card/PodsCard/index.vue +118 -0
  68. package/components/Resource/Detail/Card/ResourceUsageCard/composable.ts +51 -0
  69. package/components/Resource/Detail/Card/ResourceUsageCard/index.vue +79 -0
  70. package/components/Resource/Detail/Card/Scaler.vue +89 -0
  71. package/components/Resource/Detail/Card/StateCard/composables.ts +112 -0
  72. package/components/Resource/Detail/Card/StateCard/index.vue +39 -0
  73. package/components/Resource/Detail/Card/VerticalGap.vue +11 -0
  74. package/components/Resource/Detail/Card/__tests__/Card.test.ts +36 -0
  75. package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +84 -0
  76. package/components/Resource/Detail/Card/__tests__/ResourceUsageCard.test.ts +72 -0
  77. package/components/Resource/Detail/Card/__tests__/Scaler.test.ts +87 -0
  78. package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +53 -0
  79. package/components/Resource/Detail/Card/__tests__/VerticalGap.test.ts +14 -0
  80. package/components/Resource/Detail/Card/__tests__/index.test.ts +36 -0
  81. package/components/Resource/Detail/Card/index.vue +56 -0
  82. package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +19 -0
  83. package/components/Resource/Detail/Metadata/Annotations/composable.ts +12 -0
  84. package/components/Resource/Detail/Metadata/Annotations/index.vue +31 -0
  85. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +223 -0
  86. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +103 -0
  87. package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +72 -0
  88. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +317 -0
  89. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +140 -0
  90. package/components/Resource/Detail/Metadata/KeyValue.vue +140 -0
  91. package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +18 -0
  92. package/components/Resource/Detail/Metadata/Labels/composable.ts +12 -0
  93. package/components/Resource/Detail/Metadata/Labels/index.vue +31 -0
  94. package/components/Resource/Detail/Metadata/Rectangle.vue +34 -0
  95. package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +107 -0
  96. package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +24 -0
  97. package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +75 -0
  98. package/components/Resource/Detail/Metadata/__tests__/index.test.ts +91 -0
  99. package/components/Resource/Detail/Metadata/composables.ts +81 -0
  100. package/components/Resource/Detail/Metadata/index.vue +88 -0
  101. package/components/Resource/Detail/Page.vue +37 -0
  102. package/components/Resource/Detail/PercentageBar.vue +40 -0
  103. package/components/Resource/Detail/ResourceRow.vue +138 -0
  104. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/__tests__/composables.test.ts +29 -0
  105. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/__tests__/index.test.ts +48 -0
  106. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/composables.ts +31 -0
  107. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/index.vue +50 -0
  108. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/__tests__/composables.test.ts +66 -0
  109. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/composables.ts +21 -0
  110. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/index.vue +31 -0
  111. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Basic.vue +45 -0
  112. package/components/Resource/Detail/ResourceTabs/SecretDataTab/BasicAuth.vue +31 -0
  113. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Certificate.vue +31 -0
  114. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Registry.vue +22 -0
  115. package/components/Resource/Detail/ResourceTabs/SecretDataTab/ServiceAccountToken.vue +31 -0
  116. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Ssh.vue +32 -0
  117. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Basic.test.ts +40 -0
  118. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/BasicAuth.test.ts +33 -0
  119. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Certificate.test.ts +33 -0
  120. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Registry.test.ts +27 -0
  121. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/ServiceAccountToken.test.ts +33 -0
  122. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Ssh.test.ts +33 -0
  123. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/auth-types.test.ts +186 -0
  124. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/composables.test.ts +102 -0
  125. package/components/Resource/Detail/ResourceTabs/SecretDataTab/auth-types.ts +109 -0
  126. package/components/Resource/Detail/ResourceTabs/SecretDataTab/composeables.ts +52 -0
  127. package/components/Resource/Detail/ResourceTabs/SecretDataTab/index.vue +71 -0
  128. package/components/Resource/Detail/SpacedRow.vue +14 -0
  129. package/components/Resource/Detail/StatusBar.vue +59 -0
  130. package/components/Resource/Detail/StatusRow.vue +61 -0
  131. package/components/Resource/Detail/TitleBar/Title.vue +14 -0
  132. package/components/Resource/Detail/TitleBar/Top.vue +14 -0
  133. package/components/Resource/Detail/TitleBar/__tests__/Title.test.ts +17 -0
  134. package/components/Resource/Detail/TitleBar/__tests__/Top.test.ts +17 -0
  135. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +63 -0
  136. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +142 -0
  137. package/components/Resource/Detail/TitleBar/composables.ts +46 -0
  138. package/components/Resource/Detail/TitleBar/index.vue +204 -0
  139. package/components/Resource/Detail/Top/index.vue +34 -0
  140. package/components/Resource/Detail/__tests__/Page.test.ts +32 -0
  141. package/components/Resource/Detail/composables.ts +45 -0
  142. package/components/ResourceDetail/Masthead/__tests__/index.test.ts +70 -0
  143. package/components/ResourceDetail/{__tests__/Masthead.test.ts → Masthead/__tests__/legacy.test.ts} +3 -3
  144. package/components/ResourceDetail/Masthead/index.vue +65 -0
  145. package/components/ResourceDetail/Masthead/latest.vue +44 -0
  146. package/components/ResourceDetail/{Masthead.vue → Masthead/legacy.vue} +0 -1
  147. package/components/ResourceDetail/__tests__/index.test.ts +135 -0
  148. package/components/ResourceDetail/index.vue +75 -575
  149. package/components/ResourceDetail/legacy.vue +564 -0
  150. package/components/ResourceList/Masthead.vue +69 -20
  151. package/components/ResourceList/index.vue +3 -2
  152. package/components/ResourceTable.vue +59 -85
  153. package/components/ResourceYaml.vue +15 -2
  154. package/components/RichTranslation.vue +106 -0
  155. package/components/SlideInPanelManager.vue +116 -14
  156. package/components/SortableTable/index.vue +10 -2
  157. package/components/SortableTable/paging.js +15 -16
  158. package/components/SortableTable/selection.js +22 -10
  159. package/components/StateDot/index.vue +28 -0
  160. package/components/StatusBadge.vue +6 -4
  161. package/components/SubtleLink.vue +25 -0
  162. package/components/Tabbed/index.vue +38 -22
  163. package/components/Wizard.vue +16 -3
  164. package/components/YamlEditor.vue +1 -2
  165. package/components/__tests__/AsyncButton.test.ts +39 -0
  166. package/components/__tests__/ConfigMapSettings.test.ts +376 -0
  167. package/components/__tests__/CruResource.test.ts +63 -0
  168. package/components/__tests__/FilterPanel.test.ts +81 -0
  169. package/components/__tests__/GrowlManager.test.ts +0 -25
  170. package/components/__tests__/PromptModal.test.ts +146 -0
  171. package/components/__tests__/PromptRestore.test.ts +1 -65
  172. package/components/__tests__/RichTranslation.test.ts +115 -0
  173. package/components/auth/AuthBanner.vue +15 -14
  174. package/components/auth/Principal.vue +0 -1
  175. package/components/auth/RoleDetailEdit.vue +44 -4
  176. package/components/auth/login/ldap.vue +2 -2
  177. package/components/auth/login/oidc.vue +6 -1
  178. package/components/fleet/FleetApplications.vue +174 -0
  179. package/components/fleet/FleetClusterTargets/TargetsList.vue +66 -0
  180. package/components/fleet/FleetClusterTargets/index.vue +455 -0
  181. package/components/fleet/FleetClusters.vue +25 -6
  182. package/components/fleet/FleetGitRepoPaths.vue +476 -0
  183. package/components/fleet/FleetHelmOps.vue +123 -0
  184. package/components/fleet/FleetIntro.vue +58 -28
  185. package/components/fleet/FleetNoWorkspaces.vue +5 -1
  186. package/components/fleet/FleetOCIStorageSecret.vue +171 -0
  187. package/components/fleet/FleetRepos.vue +37 -80
  188. package/components/fleet/FleetResources.vue +69 -27
  189. package/components/fleet/FleetSummary.vue +26 -51
  190. package/components/fleet/FleetValuesFrom.vue +295 -0
  191. package/components/fleet/__tests__/FleetClusterTargets.test.ts +1224 -0
  192. package/components/fleet/__tests__/FleetGitRepoPaths.test.ts +265 -0
  193. package/components/fleet/__tests__/FleetOCIStorageSecret.test.ts +213 -0
  194. package/components/fleet/__tests__/FleetSummary.test.ts +39 -39
  195. package/components/fleet/__tests__/FleetValuesFrom.test.ts +300 -0
  196. package/components/fleet/dashboard/Empty.vue +73 -0
  197. package/components/fleet/dashboard/ResourceCard.vue +184 -0
  198. package/components/fleet/dashboard/ResourceCardSummary.vue +195 -0
  199. package/components/fleet/dashboard/ResourceDetails.vue +194 -0
  200. package/components/fleet/dashboard/ResourcePanel.vue +384 -0
  201. package/components/form/ArrayList.vue +144 -116
  202. package/components/form/BannerSettings.vue +117 -50
  203. package/components/form/ChangePassword.vue +3 -1
  204. package/components/form/ColorInput.vue +35 -6
  205. package/components/form/FileImageSelector.vue +1 -1
  206. package/components/form/Footer.vue +10 -4
  207. package/components/form/KeyValue.vue +92 -51
  208. package/components/form/LabeledSelect.vue +72 -54
  209. package/components/form/Labels.vue +91 -21
  210. package/components/form/MatchExpressions.vue +56 -9
  211. package/components/form/NameNsDescription.vue +12 -8
  212. package/components/form/Networking.vue +24 -19
  213. package/components/form/NotificationSettings.vue +15 -1
  214. package/components/form/ResourceLabeledSelect.vue +22 -8
  215. package/components/form/ResourceSelector.vue +27 -23
  216. package/components/form/ResourceTabs/index.vue +7 -1
  217. package/components/form/SSHKnownHosts/index.vue +14 -11
  218. package/components/form/SecretSelector.vue +18 -2
  219. package/components/form/Select.vue +57 -26
  220. package/components/form/SelectOrCreateAuthSecret.vue +6 -3
  221. package/components/form/SimpleSecretSelector.vue +17 -4
  222. package/components/form/Taints.vue +21 -2
  223. package/components/form/UnitInput.vue +21 -0
  224. package/components/form/ValueFromResource.vue +31 -19
  225. package/components/form/__tests__/ArrayList.test.ts +32 -0
  226. package/components/form/__tests__/ColorInput.test.ts +35 -0
  227. package/components/form/__tests__/KeyValue.test.ts +36 -0
  228. package/components/form/__tests__/LabeledSelect.test.ts +79 -2
  229. package/components/form/__tests__/Labels.test.ts +360 -0
  230. package/components/form/__tests__/MatchExpressions.test.ts +16 -13
  231. package/components/form/__tests__/Networking.test.ts +116 -0
  232. package/components/form/__tests__/SSHKnownHosts.test.ts +11 -2
  233. package/components/form/__tests__/Select.test.ts +37 -1
  234. package/components/form/__tests__/UnitInput.test.ts +23 -1
  235. package/components/form/labeled-select-utils/labeled-select-pagination.ts +3 -38
  236. package/components/formatter/ClusterLink.vue +5 -8
  237. package/components/formatter/Description.vue +30 -0
  238. package/components/formatter/FleetApplicationClustersReady.vue +77 -0
  239. package/components/formatter/FleetApplicationSource.vue +79 -0
  240. package/components/formatter/FleetSummaryGraph.vue +7 -0
  241. package/components/formatter/PodImages.vue +1 -1
  242. package/components/formatter/WorkloadHealthScale.vue +1 -1
  243. package/components/formatter/__tests__/ClusterLink.test.ts +2 -32
  244. package/components/formatter/__tests__/LiveDate.test.ts +10 -2
  245. package/components/google/AccountAccess.vue +209 -0
  246. package/components/google/types/gcp.d.ts +136 -0
  247. package/components/google/types/index.d.ts +101 -0
  248. package/components/google/util/__mocks__/gcp.ts +465 -0
  249. package/components/google/util/formatter.ts +82 -0
  250. package/components/google/util/gcp.ts +134 -0
  251. package/components/google/util/index.d.ts +11 -0
  252. package/components/nav/Favorite.vue +1 -1
  253. package/components/nav/Group.vue +5 -0
  254. package/components/nav/Header.vue +24 -38
  255. package/components/nav/NamespaceFilter.vue +141 -84
  256. package/components/nav/NotificationCenter/Notification.vue +484 -0
  257. package/components/nav/NotificationCenter/NotificationHeader.vue +112 -0
  258. package/components/nav/NotificationCenter/index.vue +148 -0
  259. package/components/nav/TopLevelMenu.helper.ts +55 -34
  260. package/components/nav/TopLevelMenu.vue +11 -0
  261. package/components/nav/Type.vue +4 -1
  262. package/components/nav/WindowManager/ContainerLogs.vue +87 -61
  263. package/components/nav/WindowManager/ContainerLogsActions.vue +76 -0
  264. package/components/nav/WindowManager/index.vue +3 -2
  265. package/components/templates/default.vue +0 -3
  266. package/components/templates/plain.vue +0 -3
  267. package/composables/drawer.ts +26 -0
  268. package/composables/focusTrap.ts +3 -3
  269. package/composables/resources.test.ts +63 -0
  270. package/composables/resources.ts +38 -0
  271. package/composables/useI18n.ts +12 -11
  272. package/composables/useIsNewDetailPageEnabled.ts +17 -0
  273. package/config/labels-annotations.js +22 -11
  274. package/config/pagination-table-headers.js +8 -1
  275. package/config/private-label.js +0 -1
  276. package/config/product/auth.js +20 -3
  277. package/config/product/{cis.js → compliance.js} +23 -26
  278. package/config/product/explorer.js +49 -17
  279. package/config/product/fleet.js +77 -17
  280. package/config/product/manager.js +1 -29
  281. package/config/product/settings.js +23 -11
  282. package/config/query-params.js +16 -1
  283. package/config/roles.ts +2 -1
  284. package/config/router/navigation-guards/authentication.js +51 -2
  285. package/config/router/navigation-guards/index.js +5 -67
  286. package/config/router/routes.js +65 -31
  287. package/config/secret.ts +15 -0
  288. package/config/settings.ts +33 -16
  289. package/config/store.js +2 -0
  290. package/config/system-namespaces.js +1 -1
  291. package/config/table-headers.js +91 -30
  292. package/config/types.js +18 -7
  293. package/config/version.js +1 -1
  294. package/core/plugin-helpers.ts +3 -2
  295. package/core/plugin.ts +32 -7
  296. package/core/types.ts +25 -7
  297. package/detail/catalog.cattle.io.app.vue +5 -1
  298. package/detail/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +22 -18
  299. package/detail/fleet.cattle.io.bundle.vue +70 -6
  300. package/detail/fleet.cattle.io.cluster.vue +28 -15
  301. package/detail/fleet.cattle.io.gitrepo.vue +11 -2
  302. package/detail/fleet.cattle.io.helmop.vue +157 -0
  303. package/detail/management.cattle.io.fleetworkspace.vue +18 -27
  304. package/detail/management.cattle.io.oidcclient.vue +369 -0
  305. package/detail/namespace.vue +0 -3
  306. package/detail/node.vue +20 -16
  307. package/detail/pod.vue +2 -2
  308. package/detail/provisioning.cattle.io.cluster.vue +16 -50
  309. package/detail/service.vue +10 -2
  310. package/detail/workload/index.vue +48 -39
  311. package/dialog/AddCustomBadgeDialog.vue +0 -1
  312. package/{pages/c/_cluster/uiplugins/AddExtensionRepos.vue → dialog/AddExtensionReposDialog.vue} +72 -42
  313. package/dialog/AddonConfigConfirmationDialog.vue +1 -1
  314. package/dialog/AssignToDialog.vue +176 -0
  315. package/dialog/ChangePasswordDialog.vue +106 -0
  316. package/{pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue → dialog/DeveloperLoadExtensionDialog.vue} +74 -71
  317. package/dialog/DisableAuthProviderDialog.vue +101 -0
  318. package/dialog/DrainNode.vue +1 -1
  319. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue → dialog/ExtensionCatalogInstallDialog.vue} +100 -88
  320. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue → dialog/ExtensionCatalogUninstallDialog.vue} +87 -66
  321. package/dialog/FeatureFlagListDialog.vue +288 -0
  322. package/dialog/ForceMachineRemoveDialog.vue +1 -1
  323. package/dialog/GenericPrompt.vue +1 -1
  324. package/dialog/HelmOpForceUpdateDialog.vue +132 -0
  325. package/{components/Import.vue → dialog/ImportDialog.vue} +8 -13
  326. package/{pages/c/_cluster/uiplugins/InstallDialog.vue → dialog/InstallExtensionDialog.vue} +124 -106
  327. package/{components/form/SSHKnownHosts → dialog}/KnownHostsEditDialog.vue +52 -62
  328. package/dialog/MoveNamespaceDialog.vue +157 -0
  329. package/dialog/OidcClientSecretDialog.vue +117 -0
  330. package/dialog/RedeployWorkloadDialog.vue +164 -0
  331. package/dialog/RotateEncryptionKeyDialog.vue +10 -30
  332. package/dialog/ScalePoolDownDialog.vue +1 -1
  333. package/{components/nav/Jump.vue → dialog/SearchDialog.vue} +34 -14
  334. package/{pages/c/_cluster/uiplugins/UninstallDialog.vue → dialog/UninstallExtensionDialog.vue} +67 -58
  335. package/dialog/WechatDialog.vue +57 -0
  336. package/{components/form/SSHKnownHosts → dialog}/__tests__/KnownHostsEditDialog.test.ts +15 -34
  337. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +3 -3
  338. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +60 -68
  339. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
  340. package/edit/__tests__/service.test.ts +2 -1
  341. package/edit/auth/ldap/__tests__/config.test.ts +14 -0
  342. package/edit/auth/ldap/config.vue +24 -0
  343. package/edit/auth/oidc.vue +159 -93
  344. package/edit/autoscaling.horizontalpodautoscaler/index.vue +4 -1
  345. package/edit/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +30 -31
  346. package/edit/{cis.cattle.io.clusterscanbenchmark.vue → compliance.cattle.io.clusterscanbenchmark.vue} +4 -4
  347. package/edit/{cis.cattle.io.clusterscanprofile.vue → compliance.cattle.io.clusterscanprofile.vue} +5 -5
  348. package/edit/configmap.vue +8 -2
  349. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  350. package/edit/fleet.cattle.io.gitrepo.vue +70 -256
  351. package/edit/fleet.cattle.io.helmop.vue +786 -0
  352. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  353. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  354. package/edit/logging-flow/index.vue +1 -0
  355. package/edit/logging.banzaicloud.io.output/index.vue +2 -1
  356. package/edit/logging.banzaicloud.io.output/providers/awsElasticsearch.vue +5 -6
  357. package/edit/management.cattle.io.fleetworkspace.vue +44 -10
  358. package/edit/management.cattle.io.oidcclient.vue +162 -0
  359. package/edit/management.cattle.io.project.vue +4 -1
  360. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
  361. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +5 -0
  362. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  363. package/edit/monitoring.coreos.com.receiver/auth.vue +3 -3
  364. package/edit/monitoring.coreos.com.receiver/index.vue +1 -0
  365. package/edit/monitoring.coreos.com.receiver/types/email.vue +1 -1
  366. package/edit/monitoring.coreos.com.route.vue +1 -0
  367. package/edit/namespace.vue +2 -4
  368. package/edit/networking.istio.io.destinationrule/index.vue +4 -1
  369. package/edit/networking.k8s.io.ingress/Certificate.vue +11 -3
  370. package/edit/networking.k8s.io.ingress/__tests__/Certificate.test.ts +37 -0
  371. package/edit/networking.k8s.io.ingress/index.vue +4 -1
  372. package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +3 -14
  373. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +57 -62
  374. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +10 -16
  375. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.test.ts +72 -41
  376. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +17 -1
  377. package/edit/networking.k8s.io.networkpolicy/index.vue +23 -31
  378. package/edit/node.vue +1 -0
  379. package/edit/persistentvolume/index.vue +4 -1
  380. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +26 -12
  381. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +69 -2
  382. package/edit/provisioning.cattle.io.cluster/__tests__/utils/rke2-test-data.ts +58 -0
  383. package/edit/provisioning.cattle.io.cluster/index.vue +21 -73
  384. package/edit/provisioning.cattle.io.cluster/rke2.vue +535 -428
  385. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +48 -39
  386. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +5 -3
  387. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +5 -0
  388. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +2 -2
  389. package/edit/resources.cattle.io.restore.vue +1 -1
  390. package/edit/secret/basic.vue +1 -0
  391. package/edit/secret/index.vue +127 -15
  392. package/edit/service.vue +17 -29
  393. package/edit/serviceaccount.vue +4 -1
  394. package/edit/storage.k8s.io.storageclass/index.vue +4 -1
  395. package/edit/workload/index.vue +11 -15
  396. package/edit/workload/mixins/workload.js +0 -2
  397. package/list/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +2 -2
  398. package/list/fleet.cattle.io.gitrepo.vue +1 -1
  399. package/list/fleet.cattle.io.helmop.vue +108 -0
  400. package/list/harvesterhci.io.management.cluster.vue +0 -17
  401. package/list/management.cattle.io.feature.vue +4 -288
  402. package/list/management.cattle.io.oidcclient.vue +108 -0
  403. package/list/management.cattle.io.user.vue +13 -20
  404. package/list/namespace.vue +6 -2
  405. package/list/node.vue +2 -0
  406. package/list/projectsecret.vue +345 -0
  407. package/list/secret.vue +109 -0
  408. package/list/workload.vue +6 -2
  409. package/machine-config/__tests__/vmwarevsphere.test.ts +5 -7
  410. package/machine-config/amazonec2.vue +3 -24
  411. package/machine-config/components/GCEImage.vue +374 -0
  412. package/machine-config/google.vue +617 -0
  413. package/machine-config/vmwarevsphere.vue +7 -17
  414. package/mixins/__tests__/brand.spec.ts +170 -0
  415. package/mixins/auth-config.js +8 -1
  416. package/mixins/brand.js +16 -17
  417. package/mixins/create-edit-view/impl.js +10 -1
  418. package/mixins/create-edit-view/index.js +5 -0
  419. package/mixins/preset.js +100 -0
  420. package/mixins/resource-fetch-api-pagination.js +73 -44
  421. package/mixins/resource-fetch.js +18 -8
  422. package/mixins/resource-table-watch.js +45 -0
  423. package/mixins/vue-select-overrides.js +1 -4
  424. package/models/__tests__/chart.test.ts +296 -0
  425. package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
  426. package/models/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
  427. package/models/__tests__/node.test.ts +7 -63
  428. package/models/__tests__/workload.test.ts +1 -0
  429. package/models/chart.js +157 -2
  430. package/models/cluster/node.js +2 -1
  431. package/models/cluster.js +32 -2
  432. package/models/cluster.x-k8s.io.machinedeployment.js +11 -2
  433. package/models/{cis.cattle.io.clusterscan.js → compliance.cattle.io.clusterscan.js} +8 -8
  434. package/models/{cis.cattle.io.clusterscanbenchmark.js → compliance.cattle.io.clusterscanbenchmark.js} +1 -1
  435. package/models/{cis.cattle.io.clusterscanprofile.js → compliance.cattle.io.clusterscanprofile.js} +5 -5
  436. package/models/{cis.cattle.io.clusterscanreport.js → compliance.cattle.io.clusterscanreport.js} +1 -1
  437. package/models/fleet-application.js +297 -0
  438. package/models/fleet.cattle.io.bundle.js +9 -8
  439. package/models/fleet.cattle.io.cluster.js +21 -4
  440. package/models/fleet.cattle.io.gitrepo.js +46 -382
  441. package/models/fleet.cattle.io.helmop.js +202 -0
  442. package/models/management.cattle.io.authconfig.js +1 -0
  443. package/models/management.cattle.io.cluster.js +0 -20
  444. package/models/management.cattle.io.feature.js +7 -1
  445. package/models/management.cattle.io.fleetworkspace.js +14 -1
  446. package/models/management.cattle.io.node.js +7 -22
  447. package/models/management.cattle.io.nodepool.js +12 -0
  448. package/models/management.cattle.io.oidcclient.js +18 -0
  449. package/models/management.cattle.io.registration.js +3 -0
  450. package/models/management.cattle.io.setting.js +0 -1
  451. package/models/namespace.js +12 -1
  452. package/models/provisioning.cattle.io.cluster.js +60 -97
  453. package/models/secret.js +157 -2
  454. package/models/service.js +28 -9
  455. package/models/storage.k8s.io.storageclass.js +2 -2
  456. package/models/workload.js +91 -51
  457. package/package.json +6 -5
  458. package/pages/about.vue +17 -61
  459. package/pages/account/index.vue +9 -1
  460. package/pages/auth/login.vue +2 -3
  461. package/pages/auth/verify.vue +13 -1
  462. package/pages/c/_cluster/apps/charts/AddRepoLink.vue +36 -0
  463. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +80 -0
  464. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +57 -0
  465. package/pages/c/_cluster/apps/charts/StatusLabel.vue +33 -0
  466. package/pages/c/_cluster/apps/charts/index.vue +501 -468
  467. package/pages/c/_cluster/apps/charts/install.vue +0 -1
  468. package/pages/c/_cluster/auth/roles/index.vue +19 -48
  469. package/pages/c/_cluster/auth/user.retention/index.vue +87 -78
  470. package/pages/c/_cluster/explorer/EventsTable.vue +1 -1
  471. package/pages/c/_cluster/explorer/index.vue +14 -3
  472. package/pages/c/_cluster/explorer/projectsecret.vue +34 -0
  473. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -1
  474. package/pages/c/_cluster/fleet/__tests__/index.test.ts +720 -0
  475. package/pages/c/_cluster/fleet/application/_resource/_id.vue +14 -0
  476. package/pages/c/_cluster/fleet/application/_resource/create.vue +14 -0
  477. package/pages/c/_cluster/fleet/application/create.vue +341 -0
  478. package/pages/c/_cluster/fleet/application/index.vue +139 -0
  479. package/pages/c/_cluster/fleet/graph/config.js +277 -0
  480. package/pages/c/_cluster/fleet/index.vue +866 -328
  481. package/pages/c/_cluster/fleet/settings/index.vue +229 -0
  482. package/pages/c/_cluster/longhorn/index.vue +5 -2
  483. package/pages/c/_cluster/settings/banners.vue +56 -2
  484. package/pages/c/_cluster/settings/brand.vue +2 -1
  485. package/pages/c/_cluster/settings/performance.vue +7 -26
  486. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +16 -1
  487. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +2 -2
  488. package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +4 -7
  489. package/pages/c/_cluster/uiplugins/index.vue +98 -55
  490. package/pages/explorer/resource/detail/configmap.vue +42 -0
  491. package/pages/explorer/resource/detail/projectsecret.vue +9 -0
  492. package/pages/explorer/resource/detail/secret.vue +63 -0
  493. package/pages/home.vue +8 -104
  494. package/pages/prefs.vue +0 -1
  495. package/pages/support/index.vue +4 -6
  496. package/plugins/clean-html.js +2 -0
  497. package/plugins/dashboard-store/__tests__/actions.test.ts +4 -1
  498. package/plugins/dashboard-store/__tests__/normalize.test.ts +223 -0
  499. package/plugins/dashboard-store/__tests__/resource-class.test.ts +191 -0
  500. package/plugins/dashboard-store/__tests__/utils/normalize-usecases.ts +1526 -0
  501. package/plugins/dashboard-store/actions.js +212 -55
  502. package/plugins/dashboard-store/getters.js +112 -24
  503. package/plugins/dashboard-store/mutations.js +61 -12
  504. package/plugins/dashboard-store/normalize.js +29 -19
  505. package/plugins/dashboard-store/resource-class.js +132 -49
  506. package/plugins/steve/__tests__/getters.test.ts +19 -12
  507. package/plugins/steve/__tests__/steve-class.test.ts +1 -0
  508. package/plugins/steve/__tests__/subscribe.spec.ts +324 -1
  509. package/plugins/steve/actions.js +37 -24
  510. package/plugins/steve/getters.js +47 -12
  511. package/plugins/steve/resourceWatcher.js +10 -3
  512. package/plugins/steve/steve-class.js +5 -0
  513. package/plugins/steve/steve-pagination-utils.ts +225 -43
  514. package/plugins/steve/subscribe.js +418 -53
  515. package/plugins/steve/worker/web-worker.advanced.js +5 -1
  516. package/rancher-components/Banner/Banner.test.ts +51 -3
  517. package/rancher-components/Banner/Banner.vue +37 -6
  518. package/rancher-components/Form/Checkbox/Checkbox.test.ts +59 -1
  519. package/rancher-components/Form/Checkbox/Checkbox.vue +27 -9
  520. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +51 -0
  521. package/rancher-components/Form/LabeledInput/LabeledInput.vue +21 -3
  522. package/rancher-components/Form/Radio/RadioButton.test.ts +36 -1
  523. package/rancher-components/Form/Radio/RadioButton.vue +21 -5
  524. package/rancher-components/Form/Radio/RadioGroup.test.ts +60 -0
  525. package/rancher-components/Form/Radio/RadioGroup.vue +81 -38
  526. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +4 -0
  527. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +22 -1
  528. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -0
  529. package/rancher-components/RcButton/RcButton.vue +1 -1
  530. package/rancher-components/RcDropdown/RcDropdown.test.ts +98 -0
  531. package/rancher-components/RcDropdown/RcDropdown.vue +6 -0
  532. package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -55
  533. package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +69 -0
  534. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +93 -0
  535. package/rancher-components/RcDropdown/RcDropdownMenu.vue +7 -8
  536. package/rancher-components/RcDropdown/index.ts +2 -0
  537. package/rancher-components/RcDropdown/useDropdownContext.ts +21 -0
  538. package/rancher-components/RcDropdown/useDropdownItem.ts +92 -0
  539. package/rancher-components/RcItemCard/RcItemCard.test.ts +189 -0
  540. package/rancher-components/RcItemCard/RcItemCard.vue +430 -0
  541. package/rancher-components/RcItemCard/RcItemCardAction.vue +24 -0
  542. package/rancher-components/RcItemCard/index.ts +2 -0
  543. package/rancher-components/StringList/StringList.vue +1 -1
  544. package/scripts/extension/publish +1 -1
  545. package/static/loading-indicator.html +1 -1
  546. package/store/action-menu.js +26 -56
  547. package/store/auth.js +3 -0
  548. package/store/catalog.js +85 -25
  549. package/store/features.js +0 -1
  550. package/store/growl.js +97 -8
  551. package/store/i18n.js +1 -1
  552. package/store/index.js +44 -14
  553. package/store/notifications.ts +426 -0
  554. package/store/prefs.js +2 -8
  555. package/store/slideInPanel.ts +6 -0
  556. package/store/type-map.js +34 -17
  557. package/store/type-map.utils.ts +49 -6
  558. package/store/uiplugins.ts +15 -1
  559. package/types/fleet.d.ts +60 -1
  560. package/types/kube/kube-api.ts +34 -0
  561. package/types/notifications/index.ts +74 -0
  562. package/types/resources/fleet.d.ts +43 -0
  563. package/types/resources/pod-security-admission.ts +36 -0
  564. package/types/resources/settings.d.ts +107 -0
  565. package/types/resources/userPreferences.d.ts +13 -0
  566. package/types/shell/index.d.ts +971 -745
  567. package/types/store/dashboard-store.types.ts +57 -4
  568. package/types/store/pagination.types.ts +41 -9
  569. package/types/store/subscribe.types.ts +50 -0
  570. package/utils/__mocks__/tabbable.js +13 -0
  571. package/utils/__tests__/back-off.test.ts +354 -0
  572. package/utils/__tests__/create-yaml.test.ts +235 -0
  573. package/utils/__tests__/fleet.test.ts +148 -0
  574. package/utils/__tests__/kontainer.test.ts +19 -0
  575. package/utils/__tests__/object.test.ts +54 -1
  576. package/utils/__tests__/string.test.ts +273 -1
  577. package/utils/__tests__/time.test.ts +31 -0
  578. package/utils/auth.js +41 -6
  579. package/utils/back-off.ts +176 -0
  580. package/utils/cluster.js +24 -20
  581. package/utils/create-yaml.js +103 -9
  582. package/utils/crypto/encryption.ts +103 -0
  583. package/utils/cspAdaptor.ts +51 -0
  584. package/utils/error.js +0 -5
  585. package/utils/fleet-types.ts +0 -0
  586. package/utils/fleet.ts +204 -74
  587. package/utils/grafana.js +1 -0
  588. package/utils/kontainer.ts +3 -5
  589. package/utils/object.js +36 -12
  590. package/utils/pagination-utils.ts +50 -3
  591. package/utils/pagination-wrapper.ts +132 -50
  592. package/utils/perf-setting.utils.ts +28 -0
  593. package/utils/release-notes.ts +48 -0
  594. package/utils/selector-typed.ts +210 -0
  595. package/utils/selector.js +29 -6
  596. package/utils/settings.ts +4 -1
  597. package/utils/string.js +24 -0
  598. package/utils/style.ts +39 -0
  599. package/utils/{time.js → time.ts} +25 -6
  600. package/utils/uiplugins.ts +41 -8
  601. package/utils/v-sphere.ts +5 -1
  602. package/utils/validators/formRules/__tests__/index.test.ts +76 -6
  603. package/utils/validators/formRules/index.ts +99 -4
  604. package/utils/window.js +11 -7
  605. package/.DS_Store +0 -0
  606. package/components/AssignTo.vue +0 -199
  607. package/components/DisableAuthProviderModal.vue +0 -115
  608. package/components/MoveModal.vue +0 -167
  609. package/components/PromptChangePassword.vue +0 -123
  610. package/components/ResourceList/Masthead-btn.vue +0 -225
  611. package/components/__tests__/ApplicationCard.test.ts +0 -27
  612. package/components/cards/ApplicationCard.vue +0 -145
  613. package/components/fleet/FleetBundleResources.vue +0 -86
  614. package/components/fleet/ForceDirectedTreeChart/chartIcons.js +0 -17
  615. package/components/formatter/RKETemplateName.vue +0 -37
  616. package/config/product/legacy.js +0 -62
  617. package/config/secret.js +0 -14
  618. package/dialog/SaveAsRKETemplateDialog.vue +0 -139
  619. package/models/etcdbackup.js +0 -45
  620. package/pages/auth copy/login.vue +0 -595
  621. package/pages/auth copy/logout.vue +0 -47
  622. package/pages/auth copy/setup.vue +0 -523
  623. package/pages/auth copy/verify.vue +0 -203
  624. package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +0 -249
  625. package/pages/c/_cluster/legacy/pages/_page.vue +0 -29
  626. package/pages/c/_cluster/legacy/project/_page.vue +0 -57
  627. package/pages/c/_cluster/legacy/project/index.vue +0 -32
  628. package/pages/c/_cluster/legacy/project/pipelines.vue +0 -96
@@ -3,8 +3,57 @@
3
3
  *
4
4
  * Covers three use cases
5
5
  * 1) Handles subscription within this file
6
- * 2) Handles `cluster` subscriptions for some basic types in a web worker (SETTING.UI_PERFORMANCE advancedWorker = false)
6
+ * 2) Handles `cluster` subscriptions for some basic types in a web worker (SETTING.UI_PERFORMANCE advancedWorker = false) (is this true??)
7
7
  * 2) Handles `cluster` subscriptions and optimisations in an advanced worker (SETTING.UI_PERFORMANCE advancedWorker = true)
8
+ *
9
+ * Very roughly this does...
10
+ *
11
+ * 1. _Subscribes_ to a web socket (v1, v3, v1 cluster)
12
+ * 2. UI --> Rancher: Sends a _watch_ message for a specific resource type (which can have qualifying filters)
13
+ * 3. Rancher --> UI: Rancher can send a number of messages back
14
+ * - `resource.start` - watch has started
15
+ * - `resource.error` - watch has errored, usually a result of bad data in the resource.start message
16
+ * - `resource.change` - a resource has changed, this is it's new value
17
+ * - `resource.changes` - if in this mode, no resource.change events are sent, instead one debounced message is sent without any resource data
18
+ * - `resource.stop` - either we have requested the watch stops, or there has been a resource.error
19
+ * 4. UI --> Rancher: Sends an _unwatch_ request for a matching _watch_ request
20
+ *
21
+ * Below are some VERY brief steps for common flows. Some will link together
22
+ *
23
+ * Successfully flow - watch
24
+ * 1. UI --> Rancher: _watch_ request
25
+ * 2. Rancher --> UI: `resource.start`. UI sets watch as started
26
+ * 3. Rancher --> UI: `resource.change` (contains data). UI caches data
27
+ *
28
+ * Successful flow - watch - new mode
29
+ * 1. UI --> Rancher: _watch_ request
30
+ * 2. Rancher --> UI: `resource.start`. UI sets watch as started
31
+ * 3. Rancher --> UI: `resource.changes` (contains no data). UI makes a HTTP request to fetch data
32
+ *
33
+ * Successful flow - unwatch
34
+ * 1. UI --> Rancher: _unwatch_ request
35
+ * 2. Rancher --> UI: `resource.stop`. UI sets watch as stopped
36
+ *
37
+ * Successful flow - resource.stop received
38
+ * 1. Rancher --> UI: `resource.stop`. UI sets watch as stopped
39
+ * 2. UI --> Rancher: _watch_ request
40
+ *
41
+ * Successful flow - socket disconnected
42
+ * 1. Socket closes|disconnects (not sure which)
43
+ * 2. UI: reopens socket
44
+ * 3. UI --> Rancher: _watch_ request (for every started watch)
45
+ *
46
+ * Error Flow
47
+ * 1. UI --> Rancher: _watch_ request
48
+ * 2. Rancher --> UI: `resource.start`. UI sets watch as started
49
+ * 3. Rancher --> UI: `resource.error`. UI sets watch as errored.
50
+ * a) UI: in the event of 'too old' the UI will make a http request to fetch a new revision and re-watch with it. This process is delayed on each call
51
+ * 4. Rancher --> UI: `resource.stop`. UI sets watch as stop (note the resource.stop flow above is avoided given error state)
52
+ *
53
+ * Additionally
54
+ * - if we receive resource.stop, unless the watch is in error, we immediately send back a watch event
55
+ * - if the web socket is disconnected (for steve based sockets it happens every 30 mins, or when there are permission changes)
56
+ * the ui will re-connect it and re-watch all previous watches using a best effort revision
8
57
  */
9
58
 
10
59
  import { addObject, clear, removeObject } from '@shell/utils/array';
@@ -34,7 +83,10 @@ import { waitFor } from '@shell/utils/async';
34
83
  import { WORKER_MODES } from './worker';
35
84
  import acceptOrRejectSocketMessage from './accept-or-reject-socket-message';
36
85
  import { BLANK_CLUSTER, STORE } from '@shell/store/store-types.js';
86
+ import { _MERGE } from '@shell/plugins/dashboard-store/actions';
87
+ import { STEVE_WATCH_EVENT, STEVE_WATCH_MODE } from '@shell/types/store/subscribe.types';
37
88
  import paginationUtils from '@shell/utils/pagination-utils';
89
+ import backOff from '@shell/utils/back-off';
38
90
 
39
91
  // minimum length of time a disconnect notification is shown
40
92
  const MINIMUM_TIME_NOTIFIED = 3000;
@@ -86,7 +138,7 @@ export async function createWorker(store, ctx) {
86
138
  postMessage: (msg) => {
87
139
  if (Object.keys(msg)?.[0] === 'destroyWorker') {
88
140
  // The worker has been destroyed before it's been set up. Flag this so we stop waiting for mgmt settings and then can destroy worker.
89
- // This can occurr when the user is redirected to the log in page
141
+ // This can occur when the user is redirected to the log in page
90
142
  // - workers created (but waiting)
91
143
  // - logout is called
92
144
  // - <store>/unsubscribe is dispatched
@@ -185,10 +237,14 @@ export async function createWorker(store, ctx) {
185
237
  }
186
238
 
187
239
  export function equivalentWatch(a, b) {
188
- const aresourceType = a.resourceType || a.type;
189
- const bresourceType = b.resourceType || b.type;
240
+ const aResourceType = a.resourceType || a.type;
241
+ const bResourceType = b.resourceType || b.type;
190
242
 
191
- if ( aresourceType !== bresourceType ) {
243
+ if ( aResourceType !== bResourceType ) {
244
+ return false;
245
+ }
246
+
247
+ if (a.mode !== b.mode && (a.mode || b.mode)) {
192
248
  return false;
193
249
  }
194
250
 
@@ -256,6 +312,34 @@ function growlsDisabled(rootGetters) {
256
312
  return getPerformanceSetting(rootGetters)?.disableWebsocketNotification;
257
313
  }
258
314
 
315
+ /**
316
+ * Supported events are listed
317
+ *
318
+ * of type { [key: STEVE_WATCH_EVENT]: STEVE_WATCH_EVENT_LISTENER[]}
319
+ */
320
+ const listeners = { [STEVE_WATCH_EVENT.CHANGES]: [] };
321
+
322
+ /**
323
+ * Given a started or error entry, is it compatible with the given change in mode?
324
+ */
325
+ const shouldUnwatchIncompatible = (messageMeta, mode) => {
326
+ if (messageMeta.mode === STEVE_WATCH_EVENT.CHANGES) {
327
+ return mode !== STEVE_WATCH_EVENT.CHANGES;
328
+ }
329
+
330
+ return mode === STEVE_WATCH_EVENT.CHANGES;
331
+ };
332
+
333
+ /**
334
+ * clear the provided error, but also ensure any backoff request associated with it is cleared as well
335
+ */
336
+ const clearInError = ({ getters, commit }, error) => {
337
+ // for this watch ... get the specific prefix we care about ... reset back-offs related to it
338
+ backOff.resetPrefix(getters.backOffId(error.obj, ''));
339
+ // Clear out stale error state (next time around we can try again with a new revision that was just fetched)
340
+ commit('clearInError', error.obj);
341
+ };
342
+
259
343
  /**
260
344
  * Actions that cover all cases (see file description)
261
345
  */
@@ -334,7 +418,9 @@ const sharedActions = {
334
418
  }
335
419
  },
336
420
 
337
- unsubscribe({ commit, getters, state }) {
421
+ async unsubscribe({
422
+ commit, getters, state, dispatch
423
+ }) {
338
424
  const socket = state.socket;
339
425
 
340
426
  commit('setWantSocket', false);
@@ -351,17 +437,85 @@ const sharedActions = {
351
437
  cleanupTasks.push(socket.disconnect());
352
438
  }
353
439
 
440
+ await dispatch('resetWatchBackOff');
441
+
354
442
  return Promise.all(cleanupTasks);
355
443
  },
356
444
 
445
+ /**
446
+ * Create a trigger for a specific type of watch event
447
+ *
448
+ * For example if a watch on mgmt clusters exists and a page wants to know when any changes occur
449
+ * @param {} ctx
450
+ * @param {STEVE_WATCH_EVENT_PARAMS} event
451
+ */
452
+ watchEvent(ctx, {
453
+ event = STEVE_WATCH_EVENT.CHANGES,
454
+ id,
455
+ callback,
456
+ /**
457
+ * of type @STEVE_WATCH_PARAMS
458
+ */
459
+ params
460
+ }) {
461
+ if (!listeners[event]) {
462
+ console.error(`Unknown event type "${ event }", only ${ Object.keys(listeners).join(',') } are supported`); // eslint-disable-line no-console
463
+
464
+ return;
465
+ }
466
+
467
+ // STEVE_WATCH_EVENT_LISTENER | undefined
468
+ let listener = listeners[event].find((l) => equivalentWatch(l.params, params));
469
+
470
+ if (!listener) {
471
+ listener = {
472
+ params,
473
+ callbacks: { }
474
+ };
475
+ listeners[event].push(listener);
476
+ }
477
+
478
+ if (!listener.callbacks[id]) {
479
+ listener.callbacks[id] = callback;
480
+ ctx.dispatch('watch', params);
481
+ }
482
+ },
483
+
484
+ /**
485
+ * @param {} ctx
486
+ * @param {STEVE_UNWATCH_EVENT_PARAMS} event
487
+ */
488
+ unwatchEvent(ctx, {
489
+ event = STEVE_WATCH_EVENT.CHANGES,
490
+ id,
491
+ /**
492
+ * of type @STEVE_WATCH_PARAMS
493
+ */
494
+ params
495
+ }) {
496
+ if (!listeners[event]) {
497
+ console.info(`Attempted to unwatch for an event "${ event }" but it had no watchers`); // eslint-disable-line no-console
498
+
499
+ return;
500
+ }
501
+
502
+ const existing = listeners[event].find((l) => equivalentWatch(l.params, params));
503
+
504
+ if (existing) {
505
+ delete existing.callbacks[id];
506
+ }
507
+ },
508
+
509
+ /**
510
+ * @param {STEVE_WATCH_PARAMS} params
511
+ */
357
512
  watch({
358
513
  state, dispatch, getters, rootGetters
359
514
  }, params) {
360
515
  state.debugSocket && console.info(`Watch Request [${ getters.storeName }]`, JSON.stringify(params)); // eslint-disable-line no-console
361
-
362
516
  let {
363
517
  // eslint-disable-next-line prefer-const
364
- type, selector, id, revision, namespace, stop, force
518
+ type, selector, id, revision, namespace, stop, force, mode
365
519
  } = params;
366
520
 
367
521
  namespace = acceptOrRejectSocketMessage.subscribeNamespace(namespace);
@@ -393,29 +547,43 @@ const sharedActions = {
393
547
  return;
394
548
  }
395
549
 
396
- if ( !stop && getters.watchStarted({
397
- type, id, selector, namespace
398
- }) ) {
550
+ const messageMeta = {
551
+ type, id, selector, namespace, mode
552
+ };
553
+
554
+ if (!stop && getters.watchStarted(messageMeta)) {
399
555
  // eslint-disable-next-line no-console
400
556
  state.debugSocket && console.debug(`Already Watching [${ getters.storeName }]`, {
401
- type, id, selector, namespace
557
+ type, id, selector, namespace, mode
402
558
  });
403
559
 
404
560
  return;
405
561
  }
406
562
 
407
- // isSteveCacheEnabled check is temporary and will be removed once Part 3 of https://github.com/rancher/dashboard/pull/10349 is resolved by backend
408
- // Steve cache backed api does not return a revision, so `revision` here is always undefined
409
- // Which means we find a revision within a resource itself and use it in the watch
410
- // That revision is probably too old and results in a watch error
563
+ if (!stop) {
564
+ dispatch('unwatchIncompatible', messageMeta);
565
+ }
566
+
411
567
  // Watch errors mean we make a http request to get latest revision (which is still missing) and try to re-watch with it...
412
568
  // etc
413
- if (typeof revision === 'undefined' && !paginationUtils.isSteveCacheEnabled({ rootGetters })) {
569
+ if (typeof revision === 'undefined') {
414
570
  revision = getters.nextResourceVersion(type, id);
415
571
  }
416
572
 
417
573
  const msg = { resourceType: type };
418
574
 
575
+ if (mode) {
576
+ msg.mode = mode;
577
+
578
+ if (mode === STEVE_WATCH_MODE.RESOURCE_CHANGES) {
579
+ const debounceMs = paginationUtils.resourceChangesDebounceMs({ rootGetters });
580
+
581
+ if (debounceMs) {
582
+ msg.debounceMs = debounceMs;
583
+ }
584
+ }
585
+ }
586
+
419
587
  if ( revision ) {
420
588
  msg.resourceVersion = `${ revision }`;
421
589
  }
@@ -451,8 +619,11 @@ const sharedActions = {
451
619
  return dispatch('send', msg);
452
620
  },
453
621
 
622
+ /**
623
+ * @param {STEVE_WATCH_PARAMS} params
624
+ */
454
625
  unwatch(ctx, {
455
- type, id, namespace, selector, all
626
+ type, id, namespace, selector, all, mode
456
627
  }) {
457
628
  const { commit, getters, dispatch } = ctx;
458
629
 
@@ -464,6 +635,7 @@ const sharedActions = {
464
635
  id,
465
636
  namespace,
466
637
  selector,
638
+ mode,
467
639
  stop: true, // Stops the watch on a type
468
640
  };
469
641
 
@@ -477,13 +649,15 @@ const sharedActions = {
477
649
  // Make sure anything in the pending queue for the type is removed, since we've now removed the type
478
650
  commit('clearFromQueue', type);
479
651
  }
652
+ // Ensure anything pinging in the background is stopped
653
+ backOff.resetPrefix(getters.backOffId(obj));
480
654
  };
481
655
 
482
656
  if (isAdvancedWorker(ctx)) {
483
657
  dispatch('watch', obj); // Ask the backend to stop watching the type
484
658
  } else if (all) {
485
659
  getters['watchesOfType'](type).forEach((obj) => {
486
- unwatch(obj);
660
+ unwatch({ ...obj, stop: true });
487
661
  });
488
662
  } else if (getters['watchStarted'](obj)) {
489
663
  unwatch(obj);
@@ -491,6 +665,68 @@ const sharedActions = {
491
665
  }
492
666
  },
493
667
 
668
+ /**
669
+ * Unwatch watches that are incompatible with the new type
670
+ */
671
+ unwatchIncompatible({
672
+ state, dispatch, getters, commit
673
+ }, messageMeta) {
674
+ // Step 1 - Clear incompatible watches that have STARTED
675
+ const watchesOfType = getters.watchesOfType(messageMeta.type);
676
+
677
+ watchesOfType
678
+ .filter((entry) => shouldUnwatchIncompatible(messageMeta, entry.mode))
679
+ .forEach((entry) => {
680
+ dispatch('unwatch', entry);
681
+ });
682
+
683
+ // Step 2 - Clear inError state for incompatible watches (these won't appear in watchesOfType / state.started)
684
+ // (important for the backoff case... for example backoff request to find would overwrite findPage res if executed after nav from detail to list)
685
+ const inErrorOfType = Object.values(state.inError || {})
686
+ .filter((error) => error.obj.type === messageMeta.type);
687
+
688
+ inErrorOfType
689
+ .filter((error) => shouldUnwatchIncompatible(messageMeta, error.obj.mode))
690
+ .forEach((error) => clearInError({ getters, commit }, error));
691
+ },
692
+
693
+ /**
694
+ * Ensure there's no back-off process waiting to run for
695
+ * - resource.changes fetchResources
696
+ * - resource.error resyncWatches
697
+ */
698
+ resetWatchBackOff({ state, getters, commit }, {
699
+ type, compareWatches, resetInError = true, resetStarted = true
700
+ } = { resetInError: true, resetStarted: true }) {
701
+ // Step 1 - Reset back-offs related to watches that have STARTED
702
+ if (resetStarted && state.started?.length) {
703
+ let entries = state.started;
704
+
705
+ if (type) { // Filter out ones for types we're no interested in
706
+ entries = entries
707
+ .filter((obj) => compareWatches ? compareWatches(obj) : obj.type === type);
708
+ }
709
+
710
+ entries.forEach((obj) => backOff.resetPrefix(getters.backOffId(obj, '')));
711
+ }
712
+
713
+ // Step 2 - Reset back-offs related to watches that are in error (and may not be started)
714
+ if (resetInError && state.inError) {
715
+ // (it would be nicer if we could store backOff state in `state.started`,
716
+ // however resource.stop clears `started` and we need the settings to persist over start-->error-->stop-->start cycles
717
+ let entries = Object.values(state.inError || {});
718
+
719
+ if (type) { // Filter out ones for types we're no interested in
720
+ entries = entries
721
+ .filter((error) => compareWatches ? compareWatches(error.obj) : error.obj.type === type);
722
+ }
723
+
724
+ entries
725
+ .filter((error) => error.reason === REVISION_TOO_OLD) // Filter out ones for reasons we're not interested in
726
+ .forEach((error) => clearInError({ getters, commit }, error));
727
+ }
728
+ },
729
+
494
730
  'ws.ping'({ getters, dispatch }, msg) {
495
731
  if ( getters.storeName === 'management' ) {
496
732
  const version = msg?.data?.version || null;
@@ -587,16 +823,30 @@ const defaultActions = {
587
823
  return Promise.all(promises);
588
824
  },
589
825
 
590
- async resyncWatch({
826
+ /**
827
+ * Socket has been closed, restart afresh (make http request, ensure we re-watch)
828
+ */
829
+ async resyncWatch({ getters, dispatch }, params) {
830
+ console.info(`Resync [${ getters.storeName }]`, params); // eslint-disable-line no-console
831
+
832
+ await dispatch('fetchResources', {
833
+ ...params,
834
+ opt: { force: true, forceWatch: true }
835
+ });
836
+ },
837
+
838
+ async fetchResources({
591
839
  state, getters, dispatch, commit
592
- }, params) {
840
+ }, { opt, ...params }) {
593
841
  const {
594
- resourceType, namespace, id, selector
842
+ resourceType, namespace, id, selector, mode
595
843
  } = params;
596
844
 
597
- console.info(`Resync [${ getters.storeName }]`, params); // eslint-disable-line no-console
845
+ if (!resourceType) {
846
+ console.error(`A socket message has prompted a request to fetch a resource but no resource type was supplied`); // eslint-disable-line no-console
598
847
 
599
- const opt = { force: true, forceWatch: true };
848
+ return;
849
+ }
600
850
 
601
851
  if ( id ) {
602
852
  await dispatch('find', {
@@ -613,7 +863,7 @@ const defaultActions = {
613
863
 
614
864
  return;
615
865
  }
616
- let have, want;
866
+ let have = []; let want = [];
617
867
 
618
868
  if ( selector ) {
619
869
  have = getters['matching'](resourceType, selector).slice();
@@ -623,17 +873,50 @@ const defaultActions = {
623
873
  opt,
624
874
  });
625
875
  } else {
626
- have = getters['all'](resourceType).slice();
876
+ if (mode === STEVE_WATCH_MODE.RESOURCE_CHANGES) {
877
+ // Other findX use options (id/ns/selector) from the messages received over socket.
878
+ // However paginated requests have more complex params so grab them from store from the store.
879
+ // of type @StorePagination
880
+ const storePagination = getters['havePage'](resourceType);
881
+
882
+ if (!!storePagination) {
883
+ have = []; // findPage removes stale entries, so we don't need to rely on below process to remove them
884
+
885
+ // This could have been kicked off given a resource.changes message
886
+ // If the messages come in quicker than findPage completes (resource.changes debounce time >= http request time),
887
+ // and the request is the same, only the first request will be processed. all others until it finishes will be ignored
888
+ // (see deferred process - `waiting.push(later);` - in request action).
889
+ // If this becomes an issue we need to debounce and work around the deferred issue within request
890
+ want = await dispatch('findPage', {
891
+ type: resourceType,
892
+ opt: {
893
+ ...opt,
894
+ namespaced: namespace,
895
+ // This brings in page, page size, filter, etc
896
+ ...storePagination.request
897
+ }
898
+ });
899
+ }
627
900
 
628
- if ( namespace ) {
629
- have = have.filter((x) => x.metadata?.namespace === namespace);
630
- }
901
+ // Should any listeners be notified of this request for them to kick off their own event handling?
902
+ const listener = listeners[STEVE_WATCH_MODE.RESOURCE_CHANGES].find((sl) => equivalentWatch(sl.params, params));
631
903
 
632
- want = await dispatch('findAll', {
633
- type: resourceType,
634
- watchNamespace: namespace,
635
- opt
636
- });
904
+ if (listener) {
905
+ Object.values(listener.callbacks).forEach((cb) => cb());
906
+ }
907
+ } else {
908
+ have = getters['all'](resourceType).slice();
909
+
910
+ if ( namespace ) {
911
+ have = have.filter((x) => x.metadata?.namespace === namespace);
912
+ }
913
+
914
+ want = await dispatch('findAll', {
915
+ type: resourceType,
916
+ watchNamespace: namespace,
917
+ opt
918
+ });
919
+ }
637
920
  }
638
921
 
639
922
  const wantMap = {};
@@ -701,15 +984,20 @@ const defaultActions = {
701
984
  }
702
985
  },
703
986
 
704
- closed({ state, getters }) {
987
+ async closed({ state, getters, dispatch }) {
705
988
  state.debugSocket && console.info(`WebSocket Closed [${ getters.storeName }]`); // eslint-disable-line no-console
989
+
990
+ await dispatch('resetWatchBackOff');
706
991
  clearTimeout(state.queueTimer);
707
992
  state.queueTimer = null;
708
993
  },
709
994
 
710
- error({
995
+ async error({
711
996
  getters, state, dispatch, rootGetters
712
997
  }, e) {
998
+ state.debugSocket && console.info(`WebSocket Error [${ getters.storeName }]`); // eslint-disable-line no-console
999
+
1000
+ await dispatch('resetWatchBackOff');
713
1001
  clearTimeout(state.queueTimer);
714
1002
  state.queueTimer = null;
715
1003
 
@@ -792,7 +1080,8 @@ const defaultActions = {
792
1080
  type: msg.resourceType,
793
1081
  namespace: msg.namespace,
794
1082
  id: msg.id,
795
- selector: msg.selector
1083
+ selector: msg.selector,
1084
+ mode: msg.mode,
796
1085
  };
797
1086
 
798
1087
  state.started.filter((entry) => {
@@ -823,7 +1112,23 @@ const defaultActions = {
823
1112
  // 1) blocks attempts by resource.stop to resub (as type is in error)
824
1113
  // 2) will be cleared when resyncWatch --> watch (with force) --> resource.start completes
825
1114
  commit('setInError', { msg, reason: REVISION_TOO_OLD });
826
- dispatch('resyncWatch', msg);
1115
+
1116
+ // See Scenario 1 from https://github.com/rancher/dashboard/issues/14974
1117
+ // The watch that results from resyncWatch will fail and end up here if the revision isn't (yet) known
1118
+ // So re-retry resyncWatch until it does OR
1119
+ // - we're already re-retrying
1120
+ // - early exist from `execute`
1121
+ // - we give up (exceed max retries)
1122
+ // - early exist from `execute`
1123
+ // - we need to stop (socket is disconnected or closed, type is 'forgotten', watch is unwatched)
1124
+ // - `reset` called asynchronously
1125
+ // - Note - we won't need to clear the id outside of the above scenarios because `too old` only occurs on fresh watches (covered by above scenarios)
1126
+ backOff.execute({
1127
+ id: getters.backOffId(msg, REVISION_TOO_OLD),
1128
+ description: `Invalid watch revision, re-syncing`,
1129
+ canFn: () => getters.canBackoff(this.$socket),
1130
+ delayedFn: () => dispatch('resyncWatch', msg),
1131
+ });
827
1132
  } else if ( err.includes('the server does not allow this method on the requested resource')) {
828
1133
  commit('setInError', { msg, reason: NO_PERMS });
829
1134
  }
@@ -846,7 +1151,8 @@ const defaultActions = {
846
1151
  type,
847
1152
  id: msg.id,
848
1153
  namespace: msg.namespace,
849
- selector: msg.selector
1154
+ selector: msg.selector,
1155
+ mode: msg.mode
850
1156
  };
851
1157
 
852
1158
  state.debugSocket && console.info(`Resource Stop [${ getters.storeName }]`, type, msg); // eslint-disable-line no-console
@@ -922,6 +1228,13 @@ const defaultActions = {
922
1228
  }
923
1229
  },
924
1230
 
1231
+ 'ws.resource.changes'({ dispatch }, msg) {
1232
+ dispatch('fetchResources', {
1233
+ ...msg,
1234
+ opt: { force: true, load: _MERGE }
1235
+ } );
1236
+ },
1237
+
925
1238
  'ws.resource.remove'(ctx, msg) {
926
1239
  const data = msg.data;
927
1240
  const type = data.type;
@@ -999,21 +1312,33 @@ const defaultMutations = {
999
1312
  setInError(state, { msg, reason }) {
1000
1313
  const key = keyForSubscribe(msg);
1001
1314
 
1002
- state.inError[key] = reason;
1315
+ const { data, resourceType, ...obj } = msg;
1316
+
1317
+ obj.type = msg.resourceType || msg.type;
1318
+
1319
+ state.inError[key] = { obj, reason };
1003
1320
  },
1004
1321
 
1005
1322
  clearInError(state, msg) {
1323
+ // Callers of this should consider using local clearInError instead
1324
+
1006
1325
  const key = keyForSubscribe(msg);
1007
1326
 
1008
1327
  delete state.inError[key];
1009
1328
  },
1010
1329
 
1330
+ /**
1331
+ * Clear out socket state
1332
+ */
1011
1333
  resetSubscriptions(state) {
1012
- // Clear out socket state. This is only ever called from reset... which is always called after we `disconnect` above.
1013
- // This could probably be folded in to there
1014
1334
  clear(state.started);
1015
1335
  clear(state.pendingFrames);
1016
1336
  clear(state.queue);
1337
+ // Note - we clear async operations here (like queueTimer) and we should also do so for backoff requests via
1338
+ // resetWatchBackOff, however can't because this is a mutation and it's an action
1339
+ // We shouldn't need to though given resetSubscription is called from store reset, which includes forgetType
1340
+ // on everything in the store, which resets backoff requests.
1341
+ // Additionally this is probably called on a cluster store, so we also call resetWatchBackOff when the socket disconnects
1017
1342
  clearTimeout(state.queueTimer);
1018
1343
  state.deferredRequests = {};
1019
1344
  state.queueTimer = null;
@@ -1031,8 +1356,27 @@ const defaultMutations = {
1031
1356
  * Getters that cover cases 1 & 2 (see file description)
1032
1357
  */
1033
1358
  const defaultGetters = {
1359
+ /**
1360
+ * Get a unique id that can be used to track a process that can be backed-off
1361
+ *
1362
+ * @param obj - the usual id/namespace/selector, etc,
1363
+ * @param postFix - something else to uniquely id this back-off
1364
+ */
1365
+ backOffId: () => (obj, postFix) => {
1366
+ return `${ keyForSubscribe(obj) }${ postFix ? `:${ postFix }` : '' }`;
1367
+ },
1368
+
1369
+ /**
1370
+ * Can the back off process run?
1371
+ *
1372
+ * If we're not connected no.
1373
+ */
1374
+ canBackoff: () => ($socket) => {
1375
+ return $socket.state === EVENT_CONNECTED;
1376
+ },
1377
+
1034
1378
  inError: (state) => (obj) => {
1035
- return state.inError[keyForSubscribe(obj)];
1379
+ return state.inError[keyForSubscribe(obj)]?.reason;
1036
1380
  },
1037
1381
 
1038
1382
  watchesOfType: (state) => (type) => {
@@ -1040,9 +1384,24 @@ const defaultGetters = {
1040
1384
  },
1041
1385
 
1042
1386
  watchStarted: (state) => (obj) => {
1043
- return !!state.started.find((entry) => equivalentWatch(obj, entry));
1387
+ const existing = state.started.find((entry) => equivalentWatch(obj, entry));
1388
+
1389
+ return !!existing;
1044
1390
  },
1045
1391
 
1392
+ /**
1393
+ * Try to determine the latest revision to use in a watch request.
1394
+ *
1395
+ * It does some dodgy revision comparisons (revisions are not guaranteed to be numerical or equate higher to newer)
1396
+ *
1397
+ * If we have an id - and that resource has a revision - use it
1398
+ * If we have a list - and the store has a revision - and it's a string - use it straight away
1399
+ * If we have a list - and the store has a revision - and it's a number - compare it to the revisions in the list and use overall highest
1400
+ *
1401
+ * Note - This used to use parseInt which does stuff like `abc-123` --> NaN, `123-abc` --> 123
1402
+ *
1403
+ * Returns string, non-zero number or null
1404
+ */
1046
1405
  nextResourceVersion: (state, getters) => (type, id) => {
1047
1406
  type = normalizeType(type);
1048
1407
  let revision = 0;
@@ -1050,32 +1409,38 @@ const defaultGetters = {
1050
1409
  if ( id ) {
1051
1410
  const existing = getters['byId'](type, id);
1052
1411
 
1053
- revision = parseInt(existing?.metadata?.resourceVersion, 10);
1412
+ revision = existing?.metadata?.resourceVersion;
1054
1413
  }
1055
1414
 
1056
1415
  if ( !revision ) {
1057
1416
  const cache = state.types[type];
1058
1417
 
1418
+ // No Cache, nothing to compare to, return early
1059
1419
  if ( !cache ) {
1060
1420
  return null;
1061
1421
  }
1062
1422
 
1063
- revision = cache.revision; // This is always zero.....
1423
+ revision = Number(cache.revision);
1064
1424
 
1065
- for ( const obj of cache.list ) {
1425
+ // Cached LIST revision isn't a number, cannot compare to, return early
1426
+ if (Number.isNaN(revision)) {
1427
+ return cache.revision || null;
1428
+ }
1429
+
1430
+ for ( const obj of cache.list || [] ) {
1066
1431
  if ( obj && obj.metadata ) {
1067
- const neu = parseInt(obj.metadata.resourceVersion, 10);
1432
+ const neu = Number(obj.metadata.resourceVersion);
1433
+
1434
+ if (Number.isNaN(neu)) {
1435
+ continue;
1436
+ }
1068
1437
 
1069
1438
  revision = Math.max(revision, neu);
1070
1439
  }
1071
1440
  }
1072
1441
  }
1073
1442
 
1074
- if ( revision ) {
1075
- return revision;
1076
- }
1077
-
1078
- return null;
1443
+ return revision || null;
1079
1444
  },
1080
1445
  };
1081
1446