@rancher/shell 3.0.7 → 3.0.8-rc.10

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 (375) hide show
  1. package/assets/brand/suse/banner.svg +1 -0
  2. package/assets/brand/suse/dark/banner.svg +1 -0
  3. package/assets/brand/suse/dark/login-landscape.svg +1 -0
  4. package/assets/brand/suse/dark/rancher-logo.svg +1 -1
  5. package/assets/brand/suse/favicon.png +0 -0
  6. package/assets/brand/suse/login-landscape.svg +1 -0
  7. package/assets/brand/suse/metadata.json +11 -1
  8. package/assets/brand/suse/rancher-logo.svg +1 -1
  9. package/assets/fonts/suse/suse-v2-latin-300.woff +0 -0
  10. package/assets/fonts/suse/suse-v2-latin-300.woff2 +0 -0
  11. package/assets/fonts/suse/suse-v2-latin-600.woff +0 -0
  12. package/assets/fonts/suse/suse-v2-latin-600.woff2 +0 -0
  13. package/assets/fonts/suse/suse-v2-latin-700.woff +0 -0
  14. package/assets/fonts/suse/suse-v2-latin-700.woff2 +0 -0
  15. package/assets/fonts/suse/suse-v2-latin-800.woff +0 -0
  16. package/assets/fonts/suse/suse-v2-latin-800.woff2 +0 -0
  17. package/assets/fonts/suse/suse-v2-latin-regular.woff +0 -0
  18. package/assets/fonts/suse/suse-v2-latin-regular.woff2 +0 -0
  19. package/assets/images/content/README.md +5 -0
  20. package/assets/images/content/cloud-native.svg +84 -0
  21. package/assets/images/content/dark/cloud-native.svg +21 -0
  22. package/assets/images/content/dark/shield.svg +59 -0
  23. package/assets/images/content/dark/suse.svg +10 -0
  24. package/assets/images/content/shield.svg +59 -0
  25. package/assets/images/content/suse.svg +10 -0
  26. package/assets/images/vendor/githubapp.svg +13 -0
  27. package/assets/styles/base/_typography.scss +2 -1
  28. package/assets/styles/fonts/_fontstack.scss +53 -1
  29. package/assets/styles/global/_cards.scss +0 -3
  30. package/assets/styles/global/_layout.scss +21 -35
  31. package/assets/styles/themes/_dark.scss +1 -1
  32. package/assets/styles/themes/_light.scss +1 -1
  33. package/assets/styles/themes/_modern.scss +16 -8
  34. package/assets/styles/themes/_suse.scss +116 -24
  35. package/assets/translations/en-us.yaml +185 -21
  36. package/assets/translations/zh-hans.yaml +0 -4
  37. package/components/AutoscalerCard.vue +113 -0
  38. package/components/AutoscalerTab.vue +94 -0
  39. package/components/BackLink.vue +8 -0
  40. package/components/BannerGraphic.vue +36 -21
  41. package/components/BrandImage.vue +17 -6
  42. package/components/ClusterIconMenu.vue +1 -1
  43. package/components/ClusterProviderIcon.vue +1 -1
  44. package/components/Cron/CronExpressionEditor.vue +1 -1
  45. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  46. package/components/Drawer/Chrome.vue +2 -6
  47. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
  48. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
  49. package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
  50. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
  51. package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
  52. package/components/Drawer/types.ts +3 -0
  53. package/components/DynamicContent/DynamicContentBanner.vue +102 -0
  54. package/components/DynamicContent/DynamicContentCloseButton.vue +42 -0
  55. package/components/DynamicContent/DynamicContentIcon.vue +132 -0
  56. package/components/DynamicContent/DynamicContentPanel.vue +112 -0
  57. package/components/DynamicContent/content.ts +78 -0
  58. package/components/EmberPage.vue +1 -1
  59. package/components/IconOrSvg.vue +2 -2
  60. package/components/Inactivity.vue +222 -106
  61. package/components/InstallHelmCharts.vue +2 -2
  62. package/components/PaginatedResourceTable.vue +2 -6
  63. package/components/PopoverCard.vue +192 -0
  64. package/components/Questions/__tests__/index.test.ts +159 -0
  65. package/components/Resource/Detail/CopyToClipboard.vue +4 -1
  66. package/components/Resource/Detail/FetchLoader/composables.ts +18 -4
  67. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  68. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +1 -1
  69. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +4 -0
  70. package/components/Resource/Detail/Metadata/KeyValueRow.vue +1 -1
  71. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  72. package/components/Resource/Detail/Metadata/composables.ts +9 -9
  73. package/components/Resource/Detail/Metadata/index.vue +3 -3
  74. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -19
  75. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +0 -29
  76. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +132 -150
  77. package/components/Resource/Detail/ResourcePopover/index.vue +54 -159
  78. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +0 -2
  79. package/components/Resource/Detail/TitleBar/composables.ts +2 -1
  80. package/components/Resource/Detail/TitleBar/index.vue +10 -6
  81. package/components/Resource/Detail/composables.ts +12 -0
  82. package/components/ResourceDetail/Masthead/latest.vue +29 -0
  83. package/components/ResourceDetail/index.vue +5 -2
  84. package/components/ResourceList/Masthead.vue +1 -1
  85. package/components/SortableTable/index.vue +18 -2
  86. package/components/Tabbed/__tests__/index.test.ts +86 -0
  87. package/components/{nav/WindowManager → Window}/ContainerLogs.vue +1 -1
  88. package/components/{nav/WindowManager → Window}/ContainerLogsActions.vue +1 -0
  89. package/components/{nav/WindowManager → Window}/__tests__/ContainerLogs.test.ts +1 -1
  90. package/components/{nav/WindowManager → Window}/__tests__/ContainerShell.test.ts +2 -2
  91. package/components/__tests__/AutoscalerCard.test.ts +154 -0
  92. package/components/__tests__/AutoscalerTab.test.ts +125 -0
  93. package/components/__tests__/PopoverCard.test.ts +204 -0
  94. package/components/auth/SelectPrincipal.vue +24 -6
  95. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  96. package/components/fleet/FleetConfigMapSelector.vue +117 -0
  97. package/components/fleet/FleetSecretSelector.vue +127 -0
  98. package/components/fleet/__tests__/FleetConfigMapSelector.test.ts +125 -0
  99. package/components/fleet/__tests__/FleetSecretSelector.test.ts +82 -0
  100. package/components/form/FileImageSelector.vue +13 -4
  101. package/components/form/FileSelector.vue +11 -2
  102. package/components/form/ResourceLabeledSelect.vue +1 -0
  103. package/components/form/__tests__/ResourceLabeledSelect.test.ts +90 -0
  104. package/components/formatter/Autoscaler.vue +97 -0
  105. package/components/formatter/InternalExternalIP.vue +198 -24
  106. package/components/formatter/__tests__/Autoscaler.test.ts +156 -0
  107. package/components/formatter/__tests__/InternalExternalIP.test.ts +133 -0
  108. package/components/google/util/__tests__/formatter.test.ts +47 -0
  109. package/components/google/util/formatter.ts +5 -2
  110. package/components/nav/Group.vue +12 -3
  111. package/components/nav/Header.vue +37 -16
  112. package/components/nav/NamespaceFilter.vue +13 -1
  113. package/components/nav/NotificationCenter/index.vue +2 -1
  114. package/components/nav/TopLevelMenu.helper.ts +16 -6
  115. package/components/nav/TopLevelMenu.vue +4 -2
  116. package/components/{DraggableZone.vue → nav/WindowManager/PinArea.vue} +47 -80
  117. package/components/nav/WindowManager/composables/useComponentsMount.ts +70 -0
  118. package/components/nav/WindowManager/composables/useDimensionsHandler.ts +105 -0
  119. package/components/nav/WindowManager/composables/useDragHandler.ts +99 -0
  120. package/components/nav/WindowManager/composables/usePanelHandler.ts +72 -0
  121. package/components/nav/WindowManager/composables/usePanelsHandler.ts +14 -0
  122. package/components/nav/WindowManager/composables/useResizeHandler.ts +167 -0
  123. package/components/nav/WindowManager/composables/useTabsHandler.ts +51 -0
  124. package/components/nav/WindowManager/constants.ts +23 -0
  125. package/components/nav/WindowManager/index.vue +61 -575
  126. package/components/nav/WindowManager/panels/HorizontalPanel.vue +265 -0
  127. package/components/nav/WindowManager/panels/TabBodyContainer.vue +39 -0
  128. package/components/nav/WindowManager/panels/VerticalPanel.vue +308 -0
  129. package/components/templates/default.vue +4 -40
  130. package/components/templates/home.vue +31 -5
  131. package/components/templates/plain.vue +30 -4
  132. package/components/templates/standalone.vue +1 -1
  133. package/composables/useI18n.ts +10 -1
  134. package/composables/useInterval.ts +15 -0
  135. package/config/__test__/uiplugins.test.ts +309 -0
  136. package/config/labels-annotations.js +9 -1
  137. package/config/product/auth.js +1 -0
  138. package/config/product/explorer.js +3 -1
  139. package/config/product/manager.js +20 -9
  140. package/config/query-params.js +1 -0
  141. package/config/router/routes.js +10 -2
  142. package/config/settings.ts +10 -2
  143. package/config/store.js +4 -2
  144. package/config/table-headers.js +8 -0
  145. package/config/types.js +11 -0
  146. package/config/uiplugins.js +46 -2
  147. package/config/version.js +1 -1
  148. package/core/__test__/extension-manager-impl.test.js +236 -0
  149. package/core/extension-manager-impl.js +23 -6
  150. package/core/plugin-helpers.ts +2 -0
  151. package/core/types-provisioning.ts +4 -1
  152. package/detail/pod.vue +1 -0
  153. package/detail/provisioning.cattle.io.cluster.vue +13 -1
  154. package/dialog/AddonConfigConfirmationDialog.vue +45 -1
  155. package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
  156. package/dialog/RollbackWorkloadDialog.vue +2 -5
  157. package/directives/ui-context.ts +103 -0
  158. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +52 -11
  159. package/edit/auth/AuthProviderWarningBanners.vue +14 -1
  160. package/edit/auth/__tests__/oidc.test.ts +26 -0
  161. package/edit/auth/github-app-steps.vue +97 -0
  162. package/edit/auth/github-steps.vue +75 -0
  163. package/edit/auth/github.vue +99 -65
  164. package/edit/auth/oidc.vue +5 -1
  165. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  166. package/edit/cloudcredential.vue +1 -1
  167. package/edit/configmap.vue +1 -0
  168. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  169. package/edit/fleet.cattle.io.gitrepo.vue +0 -10
  170. package/edit/fleet.cattle.io.helmop.vue +51 -2
  171. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  172. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  173. package/edit/logging-flow/index.vue +1 -0
  174. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  175. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  176. package/edit/management.cattle.io.project.vue +1 -0
  177. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  178. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  179. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  180. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  181. package/edit/monitoring.coreos.com.route.vue +1 -1
  182. package/edit/namespace.vue +1 -0
  183. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  184. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  185. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +15 -5
  186. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  187. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  188. package/edit/node.vue +1 -0
  189. package/edit/persistentvolume/index.vue +27 -22
  190. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  191. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  192. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  193. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  194. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  195. package/edit/persistentvolume/plugins/csi.vue +18 -16
  196. package/edit/persistentvolume/plugins/fc.vue +13 -14
  197. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  198. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  199. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  200. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  201. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  202. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  203. package/edit/persistentvolume/plugins/local.vue +1 -3
  204. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  205. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  206. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  207. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  208. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  209. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  210. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  211. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  212. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  213. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +32 -5
  214. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +35 -0
  215. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +155 -0
  216. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +11 -9
  217. package/edit/provisioning.cattle.io.cluster/index.vue +25 -15
  218. package/edit/provisioning.cattle.io.cluster/rke2.vue +98 -17
  219. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +28 -2
  220. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +107 -5
  221. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +92 -4
  222. package/edit/secret/index.vue +1 -1
  223. package/edit/service.vue +9 -4
  224. package/edit/serviceaccount.vue +1 -0
  225. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  226. package/edit/workload/index.vue +2 -1
  227. package/edit/workload/mixins/workload.js +1 -1
  228. package/initialize/App.vue +4 -4
  229. package/initialize/install-directives.js +2 -0
  230. package/initialize/install-plugins.js +19 -2
  231. package/list/projectsecret.vue +1 -1
  232. package/list/provisioning.cattle.io.cluster.vue +15 -2
  233. package/machine-config/amazonec2.vue +42 -135
  234. package/machine-config/azure.vue +1 -1
  235. package/machine-config/components/EC2Networking.vue +490 -0
  236. package/machine-config/components/__tests__/EC2Networking.test.ts +148 -0
  237. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +294 -0
  238. package/machine-config/digitalocean.vue +11 -0
  239. package/machine-config/google.vue +1 -1
  240. package/mixins/__tests__/brand.spec.ts +2 -2
  241. package/mixins/__tests__/chart.test.ts +21 -0
  242. package/mixins/brand.js +1 -7
  243. package/mixins/chart.js +8 -2
  244. package/mixins/create-edit-view/index.js +5 -0
  245. package/models/__tests__/chart.test.ts +49 -12
  246. package/models/__tests__/compliance.cattle.io.clusterscanprofile.spec.js +30 -0
  247. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
  248. package/models/catalog.cattle.io.app.js +1 -1
  249. package/models/chart.js +28 -14
  250. package/models/cluster/node.js +13 -6
  251. package/models/cluster.x-k8s.io.machine.js +10 -20
  252. package/models/cluster.x-k8s.io.machinedeployment.js +5 -1
  253. package/models/compliance.cattle.io.clusterscanprofile.js +1 -1
  254. package/models/management.cattle.io.authconfig.js +1 -0
  255. package/models/management.cattle.io.cluster.js +21 -3
  256. package/models/management.cattle.io.kontainerdriver.js +1 -0
  257. package/models/provisioning.cattle.io.cluster.js +249 -33
  258. package/package.json +6 -5
  259. package/pages/auth/login.vue +43 -4
  260. package/pages/auth/verify.vue +1 -1
  261. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +3 -2
  262. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  263. package/pages/c/_cluster/apps/charts/chart.vue +35 -17
  264. package/pages/c/_cluster/apps/charts/index.vue +11 -13
  265. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  266. package/pages/c/_cluster/explorer/EventsTable.vue +89 -3
  267. package/pages/c/_cluster/explorer/index.vue +8 -6
  268. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  269. package/pages/c/_cluster/manager/hostedprovider/index.vue +220 -0
  270. package/pages/c/_cluster/settings/brand.vue +1 -1
  271. package/pages/c/_cluster/settings/performance.vue +12 -25
  272. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  273. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  274. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  275. package/pages/home.vue +327 -16
  276. package/pkg/dynamic-importer.lib.js +4 -0
  277. package/plugins/axios.js +2 -1
  278. package/plugins/dashboard-client-init.js +3 -0
  279. package/plugins/dashboard-store/actions.js +1 -1
  280. package/plugins/dashboard-store/getters.js +18 -1
  281. package/plugins/dashboard-store/resource-class.js +21 -6
  282. package/plugins/dynamic-content.js +13 -0
  283. package/plugins/i18n.js +8 -0
  284. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
  285. package/plugins/steve/steve-pagination-utils.ts +41 -22
  286. package/plugins/steve/subscribe.js +17 -9
  287. package/plugins/subscribe-events.ts +4 -2
  288. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  289. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -34
  290. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  291. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  292. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  293. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  294. package/rancher-components/Pill/types.ts +0 -1
  295. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -0
  296. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +5 -1
  297. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  298. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  299. package/rancher-components/RcIcon/index.ts +1 -0
  300. package/rancher-components/RcIcon/types.ts +160 -0
  301. package/rancher-components/utils/status.test.ts +67 -0
  302. package/rancher-components/utils/status.ts +77 -0
  303. package/scripts/extension/publish +1 -1
  304. package/scripts/typegen.sh +1 -0
  305. package/store/action-menu.js +8 -0
  306. package/store/auth.js +11 -6
  307. package/store/aws.js +8 -6
  308. package/store/catalog.js +6 -0
  309. package/store/features.js +2 -0
  310. package/store/index.js +45 -20
  311. package/store/notifications.ts +51 -4
  312. package/store/plugins.js +7 -3
  313. package/store/prefs.js +12 -6
  314. package/store/type-map.js +3 -3
  315. package/store/ui-context.ts +86 -0
  316. package/store/wm.ts +244 -0
  317. package/types/kube/kube-api.ts +2 -1
  318. package/types/notifications/index.ts +27 -3
  319. package/types/rancher/index.d.ts +1 -0
  320. package/types/resources/settings.d.ts +29 -7
  321. package/types/shell/index.d.ts +138 -4
  322. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  323. package/types/store/pagination.types.ts +157 -9
  324. package/types/store/subscribe-events.types.ts +8 -1
  325. package/types/store/subscribe.types.ts +1 -0
  326. package/types/window-manager.ts +24 -0
  327. package/utils/__tests__/cluster.test.ts +379 -1
  328. package/utils/__tests__/object.test.ts +19 -0
  329. package/utils/__tests__/provider.test.ts +98 -0
  330. package/utils/__tests__/selector-typed.test.ts +263 -0
  331. package/utils/__tests__/version.test.ts +19 -1
  332. package/utils/autoscaler-utils.ts +7 -0
  333. package/utils/back-off.ts +3 -3
  334. package/utils/brand.ts +29 -0
  335. package/utils/chart.js +18 -0
  336. package/utils/cluster.js +157 -3
  337. package/utils/color.js +1 -1
  338. package/utils/dynamic-content/__tests__/announcement.test.ts +498 -0
  339. package/utils/dynamic-content/__tests__/config.test.ts +187 -0
  340. package/utils/dynamic-content/__tests__/index.test.ts +390 -0
  341. package/utils/dynamic-content/__tests__/info.test.ts +275 -0
  342. package/utils/dynamic-content/__tests__/new-release.test.ts +216 -0
  343. package/utils/dynamic-content/__tests__/support-notice.test.ts +262 -0
  344. package/utils/dynamic-content/__tests__/util.test.ts +235 -0
  345. package/utils/dynamic-content/announcement.ts +142 -0
  346. package/utils/dynamic-content/config.ts +55 -0
  347. package/utils/dynamic-content/example.json +40 -0
  348. package/utils/dynamic-content/index.ts +277 -0
  349. package/utils/dynamic-content/info.ts +261 -0
  350. package/utils/dynamic-content/new-release.ts +126 -0
  351. package/utils/dynamic-content/notification-handler.ts +48 -0
  352. package/utils/dynamic-content/support-notice.ts +169 -0
  353. package/utils/dynamic-content/types.d.ts +153 -0
  354. package/utils/dynamic-content/util.ts +122 -0
  355. package/utils/dynamic-importer.js +2 -2
  356. package/utils/favicon.js +4 -4
  357. package/utils/inactivity.ts +104 -0
  358. package/utils/object.js +20 -2
  359. package/utils/pagination-utils.ts +19 -4
  360. package/utils/pagination-wrapper.ts +12 -8
  361. package/utils/provider.ts +14 -0
  362. package/utils/release-notes.ts +1 -1
  363. package/utils/scroll.js +7 -0
  364. package/utils/selector-typed.ts +6 -2
  365. package/utils/settings.ts +15 -0
  366. package/utils/validators/machine-pool.ts +13 -3
  367. package/utils/version.js +15 -0
  368. package/assets/images/icons/document.svg +0 -3
  369. package/plugins/nuxt-client-init.js +0 -3
  370. package/store/wm.js +0 -95
  371. /package/components/{nav/WindowManager → Window}/ChartReadme.vue +0 -0
  372. /package/components/{nav/WindowManager → Window}/ContainerShell.vue +0 -0
  373. /package/components/{nav/WindowManager → Window}/KubectlShell.vue +0 -0
  374. /package/components/{nav/WindowManager → Window}/MachineSsh.vue +0 -0
  375. /package/components/{nav/WindowManager → Window}/Window.vue +0 -0
