@rancher/shell 3.0.5-rc.3 → 3.0.5-rc.6

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 (424) hide show
  1. package/assets/data/aws-regions.json +1 -0
  2. package/assets/images/icons/document.svg +3 -0
  3. package/assets/images/key.svg +17 -0
  4. package/assets/images/vendor/cognito.svg +1 -0
  5. package/assets/styles/app.scss +1 -0
  6. package/assets/styles/base/_basic.scss +10 -0
  7. package/assets/styles/base/_spacing.scss +29 -0
  8. package/assets/styles/global/_form.scss +1 -1
  9. package/assets/styles/global/_labeled-input.scss +1 -1
  10. package/assets/styles/global/_layout.scss +1 -1
  11. package/assets/styles/themes/_dark.scss +28 -0
  12. package/assets/styles/themes/_light.scss +68 -0
  13. package/assets/styles/vendor/vue-select.scss +1 -1
  14. package/assets/translations/en-us.yaml +721 -83
  15. package/assets/translations/zh-hans.yaml +11 -9
  16. package/cloud-credential/gcp.vue +9 -1
  17. package/components/AppModal.vue +2 -0
  18. package/components/Certificates.vue +5 -0
  19. package/components/CodeMirror.vue +1 -1
  20. package/components/ConfigMapSettings/Settings.vue +377 -0
  21. package/components/ConfigMapSettings/index.vue +354 -0
  22. package/components/CruResource.vue +1 -2
  23. package/components/DetailText.vue +61 -11
  24. package/components/Drawer/Chrome.vue +116 -0
  25. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +61 -0
  26. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +48 -0
  27. package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +54 -0
  28. package/components/Drawer/ResourceDetailDrawer/__tests__/YamlTab.test.ts +80 -0
  29. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +82 -0
  30. package/components/Drawer/ResourceDetailDrawer/__tests__/helpers.test.ts +42 -0
  31. package/components/Drawer/ResourceDetailDrawer/composables.ts +50 -0
  32. package/components/Drawer/ResourceDetailDrawer/helpers.ts +10 -0
  33. package/components/Drawer/ResourceDetailDrawer/index.vue +110 -0
  34. package/components/FilterPanel.vue +156 -0
  35. package/components/{fleet/ForceDirectedTreeChart/index.vue → ForceDirectedTreeChart.vue} +47 -41
  36. package/components/GrowlManager.vue +16 -15
  37. package/components/IconOrSvg.vue +19 -35
  38. package/components/KeyValueView.vue +1 -1
  39. package/components/LocaleSelector.vue +9 -1
  40. package/components/ProgressBarMulti.vue +1 -0
  41. package/components/PromptModal.vue +6 -1
  42. package/components/PromptRemove.vue +5 -1
  43. package/components/RelatedResources.vue +4 -12
  44. package/components/Resource/Detail/Additional.vue +46 -0
  45. package/components/Resource/Detail/Card/PodsCard/Bubble.vue +13 -0
  46. package/components/Resource/Detail/Card/PodsCard/composable.ts +30 -0
  47. package/components/Resource/Detail/Card/PodsCard/index.vue +118 -0
  48. package/components/Resource/Detail/Card/ResourceUsageCard/composable.ts +51 -0
  49. package/components/Resource/Detail/Card/ResourceUsageCard/index.vue +79 -0
  50. package/components/Resource/Detail/Card/Scaler.vue +89 -0
  51. package/components/Resource/Detail/Card/StateCard/composables.ts +112 -0
  52. package/components/Resource/Detail/Card/StateCard/index.vue +39 -0
  53. package/components/Resource/Detail/Card/VerticalGap.vue +11 -0
  54. package/components/Resource/Detail/Card/__tests__/Card.test.ts +36 -0
  55. package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +84 -0
  56. package/components/Resource/Detail/Card/__tests__/ResourceUsageCard.test.ts +72 -0
  57. package/components/Resource/Detail/Card/__tests__/Scaler.test.ts +87 -0
  58. package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +53 -0
  59. package/components/Resource/Detail/Card/__tests__/VerticalGap.test.ts +14 -0
  60. package/components/Resource/Detail/Card/__tests__/index.test.ts +36 -0
  61. package/components/Resource/Detail/Card/index.vue +56 -0
  62. package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +19 -0
  63. package/components/Resource/Detail/Metadata/Annotations/composable.ts +12 -0
  64. package/components/Resource/Detail/Metadata/Annotations/index.vue +31 -0
  65. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +223 -0
  66. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +103 -0
  67. package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +64 -0
  68. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +298 -0
  69. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +133 -0
  70. package/components/Resource/Detail/Metadata/KeyValue.vue +138 -0
  71. package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +18 -0
  72. package/components/Resource/Detail/Metadata/Labels/composable.ts +12 -0
  73. package/components/Resource/Detail/Metadata/Labels/index.vue +31 -0
  74. package/components/Resource/Detail/Metadata/Rectangle.vue +32 -0
  75. package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +107 -0
  76. package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +24 -0
  77. package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +75 -0
  78. package/components/Resource/Detail/Metadata/__tests__/index.test.ts +91 -0
  79. package/components/Resource/Detail/Metadata/composables.ts +78 -0
  80. package/components/Resource/Detail/Metadata/index.vue +73 -0
  81. package/components/Resource/Detail/Page.vue +37 -0
  82. package/components/Resource/Detail/PercentageBar.vue +40 -0
  83. package/components/Resource/Detail/ResourceRow.vue +138 -0
  84. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/__tests__/composables.test.ts +29 -0
  85. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/__tests__/index.test.ts +48 -0
  86. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/composables.ts +31 -0
  87. package/components/Resource/Detail/ResourceTabs/ConfigMapDataTab/index.vue +50 -0
  88. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/__tests__/composables.test.ts +66 -0
  89. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/composables.ts +21 -0
  90. package/components/Resource/Detail/ResourceTabs/KnownHostsTab/index.vue +31 -0
  91. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Basic.vue +45 -0
  92. package/components/Resource/Detail/ResourceTabs/SecretDataTab/BasicAuth.vue +31 -0
  93. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Certificate.vue +31 -0
  94. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Registry.vue +22 -0
  95. package/components/Resource/Detail/ResourceTabs/SecretDataTab/ServiceAccountToken.vue +31 -0
  96. package/components/Resource/Detail/ResourceTabs/SecretDataTab/Ssh.vue +32 -0
  97. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Basic.test.ts +40 -0
  98. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/BasicAuth.test.ts +33 -0
  99. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Certificate.test.ts +33 -0
  100. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Registry.test.ts +27 -0
  101. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/ServiceAccountToken.test.ts +33 -0
  102. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/Ssh.test.ts +33 -0
  103. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/auth-types.test.ts +186 -0
  104. package/components/Resource/Detail/ResourceTabs/SecretDataTab/__tests__/composables.test.ts +102 -0
  105. package/components/Resource/Detail/ResourceTabs/SecretDataTab/auth-types.ts +109 -0
  106. package/components/Resource/Detail/ResourceTabs/SecretDataTab/composeables.ts +52 -0
  107. package/components/Resource/Detail/ResourceTabs/SecretDataTab/index.vue +71 -0
  108. package/components/Resource/Detail/SpacedRow.vue +14 -0
  109. package/components/Resource/Detail/StatusBar.vue +59 -0
  110. package/components/Resource/Detail/StatusRow.vue +61 -0
  111. package/components/Resource/Detail/TitleBar/Title.vue +14 -0
  112. package/components/Resource/Detail/TitleBar/Top.vue +14 -0
  113. package/components/Resource/Detail/TitleBar/__tests__/Title.test.ts +17 -0
  114. package/components/Resource/Detail/TitleBar/__tests__/Top.test.ts +17 -0
  115. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +63 -0
  116. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +142 -0
  117. package/components/Resource/Detail/TitleBar/composables.ts +44 -0
  118. package/components/Resource/Detail/TitleBar/index.vue +196 -0
  119. package/components/Resource/Detail/Top/index.vue +34 -0
  120. package/components/Resource/Detail/__tests__/Page.test.ts +32 -0
  121. package/components/Resource/Detail/composables.ts +45 -0
  122. package/components/ResourceDetail/Masthead/__tests__/index.test.ts +70 -0
  123. package/components/ResourceDetail/{__tests__/Masthead.test.ts → Masthead/__tests__/legacy.test.ts} +3 -3
  124. package/components/ResourceDetail/Masthead/index.vue +65 -0
  125. package/components/ResourceDetail/Masthead/latest.vue +44 -0
  126. package/components/ResourceDetail/__tests__/index.test.ts +135 -0
  127. package/components/ResourceDetail/index.vue +73 -557
  128. package/components/ResourceDetail/legacy.vue +562 -0
  129. package/components/ResourceList/Masthead.vue +6 -0
  130. package/components/ResourceTable.vue +41 -7
  131. package/components/ResourceYaml.vue +14 -1
  132. package/components/SlideInPanelManager.vue +117 -10
  133. package/components/SortableTable/index.vue +13 -2
  134. package/components/SortableTable/selection.js +21 -8
  135. package/components/StateDot/index.vue +28 -0
  136. package/components/StatusBadge.vue +6 -4
  137. package/components/SubtleLink.vue +25 -0
  138. package/components/Tabbed/index.vue +11 -15
  139. package/components/Wizard.vue +16 -3
  140. package/components/YamlEditor.vue +1 -1
  141. package/components/__tests__/ConfigMapSettings.test.ts +376 -0
  142. package/components/__tests__/FilterPanel.test.ts +81 -0
  143. package/components/__tests__/GrowlManager.test.ts +0 -25
  144. package/components/auth/AuthBanner.vue +2 -3
  145. package/components/auth/RoleDetailEdit.vue +45 -3
  146. package/components/auth/login/ldap.vue +1 -1
  147. package/components/auth/login/oidc.vue +6 -1
  148. package/components/fleet/FleetApplications.vue +174 -0
  149. package/components/fleet/FleetClusterTargets/TargetsList.vue +66 -0
  150. package/components/fleet/FleetClusterTargets/index.vue +455 -0
  151. package/components/fleet/FleetClusters.vue +25 -6
  152. package/components/fleet/FleetGitRepoPaths.vue +476 -0
  153. package/components/fleet/FleetHelmOps.vue +123 -0
  154. package/components/fleet/FleetIntro.vue +58 -28
  155. package/components/fleet/FleetNoWorkspaces.vue +5 -1
  156. package/components/fleet/FleetOCIStorageSecret.vue +171 -0
  157. package/components/fleet/FleetRepos.vue +37 -80
  158. package/components/fleet/FleetResources.vue +53 -26
  159. package/components/fleet/FleetSummary.vue +26 -51
  160. package/components/fleet/FleetValuesFrom.vue +295 -0
  161. package/components/fleet/__tests__/FleetClusterTargets.test.ts +1224 -0
  162. package/components/fleet/__tests__/FleetGitRepoPaths.test.ts +265 -0
  163. package/components/fleet/__tests__/FleetOCIStorageSecret.test.ts +213 -0
  164. package/components/fleet/__tests__/FleetSummary.test.ts +39 -39
  165. package/components/fleet/__tests__/FleetValuesFrom.test.ts +300 -0
  166. package/components/fleet/dashboard/Empty.vue +73 -0
  167. package/components/fleet/dashboard/ResourceCard.vue +184 -0
  168. package/components/fleet/dashboard/ResourceCardSummary.vue +195 -0
  169. package/components/fleet/dashboard/ResourceDetails.vue +194 -0
  170. package/components/fleet/dashboard/ResourcePanel.vue +383 -0
  171. package/components/form/ArrayList.vue +19 -2
  172. package/components/form/ChangePassword.vue +3 -1
  173. package/components/form/Footer.vue +10 -4
  174. package/components/form/KeyValue.vue +81 -43
  175. package/components/form/LabeledSelect.vue +56 -16
  176. package/components/form/Labels.vue +90 -17
  177. package/components/form/MatchExpressions.vue +46 -5
  178. package/components/form/NameNsDescription.vue +1 -1
  179. package/components/form/ResourceSelector.vue +1 -0
  180. package/components/form/ResourceTabs/index.vue +5 -0
  181. package/components/form/SecretSelector.vue +9 -2
  182. package/components/form/Select.vue +57 -19
  183. package/components/form/SimpleSecretSelector.vue +17 -4
  184. package/components/form/Taints.vue +21 -2
  185. package/components/form/UnitInput.vue +8 -0
  186. package/components/form/ValueFromResource.vue +31 -19
  187. package/components/form/__tests__/LabeledSelect.test.ts +8 -4
  188. package/components/form/__tests__/Labels.test.ts +360 -0
  189. package/components/form/__tests__/MatchExpressions.test.ts +16 -13
  190. package/components/form/__tests__/Select.test.ts +5 -2
  191. package/components/formatter/FleetApplicationClustersReady.vue +77 -0
  192. package/components/formatter/FleetApplicationSource.vue +71 -0
  193. package/components/formatter/FleetSummaryGraph.vue +7 -0
  194. package/components/formatter/WorkloadHealthScale.vue +1 -1
  195. package/components/google/AccountAccess.vue +211 -0
  196. package/components/google/types/gcp.d.ts +136 -0
  197. package/components/google/types/index.d.ts +101 -0
  198. package/components/google/util/__mocks__/gcp.ts +465 -0
  199. package/components/google/util/formatter.ts +82 -0
  200. package/components/google/util/gcp.ts +134 -0
  201. package/components/google/util/index.d.ts +11 -0
  202. package/components/nav/Favorite.vue +1 -1
  203. package/components/nav/Group.vue +70 -47
  204. package/components/nav/Header.vue +13 -8
  205. package/components/nav/NamespaceFilter.vue +13 -1
  206. package/components/nav/NotificationCenter/Notification.vue +510 -0
  207. package/components/nav/NotificationCenter/NotificationHeader.vue +112 -0
  208. package/components/nav/NotificationCenter/index.vue +148 -0
  209. package/components/nav/TopLevelMenu.helper.ts +55 -34
  210. package/components/nav/TopLevelMenu.vue +11 -0
  211. package/components/nav/Type.vue +4 -1
  212. package/composables/drawer.ts +26 -0
  213. package/composables/resources.test.ts +63 -0
  214. package/composables/resources.ts +38 -0
  215. package/composables/useI18n.ts +12 -11
  216. package/composables/useIsNewDetailPageEnabled.ts +17 -0
  217. package/config/labels-annotations.js +20 -11
  218. package/config/product/auth.js +17 -1
  219. package/config/product/{cis.js → compliance.js} +23 -26
  220. package/config/product/explorer.js +5 -1
  221. package/config/product/fleet.js +77 -17
  222. package/config/product/settings.js +22 -11
  223. package/config/query-params.js +6 -1
  224. package/config/roles.ts +2 -1
  225. package/config/router/navigation-guards/authentication.js +51 -2
  226. package/config/router/routes.js +45 -31
  227. package/config/secret.ts +15 -0
  228. package/config/settings.ts +24 -5
  229. package/config/store.js +2 -0
  230. package/config/system-namespaces.js +1 -1
  231. package/config/table-headers.js +53 -23
  232. package/config/types.js +17 -6
  233. package/core/plugin-helpers.ts +3 -2
  234. package/core/plugin.ts +32 -7
  235. package/core/types.ts +18 -1
  236. package/detail/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +22 -18
  237. package/detail/fleet.cattle.io.cluster.vue +28 -15
  238. package/detail/fleet.cattle.io.gitrepo.vue +10 -1
  239. package/detail/fleet.cattle.io.helmop.vue +157 -0
  240. package/detail/management.cattle.io.fleetworkspace.vue +18 -27
  241. package/detail/management.cattle.io.oidcclient.vue +369 -0
  242. package/detail/node.vue +2 -2
  243. package/detail/pod.vue +2 -2
  244. package/detail/service.vue +10 -1
  245. package/detail/workload/index.vue +8 -2
  246. package/dialog/ExtensionCatalogUninstallDialog.vue +7 -4
  247. package/dialog/GenericPrompt.vue +1 -1
  248. package/dialog/HelmOpForceUpdateDialog.vue +132 -0
  249. package/dialog/ImportDialog.vue +8 -8
  250. package/dialog/OidcClientSecretDialog.vue +117 -0
  251. package/dialog/RedeployWorkloadDialog.vue +164 -0
  252. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +3 -3
  253. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +60 -68
  254. package/edit/auth/oidc.vue +159 -93
  255. package/edit/autoscaling.horizontalpodautoscaler/index.vue +4 -1
  256. package/edit/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +30 -31
  257. package/edit/{cis.cattle.io.clusterscanbenchmark.vue → compliance.cattle.io.clusterscanbenchmark.vue} +4 -4
  258. package/edit/{cis.cattle.io.clusterscanprofile.vue → compliance.cattle.io.clusterscanprofile.vue} +5 -5
  259. package/edit/configmap.vue +4 -1
  260. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  261. package/edit/fleet.cattle.io.gitrepo.vue +70 -255
  262. package/edit/fleet.cattle.io.helmop.vue +772 -0
  263. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  264. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  265. package/edit/logging-flow/index.vue +1 -0
  266. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  267. package/edit/management.cattle.io.fleetworkspace.vue +44 -10
  268. package/edit/management.cattle.io.oidcclient.vue +162 -0
  269. package/edit/management.cattle.io.project.vue +4 -1
  270. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
  271. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +5 -0
  272. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  273. package/edit/monitoring.coreos.com.receiver/auth.vue +30 -30
  274. package/edit/monitoring.coreos.com.receiver/index.vue +1 -0
  275. package/edit/monitoring.coreos.com.receiver/types/email.vue +1 -1
  276. package/edit/monitoring.coreos.com.route.vue +1 -0
  277. package/edit/namespace.vue +1 -0
  278. package/edit/networking.istio.io.destinationrule/index.vue +4 -1
  279. package/edit/networking.k8s.io.ingress/index.vue +4 -1
  280. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +7 -2
  281. package/edit/networking.k8s.io.networkpolicy/index.vue +6 -2
  282. package/edit/node.vue +1 -0
  283. package/edit/persistentvolume/index.vue +4 -1
  284. package/edit/provisioning.cattle.io.cluster/rke2.vue +418 -382
  285. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +27 -27
  286. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +5 -0
  287. package/edit/resources.cattle.io.restore.vue +1 -1
  288. package/edit/secret/index.vue +1 -0
  289. package/edit/service.vue +4 -1
  290. package/edit/serviceaccount.vue +4 -1
  291. package/edit/storage.k8s.io.storageclass/index.vue +4 -1
  292. package/edit/workload/index.vue +5 -0
  293. package/list/{cis.cattle.io.clusterscan.vue → compliance.cattle.io.clusterscan.vue} +2 -2
  294. package/list/fleet.cattle.io.gitrepo.vue +1 -1
  295. package/list/fleet.cattle.io.helmop.vue +108 -0
  296. package/list/management.cattle.io.oidcclient.vue +108 -0
  297. package/list/namespace.vue +5 -2
  298. package/list/node.vue +2 -0
  299. package/machine-config/amazonec2.vue +3 -24
  300. package/machine-config/components/GCEImage.vue +374 -0
  301. package/machine-config/google.vue +617 -0
  302. package/mixins/__tests__/brand.spec.ts +170 -0
  303. package/mixins/auth-config.js +8 -1
  304. package/mixins/brand.js +16 -17
  305. package/mixins/create-edit-view/index.js +5 -0
  306. package/mixins/preset.js +100 -0
  307. package/mixins/resource-fetch-api-pagination.js +18 -0
  308. package/mixins/resource-fetch.js +1 -1
  309. package/mixins/resource-table-watch.js +45 -0
  310. package/mixins/vue-select-overrides.js +1 -0
  311. package/models/__tests__/chart.test.ts +273 -0
  312. package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
  313. package/models/chart.js +144 -2
  314. package/models/{cis.cattle.io.clusterscan.js → compliance.cattle.io.clusterscan.js} +8 -8
  315. package/models/{cis.cattle.io.clusterscanbenchmark.js → compliance.cattle.io.clusterscanbenchmark.js} +1 -1
  316. package/models/{cis.cattle.io.clusterscanprofile.js → compliance.cattle.io.clusterscanprofile.js} +5 -5
  317. package/models/{cis.cattle.io.clusterscanreport.js → compliance.cattle.io.clusterscanreport.js} +1 -1
  318. package/models/fleet-application.js +314 -0
  319. package/models/fleet.cattle.io.bundle.js +9 -8
  320. package/models/fleet.cattle.io.cluster.js +11 -0
  321. package/models/fleet.cattle.io.gitrepo.js +41 -365
  322. package/models/fleet.cattle.io.helmop.js +198 -0
  323. package/models/management.cattle.io.authconfig.js +1 -0
  324. package/models/management.cattle.io.fleetworkspace.js +14 -1
  325. package/models/management.cattle.io.oidcclient.js +18 -0
  326. package/models/management.cattle.io.registration.js +3 -0
  327. package/models/provisioning.cattle.io.cluster.js +5 -5
  328. package/models/service.js +4 -0
  329. package/models/workload.js +19 -18
  330. package/package.json +2 -1
  331. package/pages/about.vue +4 -58
  332. package/pages/auth/login.vue +1 -1
  333. package/pages/auth/verify.vue +13 -1
  334. package/pages/c/_cluster/apps/charts/AddRepoLink.vue +36 -0
  335. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +80 -0
  336. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +54 -0
  337. package/pages/c/_cluster/apps/charts/StatusLabel.vue +33 -0
  338. package/pages/c/_cluster/apps/charts/index.vue +487 -465
  339. package/pages/c/_cluster/auth/user.retention/index.vue +87 -78
  340. package/pages/c/_cluster/explorer/EventsTable.vue +1 -1
  341. package/pages/c/_cluster/explorer/index.vue +3 -3
  342. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -1
  343. package/pages/c/_cluster/fleet/__tests__/index.test.ts +426 -0
  344. package/pages/c/_cluster/fleet/application/_resource/_id.vue +14 -0
  345. package/pages/c/_cluster/fleet/application/_resource/create.vue +14 -0
  346. package/pages/c/_cluster/fleet/application/create.vue +341 -0
  347. package/pages/c/_cluster/fleet/application/index.vue +139 -0
  348. package/pages/c/_cluster/fleet/graph/config.js +277 -0
  349. package/pages/c/_cluster/fleet/index.vue +809 -329
  350. package/pages/c/_cluster/fleet/settings/index.vue +229 -0
  351. package/pages/c/_cluster/longhorn/index.vue +5 -2
  352. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +16 -1
  353. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +2 -2
  354. package/pages/explorer/resource/detail/configmap.vue +42 -0
  355. package/pages/explorer/resource/detail/secret.vue +50 -0
  356. package/pages/home.vue +9 -55
  357. package/pages/support/index.vue +4 -6
  358. package/plugins/dashboard-store/actions.js +50 -14
  359. package/plugins/dashboard-store/getters.js +38 -21
  360. package/plugins/dashboard-store/mutations.js +51 -7
  361. package/plugins/dashboard-store/resource-class.js +30 -4
  362. package/plugins/steve/__tests__/subscribe.spec.ts +66 -1
  363. package/plugins/steve/actions.js +3 -0
  364. package/plugins/steve/steve-pagination-utils.ts +17 -8
  365. package/plugins/steve/subscribe.js +235 -43
  366. package/rancher-components/BadgeState/BadgeState.vue +3 -1
  367. package/rancher-components/Banner/Banner.vue +13 -0
  368. package/rancher-components/Form/Checkbox/Checkbox.vue +11 -6
  369. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  370. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -0
  371. package/rancher-components/RcItemCard/RcItemCard.test.ts +189 -0
  372. package/rancher-components/RcItemCard/RcItemCard.vue +430 -0
  373. package/rancher-components/RcItemCard/RcItemCardAction.vue +24 -0
  374. package/rancher-components/RcItemCard/index.ts +2 -0
  375. package/store/auth.js +3 -0
  376. package/store/catalog.js +85 -25
  377. package/store/growl.js +97 -8
  378. package/store/index.js +39 -14
  379. package/store/notifications.ts +426 -0
  380. package/store/prefs.js +0 -1
  381. package/store/slideInPanel.ts +6 -0
  382. package/store/type-map.js +19 -15
  383. package/store/uiplugins.ts +15 -1
  384. package/types/fleet.d.ts +59 -0
  385. package/types/notifications/index.ts +74 -0
  386. package/types/resources/settings.d.ts +19 -1
  387. package/types/shell/index.d.ts +388 -307
  388. package/types/store/dashboard-store.types.ts +33 -3
  389. package/types/store/pagination.types.ts +6 -1
  390. package/types/store/subscribe.types.ts +50 -0
  391. package/utils/__tests__/fleet.test.ts +148 -0
  392. package/utils/__tests__/object.test.ts +54 -1
  393. package/utils/__tests__/string.test.ts +273 -1
  394. package/utils/__tests__/time.test.ts +31 -0
  395. package/utils/auth.js +41 -5
  396. package/utils/crypto/encryption.ts +103 -0
  397. package/utils/cspAdaptor.ts +51 -0
  398. package/utils/fleet-types.ts +0 -0
  399. package/utils/fleet.ts +190 -2
  400. package/utils/object.js +36 -0
  401. package/utils/pagination-utils.ts +27 -2
  402. package/utils/pagination-wrapper.ts +132 -50
  403. package/utils/release-notes.ts +48 -0
  404. package/utils/selector-typed.ts +7 -2
  405. package/utils/settings.ts +4 -1
  406. package/utils/string.js +24 -0
  407. package/utils/style.ts +39 -0
  408. package/utils/{time.js → time.ts} +25 -6
  409. package/utils/uiplugins.ts +22 -0
  410. package/utils/validators/formRules/__tests__/index.test.ts +36 -3
  411. package/utils/validators/formRules/index.ts +13 -3
  412. package/utils/window.js +11 -7
  413. package/components/__tests__/ApplicationCard.test.ts +0 -27
  414. package/components/cards/ApplicationCard.vue +0 -145
  415. package/components/fleet/ForceDirectedTreeChart/chartIcons.js +0 -17
  416. package/config/product/legacy.js +0 -62
  417. package/config/secret.js +0 -14
  418. package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +0 -249
  419. package/pages/c/_cluster/legacy/pages/_page.vue +0 -29
  420. package/pages/c/_cluster/legacy/project/_page.vue +0 -57
  421. package/pages/c/_cluster/legacy/project/index.vue +0 -32
  422. package/pages/c/_cluster/legacy/project/pipelines.vue +0 -96
  423. /package/components/ResourceDetail/{Masthead.vue → Masthead/legacy.vue} +0 -0
  424. /package/{components/form/SSHKnownHosts → dialog}/__tests__/KnownHostsEditDialog.test.ts +0 -0
