@rancher/shell 3.0.12-rc.1 → 3.0.12-rc.3

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 (376) hide show
  1. package/apis/impl/apis.ts +6 -0
  2. package/apis/index.ts +26 -0
  3. package/apis/intf/resources-api/cluster-api.ts +18 -0
  4. package/apis/intf/resources-api/mgmt-api.ts +15 -0
  5. package/apis/intf/resources-api/resource-base.ts +107 -0
  6. package/apis/intf/resources-api/resource-constants.ts +147 -0
  7. package/apis/intf/resources-api/resources-api.ts +143 -0
  8. package/apis/intf/resources.ts +49 -0
  9. package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
  10. package/apis/intf/shell-api/proxy.ts +216 -0
  11. package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
  12. package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
  13. package/apis/intf/shell.ts +12 -6
  14. package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
  15. package/apis/resources/index.ts +22 -0
  16. package/apis/resources/resources-api-class.ts +187 -0
  17. package/apis/shell/__tests__/proxy.test.ts +369 -0
  18. package/apis/shell/index.ts +8 -1
  19. package/apis/shell/modal.ts +4 -1
  20. package/apis/shell/notifications.ts +9 -6
  21. package/apis/shell/proxy.ts +256 -0
  22. package/apis/shell/slide-in.ts +4 -1
  23. package/apis/vue-shim.d.ts +2 -1
  24. package/assets/data/aws-regions.json +4 -0
  25. package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
  26. package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
  27. package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
  28. package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
  29. package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
  30. package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
  31. package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
  32. package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
  33. package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
  34. package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
  35. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
  36. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
  37. package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
  38. package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
  39. package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
  40. package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
  41. package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
  42. package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
  43. package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
  44. package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
  45. package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
  46. package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
  47. package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
  48. package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
  49. package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
  50. package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
  51. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
  52. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
  53. package/assets/images/providers/entraid-black.svg +4 -0
  54. package/assets/images/providers/entraid.svg +9 -0
  55. package/assets/images/vendor/entraid.svg +9 -0
  56. package/assets/styles/app.scss +0 -1
  57. package/assets/styles/base/_variables.scss +2 -0
  58. package/assets/styles/fonts/_fontstack.scss +132 -8
  59. package/assets/translations/en-us.yaml +41 -22
  60. package/assets/translations/zh-hans.yaml +4 -8
  61. package/chart/__tests__/S3.test.ts +10 -3
  62. package/chart/monitoring/index.vue +10 -1
  63. package/components/ActionDropdownShell.vue +2 -1
  64. package/components/CountBox.vue +20 -0
  65. package/components/CreateDriver.vue +0 -12
  66. package/components/CruResourceFooter.vue +9 -5
  67. package/components/DetailText.vue +12 -3
  68. package/components/ExplorerProjectsNamespaces.vue +1 -1
  69. package/components/InstallHelmCharts.vue +2 -2
  70. package/components/LandingPagePreference.vue +14 -5
  71. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
  72. package/components/Resource/Detail/Metadata/index.vue +6 -0
  73. package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
  74. package/components/Resource/Detail/SpacedRow.vue +3 -1
  75. package/components/Resource/Detail/TitleBar/index.vue +10 -11
  76. package/components/ResourceList/Masthead.vue +12 -8
  77. package/components/SelectIconGrid.vue +5 -10
  78. package/components/SingleClusterInfo.vue +1 -0
  79. package/components/SortableTable/__tests__/sorting.test.ts +126 -0
  80. package/components/SortableTable/index.vue +6 -9
  81. package/components/SortableTable/selection.js +23 -5
  82. package/components/SortableTable/sorting.js +6 -3
  83. package/components/Wizard.vue +14 -13
  84. package/components/__tests__/CountBox.test.ts +72 -0
  85. package/components/__tests__/DetailText.test.ts +113 -0
  86. package/components/fleet/FleetBundles.vue +100 -12
  87. package/components/fleet/FleetClusterTargets/index.vue +54 -15
  88. package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
  89. package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
  90. package/components/form/InputWithSelect.vue +18 -10
  91. package/components/form/KeyValue.vue +17 -1
  92. package/components/form/LabeledSelect.vue +101 -26
  93. package/components/form/NameNsDescription.vue +11 -0
  94. package/components/form/Security.vue +6 -2
  95. package/components/form/Select.vue +73 -56
  96. package/components/form/ServiceNameSelect.vue +13 -11
  97. package/components/form/WorkloadPorts.vue +2 -7
  98. package/components/form/__tests__/KeyValue.test.ts +66 -0
  99. package/components/form/__tests__/NodeScheduling.test.ts +9 -0
  100. package/components/form/__tests__/Security.test.ts +76 -0
  101. package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
  102. package/components/formatter/Autoscaler.vue +4 -4
  103. package/components/formatter/ClusterKubeVersion.vue +27 -0
  104. package/components/formatter/ClusterLink.vue +1 -7
  105. package/components/formatter/ClusterProvider.vue +6 -10
  106. package/components/formatter/FleetSummaryGraph.vue +0 -3
  107. package/components/formatter/MachineSummaryGraph.vue +1 -1
  108. package/components/formatter/PodsUsage.vue +2 -2
  109. package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
  110. package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
  111. package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
  112. package/components/nav/Group.vue +7 -6
  113. package/components/nav/Header.vue +24 -3
  114. package/components/nav/NamespaceFilter.vue +2 -2
  115. package/components/nav/NotificationCenter/Notification.vue +4 -1
  116. package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
  117. package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
  118. package/components/nav/TopLevelMenu.helper.ts +15 -3
  119. package/components/nav/TopLevelMenu.vue +16 -5
  120. package/components/nav/Type.vue +8 -7
  121. package/components/nav/WindowManager/index.vue +2 -1
  122. package/components/nav/WorkspaceSwitcher.vue +13 -0
  123. package/components/nav/__tests__/Group.test.ts +67 -0
  124. package/components/nav/__tests__/Header.test.ts +235 -0
  125. package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
  126. package/components/nav/__tests__/Type.test.ts +20 -3
  127. package/components/templates/default.vue +34 -4
  128. package/components/templates/home.vue +30 -25
  129. package/components/templates/plain.vue +31 -26
  130. package/components/templates/standalone.vue +17 -0
  131. package/composables/useFormValidation.ts +93 -0
  132. package/composables/useLabeledFormElement.ts +10 -2
  133. package/composables/useLabeledSelect.ts +60 -0
  134. package/composables/useUserRetentionValidation.ts +1 -49
  135. package/composables/useVeeValidateField.test.ts +159 -0
  136. package/composables/useVeeValidateField.ts +67 -0
  137. package/config/cookies.js +0 -1
  138. package/config/labels-annotations.js +1 -0
  139. package/config/pagination-table-headers.js +18 -1
  140. package/config/product/manager.js +82 -21
  141. package/config/query-params.js +1 -0
  142. package/config/router/routes.js +6 -8
  143. package/config/table-headers.js +20 -1
  144. package/config/types.js +2 -1
  145. package/core/__tests__/plugin-products.test.ts +1505 -30
  146. package/core/plugin-products-base.ts +137 -20
  147. package/core/plugin-products-helpers.ts +5 -4
  148. package/core/plugin-products.ts +4 -0
  149. package/core/plugin-types.ts +129 -4
  150. package/core/plugin.ts +15 -7
  151. package/core/productDebugger.js +9 -4
  152. package/core/types-provisioning.ts +43 -30
  153. package/core/types.ts +58 -19
  154. package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
  155. package/detail/__tests__/pod.test.ts +41 -0
  156. package/detail/harvesterhci.io.management.cluster.vue +6 -2
  157. package/detail/management.cattle.io.fleetworkspace.vue +49 -0
  158. package/detail/pod.vue +1 -1
  159. package/detail/provisioning.cattle.io.cluster.vue +4 -10
  160. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
  161. package/edit/__tests__/kontainerDriver.test.ts +0 -13
  162. package/edit/__tests__/nodeDriver.test.ts +5 -11
  163. package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
  164. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  165. package/edit/auth/__tests__/azuread.test.ts +217 -34
  166. package/edit/auth/__tests__/oidc.test.ts +54 -0
  167. package/edit/auth/azuread.vue +123 -15
  168. package/edit/auth/oidc.vue +10 -2
  169. package/edit/kontainerDriver.vue +1 -2
  170. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
  171. package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
  172. package/edit/networking.k8s.io.ingress/index.vue +75 -20
  173. package/edit/nodeDriver.vue +0 -2
  174. package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
  175. package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
  176. package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
  177. package/edit/provisioning.cattle.io.cluster/index.vue +81 -106
  178. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
  179. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
  180. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
  181. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
  182. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
  183. package/edit/secret/__tests__/ssh.test.ts +5 -6
  184. package/edit/secret/basic.vue +31 -0
  185. package/edit/secret/index.vue +68 -17
  186. package/edit/secret/registry.vue +38 -0
  187. package/edit/secret/ssh.vue +29 -0
  188. package/edit/secret/tls.vue +30 -0
  189. package/edit/service.vue +4 -4
  190. package/edit/workload/Upgrading.vue +3 -3
  191. package/edit/workload/__tests__/Upgrading.test.ts +6 -9
  192. package/edit/workload/mixins/workload.js +2 -1
  193. package/initialize/App.vue +29 -2
  194. package/initialize/install-plugins.js +0 -2
  195. package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
  196. package/list/catalog.cattle.io.app.vue +25 -5
  197. package/list/fleet.cattle.io.bundle.vue +7 -104
  198. package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
  199. package/list/management.cattle.io.feature.vue +1 -1
  200. package/list/management.cattle.io.fleetworkspace.vue +8 -0
  201. package/list/provisioning.cattle.io.cluster.vue +262 -180
  202. package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
  203. package/machine-config/amazonec2.vue +1 -0
  204. package/mixins/__tests__/chart.test.ts +112 -0
  205. package/mixins/brand.js +2 -1
  206. package/mixins/chart.js +50 -15
  207. package/mixins/resource-fetch-api-pagination.js +41 -5
  208. package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
  209. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
  210. package/models/__tests__/chart.test.ts +99 -6
  211. package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
  212. package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
  213. package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
  214. package/models/__tests__/management.cattle.io.node.ts +6 -5
  215. package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
  216. package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
  217. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
  218. package/models/base-cluster.x-k8s.io.js +26 -0
  219. package/models/catalog.cattle.io.app.js +21 -17
  220. package/models/catalog.cattle.io.clusterrepo.js +39 -11
  221. package/models/chart.js +33 -19
  222. package/models/cluster.js +1 -1
  223. package/models/cluster.x-k8s.io.machine.js +4 -22
  224. package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
  225. package/models/cluster.x-k8s.io.machineset.js +2 -20
  226. package/models/compliance.cattle.io.clusterscan.js +130 -2
  227. package/models/ext.cattle.io.kubeconfig.ts +4 -7
  228. package/models/fleet-application.js +4 -2
  229. package/models/fleet.cattle.io.bundle.js +1 -1
  230. package/models/kontainerdriver.js +11 -0
  231. package/models/management.cattle.io.authconfig.js +5 -1
  232. package/models/management.cattle.io.cluster.js +402 -78
  233. package/models/management.cattle.io.feature.js +3 -3
  234. package/models/management.cattle.io.kontainerdriver.js +1 -26
  235. package/models/management.cattle.io.node.js +6 -4
  236. package/models/management.cattle.io.nodepool.js +1 -1
  237. package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
  238. package/models/networking.k8s.io.ingress.js +12 -4
  239. package/models/nodedriver.js +7 -0
  240. package/models/provisioning.cattle.io.cluster.js +47 -330
  241. package/models/rke.cattle.io.etcdsnapshot.js +1 -2
  242. package/package.json +20 -37
  243. package/pages/__tests__/readme.test.ts +49 -0
  244. package/pages/auth/setup.vue +2 -3
  245. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +265 -0
  246. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
  247. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
  248. package/pages/c/_cluster/apps/charts/chart.vue +275 -39
  249. package/pages/c/_cluster/apps/charts/index.vue +2 -2
  250. package/pages/c/_cluster/apps/charts/install.vue +18 -10
  251. package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
  252. package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
  253. package/pages/c/_cluster/explorer/index.vue +5 -49
  254. package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
  255. package/pages/c/_cluster/istio/index.vue +21 -6
  256. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
  257. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +40 -2
  258. package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
  259. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +735 -13
  260. package/pages/c/_cluster/uiplugins/index.vue +226 -222
  261. package/pages/diagnostic.vue +13 -17
  262. package/pages/fail-whale.vue +18 -0
  263. package/pages/home.vue +77 -260
  264. package/pages/readme.vue +88 -0
  265. package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
  266. package/plugins/dashboard-store/actions.js +40 -18
  267. package/plugins/dashboard-store/resource-class.js +5 -2
  268. package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
  269. package/plugins/steve/steve-pagination-utils.ts +11 -3
  270. package/plugins/steve/subscribe.js +35 -5
  271. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +211 -1
  272. package/rancher-components/Form/LabeledInput/LabeledInput.vue +37 -4
  273. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
  274. package/rancher-components/RcButton/RcButton.test.ts +37 -1
  275. package/rancher-components/RcButton/RcButton.vue +38 -8
  276. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
  277. package/scripts/test-plugins-build.sh +5 -2
  278. package/server/server-middleware.js +2 -2
  279. package/static/humans.txt +1 -0
  280. package/static/robots.txt +34 -0
  281. package/static/welcome-cow.svg +18 -0
  282. package/store/__tests__/catalog.test.ts +276 -12
  283. package/store/__tests__/type-map.test.ts +556 -1
  284. package/store/action-menu.js +8 -3
  285. package/store/auth.js +1 -4
  286. package/store/aws.js +27 -16
  287. package/store/catalog.js +87 -11
  288. package/store/digitalocean.js +20 -38
  289. package/store/index.js +2 -0
  290. package/store/linode.js +25 -40
  291. package/store/pnap.js +1 -0
  292. package/store/type-map.js +111 -29
  293. package/tsconfig.paths.json +8 -8
  294. package/types/kube/kube-api.ts +14 -1
  295. package/types/rancher/steve.api.ts +12 -12
  296. package/types/resources/settings.d.ts +2 -1
  297. package/types/shell/index.d.ts +128 -24
  298. package/types/store/dashboard-store.types.ts +108 -11
  299. package/types/store/pagination.types.ts +6 -3
  300. package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
  301. package/utils/__tests__/async.test.ts +87 -0
  302. package/utils/__tests__/aws.test.ts +140 -0
  303. package/utils/__tests__/banners.test.ts +176 -0
  304. package/utils/__tests__/chart.test.ts +64 -1
  305. package/utils/__tests__/color.test.ts +226 -0
  306. package/utils/__tests__/duration.test.ts +140 -0
  307. package/utils/__tests__/fleet.test.ts +340 -0
  308. package/utils/__tests__/git.test.ts +270 -0
  309. package/utils/__tests__/inactivity.test.ts +316 -0
  310. package/utils/__tests__/ingress.test.ts +553 -0
  311. package/utils/__tests__/kube.test.ts +68 -0
  312. package/utils/__tests__/namespace-filter.test.ts +109 -0
  313. package/utils/__tests__/object.test.ts +77 -0
  314. package/utils/__tests__/pagination-utils.test.ts +361 -0
  315. package/utils/__tests__/parse-externalid.test.ts +137 -0
  316. package/utils/__tests__/perf-setting.utils.test.ts +98 -0
  317. package/utils/__tests__/poller-sequential.test.ts +177 -0
  318. package/utils/__tests__/poller.test.ts +170 -0
  319. package/utils/__tests__/promise.test.ts +346 -0
  320. package/utils/__tests__/settings.test.ts +140 -0
  321. package/utils/__tests__/sort-utils.test.ts +301 -0
  322. package/utils/__tests__/string-utils.test.ts +798 -0
  323. package/utils/__tests__/string.test.ts +23 -1
  324. package/utils/__tests__/style.test.ts +154 -0
  325. package/utils/__tests__/svg-filter.test.ts +184 -0
  326. package/utils/__tests__/time.test.ts +14 -1
  327. package/utils/__tests__/units.test.ts +417 -0
  328. package/utils/__tests__/url.test.ts +246 -0
  329. package/utils/__tests__/versions.test.ts +128 -0
  330. package/utils/__tests__/xccdf.test.ts +391 -0
  331. package/utils/chart.js +36 -0
  332. package/utils/fleet.ts +13 -3
  333. package/utils/gatekeeper/__tests__/util.test.ts +174 -0
  334. package/utils/gc/__tests__/gc-interval.test.ts +119 -0
  335. package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
  336. package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
  337. package/utils/gc/__tests__/gc.test.ts +487 -0
  338. package/utils/ingress.ts +9 -1
  339. package/utils/object.js +33 -2
  340. package/utils/pagination-utils.ts +2 -1
  341. package/utils/string.js +25 -2
  342. package/utils/time.ts +5 -0
  343. package/utils/uiplugins.ts +5 -5
  344. package/utils/validators/__tests__/cluster-name.test.ts +110 -0
  345. package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
  346. package/utils/validators/__tests__/index.test.ts +481 -0
  347. package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
  348. package/utils/validators/__tests__/misc-validators.test.ts +246 -0
  349. package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
  350. package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
  351. package/utils/validators/__tests__/role-template.test.ts +149 -0
  352. package/utils/validators/__tests__/service.test.ts +283 -0
  353. package/utils/validators/__tests__/setting.test.js +32 -0
  354. package/utils/validators/formRules/__tests__/index.test.ts +50 -0
  355. package/utils/validators/formRules/index.ts +5 -5
  356. package/utils/validators/machine-pool.ts +1 -1
  357. package/utils/validators/setting.js +18 -3
  358. package/utils/xccdf.ts +418 -0
  359. package/vue.config.js +0 -9
  360. package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
  361. package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
  362. package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
  363. package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
  364. package/assets/images/providers/azuread-black.svg +0 -22
  365. package/assets/images/providers/azuread.svg +0 -25
  366. package/assets/images/vendor/azuread.svg +0 -18
  367. package/assets/styles/fonts/_dots.scss +0 -18
  368. package/components/EmberPage.vue +0 -622
  369. package/components/EmberPageView.vue +0 -39
  370. package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
  371. package/mixins/labeled-form-element.ts +0 -225
  372. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
  373. package/pages/c/_cluster/manager/pages/_page.vue +0 -22
  374. package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
  375. package/plugins/ember-cookie.js +0 -17
  376. package/utils/ember-page.js +0 -30