@@ -3,11 +3,14 @@ import ModalWithCard from '@shell/components/ModalWithCard';
3
3
  import { Banner } from '@components/Banner';
4
4
  import PercentageBar from '@shell/components/PercentageBar.vue';
5
5
  import throttle from 'lodash/throttle';
6
- import { MANAGEMENT } from '@shell/config/types';
7
- import { DEFAULT_PERF_SETTING, SETTING } from '@shell/config/settings';
6
+ import Inactivity from '@shell/utils/inactivity';
7
+ import { MANAGEMENT, EXT, NORMAN } from '@shell/config/types';
8
+ import { SETTING } from '@shell/config/settings';
8
9
 
9
10
  let globalId;
10
11
 
12
+ const MODAL_VISIBILITY_CHECK_DELAY_SECONDS = 10;
13
+
11
14
  export default {
12
15
  name: 'Inactivity',
13
16
  components: {
@@ -15,64 +18,151 @@ export default {
15
18
  },
16
19
  data() {
17
20
  return {
18
- enabled: null,
19
- isOpen: false,
20
- isInactive: false,
21
- showModalAfter: null,
22
- inactivityTimeoutId: null,
23
- courtesyTimer: null,
24
- courtesyTimerId: null,
25
- courtesyCountdown: null,
26
- trackInactivity: throttle(this._trackInactivity, 1000),
27
- id: null,
21
+ sessionTokenName: null,
22
+ tokens: [],
23
+ isUserActive: false,
24
+ userActivityIsoDate: '',
25
+ modalVisibilityCheckRan: false,
26
+ isOpen: false,
27
+ showModalAfter: null,
28
+ expiresAt: null,
29
+ inactivityTimeoutId: null,
30
+ courtesyTimer: null,
31
+ courtesyTimerId: null,
32
+ courtesyCountdown: null,
33
+ trackInactivity: throttle(this._trackInactivity, 1000),
34
+ id: null
28
35
  };
29
36
  },
30
- async mounted() {
31
- // Info: normally, this is done in the fetch hook but for some reasons while awaiting for things that will take a while, it won't be ready by the time mounted() is called, pending for investigation.
32
- let settings;
33
-
34
- try {
35
- const settingsString = await this.$store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.UI_PERFORMANCE });
37
+ beforeUnmount() {
38
+ this.removeEventListeners();
39
+ this.clearAllTimeouts();
40
+ },
41
+ computed: {
42
+ timerPercentageLeft() {
43
+ return Math.floor((this.courtesyCountdown / this.courtesyTimer ) * 100);
44
+ },
45
+ colorStops() {
46
+ return {
47
+ 0: '--info', 30: '--info', 70: '--info'
48
+ };
49
+ },
50
+ userSessionTtlIdleSetting() {
51
+ return this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.AUTH_USER_SESSION_IDLE_TTL_MINUTES);
52
+ },
53
+ userSessionTtlSetting() {
54
+ return this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.AUTH_USER_SESSION_TTL_MINUTES);
55
+ },
56
+ userActivityResource() {
57
+ return this.$store.getters['management/byId'](EXT.USER_ACTIVITY, this.sessionTokenName);
58
+ },
59
+ ttlIdleValue() {
60
+ return parseInt(this.userSessionTtlIdleSetting?.value || 0);
61
+ },
62
+ ttlValue() {
63
+ return parseInt(this.userSessionTtlSetting?.value || 0);
64
+ },
65
+ isFeatureEnabled() {
66
+ return this.ttlIdleValue < this.ttlValue;
67
+ },
68
+ userActivityExpiresAt() {
69
+ return this.userActivityResource?.status?.expiresAt || '';
70
+ },
71
+ watcherData() {
72
+ return {
73
+ userActivityExpiresAt: this.userActivityExpiresAt,
74
+ sessionTokenName: this.sessionTokenName,
75
+ isFeatureEnabled: this.isFeatureEnabled
76
+ };
77
+ }
78
+ },
36
79
 