@@ -1,36 +1,48 @@
1
1
  <script>
2
- import { mapState } from 'vuex';
2
+ import { getVersionData } from '@shell/config/version';
3
+ import { mapState, mapGetters } from 'vuex';
4
+ import { isEmpty } from '@shell/utils/object';
3
5
  import { FLEET } from '@shell/config/types';
4
6
  import { WORKSPACE } from '@shell/store/prefs';
5
- import {
6
- getStateLabel,
7
- primaryDisplayStatusFromCount,
8
- STATES,
9
- STATES_ENUM,
10
- } from '@shell/plugins/dashboard-store/resource-class';
11
7
  import Loading from '@shell/components/Loading';
12
- import CollapsibleCard from '@shell/components/CollapsibleCard.vue';
13
- import ResourceTable from '@shell/components/ResourceTable';
14
- import CompoundStatusBadge from '@shell/components/CompoundStatusBadge';
15
8
  import { checkPermissions, checkSchemasForFindAllHash } from '@shell/utils/auth';
16
9
  import { WORKSPACE_ANNOTATION } from '@shell/config/labels-annotations';
17
10
  import { filterBy } from '@shell/utils/array';
18
- import FleetNoWorkspaces from '@shell/components/fleet/FleetNoWorkspaces.vue';
19
- import { NAME } from '@shell/config/product/fleet';
20
- import { xOfy } from '@shell/utils/string';
11
+ import NoWorkspaces from '@shell/components/fleet/FleetNoWorkspaces.vue';
12
+ import { RcButton } from '@components/RcButton';
13
+ import ResourcePanel from '@shell/components/fleet/dashboard/ResourcePanel.vue';
14
+ import ResourceCard from '@shell/components/fleet/dashboard/ResourceCard.vue';
15
+ import ResourceDetails from '@shell/components/fleet/dashboard/ResourceDetails.vue';
16
+ import EmptyDashboard from '@shell/components/fleet/dashboard/Empty.vue';
17
+ import ButtonGroup from '@shell/components/ButtonGroup';
18
+ import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
19
+ import FleetApplications from '@shell/components/fleet/FleetApplications.vue';
20
+ import FleetUtils from '@shell/utils/fleet';
21
+ import Preset from '@shell/mixins/preset';
22
+
23
+ const VIEW_MODE = {
24
+ TABLE: 'flat',
25
+ CARDS: 'cards'
26
+ };
21
27
 
