abstractMenuBuilder.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import type { RuntimeConfig } from '@nuxt/schema'
  2. import type { AnyAbility } from '@casl/ability'
  3. import type { Router } from 'vue-router'
  4. import type {
  5. IconItem,
  6. MenuBuilder,
  7. MenuGroup,
  8. MenuItem,
  9. MenuItems,
  10. } from '~/types/layout'
  11. import { MENU_LINK_TYPE } from '~/types/enum/layout'
  12. import UrlUtils from '~/services/utils/urlUtils'
  13. import type { AccessProfile, organizationState } from '~/types/interfaces'
  14. /**
  15. * Classe de base des menus et sous-menus.
  16. *
  17. * La méthode principale est la méthode build
  18. */
  19. abstract class AbstractMenuBuilder implements MenuBuilder {
  20. protected runtimeConfig: RuntimeConfig
  21. protected ability: AnyAbility
  22. protected organizationProfile: organizationState
  23. protected accessProfile: AccessProfile
  24. protected router: Router
  25. /**
  26. * Nom court désignant le menu que construit ce builder
  27. */
  28. static readonly menuName: string
  29. constructor(
  30. runtimeConfig: RuntimeConfig,
  31. ability: AnyAbility,
  32. organizationProfile: organizationState,
  33. accessProfile: AccessProfile,
  34. router: Router,
  35. ) {
  36. this.runtimeConfig = runtimeConfig
  37. this.ability = ability
  38. this.organizationProfile = organizationProfile
  39. this.accessProfile = accessProfile
  40. this.router = router
  41. }
  42. /**
  43. * Permet un accès non statique à la variable menuName
  44. */
  45. public getMenuName(): string {
  46. return Object.getPrototypeOf(this).constructor.menuName
  47. }
  48. /**
  49. * Construit et retourne un menu ou sous-menu selon le profil de l'utilisateur, le profil de son organisation
  50. * et les droits de l'utilisateur.
  51. *
  52. * Si le menu comporte plusieurs éléments, retourne une instance de MenuGroup
  53. * Si le menu ne comporte qu'un seul élément, retourne une instance de MenuItem
  54. * Si le menu ne comporte aucun élément, retourne null.
  55. */
  56. abstract build(): MenuItem | MenuGroup | null
  57. /**
  58. * Construit et retourne un MenuGroup
  59. *
  60. * @param label
  61. * @param icon
  62. * @param {Array<MenuItem>} children Tableau d'ItemMenu représentant les sous menu du menu principal
  63. * @param actions
  64. */
  65. protected createGroup(
  66. label: string,
  67. icon?: IconItem,
  68. children: MenuItems = [],
  69. actions: Array<MenuItem> = [],
  70. ): MenuGroup {
  71. return { label, icon, children, actions }
  72. }
  73. /**
  74. * Construit et retourne un MenuItem
  75. *
  76. * @param {IconItem} icon
  77. * @param {string} label Titre qui sera traduit
  78. * @param to
  79. * @param type
  80. * @param noWarning
  81. * @return {MenuItem}
  82. */
  83. protected createItem(
  84. label: string,
  85. icon?: IconItem,
  86. to: string = '',
  87. type: MENU_LINK_TYPE = MENU_LINK_TYPE.INTERNAL,
  88. ): MenuItem {
  89. let url: string
  90. if (type === MENU_LINK_TYPE.INTERNAL) {
  91. console.warn(
  92. "'createItem()' should not be used for internal links, use 'addChildItemIfAllowed()'",
  93. )
  94. }
  95. switch (type) {
  96. case MENU_LINK_TYPE.V1:
  97. // eslint-disable-next-line no-case-declarations
  98. const v1BaseURL =
  99. this.runtimeConfig.baseUrlAdminLegacy ||
  100. this.runtimeConfig.public.baseUrlAdminLegacy
  101. url = UrlUtils.join(v1BaseURL, '#', to)
  102. break
  103. case MENU_LINK_TYPE.EXTERNAL:
  104. url = UrlUtils.prependHttps(to)
  105. break
  106. default:
  107. url = to
  108. }
  109. return { icon, label, to: url, type, active: false }
  110. }
  111. protected buildSubmenu(menuBuilder: typeof AbstractMenuBuilder) {
  112. // @ts-expect-error this method has to be called from non-abstract subclasses
  113. // eslint-disable-next-line new-cap
  114. const builder = new menuBuilder(
  115. this.runtimeConfig,
  116. this.ability,
  117. this.organizationProfile,
  118. this.accessProfile,
  119. )
  120. return builder.build()
  121. }
  122. /**
  123. * Make a list of MenuItems according to user abilities
  124. *
  125. * @param items
  126. * @protected
  127. */
  128. protected makeChildren(
  129. items: Array<{ pageName: string; icon?: string }>,
  130. ): MenuItems {
  131. const children: MenuItems = []
  132. items.forEach((item) => {
  133. const { pageName, icon } = item
  134. if (this.ability.can('display', pageName)) {
  135. const to = this.router.resolve({ name: pageName })
  136. if (!to) {
  137. throw new Error('unknown page name : ' + pageName)
  138. }
  139. children.push({
  140. icon: icon ? { name: icon } : undefined,
  141. label: pageName,
  142. to: to.href,
  143. type: MENU_LINK_TYPE.INTERNAL,
  144. active: false,
  145. })
  146. }
  147. })
  148. return children
  149. }
  150. }
  151. export default AbstractMenuBuilder