37
- settings = settingsString?.value ? JSON.parse(settingsString.value) : DEFAULT_PERF_SETTING;
38
- } catch { }
80
+ watch: {
81
+ // every time the Idle setting changes, we need to fetch the updated userActivity
82
+ async ttlIdleValue() {
83
+ await Inactivity.getUserActivity(this.$store, this.sessionTokenName);
84
+ },
85
+ watcherData: {
86
+ async handler(neu, old) {
87
+ if (!old?.isFeatureEnabled && neu?.isFeatureEnabled) {
88
+ const tokenName = Inactivity.getSessionTokenName();
39
89
 
40
- if (!settings || !settings?.inactivity || !settings?.inactivity.enabled) {
41
- return;
42
- }
90
+ if (tokenName) {
91
+ this.sessionTokenName = tokenName;
92
+ }
43
93
 
44
- this.enabled = settings?.inactivity?.enabled || false;
94
+ await this.initializeInactivityData();
95
+ }
45
96
 
46
- // Total amount of time before the user's session is lost
47
- const thresholdToSeconds = settings?.inactivity?.threshold * 60;
97
+ const currDate = Date.now();
98
+ const endDate = new Date(neu.userActivityExpiresAt || '0001-01-01 00:00:00 +0000 UTC').getTime();
48
99
 
49
- // Amount of time the user sees the inactivity warning
50
- this.courtesyTimer = Math.floor(thresholdToSeconds * 0.1);
51
- this.courtesyTimer = Math.min(this.courtesyTimer, 60 * 5); // Never show the modal more than 5 minutes
52
- // Amount of time before the user sees the inactivity warning
53
- // Note - time before warning is shown + time warning is shown = settings threshold (total amount of time)
54
- this.showModalAfter = thresholdToSeconds - this.courtesyTimer;
100
+ if (endDate > currDate && neu?.sessionTokenName && neu?.isFeatureEnabled) {
101
+ // feature is considered as enabled
102
+ // make sure we always clean up first so that we don't get duplicate timers running
103
+ this.stopInactivity();
55
104
 
56
- console.debug(`Inactivity modal will show after ${ this.showModalAfter / 60 }(m) and be shown for ${ this.courtesyTimer / 60 }(m)`); // eslint-disable-line no-console
105
+ // resets inactivity data and timers, starting the inactivity again with the proper data
106
+ this.resetInactivityDataAndTimers(this.userActivityResource);
57
107
 
58
- this.courtesyCountdown = this.courtesyTimer;
108
+ // add event listeners for UI interaction
109
+ this.addIdleListeners();
110
+ }
59
111
 
60
- if (settings?.inactivity.enabled) {
61
- this.trackInactivity();
62
- this.addIdleListeners();
112
+ if (!neu?.isFeatureEnabled) {
113
+ this.stopInactivity();
114
+ }
115
+ },
116
+ immediate: true,
117
+ deep: true
63
118
  }
64
119
  },
65
- beforeUnmount() {
66
- this.removeEventListener();
67
- this.clearAllTimeouts();
68
- },
120
+
69
121
  methods: {
122
+ async initializeInactivityData() {
123
+ const canListUserAct = this.$store.getters[`management/canList`](EXT.USER_ACTIVITY);
124
+ const canListTokens = this.$store.getters[`rancher/canList`](NORMAN.TOKEN);
125
+
126
+ if (canListUserAct && canListTokens) {
127
+ const tokens = await this.$store.dispatch('rancher/findAll', { type: NORMAN.TOKEN, opt: { watch: false } });
128
+
129
+ this.tokens = tokens;
130
+
131
+ // handle the fetching/storage of session token name
132
+ if (!this.sessionTokenName) {
133
+ const sessionToken = this.tokens.find((token) => {
134
+ return token.description === 'UI session' && token.current;
135
+ });
136
+
137
+ if (sessionToken?.name) {
138
+ this.sessionTokenName = sessionToken.name;
139
+ Inactivity.setSessionTokenName(sessionToken.name);
140
+ }
141
+ }
142
+
143
+ // get the latest userActivity data so that get reactivity on all this logic
144
+ const userActivityData = await Inactivity.getUserActivity(this.$store, this.sessionTokenName, false);
145
+
146
+ const expiresAt = userActivityData?.status?.expiresAt;
147
+ const currDate = Date.now();
148
+ const endDate = new Date(expiresAt).getTime();
149
+
150
+ // If expiresAt isn't initialised yet '0001-01-01 00:00:00 +0000 UTC' || '', or just passed the 'now' date
151
+ // We need to update/initialise the UserActivity resource
152
+ if ((currDate > endDate) || !expiresAt) {
153
+ const updatedData = await Inactivity.updateUserActivity(this.userActivityResource, this.sessionTokenName, new Date().toISOString());
154
+
155
+ this.expiresAt = updatedData?.status?.expiresAt;
156
+ } else if (expiresAt) {
157
+ this.expiresAt = expiresAt;
158
+ }
159
+ }
160
+ },
70
161
  _trackInactivity() {
71
- if (this.isInactive || this.isOpen || !this.showModalAfter) {
162
+ if (this.isOpen || !this.showModalAfter) {
72
163
  return;
73
164
  }
74
165
 
75
- this.clearAllTimeouts();
76
166
  const endTime = Date.now() + this.showModalAfter * 1000;
77
167
 
78
168
  this.id = endTime;
@@ -89,6 +179,18 @@ export default {
89
179
  this.isOpen = true;
90
180
  this.startCountdown();
91
181
  } else {
182
+ // When we have X seconds to go until we display the modal, check for activity on the backend flag
183
+ // it may have come from another tab in the same browser
184
+ if (now >= endTime - (MODAL_VISIBILITY_CHECK_DELAY_SECONDS * 1000) && !this.modalVisibilityCheckRan) {
185
+ this.modalVisibilityCheckRan = true;
186
+
187
+ if (this.isUserActive) {
188
+ this.resetUserActivity();
189
+ } else {
190
+ this.checkBackendInactivity(this.expiresAt);
191
+ }
192
+ }
193
+
92
194
  this.inactivityTimeoutId = setTimeout(checkInactivityTimer, 1000);
93
195
  }
94
196
  };
@@ -98,13 +200,16 @@ export default {
98
200
  startCountdown() {
99
201
  const endTime = Date.now() + (this.courtesyCountdown * 1000);
100
202
 
101
- const checkCountdown = () => {
203
+ const checkCountdown = async() => {
102
204
  const now = Date.now();
103
205
 
104
206
  if (now >= endTime) {
105
- this.isInactive = true;
106
- this.unsubscribe();
107
207
  this.clearAllTimeouts();
208
+ const isUserActive = await this.checkBackendInactivity(this.expiresAt);
209
+
210
+ if (!isUserActive) {
211
+ return this.$store.dispatch('auth/logout', { sessionIdle: true });
212
+ }
108
213
  } else {
109
214
  this.courtesyCountdown = Math.floor((endTime - now) / 1000);
110
215
  this.courtesyTimerId = setTimeout(checkCountdown, 1000);
@@ -113,63 +218,85 @@ export default {
113
218
 
114
219
  checkCountdown();
115
220
  },
221
+ async checkBackendInactivity(currExpiresAt) {
222
+ let isUserActive = false;
223
+ const userActivityData = await Inactivity.getUserActivity(this.$store, this.sessionTokenName);
224
+
225
+ // this means that something updated the backend expiresAt, which means we must now reset the timers and adjust for new data
226
+ if (userActivityData?.status?.expiresAt && (userActivityData?.status?.expiresAt !== currExpiresAt)) {
227
+ isUserActive = true;
228
+ this.resetInactivityDataAndTimers(userActivityData);
229
+ }
230
+
231
+ return isUserActive;
232
+ },
233
+ setUserAsActive() {
234
+ this.isUserActive = true;
235
+ this.userActivityIsoDate = new Date().toISOString();
236
+ },
116
237
  addIdleListeners() {
117
- document.addEventListener('mousemove', this.trackInactivity);
118
- document.addEventListener('mousedown', this.trackInactivity);
119
- document.addEventListener('keypress', this.trackInactivity);
120
- document.addEventListener('touchmove', this.trackInactivity);
121
- document.addEventListener('visibilitychange', this.trackInactivity);
122
- },
123
- removeEventListener() {
124
- document.removeEventListener('mousemove', this.trackInactivity);
125
- document.removeEventListener('mousedown', this.trackInactivity);
126
- document.removeEventListener('keypress', this.trackInactivity);
127
- document.removeEventListener('touchmove', this.trackInactivity);
128
- document.removeEventListener('visibilitychange', this.trackInactivity);
129
- },
130
-
131
- resume() {
132
- this.isInactive = false;
238
+ document.addEventListener('mousemove', this.setUserAsActive);
239
+ document.addEventListener('mousedown', this.setUserAsActive);
240
+ document.addEventListener('keypress', this.setUserAsActive);
241
+ document.addEventListener('touchmove', this.setUserAsActive);
242
+ document.addEventListener('visibilitychange', this.setUserAsActive);
243
+ },
244
+ removeEventListeners() {
245
+ document.removeEventListener('mousemove', this.setUserAsActive);
246
+ document.removeEventListener('mousedown', this.setUserAsActive);
247
+ document.removeEventListener('keypress', this.setUserAsActive);
248
+ document.removeEventListener('touchmove', this.setUserAsActive);
249
+ document.removeEventListener('visibilitychange', this.setUserAsActive);
250
+ },
251
+ async resetUserActivity(useCurrDate = false) {
252
+ let seenAt;
253
+
254
+ if (useCurrDate) {
255
+ seenAt = new Date().toISOString();
256
+ } else {
257
+ seenAt = this.userActivityIsoDate;
258
+ }
259
+
260
+ const userActivityData = await Inactivity.updateUserActivity(this.userActivityResource, this.sessionTokenName, seenAt);
261
+
262
+ this.resetInactivityDataAndTimers(userActivityData);
263
+ },
264
+ stopInactivity() {
265
+ this.modalVisibilityCheckRan = false;
133
266
  this.isOpen = false;
134
- this.courtesyCountdown = this.courtesyTimer;
267
+ this.isUserActive = false;
268
+ this.userActivityIsoDate = '';
269
+
270
+ this.removeEventListeners();
135
271
  this.clearAllTimeouts();
136
272
  },
273
+ resetInactivityDataAndTimers(userActivityData) {
274
+ const data = Inactivity.parseTTLData(userActivityData);
137
275
 
138
- refresh() {
139
- window.location.reload();
140
- },
276
+ this.modalVisibilityCheckRan = false;
277
+ this.isOpen = false;
278
+ this.isUserActive = false;
279
+ this.userActivityIsoDate = '';
141
280
 
142
- unsubscribe() {
143
- console.debug('Unsubscribing from all websocket events'); // eslint-disable-line no-console
144
- this.$store.dispatch('unsubscribe');
281
+ this.courtesyTimer = data.courtesyTimer;
282
+ this.courtesyCountdown = data.courtesyCountdown;
283
+ this.showModalAfter = data.showModalAfter;
284
+ this.sessionTokenName = data.sessionTokenName;
285
+ this.expiresAt = data.expiresAt;
286
+
287
+ const shownAfter = Math.round(((data.showModalAfter || 0) / 60) * 100) / 100;
288
+ const shownFor = Math.round(((data.courtesyTimer || 0) / 60) * 100) / 100;
289
+
290
+ console.debug(`UI inactivity modal (backend-based) will show after ${ shownAfter }(m) and be shown for ${ shownFor }(m)`); // eslint-disable-line no-console
291
+
292
+ this.clearAllTimeouts();
293
+ this.trackInactivity();
145
294
  },
146
295
  clearAllTimeouts() {
147
296
  clearTimeout(this.inactivityTimeoutId);
148
297
  clearTimeout(this.courtesyTimerId);
149
298
  }
150
-
151
299
  },
152
- computed: {
153
- isInactiveTexts() {
154
- return this.isInactive ? {
155
- title: this.t('inactivity.titleExpired'),
156
- banner: this.t('inactivity.bannerExpired'),
157
- content: this.t('inactivity.contentExpired'),
158
- } : {
159
- title: this.t('inactivity.title'),
160
- banner: this.t('inactivity.banner'),
161
- content: this.t('inactivity.content'),
162
- };
163
- },
164
- timerPercentageLeft() {
165
- return Math.floor((this.courtesyCountdown / this.courtesyTimer ) * 100);
166
- },
167
- colorStops() {
168
- return {
169
- 0: '--info', 30: '--info', 70: '--info'
170
- };
171
- },
172
- }
173
300
  };
174
301
  </script>
175
302
 
@@ -179,24 +306,22 @@ export default {
179
306
  ref="inactivityModal"
180
307
  name="inactivityModal"
181
308
  save-text="Continue"
182
- @finish="resume"
183
309
  >
184
310
  <template #title>
185
- {{ isInactiveTexts.title }}
311
+ {{ t('inactivity.title') }}
186
312
  </template>
187
313
  <span>{{ courtesyCountdown }}</span>
188
314
 
189
315
  <template #content>
190
316
  <Banner color="info">
191
- {{ isInactiveTexts.banner }}
317
+ {{ t('inactivity.banner') }}
192
318
  </Banner>
193
319
 
194
320
  <p>
195
- {{ isInactiveTexts.content }}
321
+ {{ t('inactivity.content') }}
196
322
  </p>
197
323
 
198
324
  <PercentageBar
199
- v-if="!isInactive"
200
325
  class="mt-20"
201
326
  :modelValue="timerPercentageLeft"
202
327
  :color-stops="colorStops"
@@ -208,20 +333,11 @@ export default {
208
333
  >
209
334
  <div class="card-actions">
210
335
  <button
211
- v-if="!isInactive"
212
336
  class="btn role-tertiary bg-primary"
213
- @click.prevent="resume"
337
+ @click.prevent="resetUserActivity(true)"
214
338
  >
215
339
  <t k="inactivity.cta" />
216
340
  </button>
217
-
218
- <button
219
- v-if="isInactive"
220
- class="btn role-tertiary bg-primary"
221
- @click.prevent="refresh"
222
- >
223
- <t k="inactivity.ctaExpired" />
224
- </button>
225
341
  </div>
226
342
  </template>
227
343
  </ModalWithCard>
@@ -117,7 +117,7 @@ export default {
117
117
 
118
118
  // server url and project ids are used in global values
119
119
  try {
120
- this.serverUrlSetting = await this.$store.dispatch(`${ this.store }/find`, {
120
+ this.serverUrlSetting = await this.$store.dispatch(`management/find`, {
121
121
  type: MANAGEMENT.SETTING,
122
122
  id: SETTING.SERVER_URL,
123
123
  });
@@ -125,7 +125,7 @@ export default {
125
125
  this.$store.dispatch('growl/fromError', { err: e });
126
126
  }
127
127
 
128
- await this.$store.dispatch(`${ this.store }/findAll`, { type: MANAGEMENT.PROJECT });
128
+ await this.$store.dispatch(`management/findAll`, { type: MANAGEMENT.PROJECT });
129
129
  }
130
130
  },
131
131
 
@@ -116,15 +116,11 @@ export default defineComponent({
116
116
  },
117
117
 
118
118
  async fetch() {
119
- const promises = [
120
- this.$fetchType(this.resource, [], this.overrideInStore || this.inStore),
121
- ];
122
-
123
119
  if (this.fetchSecondaryResources) {
124
- promises.push(this.fetchSecondaryResources({ canPaginate: this.canPaginate }));
120
+ await this.fetchSecondaryResources({ canPaginate: this.canPaginate });
125
121
  }
126
122
 
127
- await Promise.all(promises);
123
+ await this.$fetchType(this.resource, [], this.overrideInStore || this.inStore);
128
124
  },
129
125
 
130
126
  computed: {
@@ -0,0 +1,192 @@
1
+ <script lang="ts">
2
+ import Card from '@shell/components/Resource/Detail/Card/index.vue';
3
+ import { ref, watch } from 'vue';
4
+ import {
5
+ DEFAULT_FOCUS_TRAP_OPTS,
6
+ useWatcherBasedSetupFocusTrapWithDestroyIncluded
7
+ } from '@shell/composables/focusTrap';
8
+ import RcButton from '@components/RcButton/RcButton.vue';
9
+
10
+ export interface Props {
11
+ cardTitle: string;
12
+ fallbackFocus?: string;
13
+ showPopoverAriaLabel?: string;
14
+ }
15
+ </script>
16
+
17
+ <script setup lang="ts">
18
+ const props = withDefaults(defineProps<Props>(), { fallbackFocus: 'body', showPopoverAriaLabel: 'Show more' });
19
+ const card = ref<any>(null);
20
+ const popoverContainer = ref(null);
21
+ const showPopover = ref<boolean>(false);
22
+ const focusOpen = ref<boolean>(false);
23
+
24
+ // Set focus trap when card opened using keyboard
25
+ watch(
26
+ () => card.value,
27
+ (neu) => {
28
+ if (neu && focusOpen.value) {
29
+ const opts = {
30
+ ...DEFAULT_FOCUS_TRAP_OPTS,
31
+ fallbackFocus: props.fallbackFocus,
32
+ setReturnFocus: () => '.focus-button'
33
+ };
34
+
35
+ useWatcherBasedSetupFocusTrapWithDestroyIncluded(() => showPopover.value, '#popover-card', opts);
36
+ }
37
+ }
38
+ );
39
+ </script>
40
+
41
+ <template>
42
+ <div
43
+ class="popover-card-base"
44
+ :class="{open: showPopover}"
45
+ @mouseleave="showPopover=false; focusOpen=false"
46
+ @keydown.escape="showPopover=false; focusOpen=false"
47
+ >
48
+ <v-dropdown
49
+ :triggers="[]"
50
+ :container="popoverContainer"
51
+ :shown="showPopover"
52
+ placement="bottom-start"
53
+ >
54
+ <div
55
+ class="popover-card-target"
56
+ @mouseenter="showPopover=true"
57
+ >
58
+ <slot name="default" />
59
+ <RcButton
60
+ ghost
61
+ class="focus-button"
62
+ :aria-label="props.showPopoverAriaLabel"
63
+ aria-haspopup="true"
64
+ :aria-expanded="showPopover"
65
+ @click="showPopover=true; focusOpen=true;"
66
+ >
67
+ <i class="icon icon-chevron-down icon-sm" />
68
+ </RcButton>
69
+ <div
70
+ ref="popoverContainer"
71
+ class="popover-card-container"
72
+ >
73
+ <!--Empty container for mounting popper content-->
74
+ </div>
75
+ </div>
76
+
77
+ <template
78
+ #popper
79
+ >
80
+ <slot name="card">
81
+ <Card
82
+ id="popover-card"
83
+ ref="card"
84
+ class="popover-card"
85
+ :title="props.cardTitle"
86
+ >
87
+ <template #heading-action>
88
+ <slot
89
+ name="heading-action"
90
+ :close="() => {showPopover=false; focusOpen=false;}"
91
+ />
92
+ </template>
93
+ <slot name="card-body" />
94
+ </Card>
95
+ </slot>
96
+ </template>
97
+ </v-dropdown>
98
+ </div>
99
+ </template>
100
+
101
+ <style lang="scss" scoped>
102
+ .popover-card-base {
103
+ position: relative;
104
+ width: 100%;
105
+
106
+ .popover-card {
107
+ border: none;
108
+ }
109
+
110
+ .display-container {
111
+ position: absolute;
112
+ left: 0;
113
+ right: 0;
114
+ top: 0;
115
+ bottom: 0;
116
+ }
117
+
118
+ .display {
119
+ display: inline-flex;
120
+ max-width: 100%;
121
+ a {
122
+ flex: 1;
123
+ }
124
+ }
125
+
126
+ .popover-card-target {
127
+ height: 17px;
128
+ display: inline-block;
129
+ }
130
+
131
+ .focus-button {
132
+ margin-left: 4px;
133
+ margin-right: 2px;
134
+ padding: 0;
135
+ width: 0px;
136
+ height: initial;
137
+ min-height: initial;
138
+ overflow: hidden;
139
+ border-width: 0;
140
+
141
+ &:focus {
142
+ width: initial;
143
+ border-width: 1px;
144
+ }
145
+ }
146
+
147
+ .popover-card-base {
148
+ border: none;
149
+ }
150
+
151
+ .popover-card-container {
152
+ position: absolute;
153
+ $size: 10px;
154
+ height: $size;
155
+ bottom: -$size;
156
+ }
157
+
158
+ &.open .popover-card-container {
159
+ width: 100%;
160
+ }
161
+
162
+ &:deep() {
163
+ & > .v-popper > .btn.role-link {
164
+ padding: 0;
165
+ min-height: initial;
166
+ line-height: initial;
167
+
168
+ &:hover {
169
+ background: none;
170
+ }
171
+ }
172
+
173
+ .popover-card-container > .v-popper__popper {
174
+ border-radius: 6px;
175
+ box-shadow: 4px 4px 8px 0 rgba(0, 0, 0, 0.04);
176
+
177
+ & > .v-popper__wrapper {
178
+ .v-popper__arrow-container {
179
+ display: none;
180
+ }
181
+
182
+ & > .v-popper__inner {
183
+ overflow: initial;
184
+ &, & > div > .dropdownTarget {
185
+ padding: 0;
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ </style>