@@ -1,5 +1,8 @@
1
+ import { BundleDeployment, BundleDeploymentStatus } from '@shell/types/resources/fleet';
1
2
  import { Target } from '@shell/types/fleet';
2
3
  import FleetUtils from '@shell/utils/fleet';
4
+ import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
5
+ import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
3
6
 
4
7
  describe('fx: util.getTargetMode', () => {
5
8
  const util = FleetUtils.Application;
@@ -153,3 +156,340 @@ describe('fx: util.getTargetMode', () => {
153
156
  expect(util.getTargetMode(targets, namespace)).toBe('all');
154
157
  });
155
158
  });
159
+
160
+ describe('fleet: quacksLikeAHash', () => {
161
+ it.each([
162
+ {
163
+ desc: '40-char lowercase hex string', input: 'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2', expected: true
164
+ },
165
+ {
166
+ desc: '40-char uppercase hex string', input: 'A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2', expected: true
167
+ },
168
+ {
169
+ desc: '64-char sha256 hex string', input: 'a'.repeat(64), expected: true
170
+ },
171
+ {
172
+ desc: '39-char hex string (too short)', input: 'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1', expected: false
173
+ },
174
+ {
175
+ desc: 'non-hex characters', input: 'z1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2', expected: false
176
+ },
177
+ {
178
+ desc: 'empty string', input: '', expected: false
179
+ },
180
+ {
181
+ desc: 'semantic version string', input: 'v1.2.3', expected: false
182
+ },
183
+ {
184
+ desc: 'branch name', input: 'main', expected: false
185
+ },
186
+ ])('$desc', ({ input, expected }) => {
187
+ expect(FleetUtils.quacksLikeAHash(input as string)).toBe(expected);
188
+ });
189
+ });
190
+
191
+ describe('fleet: parseSSHUrl', () => {
192
+ it('parses a standard git ssh url', () => {
193
+ const result = FleetUtils.parseSSHUrl('git@github.com:rancher/dashboard.git');
194
+
195
+ expect(result).toStrictEqual({ sshUserAndHost: 'git@github.com', repoPath: 'rancher/dashboard' });
196
+ });
197
+
198
+ it('handles url with no colon', () => {
199
+ const result = FleetUtils.parseSSHUrl('git@github.com');
200
+
201
+ expect(result).toStrictEqual({ sshUserAndHost: 'git@github.com', repoPath: undefined });
202
+ });
203
+
204
+ it('handles empty string', () => {
205
+ const result = FleetUtils.parseSSHUrl('');
206
+
207
+ expect(result).toStrictEqual({ sshUserAndHost: '', repoPath: undefined });
208
+ });
209
+ });
210
+
211
+ describe('fleet: resourceId', () => {
212
+ it.each([
213
+ {
214
+ desc: 'namespace/name when namespace is present',
215
+ resource: {
216
+ kind: 'Pod', apiVersion: 'v1', namespace: 'default', name: 'my-pod'
217
+ },
218
+ expected: 'default/my-pod'
219
+ },
220
+ {
221
+ desc: 'only name when namespace is absent',
222
+ resource: {
223
+ kind: 'ClusterRole', apiVersion: 'rbac.authorization.k8s.io/v1', name: 'my-role'
224
+ },
225
+ expected: 'my-role'
226
+ },
227
+ {
228
+ desc: 'only name when namespace is empty string',
229
+ resource: {
230
+ kind: 'Pod', apiVersion: 'v1', namespace: '', name: 'my-pod'
231
+ },
232
+ expected: 'my-pod'
233
+ },
234
+ ])('returns $desc', ({ resource, expected }) => {
235
+ expect(FleetUtils.resourceId(resource)).toBe(expected);
236
+ });
237
+ });
238
+
239
+ describe('fleet: resourceType', () => {
240
+ it.each([
241
+ {
242
+ desc: 'lowercase kind when apiVersion is v1',
243
+ resource: {
244
+ kind: 'Pod', apiVersion: 'v1', name: 'p', state: 'ready'
245
+ },
246
+ expected: 'pod'
247
+ },
248
+ {
249
+ desc: 'lowercase kind when apiVersion is absent',
250
+ resource: {
251
+ kind: 'Pod', apiVersion: '', name: 'p', state: 'ready'
252
+ },
253
+ expected: 'pod'
254
+ },
255
+ {
256
+ desc: 'group prefix for non-core resources',
257
+ resource: {
258
+ kind: 'Deployment', apiVersion: 'apps/v1', name: 'd', state: 'ready'
259
+ },
260
+ expected: 'apps.deployment'
261
+ },
262
+ {
263
+ desc: 'first segment of apiVersion as group',
264
+ resource: {
265
+ kind: 'Certificate', apiVersion: 'cert-manager.io/v1', name: 'c', state: 'ready'
266
+ },
267
+ expected: 'cert-manager.io.certificate'
268
+ },
269
+ ])('returns $desc', ({ resource, expected }) => {
270
+ expect(FleetUtils.resourceType(resource)).toBe(expected);
271
+ });
272
+ });
273
+
274
+ describe('fleet: bundleDeploymentState', () => {
275
+ const makeDeployment = (overrides: Partial<BundleDeployment> = {}): BundleDeployment => ({
276
+ spec: { deploymentId: 'dep-1', stagedDeploymentId: 'dep-1' },
277
+ status: {
278
+ appliedDeploymentId: 'dep-1',
279
+ ready: true,
280
+ nonModified: true,
281
+ conditions: [],
282
+ },
283
+ ...overrides,
284
+ });
285
+
286
+ it('returns ready when all conditions are nominal', () => {
287
+ expect(FleetUtils.bundleDeploymentState(makeDeployment())).toBe(STATES_ENUM.READY);
288
+ });
289
+
290
+ it('returns errapplied when appliedDeploymentId differs and Deployed condition is false', () => {
291
+ const bd = makeDeployment({
292
+ status: {
293
+ appliedDeploymentId: 'dep-0', ready: true, nonModified: true, conditions: []
294
+ }
295
+ });
296
+
297
+ expect(FleetUtils.bundleDeploymentState(bd)).toBe(STATES_ENUM.ERR_APPLIED);
298
+ });
299
+
300
+ it('returns waitapplied when appliedDeploymentId differs and Deployed condition is true', () => {
301
+ const bd = makeDeployment({
302
+ status: {
303
+ appliedDeploymentId: 'dep-0',
304
+ ready: true,
305
+ nonModified: true,
306
+ conditions: [{ type: 'Deployed', status: 'True' }],
307
+ },
308
+ });
309
+
310
+ expect(FleetUtils.bundleDeploymentState(bd)).toBe(STATES_ENUM.WAIT_APPLIED);
311
+ });
312
+
313
+ it('returns notready when applied matches but not ready', () => {
314
+ const bd = makeDeployment({
315
+ status: {
316
+ appliedDeploymentId: 'dep-1', ready: false, nonModified: true, conditions: []
317
+ }
318
+ });
319
+
320
+ expect(FleetUtils.bundleDeploymentState(bd)).toBe(STATES_ENUM.NOT_READY);
321
+ });
322
+
323
+ it('returns outofsync when deploymentId differs from stagedDeploymentId', () => {
324
+ const bd: BundleDeployment = {
325
+ spec: { deploymentId: 'dep-1', stagedDeploymentId: 'dep-2' },
326
+ status: {
327
+ appliedDeploymentId: 'dep-1',
328
+ ready: true,
329
+ nonModified: true,
330
+ conditions: [],
331
+ },
332
+ };
333
+
334
+ expect(FleetUtils.bundleDeploymentState(bd)).toBe(STATES_ENUM.OUT_OF_SYNC);
335
+ });
336
+
337
+ it('returns modified when nonModified is false', () => {
338
+ const bd = makeDeployment({
339
+ status: {
340
+ appliedDeploymentId: 'dep-1', ready: true, nonModified: false, conditions: []
341
+ }
342
+ });
343
+
344
+ expect(FleetUtils.bundleDeploymentState(bd)).toBe(STATES_ENUM.MODIFIED);
345
+ });
346
+ });
347
+
348
+ describe('fleet: resourcesFromBundleDeploymentStatus', () => {
349
+ it('returns empty array for empty status', () => {
350
+ const result = FleetUtils.resourcesFromBundleDeploymentStatus({} as BundleDeploymentStatus);
351
+
352
+ expect(result).toStrictEqual([]);
353
+ });
354
+
355
+ it('marks resources as ready when only in status.resources', () => {
356
+ const status: BundleDeploymentStatus = {
357
+ resources: [{
358
+ kind: 'Pod', apiVersion: 'v1', namespace: 'ns', name: 'pod-1'
359
+ }],
360
+ ready: true,
361
+ nonModified: true,
362
+ conditions: [],
363
+ };
364
+ const result = FleetUtils.resourcesFromBundleDeploymentStatus(status);
365
+
366
+ expect(result).toHaveLength(1);
367
+ expect(result[0].state).toBe(STATES_ENUM.READY);
368
+ expect(result[0].name).toBe('pod-1');
369
+ });
370
+
371
+ it('marks resource as missing when in modifiedStatus with missing=true', () => {
372
+ const status: BundleDeploymentStatus = {
373
+ modifiedStatus: [{
374
+ kind: 'Pod', apiVersion: 'v1', namespace: 'ns', name: 'pod-1', missing: true, patch: ''
375
+ }],
376
+ ready: true,
377
+ nonModified: true,
378
+ conditions: [],
379
+ };
380
+ const result = FleetUtils.resourcesFromBundleDeploymentStatus(status);
381
+
382
+ expect(result).toHaveLength(1);
383
+ expect(result[0].state).toBe(STATES_ENUM.MISSING);
384
+ });
385
+
386
+ it('marks resource as orphaned when in modifiedStatus with delete=true', () => {
387
+ const status: BundleDeploymentStatus = {
388
+ modifiedStatus: [{
389
+ kind: 'Pod', apiVersion: 'v1', namespace: 'ns', name: 'pod-1', delete: true, patch: ''
390
+ }],
391
+ ready: true,
392
+ nonModified: true,
393
+ conditions: [],
394
+ };
395
+ const result = FleetUtils.resourcesFromBundleDeploymentStatus(status);
396
+
397
+ expect(result[0].state).toBe(STATES_ENUM.ORPHANED);
398
+ });
399
+
400
+ it('marks resource as modified when in modifiedStatus without missing/delete', () => {
401
+ const status: BundleDeploymentStatus = {
402
+ modifiedStatus: [{
403
+ kind: 'Pod', apiVersion: 'v1', namespace: 'ns', name: 'pod-1', patch: 'diff'
404
+ }],
405
+ ready: true,
406
+ nonModified: true,
407
+ conditions: [],
408
+ };
409
+ const result = FleetUtils.resourcesFromBundleDeploymentStatus(status);
410
+
411
+ expect(result[0].state).toBe(STATES_ENUM.MODIFIED);
412
+ });
413
+
414
+ it('updates state of a resource that appears in both resources and modifiedStatus', () => {
415
+ const status: BundleDeploymentStatus = {
416
+ resources: [{
417
+ kind: 'Pod', apiVersion: 'v1', namespace: 'ns', name: 'pod-1'
418
+ }],
419
+ modifiedStatus: [{
420
+ kind: 'Pod', apiVersion: 'v1', namespace: 'ns', name: 'pod-1', missing: true, patch: ''
421
+ }],
422
+ ready: true,
423
+ nonModified: true,
424
+ conditions: [],
425
+ };
426
+ const result = FleetUtils.resourcesFromBundleDeploymentStatus(status);
427
+
428
+ expect(result).toHaveLength(1);
429
+ expect(result[0].state).toBe(STATES_ENUM.MISSING);
430
+ });
431
+ });
432
+
433
+ describe('fleet: clusterIdFromBundleDeploymentLabels', () => {
434
+ it('returns namespace/name from labels', () => {
435
+ const labels = {
436
+ [FLEET_LABELS.CLUSTER_NAMESPACE]: 'fleet-default',
437
+ [FLEET_LABELS.CLUSTER]: 'cluster-1',
438
+ };
439
+
440
+ expect(FleetUtils.clusterIdFromBundleDeploymentLabels(labels)).toBe('fleet-default/cluster-1');
441
+ });
442
+
443
+ it('returns undefined/undefined when labels are absent', () => {
444
+ expect(FleetUtils.clusterIdFromBundleDeploymentLabels(undefined)).toBe('undefined/undefined');
445
+ });
446
+ });
447
+
448
+ describe('fleet: bundleIdFromBundleDeploymentLabels', () => {
449
+ it('returns namespace/name from labels', () => {
450
+ const labels = {
451
+ [FLEET_LABELS.BUNDLE_NAMESPACE]: 'fleet-default',
452
+ [FLEET_LABELS.BUNDLE_NAME]: 'my-bundle',
453
+ };
454
+
455
+ expect(FleetUtils.bundleIdFromBundleDeploymentLabels(labels)).toBe('fleet-default/my-bundle');
456
+ });
457
+
458
+ it('returns undefined/undefined when labels are absent', () => {
459
+ expect(FleetUtils.bundleIdFromBundleDeploymentLabels(undefined)).toBe('undefined/undefined');
460
+ });
461
+ });
462
+
463
+ describe('fleet: getDashboardStateId', () => {
464
+ it.each([
465
+ {
466
+ desc: 'strips "text-" prefix from stateColor', stateColor: 'text-error', expected: 'error'
467
+ },
468
+ {
469
+ desc: 'returns "warning" when stateColor is falsy', stateColor: '', expected: 'warning'
470
+ },
471
+ {
472
+ desc: 'returns stateColor unchanged when no "text-" prefix', stateColor: 'success', expected: 'success'
473
+ },
474
+ ])('$desc', ({ stateColor, expected }) => {
475
+ expect(FleetUtils.getDashboardStateId({ stateColor })).toBe(expected);
476
+ });
477
+ });
478
+
479
+ describe('fleet: getDashboardState', () => {
480
+ it('returns the matching dashboard state for a known stateColor', () => {
481
+ const state = FleetUtils.getDashboardState({ stateColor: 'text-error' }) as { id: string };
482
+
483
+ expect(state.id).toBe('error');
484
+ });
485
+
486
+ it('returns empty object for an unknown stateColor', () => {
487
+ expect(FleetUtils.getDashboardState({ stateColor: 'text-unknown-state' })).toStrictEqual({});
488
+ });
489
+
490
+ it('returns warning state when stateColor is empty', () => {
491
+ const state = FleetUtils.getDashboardState({ stateColor: '' }) as { id: string };
492
+
493
+ expect(state.id).toBe('warning');
494
+ });
495
+ });
@@ -0,0 +1,270 @@
1
+ import { GitUtils, Commit } from '@shell/utils/git';
2
+
3
+ describe('git utils', () => {
4
+ describe('gitUtils.github.normalize.repo', () => {
5
+ it('maps owner fields from GitHub API response', () => {
6
+ const data = {
7
+ owner: {
8
+ login: 'octocat',
9
+ html_url: 'https://github.com/octocat',
10
+ avatar_url: 'https://avatars.githubusercontent.com/u/1?v=4'
11
+ },
12
+ description: 'Hello World',
13
+ created_at: '2021-01-01T00:00:00Z',
14
+ updated_at: '2021-06-01T00:00:00Z',
15
+ html_url: 'https://github.com/octocat/hello-world',
16
+ name: 'hello-world'
17
+ };
18
+
19
+ const result = GitUtils.github.normalize.repo(data);
20
+
21
+ expect(result.owner).toStrictEqual({
22
+ name: 'octocat',
23
+ htmlUrl: 'https://github.com/octocat',
24
+ avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4'
25
+ });
26
+ });
27
+
28
+ it('maps repo-level fields from GitHub API response', () => {
29
+ const data = {
30
+ owner: {
31
+ login: 'octocat', html_url: '', avatar_url: ''
32
+ },
33
+ description: 'A repository description',
34
+ created_at: '2021-01-01T00:00:00Z',
35
+ updated_at: '2022-03-15T12:00:00Z',
36
+ html_url: 'https://github.com/octocat/repo',
37
+ name: 'my-repo'
38
+ };
39
+
40
+ const result = GitUtils.github.normalize.repo(data);
41
+
42
+ expect(result.description).toStrictEqual('A repository description');
43
+ expect(result.created_at).toStrictEqual('2021-01-01T00:00:00Z');
44
+ expect(result.updated_at).toStrictEqual('2022-03-15T12:00:00Z');
45
+ expect(result.htmlUrl).toStrictEqual('https://github.com/octocat/repo');
46
+ expect(result.name).toStrictEqual('my-repo');
47
+ });
48
+
49
+ it('handles missing owner gracefully', () => {
50
+ const data = {
51
+ owner: undefined,
52
+ description: 'No owner',
53
+ created_at: '2021-01-01T00:00:00Z',
54
+ updated_at: '2021-01-01T00:00:00Z',
55
+ html_url: 'https://github.com/no/owner',
56
+ name: 'no-owner'
57
+ };
58
+
59
+ const result = GitUtils.github.normalize.repo(data);
60
+
61
+ expect(result.owner).toStrictEqual({
62
+ name: undefined,
63
+ htmlUrl: undefined,
64
+ avatarUrl: undefined
65
+ });
66
+ });
67
+ });
68
+
69
+ describe('gitUtils.github.normalize.commit', () => {
70
+ it('maps commit fields from GitHub API response', () => {
71
+ const data = {
72
+ commit: {
73
+ message: 'fix: resolve issue',
74
+ committer: { date: '2022-01-15T10:30:00Z' }
75
+ },
76
+ html_url: 'https://github.com/octocat/repo/commit/abc1234567890',
77
+ sha: 'abc1234567890abcdef',
78
+ author: {
79
+ login: 'octocat',
80
+ avatar_url: 'https://avatars.githubusercontent.com/u/1?v=4',
81
+ htmlUrl: 'https://github.com/octocat'
82
+ }
83
+ };
84
+
85
+ const result = GitUtils.github.normalize.commit(data);
86
+
87
+ expect(result.message).toStrictEqual('fix: resolve issue');
88
+ expect(result.htmlUrl).toStrictEqual('https://github.com/octocat/repo/commit/abc1234567890');
89
+ expect(result.sha).toStrictEqual('abc1234');
90
+ expect(result.commitId).toStrictEqual('abc1234567890abcdef');
91
+ expect(result.date).toStrictEqual('2022-01-15T10:30:00Z');
92
+ expect(result.isChecked).toStrictEqual(false);
93
+ });
94
+
95
+ it('truncates sha to 7 characters', () => {
96
+ const data = {
97
+ commit: { message: 'chore: update deps', committer: { date: '2022-01-01T00:00:00Z' } },
98
+ html_url: 'https://github.com/octocat/repo/commit/1234567890',
99
+ sha: '1234567890abcdef1234',
100
+ author: {
101
+ login: 'user', avatar_url: '', htmlUrl: ''
102
+ }
103
+ };
104
+
105
+ const result = GitUtils.github.normalize.commit(data);
106
+
107
+ expect(result.sha).toStrictEqual('1234567');
108
+ });
109
+
110
+ it('returns undefined sha when sha is empty string', () => {
111
+ const data = {
112
+ commit: { message: 'fix: bug', committer: { date: '2022-01-01T00:00:00Z' } },
113
+ html_url: 'https://github.com/octocat/repo/commit/x',
114
+ sha: '',
115
+ author: {
116
+ login: 'user', avatar_url: '', htmlUrl: ''
117
+ }
118
+ };
119
+
120
+ const result: Commit = GitUtils.github.normalize.commit(data);
121
+
122
+ expect(result.sha).toBeUndefined();
123
+ });
124
+
125
+ it('maps author fields from GitHub API response', () => {
126
+ const data = {
127
+ commit: { message: 'feat: new feature', committer: { date: '2022-01-01T00:00:00Z' } },
128
+ html_url: 'https://github.com/octocat/repo/commit/abc',
129
+ sha: 'abcdef1234567890',
130
+ author: {
131
+ login: 'contributor',
132
+ avatar_url: 'https://avatars.githubusercontent.com/u/2?v=4',
133
+ htmlUrl: 'https://github.com/contributor'
134
+ }
135
+ };
136
+
137
+ const result = GitUtils.github.normalize.commit(data);
138
+
139
+ expect(result.author).toStrictEqual({
140
+ name: 'contributor',
141
+ avatarUrl: 'https://avatars.githubusercontent.com/u/2?v=4',
142
+ htmlUrl: 'https://github.com/contributor'
143
+ });
144
+ });
145
+ });
146
+
147
+ describe('gitUtils.gitlab.normalize.repo', () => {
148
+ it('maps owner fields from GitLab API response', () => {
149
+ const data = {
150
+ namespace: {
151
+ name: 'my-group',
152
+ web_url: 'https://gitlab.com/my-group',
153
+ avatar_url: 'https://gitlab.com/uploads/group.png'
154
+ },
155
+ description: 'GitLab repo description',
156
+ created_at: '2021-02-01T00:00:00Z',
157
+ last_activity_at: '2022-07-20T00:00:00Z',
158
+ web_url: 'https://gitlab.com/my-group/project',
159
+ name: 'project'
160
+ };
161
+
162
+ const result = GitUtils.gitlab.normalize.repo(data);
163
+
164
+ expect(result.owner).toStrictEqual({
165
+ name: 'my-group',
166
+ htmlUrl: 'https://gitlab.com/my-group',
167
+ avatarUrl: 'https://gitlab.com/uploads/group.png'
168
+ });
169
+ });
170
+
171
+ it('maps repo-level fields from GitLab API response', () => {
172
+ const data = {
173
+ namespace: {
174
+ name: 'ns', web_url: '', avatar_url: ''
175
+ },
176
+ description: 'My GitLab project',
177
+ created_at: '2020-05-01T00:00:00Z',
178
+ last_activity_at: '2023-01-10T00:00:00Z',
179
+ web_url: 'https://gitlab.com/ns/myproject',
180
+ name: 'myproject'
181
+ };
182
+
183
+ const result = GitUtils.gitlab.normalize.repo(data);
184
+
185
+ expect(result.description).toStrictEqual('My GitLab project');
186
+ expect(result.created_at).toStrictEqual('2020-05-01T00:00:00Z');
187
+ expect(result.updated_at).toStrictEqual('2023-01-10T00:00:00Z');
188
+ expect(result.htmlUrl).toStrictEqual('https://gitlab.com/ns/myproject');
189
+ expect(result.name).toStrictEqual('myproject');
190
+ });
191
+
192
+ it('maps updated_at from last_activity_at (not updated_at)', () => {
193
+ const data = {
194
+ namespace: {
195
+ name: 'ns', web_url: '', avatar_url: ''
196
+ },
197
+ description: '',
198
+ created_at: '2020-01-01T00:00:00Z',
199
+ last_activity_at: '2023-06-15T08:00:00Z',
200
+ updated_at: 'should-be-ignored',
201
+ web_url: 'https://gitlab.com/ns/proj',
202
+ name: 'proj'
203
+ };
204
+
205
+ const result = GitUtils.gitlab.normalize.repo(data);
206
+
207
+ expect(result.updated_at).toStrictEqual('2023-06-15T08:00:00Z');
208
+ });
209
+ });
210
+
211
+ describe('gitUtils.gitlab.normalize.commit', () => {
212
+ it('maps commit fields from GitLab API response', () => {
213
+ const data = {
214
+ message: 'refactor: clean up code',
215
+ web_url: 'https://gitlab.com/ns/proj/-/commit/abc1234',
216
+ short_id: 'abc1234',
217
+ id: 'abc1234567890abcdef',
218
+ author_name: 'Jane Doe',
219
+ avatar_url: 'https://gitlab.com/uploads/jane.png',
220
+ committed_date: '2022-03-10T14:00:00Z'
221
+ };
222
+
223
+ const result = GitUtils.gitlab.normalize.commit(data);
224
+
225
+ expect(result.message).toStrictEqual('refactor: clean up code');
226
+ expect(result.htmlUrl).toStrictEqual('https://gitlab.com/ns/proj/-/commit/abc1234');
227
+ expect(result.sha).toStrictEqual('abc1234');
228
+ expect(result.commitId).toStrictEqual('abc1234567890abcdef');
229
+ expect(result.date).toStrictEqual('2022-03-10T14:00:00Z');
230
+ expect(result.isChecked).toStrictEqual(false);
231
+ });
232
+
233
+ it('maps author fields from GitLab API response', () => {
234
+ const data = {
235
+ message: 'feat: add feature',
236
+ web_url: 'https://gitlab.com/ns/proj/-/commit/xyz',
237
+ short_id: 'xyz',
238
+ id: 'xyzabcdef',
239
+ author_name: 'John Smith',
240
+ avatar_url: 'https://gitlab.com/uploads/john.png',
241
+ committed_date: '2022-04-01T00:00:00Z'
242
+ };
243
+
244
+ const result = GitUtils.gitlab.normalize.commit(data);
245
+
246
+ expect(result.author).toStrictEqual({
247
+ name: 'John Smith',
248
+ avatarUrl: 'https://gitlab.com/uploads/john.png',
249
+ htmlUrl: 'https://gitlab.com/ns/proj/-/commit/xyz'
250
+ });
251
+ });
252
+
253
+ it('uses web_url for both htmlUrl and author.htmlUrl', () => {
254
+ const data = {
255
+ message: 'fix: something',
256
+ web_url: 'https://gitlab.com/ns/proj/-/commit/def456',
257
+ short_id: 'def456',
258
+ id: 'def456abc',
259
+ author_name: 'Dev',
260
+ avatar_url: '',
261
+ committed_date: '2022-01-01T00:00:00Z'
262
+ };
263
+
264
+ const result = GitUtils.gitlab.normalize.commit(data);
265
+
266
+ expect(result.htmlUrl).toStrictEqual('https://gitlab.com/ns/proj/-/commit/def456');
267
+ expect((result.author as any).htmlUrl).toStrictEqual('https://gitlab.com/ns/proj/-/commit/def456');
268
+ });
269
+ });
270
+ });