22
28
  export default {
23
29
  name: 'FleetDashboard',
24
30
  components: {
31
+ ButtonGroup,
32
+ Checkbox,
33
+ EmptyDashboard,
34
+ FleetApplications,
25
35
  Loading,
26
- ResourceTable,
27
- CollapsibleCard,
28
- CompoundStatusBadge,
29
- FleetNoWorkspaces
36
+ NoWorkspaces,
37
+ RcButton,
38
+ ResourceCard,
39
+ ResourcePanel,
30
40
  },
31
41
 
42
+ mixins: [Preset],
43
+
32
44
  async fetch() {
33
- const hash = await checkSchemasForFindAllHash({
45
+ const schemas = {
34
46
  fleetWorkspaces: {
35
47
  inStoreType: 'management',
36
48
  type: FLEET.WORKSPACE,
@@ -51,17 +63,37 @@ export default {
51
63
  inStoreType: 'management',
52
64
  type: FLEET.GIT_REPO,
53
65
  },
66
+ helmOps: {
67
+ inStoreType: 'management',
68
+ type: FLEET.HELM_OP,
69
+ },
54
70
  fleetClusters: {
55
71
  inStoreType: 'management',
56
72
  type: FLEET.CLUSTER,
57
73
  }
58
- }, this.$store);
74
+ };
75
+
76
+ const hash = await checkSchemasForFindAllHash(schemas, this.$store);
77
+
78
+ this.fleetWorkspaces = hash.fleetWorkspaces || [];
59
79
 
60
- this.gitRepos = hash.gitRepos;
61
- this.fleetWorkspacesData = hash.fleetWorkspaces || [];
80
+ this[FLEET.GIT_REPO] = hash.gitRepos || [];
81
+ this[FLEET.HELM_OP] = hash.helmOps || [];
62
82
 
63
83
  try {
64
- const permissions = await checkPermissions({ workspaces: { type: FLEET.WORKSPACE }, gitRepos: { type: FLEET.GIT_REPO, schemaValidator: (schema) => schema.resourceMethods.includes('PUT') } }, this.$store.getters);
84
+ const permissionsSchemas = {
85
+ workspaces: { type: FLEET.WORKSPACE },
86
+ gitRepos: {
87
+ type: FLEET.GIT_REPO,
88
+ schemaValidator: (schema) => schema.resourceMethods.includes('PUT')
89
+ },
90
+ helmOps: {
91
+ type: FLEET.HELM_OP,
92
+ schemaValidator: (schema) => schema.resourceMethods.includes('PUT')
93
+ },
94
+ };
95
+
96
+ const permissions = await checkPermissions(permissionsSchemas, this.$store.getters);
65
97
 
66
98
  this.permissions = permissions;
67
99
  } catch (e) {
@@ -71,211 +103,340 @@ export default {
71
103
 
72
104
  data() {
73
105
  return {
74
- admissableAreas: ['clusters', 'bundles', 'resources'],
75
- headers: [
106
+ permissions: {},
107
+ FLEET,
108
+ [FLEET.REPO]: [],
109
+ [FLEET.HELM_OP]: [],
110
+ fleetWorkspaces: [],
111
+ VIEW_MODE,
112
+ viewModeOptions: [
76
113
  {
77
- name: 'name',
78
- labelKey: 'tableHeaders.repoName',
79
- value: 'nameDisplay',
80
- sort: ['nameSort'],
81
- formatter: 'LinkDetail',
82
- canBeVariable: true,
114
+ tooltipKey: 'fleet.dashboard.viewMode.table',
115
+ icon: 'icon-list-flat',
116
+ value: VIEW_MODE.TABLE,
83
117
  },
84
118
  {
85
- name: 'clustersReady',
86
- labelKey: 'tableHeaders.clustersReady',
87
- value: 'status.readyClusters',
88
- sort: 'status.readyClusters',
89
- search: false,
119
+ tooltipKey: 'fleet.dashboard.viewMode.cards',
120
+ icon: 'icon-apps',
121
+ value: VIEW_MODE.CARDS,
90
122
  },
91
- {
92
- name: 'bundlesReady',
93
- labelKey: 'tableHeaders.bundlesReady',
94
- value: 'status.readyClusters',
95
- sort: 'status.readyClusters',
96
- search: false,
97
- },
98
- {
99
- name: 'resourcesReady',
100
- labelKey: 'tableHeaders.resourcesReady',
101
- value: 'status.resourceCounts.ready',
102
- sort: 'status.resourceCounts.ready',
103
- }
104
123
  ],
105
- schema: {},
106
- gitRepos: [],
107
- fleetWorkspacesData: [],
108
- isCollapsed: {},
109
- permissions: {},
110
- getStartedLink: {
111
- name: 'c-cluster-product-resource-create',
112
- params: {
113
- product: NAME,
114
- resource: FLEET.GIT_REPO
115
- },
116
- }
124
+ CARDS_MIN: 50,
125
+ CARDS_SIZE: 50,
126
+ cardsCount: {},
127
+ viewMode: VIEW_MODE.CARDS,
128
+ isWorkspaceCollapsed: {},
129
+ isStateCollapsed: {},
130
+ typeFilter: {},
131
+ stateFilter: {},
132
+ selectedCard: null,
133
+ presetVersion: getVersionData()?.Version,
117
134
  };
118
135
  },
136
+
137
+ created() {
138
+ this.$store.dispatch('showWorkspaceSwitcher', false);
139
+ },
140
+
141
+ mounted() {
142
+ this.preset('cardsCount', 'object');
143
+ this.preset('viewMode', 'string');
144
+ },
145
+
146
+ beforeUnmount() {
147
+ this.$store.dispatch('showWorkspaceSwitcher', true);
148
+ },
149
+
119
150
  computed: {
120
151
  ...mapState(['workspace', 'allNamespaces']),
121
- fleetWorkspaces() {
122
- if (this.fleetWorkspacesData?.length) {
123
- return this.fleetWorkspacesData;
152
+ ...mapGetters({ isOpenSlideInPanel: 'slideInPanel/isOpen' }),
153
+ ...mapGetters({ isClosingSlideInPanel: 'slideInPanel/isClosing' }),
154
+
155
+ repoSchema() {
156
+ return this.$store.getters['management/schemaFor'](FLEET.GIT_REPO);
157
+ },
158
+
159
+ createRoute() {
160
+ return { name: 'c-cluster-fleet-application-create' };
161
+ },
162
+
163
+ workspaces() {
164
+ if (this.fleetWorkspaces?.length) {
165
+ return this.fleetWorkspaces;
124
166
  }
125
167
 
126
168
  // When user doesn't have access to the workspaces fall back to namespaces
127
169
  return this.allNamespaces.filter((item) => {
128
170
  return item.metadata.annotations[WORKSPACE_ANNOTATION] === WORKSPACE;
129
171
  }).map(( obj ) => {
130
- const repos = filterBy(this.gitRepos, 'metadata.namespace', obj.id);
172
+ const repos = filterBy(this[FLEET.GIT_REPO], 'metadata.namespace', obj.id);
173
+ const helmOps = filterBy(this[FLEET.HELM_OP], 'metadata.namespace', obj.id);
131
174
 
132
175
  return {
133
176
  ...obj,
134
- counts: {
135
- clusters: '-',
136
- clusterGroups: '-',
137
- gitRepos: repos.length
138
- },
139
177
  repos,
140
- nameDisplay: obj.id
178
+ helmOps,
179
+ id: obj.id
141
180
  };
142
181
  });
143
182
  },
144
- workspacesData() {
145
- return this.fleetWorkspaces.filter((ws) => ws.counts.gitRepos > 0);
183
+
184
+ applicationStates() {
185
+ return this._groupByWorkspace((ws) => this._resourceStates([...ws.repos, ...ws.helmOps]));
146
186
  },
147
- emptyWorkspaces() {
148
- return this.fleetWorkspaces.filter((ws) => ws.counts.gitRepos === 0);
187
+
188
+ clusterStates() {
189
+ return this._groupByWorkspace((ws) => this._resourceStates(ws.clusters));
149
190
  },
150
- areAllCardsExpanded() {
151
- return Object.keys(this.isCollapsed).every((key) => !this.isCollapsed[key]);
191
+
192
+ clusterGroupsStates() {
193
+ return this._groupByWorkspace((ws) => this._resourceStates(ws.clusterGroups));
152
194
  },
153
- gitReposCounts() {
154
- return this.gitRepos.reduce((prev, gitRepo) => {
155
- prev[gitRepo.id] = {
156
- bundles: gitRepo.allBundlesStatuses,
157
- resources: gitRepo.allResourceStatuses,
158
- };
159
195
 
160
- return prev;
161
- }, {});
196
+ cardResources() {
197
+ return this._groupByWorkspace((ws) => {
198
+ const filtered = this.applicationStates[ws.id].reduce((acc, state) => ({
199
+ ...acc,
200
+ [state.stateDisplay]: this._filterResources(state),
201
+ }), {});
202
+
203
+ return filtered;
204
+ });
162
205
  },
163
- },
164
- methods: {
165
- setWorkspaceFilterAndLinkToGitRepo(value) {
166
- this.$store.commit('updateWorkspace', { value, getters: this.$store.getters } );
167
- this.$store.dispatch('prefs/set', { key: WORKSPACE, value });
168
-
169
- this.$router.push({
170
- name: 'c-cluster-product-resource',
171
- params: {
172
- product: NAME,
173
- resource: FLEET.GIT_REPO
174
- },
206
+
207
+ tableResources() {
208
+ return this._groupByWorkspace((ws) => {
209
+ const filtered = this.applicationStates[ws.id].reduce((acc, state) => ([
210
+ ...acc,
211
+ ...this._filterResources(state)
212
+ ]), []);
213
+
214
+ return filtered;
175
215
  });
176
216
  },
177
- getStatusInfo(area, row, rowCounts) {
178
- const defaultStatusInfo = {
179
- badgeClass: `${ STATES[STATES_ENUM.NOT_READY].color } badge-class-default`,
180
- icon: STATES[STATES_ENUM.NOT_READY].compoundIcon
181
- };
182
217
 
183
- // classes are defined in the themes SASS files...
184
- return this.getBadgeClassAndIcon(area, row, rowCounts) || defaultStatusInfo;
218
+ isEmptyDashboard() {
219
+ return this[FLEET.GIT_REPO]?.length === 0 && this[FLEET.HELM_OP]?.length === 0;
185
220
  },
186
- getBadgeClassAndIcon(area, row, rowCounts) {
187
- if (!this.admissableAreas.includes(area)) {
188
- return false;
189
- }
190
221
 
191
- let group;
222
+ allCardsExpanded() {
223
+ return Object.keys(this.isWorkspaceCollapsed).every((key) => !this.isWorkspaceCollapsed[key]);
224
+ },
225
+ },
192
226
 
193
- if (area === 'clusters') {
194
- const clusterInfo = row.clusterInfo;
195
- const state = clusterInfo.ready === clusterInfo.total ? STATES_ENUM.ACTIVE : STATES_ENUM.NOT_READY;
227
+ methods: {
228
+ selectStates(workspace, state) {
229
+ this._checkInit(workspace, 'stateFilter');
196
230
 
197
- return {
198
- badgeClass: `${ STATES[state].color } badge-class-area-${ area }`,
199
- icon: STATES[state].compoundIcon
200
- };
201
- } else if (area === 'bundles') {
202
- group = rowCounts[row.id].bundles;
203
- } else if (area === 'resources') {
204
- group = rowCounts[row.id].resources;
231
+ this._cleanStateFilter(workspace);
232
+
233
+ if (this.stateFilter[workspace][state]) {
234
+ delete this.stateFilter[workspace][state];
205
235
  } else {
206
- // unreachable
207
- return false;
236
+ this.stateFilter[workspace][state] = true;
208
237
  }
209
238
 
210
- if (group.total === group.states.ready) {
211
- return {
212
- badgeClass: STATES[STATES_ENUM.ACTIVE].color,
213
- icon: STATES[STATES_ENUM.ACTIVE].compoundIcon,
214
- };
239
+ if (this.isWorkspaceCollapsed[workspace]) {
240
+ this.toggleCard(workspace);
215
241
  }
216
- const state = primaryDisplayStatusFromCount(group.states);
217
242
 
218
- return {
219
- badgeClass: STATES[state].color ? STATES[state].color : `${ STATES[STATES_ENUM.UNKNOWN].color } bg-unmapped-state`,
220
- icon: STATES[state].compoundIcon ? STATES[state].compoundIcon : `${ STATES[STATES_ENUM.UNKNOWN].compoundIcon } unmapped-icon`
221
- };
243
+ this.$nextTick(() => {
244
+ this.toggleStateAll(workspace, 'expand');
245
+ });
222
246
  },
223
- getTooltipInfo(area, row, rowCounts) {
224
- if (!this.admissableAreas.includes(area)) {
225
- return {};
226
- }
227
247
 
228
- if (area === 'bundles') {
229
- return this.generateTooltipData(rowCounts[row.id].bundles.states);
230
- } else if (area === 'resources') {
231
- return this.generateTooltipData(rowCounts[row.id].resources.states);
232
- }
248
+ selectType(workspace, type, value) {
249
+ this._checkInit(workspace, 'typeFilter');
250
+
251
+ this.typeFilter[workspace][type] = value;
252
+
253
+ this.toggleStateAll(workspace, 'expand');
254
+ },
255
+
256
+ toggleCard(key) {
257
+ this.isWorkspaceCollapsed[key] = !this.isWorkspaceCollapsed[key];
258
+ },
259
+
260
+ toggleCardAll(action) {
261
+ const val = action !== 'expand';
233
262
 
234
- return '';
263
+ Object.keys(this.isWorkspaceCollapsed).forEach((key) => {
264
+ this.isWorkspaceCollapsed[key] = val;
265
+ });
235
266
  },
236
- generateTooltipData(infoObj) {
237
- return Object.keys(infoObj)
238
- .filter((key) => infoObj[key] > 0) // filter zero values
239
- .map((key) => `${ getStateLabel(key) }: ${ infoObj[key] }<br>`).join('');
267
+
268
+ toggleState(workspace, state) {
269
+ this._checkInit(workspace, 'isStateCollapsed');
270
+
271
+ this.isStateCollapsed[workspace][state] = !this.isStateCollapsed[workspace][state];
240
272
  },
241
- getBadgeValue(area, row, rowCounts) {
242
- let value;
243
273
 
244
- if (!this.admissableAreas.includes(area)) {
245
- return 'N/A';
274
+ toggleStateAll(workspace, action) {
275
+ const val = action !== 'expand';
276
+
277
+ Object.keys(this.isStateCollapsed[workspace] || []).forEach((state) => {
278
+ this.isStateCollapsed[workspace][state] = val;
279
+ });
280
+ },
281
+
282
+ loadMore(workspace, state) {
283
+ this._checkInit(workspace, 'cardsCount');
284
+
285
+ const count = this.cardsCount[workspace][state] || this.CARDS_MIN;
286
+
287
+ const val = count + this.CARDS_SIZE;
288
+
289
+ this.cardsCount[workspace][state] = val;
290
+ },
291
+
292
+ loadLess(workspace, state) {
293
+ this._checkInit(workspace, 'cardsCount');
294
+
295
+ const count = this.cardsCount[workspace][state] || this.CARDS_MIN;
296
+
297
+ const val = count - this.CARDS_MIN < 0 ? this.CARDS_MIN : count - this.CARDS_SIZE;
298
+
299
+ this.cardsCount[workspace][state] = val;
300
+ },
301
+
302
+ createResource(workspace) {
303
+ this.$store.dispatch('showWorkspaceSwitcher', true);
304
+
305
+ this.$nextTick(() => {
306
+ this.$store.commit('updateWorkspace', { value: workspace, getters: this.$store.getters });
307
+ this.$router.push(this.createRoute);
308
+ });
309
+ },
310
+
311
+ showResourceDetails(value, statePanel, workspace, selected) {
312
+ if (this.isClosingSlideInPanel) {
313
+ return;
246
314
  }
247
315
 
248
- if (area === 'clusters') {
249
- value = `${ row.clusterInfo.ready }/${ row.clusterInfo.total }`;
250
- } else if (area === 'bundles') {
251
- const bundles = rowCounts[row.id].bundles;
316
+ this.selectedCard = selected;
317
+
318
+ this.$shell.slideInPanel({
319
+ component: ResourceDetails,
320
+ componentProps: {
321
+ value,
322
+ statePanel,
323
+ workspace,
324
+ showHeader: false,
325
+ width: window.innerWidth / 3 > 530 ? `${ window.innerWidth / 3 }px` : '530px',
326
+ zIndex: 1,
327
+ triggerFocusTrap: true,
328
+ returnFocusSelector: `[data-testid="resource-card-${ value.id }"]`
329
+ }
330
+ });
331
+ },
332
+
333
+ _resourceStates(resources) {
334
+ const out = [];
335
+
336
+ resources.forEach((obj) => {
337
+ const {
338
+ stateDisplay,
339
+ stateSort
340
+ } = obj;
341
+
342
+ const exists = out.find((s) => s.stateDisplay === stateDisplay);
343
+
344
+ if (exists) {
345
+ exists.resources.push(obj);
346
+ } else {
347
+ out.push({
348
+ stateDisplay,
349
+ stateSort,
350
+ statePanel: FleetUtils.getDashboardState(obj),
351
+ resources: [obj]
352
+ });
353
+ }
354
+ });
355
+
356
+ return out.sort((a, b) => a.stateSort.localeCompare(b.stateSort));
357
+ },
358
+
359
+ _filterResources(state) {
360
+ return state.resources.filter((item) => this._decodeTypeFilter(item.namespace, item.type) &&
361
+ this._decodeStateFilter(item.namespace, state)
362
+ );
363
+ },
364
+
365
+ _groupByWorkspace(callback) {
366
+ return this.workspaces.reduce((acc, ws) => ({
367
+ ...acc,
368
+ [ws.id]: callback(ws)
369
+ }), {});
370
+ },
371
+
372
+ _stateExistsInWorkspace(workspace, state) {
373
+ return !!this.applicationStates[workspace].find((s) => s.statePanel.id === state);
374
+ },
252
375
 
253
- value = xOfy(bundles.states.ready || 0, bundles.total);
254
- } else if (area === 'resources') {
255
- const resources = rowCounts[row.id].resources;
376
+ _decodeStateFilter(workspace, state) {
377
+ const stateFilter = Object.keys(this.stateFilter[workspace] || {});
256
378
 
257
- value = xOfy(resources.states.ready || 0, resources.total);
379
+ if (stateFilter.length === 0) {
380
+ return true;
258
381
  }
259
382
 
260
- return value;
383
+ if (stateFilter.filter((key) => this.stateFilter[workspace][key] && this._stateExistsInWorkspace(workspace, key)).length === 0) {
384
+ return true;
385
+ }
386
+
387
+ if (this.stateFilter[workspace][state.statePanel.id]) {
388
+ return true;
389
+ }
390
+
391
+ return false;
261
392
  },
262
- toggleCollapse(val, key) {
263
- this.isCollapsed[key] = val;
393
+
394
+ _decodeTypeFilter(workspace, type) {
395
+ const emptyFilter = isEmpty(this.typeFilter) || !this.viewMode;
396
+
397
+ return emptyFilter || this.typeFilter[workspace]?.[type];
264
398
  },
265
- toggleAll(action) {
266
- const val = action !== 'expand';
267
399
 
268
- Object.keys(this.isCollapsed).forEach((key) => {
269
- this.isCollapsed[key] = val;
400
+ _cleanStateFilter(workspace) {
401
+ const all = [...Object.keys(this.stateFilter[workspace] || {})];
402
+
403
+ all.forEach((state) => {
404
+ const exists = this._stateExistsInWorkspace(workspace, state);
405
+
406
+ if (!exists) {
407
+ delete this.stateFilter[workspace][state];
408
+ }
270
409
  });
271
- }
410
+ },
411
+
412
+ _checkInit(workspace, name) {
413
+ if (!this[name][workspace]) {
414
+ this[name][workspace] = {};
415
+ }
416
+ },
272
417
  },
273
418
 
274
419
  watch: {
275
- fleetWorkspaces(value) {
276
- value?.filter((ws) => ws.repos?.length).forEach((ws) => {
277
- this.isCollapsed[ws.id] = false;
278
- });
420
+ workspaces(neu) {
421
+ if (neu) {
422
+ neu?.forEach((ws) => {
423
+ this.isWorkspaceCollapsed[ws.id] = neu.length > 1;
424
+
425
+ this.isStateCollapsed[ws.id] = { Active: true };
426
+
427
+ this.typeFilter[ws.id] = {
428
+ [FLEET.GIT_REPO]: true,
429
+ [FLEET.HELM_OP]: true,
430
+ };
431
+
432
+ this.stateFilter[ws.id] = {};
433
+ });
434
+
435
+ this.preset('isWorkspaceCollapsed', 'object');
436
+ this.preset('isStateCollapsed', 'object');
437
+ this.preset('typeFilter', 'object');
438
+ this.preset('stateFilter', 'object');
439
+ }
279
440
  }
280
441
  }
281
442
  };
@@ -284,223 +445,542 @@ export default {
284
445
  <template>
285
446
  <div>
286
447
  <Loading v-if="$fetchState.pending" />
287
- <!-- no git repos -->
288
- <FleetNoWorkspaces
289
- v-else-if="!fleetWorkspacesData.length"
448
+ <NoWorkspaces
449
+ v-else-if="!workspaces?.length"
290
450
  :can-view="permissions.workspaces"
291
451
  />
292
- <div
293
- v-else-if="!gitRepos.length"
294
- class="fleet-empty-dashboard"
295
- >
296
- <i class="icon-fleet mb-30" />
297
- <h1>{{ t('fleet.dashboard.welcome') }}</h1>
298
- <p class="mb-30">
299
- <span>{{ t('fleet.dashboard.gitOpsScale') }}</span>
300
- <a
301
- :href="t('fleet.dashboard.learnMoreLink')"
302
- target="_blank"
303
- rel="noopener noreferrer nofollow"
304
- >
305
- {{ t('fleet.dashboard.learnMore') }} <i class="icon icon-external-link" />
306
- </a>
307
- </p>
308
- <template v-if="permissions.gitRepos">
309
- <h3 class="mb-30">
310
- {{ t('fleet.dashboard.noRepo', null, true) }}
311
- </h3>
312
- <router-link
313
- :to="getStartedLink"
314
- class="btn role-secondary"
315
- >
316
- {{ t('fleet.dashboard.getStarted') }}
317
- </router-link>
318
- </template>
319
- </div>
320
- <!-- fleet dashboard with repos -->
452
+ <EmptyDashboard
453
+ v-else-if="isEmptyDashboard"
454
+ :permissions="permissions"
455
+ />
321
456
  <div
322
457
  v-else
323
- class="fleet-dashboard-data"
458
+ class="dashboard"
459
+ :data-testid="'fleet-dashboard-workspace-cards'"
324
460
  >
325
- <div class="title">
461
+ <div class="dashboard-header">
326
462
  <h1>
327
463
  <t k="fleet.dashboard.pageTitle" />
328
464
  </h1>
329
- <div>
330
- <p
331
- v-if="areAllCardsExpanded"
332
- @click="toggleAll('collapse')"
333
- >
334
- {{ t('fleet.dashboard.collapseAll') }}
335
- </p>
336
- <p
337
- v-else
338
- @click="toggleAll('expand')"
465
+
466
+ <div class="dashboard-main-actions">
467
+ <ButtonGroup
468
+ :data-testid="'view-button'"
469
+ :value="viewMode"
470
+ :options="viewModeOptions"
471
+ @update:value="viewMode = $event"
472
+ />
473
+ <RcButton
474
+ small
475
+ ghost
476
+ data-testid="fleet-dashboard-expand-all"
477
+ class="collapse-all-btn"
478
+ @click="toggleCardAll(allCardsExpanded ? 'collapse' : 'expand')"
339
479
  >
340
- {{ t('fleet.dashboard.expandAll') }}
341
- </p>
480
+ <p class="ml-10">
481
+ {{ allCardsExpanded ? t('fleet.dashboard.collapseAll') : t('fleet.dashboard.expandAll') }}
482
+ </p>
483
+ <template #after>
484
+ <i
485
+ :class="{
486
+ ['icon icon-chevron-down']: !allCardsExpanded,
487
+ ['icon icon-chevron-up']: allCardsExpanded,
488
+ }"
489
+ aria-hidden="true"
490
+ />
491
+ </template>
492
+ </RcButton>
342
493
  </div>
343
494
  </div>
344
495
  <div
345
- v-if="emptyWorkspaces.length"
346
- class="title-footnote"
347
- >
348
- <p>{{ t('fleet.dashboard.thereIsMore', { count: emptyWorkspaces.length }) }}:&nbsp;</p>
349
- <p
350
- v-for="(ews, i) in emptyWorkspaces"
351
- :key="i"
352
- >
353
- {{ ews.nameDisplay }}<span v-if="i != (emptyWorkspaces.length - 1)">,&nbsp;</span>
354
- </p>
355
- </div>
356
- <CollapsibleCard
357
- v-for="(ws, i) in workspacesData"
496
+ v-for="(workspace, i) in workspaces"
358
497
  :key="i"
359
- class="mt-20 mb-40"
360
- :title="`${t('resourceDetail.masthead.workspace')}: ${ws.nameDisplay}`"
361
- :is-collapsed="isCollapsed[ws.id]"
362
- :is-title-clickable="true"
363
- :data-testid="`collapsible-card-${ ws.id }`"
364
- @toggleCollapse="toggleCollapse($event, ws.id)"
365
- @titleClick="setWorkspaceFilterAndLinkToGitRepo(ws.id)"
498
+ class="workspace-card-container m-0 mt-20"
499
+ :data-testid="`fleet-dashboard-workspace-card-${ workspace.id }`"
500
+ :show-actions="false"
501
+ :show-separator="false"
502
+ :show-highlight-border="false"
366
503
  >
367
- <template v-slot:header-right>
368
- <div class="header-icons">
369
- <p>
370
- <i class="icon icon-repository" />
371
- <span>{{ t('tableHeaders.repositories') }}: <span>{{ ws.counts.gitRepos }}</span></span>
372
- </p>
373
- <p>
374
- <i class="icon icon-storage" />
375
- <span>{{ t('tableHeaders.clusters') }}: <span>{{ ws.counts.clusters }}</span></span>
376
- </p>
377
- <p>
378
- <i class="icon icon-folder" />
379
- <span>{{ t('tableHeaders.clusterGroups') }}: <span>{{ ws.counts.clusterGroups }}</span></span>
380
- </p>
381
- </div>
382
- </template>
383
- <template v-slot:content>
384
- <ResourceTable
385
- :schema="schema"
386
- :headers="headers"
387
- :rows="ws.repos"
388
- key-field="_key"
389
- :search="false"
390
- :table-actions="false"
504
+ <div class="card-panel-main">
505
+ <div
506
+ class="card-panel-main-details"
507
+ :class="{ expand: !isWorkspaceCollapsed[workspace.id] }"
391
508
  >
392
- <template #cell:clustersReady="{row}">
393
- <span v-if="ws.type === 'namespace'"> - </span>
394
- <CompoundStatusBadge
395
- v-else
396
- data-testid="clusters-ready"
397
- :tooltip-text="getTooltipInfo('clusters', row, gitReposCounts)"
398
- :badge-class="getStatusInfo('clusters', row, gitReposCounts).badgeClass"
399
- :icon="getStatusInfo('clusters', row, gitReposCounts).icon"
400
- :value="getBadgeValue('clusters', row, gitReposCounts)"
509
+ <h2 class="workspace-title">
510
+ <span class="workspace-label label-secondary">
511
+ <i class="icon icon-folder" />
512
+ <span>{{ t('fleet.dashboard.workspace') }} : &nbsp;</span>
513
+ </span>
514
+ <router-link
515
+ class="name"
516
+ role="link"
517
+ tabindex="0"
518
+ :aria-label="workspace.nameDisplay"
519
+ :to="workspace.detailLocation || {}"
520
+ >
521
+ {{ workspace.nameDisplay }}
522
+ </router-link>
523
+ </h2>
524
+ <div class="body">
525
+ <ResourcePanel
526
+ v-if="workspace.repos?.length || workspace.helmOps?.length"
527
+ :data-testid="'resource-panel-applications'"
528
+ :states="applicationStates[workspace.id]"
529
+ :workspace="workspace.id"
530
+ :type="FLEET.APPLICATION"
531
+ :selected-states="stateFilter[workspace.id] || {}"
532
+ @click:state="selectStates(workspace.id, $event)"
401
533
  />
402
- </template>
403
- <template #cell:bundlesReady="{row}">
404
- <span v-if="ws.type === 'namespace'"> - </span>
405
- <CompoundStatusBadge
406
- v-else
407
- data-testid="bundles-ready"
408
- :tooltip-text="getTooltipInfo('bundles', row, gitReposCounts)"
409
- :badge-class="getStatusInfo('bundles', row, gitReposCounts).badgeClass"
410
- :icon="getStatusInfo('bundles', row, gitReposCounts).icon"
411
- :value="getBadgeValue('bundles', row, gitReposCounts)"
534
+ <ResourcePanel
535
+ v-if="workspace.clusters?.length"
536
+ :data-testid="'resource-panel-clusters'"
537
+ :states="clusterStates[workspace.id]"
538
+ :workspace="workspace.id"
539
+ :type="FLEET.CLUSTER"
540
+ :selectable="false"
412
541
  />
413
- </template>
414
- <template #cell:resourcesReady="{row}">
415
- <CompoundStatusBadge
416
- data-testid="resources-ready"
417
- :tooltip-text="getTooltipInfo('resources', row, gitReposCounts)"
418
- :badge-class="getStatusInfo('resources', row, gitReposCounts).badgeClass"
419
- :icon="getStatusInfo('resources', row, gitReposCounts).icon"
420
- :value="getBadgeValue('resources', row, gitReposCounts)"
542
+ <ResourcePanel
543
+ v-if="workspace.clusterGroups?.length"
544
+ :data-testid="'resource-panel-cluster-groups'"
545
+ :states="clusterGroupsStates[workspace.id]"
546
+ :workspace="workspace.id"
547
+ :type="FLEET.CLUSTER_GROUP"
548
+ :show-chart="false"
549
+ :selectable="false"
421
550
  />
422
- </template>
423
-
424
- <template #cell:target="{row}">
425
- {{ row.targetInfo.modeDisplay }}
426
- </template>
427
- </ResourceTable>
428
- </template>
429
- </CollapsibleCard>
551
+ </div>
552
+ </div>
553
+ <div class="card-panel-main-actions">
554
+ <div
555
+ v-if="workspace.repos?.length || workspace.helmOps?.length"
556
+ class="expand-button"
557
+ :data-testid="'expand-button'"
558
+ >
559
+ <RcButton
560
+ small
561
+ ghost
562
+ :aria-label="`workspace-expand-btn-${ workspace.id }`"
563
+ @click="toggleCard(workspace.id)"
564
+ >
565
+ <i
566
+ :class="{
567
+ ['icon icon-lg icon-chevron-down']: isWorkspaceCollapsed[workspace.id],
568
+ ['icon icon-lg icon-chevron-up']: !isWorkspaceCollapsed[workspace.id],
569
+ }"
570
+ aria-hidden="true"
571
+ />
572
+ </RcButton>
573
+ </div>
574
+ </div>
575
+ </div>
576
+ <div
577
+ v-if="!isWorkspaceCollapsed[workspace.id] && (workspace.repos?.length || workspace.helmOps?.length)"
578
+ class="panel-expand mt-10"
579
+ :data-testid="`fleet-dashboard-expanded-panel-${ workspace.id }`"
580
+ >
581
+ <div class="actions">
582
+ <div class="type-filters">
583
+ <Checkbox
584
+ :data-testid="'fleet-dashboard-filter-git-repos'"
585
+ :value="typeFilter[workspace.id]?.[FLEET.GIT_REPO]"
586
+ @update:value="selectType(workspace.id, FLEET.GIT_REPO, $event)"
587
+ >
588
+ <template #label>
589
+ <i class="icon icon-lg icon-git mr-5" />
590
+ <span class="label">{{ t('fleet.dashboard.cards.filters.gitRepos') }}</span>
591
+ </template>
592
+ </Checkbox>
593
+ <Checkbox
594
+ :data-testid="'fleet-dashboard-filter-helm-ops'"
595
+ :value="typeFilter[workspace.id]?.[FLEET.HELM_OP]"
596
+ @update:value="selectType(workspace.id, FLEET.HELM_OP, $event)"
597
+ >
598
+ <template #label>
599
+ <i class="icon icon-lg icon-helm mr-5" />
600
+ <span class="label">{{ t('fleet.dashboard.cards.filters.helmOps') }}</span>
601
+ </template>
602
+ </Checkbox>
603
+ </div>
604
+ <div
605
+ v-if="permissions.gitRepos || permissions.helmOps"
606
+ class="create-button"
607
+ >
608
+ <RcButton
609
+ small
610
+ @click="createResource(workspace.id)"
611
+ >
612
+ {{ t('fleet.application.intro.add') }}
613
+ </RcButton>
614
+ </div>
615
+ </div>
616
+ <div
617
+ v-if="viewMode === 'cards'"
618
+ class="cards-panel"
619
+ >
620
+ <div
621
+ v-for="(state, j) in applicationStates[workspace.id]"
622
+ :key="j"
623
+ :data-testid="`state-panel-${ state.stateDisplay }`"
624
+ >
625
+ <div
626
+ v-if="cardResources[workspace.id][state.stateDisplay]?.length"
627
+ class="card-panel"
628
+ >
629
+ <div
630
+ role="button"
631
+ tabindex="0"
632
+ class="title"
633
+ :aria-label="`state-expand-btn-${ state.stateDisplay }`"
634
+ @click="toggleState(workspace.id, state.stateDisplay)"
635
+ @keydown.space.enter.stop.prevent="toggleState(workspace.id, state.stateDisplay)"
636
+ >
637
+ <i
638
+ :class="{
639
+ ['icon icon-chevron-right']: isStateCollapsed[workspace.id]?.[state.stateDisplay],
640
+ ['icon icon-chevron-down']: !isStateCollapsed[workspace.id]?.[state.stateDisplay],
641
+ }"
642
+ />
643
+ <i
644
+ v-if="state.statePanel.id !== 'success'"
645
+ class="state-icon"
646
+ :class="state.statePanel.icon"
647
+ :style="{ color: state.statePanel.color }"
648
+ />
649
+ <h3 class="state-title">
650
+ <span class="state-label">
651
+ {{ state.stateDisplay }}
652
+ </span>
653
+ <span class="state-amount">
654
+ {{ cardResources[workspace.id]?.[state.stateDisplay]?.length }}
655
+ </span>
656
+ <span class="total label-secondary">/{{ [ ...workspace.repos, ...workspace.helmOps ].length }}</span>
657
+ </h3>
658
+ </div>
659
+ <div
660
+ v-if="!isStateCollapsed[workspace.id]?.[state.stateDisplay]"
661
+ class="card-panel-body"
662
+ >
663
+ <div class="resource-cards-container">
664
+ <div
665
+ v-for="(item, y) in cardResources[workspace.id][state.stateDisplay]"
666
+ :key="y"
667
+ class="resource-card"
668
+ :class="{
669
+ ['selected']: selectedCard === `${ item.id }-${ y }` && isOpenSlideInPanel
670
+ }"
671
+ :data-testid="`card-${ item.id }`"
672
+ >
673
+ <ResourceCard
674
+ v-if="y < (cardsCount[workspace.id]?.[state.stateDisplay] || CARDS_MIN)"
675
+ role="button"
676
+ tabindex="0"
677
+ :aria-label="`resource-card-${ item.id }`"
678
+ :data-testid="`resource-card-${ item.id }`"
679
+ :value="item"
680
+ :state-panel="state.statePanel"
681
+ @click="showResourceDetails(item, state.statePanel, workspace, `${ item.id }-${ y }`)"
682
+ />
683
+ </div>
684
+ </div>
685
+ <div class="resource-cards-action">
686
+ <p
687
+ v-if="(cardsCount[workspace.id]?.[state.stateDisplay] || 0) > CARDS_MIN"
688
+ @click="loadLess(workspace.id, state.stateDisplay)"
689
+ >
690
+ {{ t('generic.showLess') }}
691
+ </p>
692
+ <div />
693
+ <p
694
+ v-if="cardResources[workspace.id][state.stateDisplay]?.length > (cardsCount[workspace.id]?.[state.stateDisplay] || CARDS_MIN)"
695
+ @click="loadMore(workspace.id, state.stateDisplay)"
696
+ >
697
+ {{ t('generic.showMore') }}
698
+ </p>
699
+ </div>
700
+ </div>
701
+ </div>
702
+ </div>
703
+ </div>
704
+ <div
705
+ v-if="viewMode === VIEW_MODE.TABLE"
706
+ class="table-panel"
707
+ >
708
+ <FleetApplications
709
+ :workspace="workspace.id"
710
+ :rows="tableResources[workspace.id]"
711
+ :schema="{
712
+ id: FLEET.APPLICATION,
713
+ type: 'schema'
714
+ }"
715
+ :loading="$fetchState.pending"
716
+ :use-query-params-for-simple-filtering="true"
717
+ :show-intro="false"
718
+ />
719
+ </div>
720
+ </div>
721
+ </div>
430
722
  </div>
431
723
  </div>
432
724
  </template>
433
725
 
434
726
  <style lang="scss" scoped>
435
- .fleet-empty-dashboard {
436
- flex: 1;
727
+
728
+ .dashboard-main-actions {
437
729
  display: flex;
438
730
  align-items: center;
439
- justify-content: center;
440
- flex-direction: column;
441
- min-height: 100%;
731
+ justify-content: end;
732
+ gap: 16px;
442
733
 
443
- .icon-fleet {
444
- font-size: 100px;
445
- color: var(--disabled-text);
734
+ .collapse-all-btn {
735
+ width: 105px;
446
736
  }
737
+ }
738
+
739
+ .dashboard-header {
740
+ display: flex;
741
+ align-items: center;
742
+ justify-content: space-between;
447
743
 
448
- > p > span {
449
- color: var(--disabled-text);
744
+ h1 {
745
+ margin: 0;
746
+ }
747
+
748
+ > div {
749
+ display: flex;
750
+ align-items: center;
751
+
752
+ i {
753
+ color: var(--primary);
754
+ }
450
755
  }
451
756
  }
452
757
 
453
- .fleet-dashboard-data {
454
- .title {
758
+ .workspace-card-container {
759
+ display: flex;
760
+ flex-direction: column;
761
+ border: 1px solid var(--border);
762
+ border-radius: 16px;
763
+ background-color: var(--body-bg);
764
+ box-shadow: none;
765
+ min-width: 500px;
766
+ padding: 16px;
767
+
768
+ :focus-visible {
769
+ @include focus-outline;
770
+ }
771
+
772
+ .card-panel-main {
455
773
  display: flex;
456
774
  align-items: center;
457
775
  justify-content: space-between;
458
- min-height: 48px;
776
+ margin-top: auto;
777
+ margin-bottom: auto;
459
778
 
460
- > div {
779
+ .card-panel-main-details {
461
780
  display: flex;
462
781
  align-items: center;
463
782
 
464
- p{
465
- color: var(--primary);
783
+ .workspace-title {
784
+ min-width: 150px;
785
+ margin: 0 32px 0 0;
786
+ display: flex;
787
+ flex-direction: column;
788
+
789
+ .workspace-label {
790
+ font-size: 16px;
791
+ font-weight: normal;
792
+ display: flex;
793
+ align-items: center;
794
+ margin: 0 0 2px 0;
795
+
796
+ .icon {
797
+ margin-right: 5px;
798
+ }
799
+ }
800
+
801
+ .name {
802
+ font-size: 21px;
803
+ }
804
+ }
805
+
806
+ .body {
807
+ display: flex;
808
+ justify-content: flex-start;
809
+ flex-wrap: wrap;
810
+ gap: 24px;
811
+
812
+ .spacer {
813
+ border-left: 1px solid var(--border);
814
+ }
815
+ }
816
+ }
817
+
818
+ .card-panel-main-actions {
819
+ display: flex;
820
+ flex-direction: column;
821
+ align-items: end;
822
+
823
+ .expand-button {
824
+ display: flex;
825
+ align-items: center;
466
826
 
467
827
  &:hover {
468
- text-decoration: underline;
469
828
  cursor: pointer;
470
829
  }
471
830
  }
472
831
  }
473
832
  }
474
833
 
475
- .title-footnote {
476
- display: flex;
477
- align-items: center;
478
- color: var(--darker);
479
- }
834
+ .panel-expand {
835
+ animation: slideInOut 0.5s ease-in-out;
480
836
 
481
- .header-icons {
482
- display: flex;
483
- align-items: center;
837
+ :focus-visible {
838
+ @include focus-outline;
839
+ }
484
840
 
485
- p {
486
- margin-right: 30px;
841
+ .actions {
487
842
  display: flex;
488
843
  align-items: center;
844
+ justify-content: space-between;
845
+
846
+ .type-filters {
847
+ display: flex;
848
+ flex-direction: column;
849
+ margin-top: 5px;
489
850
 
490
- > span {
491
- color: var(--disabled-text);
851
+ .checkbox-outer-container {
852
+ width: fit-content;
853
+ }
492
854
 
493
- > span {
494
- color: var(--body-text);
855
+ .label {
856
+ margin-top: 2px;
857
+ line-height: 20px;
858
+ }
859
+
860
+ .icon {
861
+ padding: 2px;
862
+ font-size: 25px;
495
863
  }
496
864
  }
865
+ }
866
+
867
+ .cards-panel {
868
+ .card-panel {
869
+ margin-top: 24px;
497
870
 
498
- i {
499
- color: var(--disabled-text);
500
- font-size: 20px;
501
- margin-right: 10px;
871
+ .title {
872
+ display: flex;
873
+ align-items: center;
874
+ cursor: pointer;
875
+ width: fit-content;
876
+ margin-bottom: 12px;
877
+
878
+ .icon {
879
+ margin-right: 8px;
880
+ }
881
+
882
+ .state-icon,
883
+ .state-title {
884
+ font-size: 21px;
885
+ }
886
+
887
+ .state-icon {
888
+ margin-top: 1px;
889
+ }
890
+
891
+ .state-title {
892
+ display: flex;
893
+ align-items: baseline;
894
+ margin: 0;
895
+
896
+ .state-amount {
897
+ margin-left: 4px
898
+ }
899
+
900
+ .total {
901
+ margin-left: 4px;
902
+ font-size: 16px;
903
+ }
904
+
905
+ p {
906
+ font-size: small;
907
+
908
+ .icon {
909
+ line-height: -1px;
910
+ }
911
+ }
912
+ }
913
+ }
914
+
915
+ .card-panel-body {
916
+ .resource-cards-container {
917
+ display: grid;
918
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
919
+ gap: 16px;
920
+ min-height: 100%;
921
+
922
+ .resource-card {
923
+ cursor: pointer;
924
+
925
+ &.selected {
926
+ .dashboard-resource-card {
927
+ border: 2px solid var(--primary);
928
+ margin: 0;
929
+ }
930
+ }
931
+ }
932
+ }
933
+
934
+ .resource-cards-action {
935
+ display: flex;
936
+ justify-content: space-between;
937
+
938
+ p {
939
+ width: fit-content;
940
+ margin-left: 15px;
941
+ }
942
+ }
943
+ }
502
944
  }
503
945
  }
946
+
947
+ .table-panel {
948
+ margin-top: 20px;
949
+ }
950
+ }
951
+ }
952
+
953
+ p {
954
+ color: var(--primary);
955
+ margin-right: 2px;
956
+
957
+ &:hover {
958
+ text-decoration: underline;
959
+ cursor: pointer;
960
+ }
961
+ }
962
+
963
+ .label-secondary{
964
+ color: var(--label-secondary);
965
+ }
966
+
967
+ @keyframes slideInOut {
968
+ 0% {
969
+ opacity: 0;
970
+ visibility: hidden;
971
+ transform: translateY(-10px);
972
+ }
973
+
974
+ 50% {
975
+ opacity: 0.5;
976
+ visibility: visible;
977
+ transform: translateY(0);
978
+ }
979
+
980
+ 100% {
981
+ opacity: 1;
982
+ visibility: visible;
983
+ transform: translateY(0);
504
984
  }
505
985
  }
506
986
  </style>