Browse Source

Merge branch 'hotfix/V8-7510-mise--jour-des-menus-v1-dans-la-' into develop

Olivier Massot 5 months ago
parent
commit
8d7d066d60
25 changed files with 456 additions and 270 deletions
  1. 4 0
      assets/css/global.scss
  2. 4 0
      components/Layout/Header/Menu.vue
  3. 1 1
      i18n/lang/fr.json
  4. 10 2
      services/layout/menuBuilder/abstractMenuBuilder.ts
  5. 12 2
      services/layout/menuBuilder/accountMenuBuilder.ts
  6. 81 67
      services/layout/menuBuilder/configurationMenuBuilder.ts
  7. 19 2
      tests/units/services/layout/menuBuilder/abstractMenuBuilder.test.ts
  8. 7 0
      tests/units/services/layout/menuBuilder/accessMenuBuilder.test.ts
  9. 117 92
      tests/units/services/layout/menuBuilder/accountMenuBuilder.test.ts
  10. 7 0
      tests/units/services/layout/menuBuilder/admin2iosMenuBuilder.test.ts
  11. 2 0
      tests/units/services/layout/menuBuilder/agendaMenuBuilder.test.ts
  12. 3 0
      tests/units/services/layout/menuBuilder/basicomptaMenuBuilder.test.ts
  13. 10 0
      tests/units/services/layout/menuBuilder/billingMenuBuilder.test.ts
  14. 3 0
      tests/units/services/layout/menuBuilder/communicationMenuBuilder.test.ts
  15. 130 104
      tests/units/services/layout/menuBuilder/configurationMenuBuilder.test.ts
  16. 17 0
      tests/units/services/layout/menuBuilder/cotisationsMenuBuilder.test.ts
  17. 1 0
      tests/units/services/layout/menuBuilder/donorsMenuBuilder.test.ts
  18. 6 0
      tests/units/services/layout/menuBuilder/educationalMenuBuilder.test.ts
  19. 1 0
      tests/units/services/layout/menuBuilder/equipmentMenuBuilder.test.ts
  20. 3 0
      tests/units/services/layout/menuBuilder/myAccessesMenuBuilder.test.ts
  21. 4 0
      tests/units/services/layout/menuBuilder/myFamilyMenuBuilder.test.ts
  22. 4 0
      tests/units/services/layout/menuBuilder/statsMenuBuilder.test.ts
  23. 1 0
      tests/units/services/layout/menuBuilder/websiteAdminMenuBuilder.test.ts
  24. 7 0
      tests/units/services/layout/menuBuilder/websiteListMenuBuilder.test.ts
  25. 2 0
      types/layout.d.ts

+ 4 - 0
assets/css/global.scss

@@ -63,6 +63,10 @@ header .v-toolbar__content {
       border-bottom: 1px solid;
       border-bottom-color: rgb(var(--v-theme-neutral));
     }
+
+    .v-list-item.end-of-section {
+      border-bottom: 3px solid rgb(var(--v-theme-neutral));
+    }
   }
 }
 

+ 4 - 0
components/Layout/Header/Menu.vue

@@ -41,6 +41,10 @@ header principal (configuration, paramètres du compte...)
                 :id="child.label"
                 :href="!isInternalLink(child) ? child.to : undefined"
                 :to="isInternalLink(child) ? child.to : undefined"
+                :class="{
+                  'end-of-section':
+                    'endOfSubsection' in child && child.endOfSubsection,
+                }"
               >
                 <span v-if="child.icon" class="pr-2 d-flex align-center">
                   <v-avatar

+ 1 - 1
i18n/lang/fr.json

@@ -11,7 +11,7 @@
   "opentalent_options": "Les options Opentalent",
   "opentalent_offers": "Les offres Opentalent",
   "service_detail": "Détail des services",
-  "my_settings_page": "Mes paramètres",
+  "my_settings_page": "Mes préférences",
   "allow_report_message": "Je souhaite recevoir les rapports d'envoi des emails que j'envoie",
   "my-settings_breadcrumbs": "Mes paramètres",
   "message_settings": "Paramètres des messages",

+ 10 - 2
services/layout/menuBuilder/abstractMenuBuilder.ts

@@ -86,6 +86,7 @@ abstract class AbstractMenuBuilder implements MenuBuilder {
    * @param to
    * @param type
    * @param newTab
+   * @param endOfSubsection
    * @return {MenuItem}
    */
   protected createItem(
@@ -94,6 +95,7 @@ abstract class AbstractMenuBuilder implements MenuBuilder {
     to: string = '',
     type: MENU_LINK_TYPE = MENU_LINK_TYPE.INTERNAL,
     newTab: boolean = false,
+    endOfSubsection: boolean = false,
   ): MenuItem {
     let url: string
     if (type === MENU_LINK_TYPE.INTERNAL) {
@@ -122,6 +124,7 @@ abstract class AbstractMenuBuilder implements MenuBuilder {
       type,
       active: false,
       target: newTab ? LINK_TARGET.BLANK : LINK_TARGET.SELF,
+      endOfSubsection,
     }
   }
 
@@ -143,12 +146,16 @@ abstract class AbstractMenuBuilder implements MenuBuilder {
    * @protected
    */
   protected makeChildren(
-    items: Array<{ pageName: string; icon?: string }>,
+    items: Array<{
+      pageName: string
+      icon?: string
+      endOfSubsection?: boolean
+    }>,
   ): MenuItems {
     const children: MenuItems = []
 
     items.forEach((item) => {
-      const { pageName, icon } = item
+      const { pageName, icon, endOfSubsection = false } = item
 
       if (this.ability.can('display', pageName)) {
         const to = this.router.resolve({ name: pageName })
@@ -161,6 +168,7 @@ abstract class AbstractMenuBuilder implements MenuBuilder {
           to: to.href,
           type: MENU_LINK_TYPE.INTERNAL,
           active: false,
+          endOfSubsection,
         })
       }
     })

+ 12 - 2
services/layout/menuBuilder/accountMenuBuilder.ts

@@ -132,11 +132,17 @@ export default class AccountMenuBuilder extends AbstractMenuBuilder {
           undefined,
           `/adherent_contacts/list/`,
           MENU_LINK_TYPE.V1,
+          false,
+          true,
         ),
       )
     }
 
-    children.push(...this.makeChildren([{ pageName: 'subscription_page' }]))
+    children.push(
+      ...this.makeChildren([
+        { pageName: 'subscription_page', endOfSubsection: true },
+      ]),
+    )
 
     if (this.ability.can('display', 'my_bills_page')) {
       children.push(
@@ -160,7 +166,11 @@ export default class AccountMenuBuilder extends AbstractMenuBuilder {
       )
     }
 
-    children.push(...this.makeChildren([{ pageName: 'my_settings_page' }]))
+    children.push(
+      ...this.makeChildren([
+        { pageName: 'my_settings_page', endOfSubsection: true },
+      ]),
+    )
 
     actions.push(
       this.createItem('logout', undefined, `/logout`, MENU_LINK_TYPE.V1),

+ 81 - 67
services/layout/menuBuilder/configurationMenuBuilder.ts

@@ -15,6 +15,7 @@ export default class ConfigurationMenuBuilder extends AbstractMenuBuilder {
   build(): MenuItem | MenuGroup | null {
     const children: MenuItems = []
 
+    // 1. "Fiche de la structure" -> 'organization_page'
     if (this.ability.can('display', 'organization_page')) {
       children.push(
         this.createItem(
@@ -30,91 +31,79 @@ export default class ConfigurationMenuBuilder extends AbstractMenuBuilder {
       )
     }
 
-    // if (this.ability.can('display', 'cmf_licence_page')) {
-    //   children.push(
-    //     this.createItem(
-    //       'cmf_licence_generate',
-    //       undefined,
-    //       '/cmf_licence_structure',
-    //       MENU_LINK_TYPE.INTERNAL,
-    //     ),
-    //   )
-    // }
+    // 2. "Préférences" -> 'parameters_page'
+    children.push(
+      ...this.makeChildren([
+        { pageName: 'parameters_page', endOfSubsection: true },
+      ]),
+    )
 
-    if (this.ability.can('display', 'cmf_licence_page')) {
+    // 3. "Enseignements" -> 'education'
+    if (this.ability.can('display', 'education_page')) {
       children.push(
         this.createItem(
-          'cmf_licence_generate',
+          'education',
           undefined,
-          '/licence_cmf/organization',
+          '/educations/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    // if (this.ability.can('display', 'parameters_page')) {
-    //   children.push(
-    //     this.createItem(
-    //       'parameters',
-    //       undefined,
-    //       `/parameters`,
-    //       MENU_LINK_TYPE.INTERNAL,
-    //     ),
-    //   )
-    // }
-
-    children.push(...this.makeChildren([{ pageName: 'parameters_page' }]))
-
-    if (this.ability.can('display', 'place_page')) {
+    // 4. "Parcours" -> 'parcours'
+    if (this.ability.can('display', 'parcours_page')) {
       children.push(
         this.createItem(
-          'places',
+          'parcours',
           undefined,
-          '/places/list/',
+          '/education_curriculum_packs/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'education_page')) {
+    // 5. "Sections" -> 'activities'
+    if (this.ability.can('display', 'activities_page')) {
       children.push(
         this.createItem(
-          'education',
+          'activities',
           undefined,
-          '/educations/list/',
+          '/activities/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'tag_page')) {
-      children.push(
-        this.createItem('tags', undefined, '/taggs/list/', MENU_LINK_TYPE.V1),
-      )
-    }
-
-    if (this.ability.can('display', 'activities_page')) {
+    // 6. "Préinscription(s) en ligne" -> 'online_registration_settings'
+    if (this.ability.can('display', 'online_registration_settings_page')) {
       children.push(
         this.createItem(
-          'activities',
+          'online_registration_settings',
           undefined,
-          '/activities/list/',
+          UrlUtils.join(
+            '/main/edit/online_registration_settings/',
+            this.organizationProfile.id ?? '',
+          ),
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'template_systems_page')) {
+    // 7. "Dupliquer les cours hebdomadaires" -> 'course_duplication'
+    if (this.ability.can('display', 'course_duplication_page')) {
       children.push(
         this.createItem(
-          'template_systems',
+          'course_duplication',
           undefined,
-          '/template_systems/list/',
+          '/duplicate_courses',
           MENU_LINK_TYPE.V1,
+          false,
+          true,
         ),
       )
     }
 
+    // 8. "Facturation" -> 'billing_settings'
     if (this.ability.can('display', 'billing_settings_page')) {
       children.push(
         this.createItem(
@@ -129,76 +118,101 @@ export default class ConfigurationMenuBuilder extends AbstractMenuBuilder {
       )
     }
 
-    if (this.ability.can('display', 'online_registration_settings_page')) {
+    // 9. "Liste des produits" -> 'billing_product'
+    if (this.ability.can('display', 'billing_product_page')) {
       children.push(
         this.createItem(
-          'online_registration_settings',
+          'billing_product',
           undefined,
-          UrlUtils.join(
-            '/main/edit/online_registration_settings/',
-            this.organizationProfile.id ?? '',
-          ),
+          '/intangibles/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'course_duplication_page')) {
+    // 10. "Modèles de quotients familiaux" -> 'family_quotient_models'
+    if (this.ability.can('display', 'family_quotient_models_page')) {
       children.push(
         this.createItem(
-          'course_duplication',
+          'family_quotient_models',
           undefined,
-          '/duplicate_courses',
+          '/family_quotient_models/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'import_page')) {
+    // 11. "Echéanciers de facturation" -> 'billing_schedules'
+    if (this.ability.can('display', 'billing_schedules_settings_page')) {
       children.push(
-        this.createItem('import', undefined, '/import/all', MENU_LINK_TYPE.V1),
+        this.createItem(
+          'billing_schedules',
+          undefined,
+          '/bill_schedules/list/',
+          MENU_LINK_TYPE.V1,
+          false,
+          true,
+        ),
       )
     }
 
-    if (this.ability.can('display', 'parcours_page')) {
+    // 12. "Lieux" -> 'places'
+    if (this.ability.can('display', 'place_page')) {
       children.push(
         this.createItem(
-          'parcours',
+          'places',
           undefined,
-          '/family_quotient_models/list/',
+          '/places/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'family_quotient_models_page')) {
+    // 13. "Mails système" -> 'template_systems'
+    if (this.ability.can('display', 'template_systems_page')) {
       children.push(
         this.createItem(
-          'family_quotient_models',
+          'template_systems',
           undefined,
-          '/family_quotient_models/list/',
+          '/template_systems/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'billing_schedules_settings_page')) {
+    // 14. "Pseudonymisation" -> 'pseudonymization'
+    if (this.ability.can('display', 'pseudonymization_page')) {
       children.push(
         this.createItem(
-          'billing_schedules',
+          'pseudonymization',
           undefined,
-          '/bill_schedules/list/',
+          '/pseudonymizationList/list/',
           MENU_LINK_TYPE.V1,
         ),
       )
     }
 
-    if (this.ability.can('display', 'pseudonymization_page')) {
+    // 15. "Tags" -> 'tags'
+    if (this.ability.can('display', 'tag_page')) {
+      children.push(
+        this.createItem('tags', undefined, '/taggs/list/', MENU_LINK_TYPE.V1),
+      )
+    }
+
+    // 16. "Importer" -> 'import'
+    if (this.ability.can('display', 'import_page')) {
+      children.push(
+        this.createItem('import', undefined, '/import/all', MENU_LINK_TYPE.V1),
+      )
+    }
+
+    // CMF licence (not in the required order, but keeping it at the end)
+    if (this.ability.can('display', 'cmf_licence_page')) {
       children.push(
         this.createItem(
-          'pseudonymization',
+          'cmf_licence_generate',
           undefined,
-          '/pseudonymizationList/list/',
+          '/licence_cmf/organization',
           MENU_LINK_TYPE.V1,
         ),
       )

+ 19 - 2
tests/units/services/layout/menuBuilder/abstractMenuBuilder.test.ts

@@ -110,7 +110,15 @@ describe('createItem', () => {
 
     const result = menuBuilder.createItem(label, icon, to, type)
 
-    expect(result).toEqual({ icon, label, to, target, type, active: false })
+    expect(result).toEqual({
+      icon,
+      label,
+      to,
+      target,
+      type,
+      active: false,
+      endOfSubsection: false,
+    })
   })
 
   test('default values', () => {
@@ -123,6 +131,7 @@ describe('createItem', () => {
       target: '_self',
       type: MENU_LINK_TYPE.INTERNAL,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -192,6 +201,7 @@ describe('makeChildren', () => {
         to: 'foo',
         type: 0,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })
@@ -207,7 +217,14 @@ describe('makeChildren', () => {
     ])
 
     expect(children).toEqual([
-      { label: 'foo_page', icon: undefined, to: 'foo', type: 0, active: false },
+      {
+        label: 'foo_page',
+        icon: undefined,
+        to: 'foo',
+        type: 0,
+        active: false,
+        endOfSubsection: false,
+      },
     ])
   })
   test('not allowed', () => {

+ 7 - 0
tests/units/services/layout/menuBuilder/accessMenuBuilder.test.ts

@@ -74,6 +74,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
 
     // @ts-ignore
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -102,6 +104,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -118,6 +121,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -134,6 +138,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -150,6 +155,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -166,6 +172,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 117 - 92
tests/units/services/layout/menuBuilder/accountMenuBuilder.test.ts

@@ -61,16 +61,13 @@ describe('build', () => {
 
     // Has the logout action
     // @ts-ignore
-    expect(result.actions).toEqual([
-      {
-        label: 'logout',
-        icon: undefined,
-        to: 'https://mydomain.com/#/logout',
-        target: '_self',
-        type: MENU_LINK_TYPE.V1,
-        active: false,
-      },
-    ])
+    const logoutAction = result.actions[0]
+    expect(logoutAction).toHaveProperty('label', 'logout')
+    expect(logoutAction).toHaveProperty('icon', undefined)
+    expect(logoutAction).toHaveProperty('to', 'https://mydomain.com/#/logout')
+    expect(logoutAction).toHaveProperty('target', '_self')
+    expect(logoutAction).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(logoutAction).toHaveProperty('active', false)
   })
 
   test('has profile icon : mister)', () => {
@@ -108,16 +105,15 @@ describe('build', () => {
 
     // Still has the logout action
     // @ts-ignore
-    expect(group.actions).toEqual([
-      {
-        label: 'logout',
-        icon: undefined,
-        to: 'https://mydomain.com/#/logout',
-        target: '_self',
-        type: MENU_LINK_TYPE.V1,
-        active: false,
-      },
-    ])
+    expect(group.actions.length).toEqual(1)
+    // @ts-ignore
+    const logoutAction = group.actions[0]
+    expect(logoutAction).toHaveProperty('label', 'logout')
+    expect(logoutAction).toHaveProperty('icon', undefined)
+    expect(logoutAction).toHaveProperty('to', 'https://mydomain.com/#/logout')
+    expect(logoutAction).toHaveProperty('target', '_self')
+    expect(logoutAction).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(logoutAction).toHaveProperty('active', false)
   })
 
   test('has only rights for menu my_schedule_page', () => {
@@ -127,14 +123,14 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_schedule_page',
-      icon: undefined,
-      to: 'https://mydomain.com/#/my_calendar',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_schedule_page')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty('to', 'https://mydomain.com/#/my_calendar')
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu attendance_bookings_menu', () => {
@@ -144,14 +140,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'attendance_bookings_menu',
-      icon: undefined,
-      to: 'https://mydomain.com/#/own_attendance',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'attendance_bookings_menu')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/own_attendance',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_attendance', () => {
@@ -161,14 +160,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_attendance',
-      icon: undefined,
-      to: 'https://mydomain.com/#/my_attendances/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_attendance')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/my_attendances/list/',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_invitation', () => {
@@ -178,14 +180,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_invitation',
-      icon: undefined,
-      to: 'https://mydomain.com/#/my_invitations/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_invitation')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/my_invitations/list/',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_students', () => {
@@ -195,14 +200,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_students',
-      icon: undefined,
-      to: 'https://mydomain.com/#/my_students/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_students')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/my_students/list/',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_students_education_students', () => {
@@ -213,14 +221,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_students_education_students',
-      icon: undefined,
-      to: 'https://mydomain.com/#/my_students_education_students/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_students_education_students')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/my_students_education_students/list/',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_education_students', () => {
@@ -230,14 +241,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_education_students',
-      icon: undefined,
-      to: 'https://mydomain.com/#/main/my_profile/123/dashboard/my_education_students/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_education_students')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/main/my_profile/123/dashboard/my_education_students/list/',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu send_an_email', () => {
@@ -247,14 +261,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'send_an_email',
-      icon: undefined,
-      to: 'https://mydomain.com/#/list/create/emails',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'send_an_email')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/list/create/emails',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_documents', () => {
@@ -264,14 +281,17 @@ describe('build', () => {
     )
 
     // @ts-ignore
-    expect(menuBuilder.build().children[0]).toEqual({
-      label: 'my_documents',
-      icon: undefined,
-      to: 'https://mydomain.com/#/main/my_profile/123/dashboard/show/my_access_file',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const menuItem = menuBuilder.build().children[0]
+    expect(menuItem).toHaveProperty('label', 'my_documents')
+    expect(menuItem).toHaveProperty('icon', undefined)
+    expect(menuItem).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/main/my_profile/123/dashboard/show/my_access_file',
+    )
+    expect(menuItem).toHaveProperty('target', '_self')
+    expect(menuItem).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(menuItem).toHaveProperty('active', false)
+    expect(menuItem).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu my_profile', () => {
@@ -288,6 +308,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -305,6 +326,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: true,
     })
   })
 
@@ -325,6 +347,7 @@ describe('build', () => {
       to: 'subscription',
       type: MENU_LINK_TYPE.INTERNAL,
       active: false,
+      endOfSubsection: true,
     })
 
     expect(router.resolve).toHaveBeenCalledWith({ name: 'subscription_page' })
@@ -344,6 +367,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -361,6 +385,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 7 - 0
tests/units/services/layout/menuBuilder/admin2iosMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -102,6 +104,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -118,6 +121,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -134,6 +138,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -150,6 +155,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -166,6 +172,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 2 - 0
tests/units/services/layout/menuBuilder/agendaMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 3 - 0
tests/units/services/layout/menuBuilder/basicomptaMenuBuilder.test.ts

@@ -62,6 +62,7 @@ describe('build', () => {
       type: MENU_LINK_TYPE.V1,
       target: '_self',
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -77,6 +78,7 @@ describe('build', () => {
       type: MENU_LINK_TYPE.V1,
       target: '_self',
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -92,6 +94,7 @@ describe('build', () => {
       type: MENU_LINK_TYPE.V1,
       target: '_self',
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 10 - 0
tests/units/services/layout/menuBuilder/billingMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -102,6 +104,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -118,6 +121,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -134,6 +138,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -150,6 +155,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -166,6 +172,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -182,6 +189,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -198,6 +206,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -214,6 +223,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 3 - 0
tests/units/services/layout/menuBuilder/communicationMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -102,6 +104,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 130 - 104
tests/units/services/layout/menuBuilder/configurationMenuBuilder.test.ts

@@ -52,7 +52,7 @@ describe('build', () => {
     expect(result.label).toEqual('configuration')
     expect(result.icon).toEqual({ name: 'fas fa-cogs' })
     // @ts-ignore
-    expect(result.children.length).toEqual(16)
+    expect(result.children.length).toEqual(17)
   })
 
   test('has no items', () => {
@@ -67,14 +67,17 @@ describe('build', () => {
     )
     organizationProfile.id = 123
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'organization_page',
-      icon: undefined,
-      to: 'https://mydomain.com/#/main/organizations/123/dashboard',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'organization_page')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/main/organizations/123/dashboard',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu cmf_licence_generate', () => {
@@ -83,14 +86,17 @@ describe('build', () => {
         action === 'display' && subject === 'cmf_licence_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'cmf_licence_generate',
-      icon: undefined,
-      to: 'https://mydomain.com/#/licence_cmf/organization',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'cmf_licence_generate')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/licence_cmf/organization',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
     //
     // expect(menuBuilder.build()).toEqual({
     //   label: 'cmf_licence_generate',
@@ -109,13 +115,12 @@ describe('build', () => {
 
     menuBuilder.organizationProfile.id = 123
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'parameters_page',
-      icon: undefined,
-      to: undefined,
-      type: MENU_LINK_TYPE.INTERNAL,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'parameters_page')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.INTERNAL)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', true)
 
     // expect(menuBuilder.build()).toEqual({
     //   label: 'parameters',
@@ -132,14 +137,14 @@ describe('build', () => {
         action === 'display' && subject === 'place_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'places',
-      icon: undefined,
-      to: 'https://mydomain.com/#/places/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'places')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty('to', 'https://mydomain.com/#/places/list/')
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu education', () => {
@@ -148,14 +153,17 @@ describe('build', () => {
         action === 'display' && subject === 'education_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'education',
-      icon: undefined,
-      to: 'https://mydomain.com/#/educations/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'education')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/educations/list/',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu tag', () => {
@@ -164,14 +172,14 @@ describe('build', () => {
         action === 'display' && subject === 'tag_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'tags',
-      icon: undefined,
-      to: 'https://mydomain.com/#/taggs/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'tags')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty('to', 'https://mydomain.com/#/taggs/list/')
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu activities', () => {
@@ -180,14 +188,17 @@ describe('build', () => {
         action === 'display' && subject === 'activities_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'activities',
-      icon: undefined,
-      to: 'https://mydomain.com/#/activities/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'activities')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/activities/list/',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu course_duplication', () => {
@@ -196,14 +207,17 @@ describe('build', () => {
         action === 'display' && subject === 'course_duplication_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'course_duplication',
-      icon: undefined,
-      to: 'https://mydomain.com/#/duplicate_courses',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'course_duplication')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/duplicate_courses',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', true)
   })
 
   test('has only rights for menu import', () => {
@@ -212,14 +226,14 @@ describe('build', () => {
         action === 'display' && subject === 'import_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'import',
-      icon: undefined,
-      to: 'https://mydomain.com/#/import/all',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'import')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty('to', 'https://mydomain.com/#/import/all')
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu parcours', () => {
@@ -228,14 +242,17 @@ describe('build', () => {
         action === 'display' && subject === 'parcours_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'parcours',
-      icon: undefined,
-      to: 'https://mydomain.com/#/family_quotient_models/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'parcours')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/family_quotient_models/list/',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu family_quotient_models', () => {
@@ -244,14 +261,17 @@ describe('build', () => {
         action === 'display' && subject === 'family_quotient_models_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'family_quotient_models',
-      icon: undefined,
-      to: 'https://mydomain.com/#/family_quotient_models/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'family_quotient_models')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/family_quotient_models/list/',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 
   test('has only rights for menu billing_schedules', () => {
@@ -260,14 +280,17 @@ describe('build', () => {
         action === 'display' && subject === 'billing_schedules_settings_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'billing_schedules',
-      icon: undefined,
-      to: 'https://mydomain.com/#/bill_schedules/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'billing_schedules')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/bill_schedules/list/',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', true)
   })
 
   test('has only rights for menu pseudonymization', () => {
@@ -276,13 +299,16 @@ describe('build', () => {
         action === 'display' && subject === 'pseudonymization_page',
     )
 
-    expect(menuBuilder.build()).toEqual({
-      label: 'pseudonymization',
-      icon: undefined,
-      to: 'https://mydomain.com/#/pseudonymizationList/list/',
-      target: '_self',
-      type: MENU_LINK_TYPE.V1,
-      active: false,
-    })
+    const result = menuBuilder.build()
+    expect(result).toHaveProperty('label', 'pseudonymization')
+    expect(result).toHaveProperty('icon', undefined)
+    expect(result).toHaveProperty(
+      'to',
+      'https://mydomain.com/#/pseudonymizationList/list/',
+    )
+    expect(result).toHaveProperty('target', '_self')
+    expect(result).toHaveProperty('type', MENU_LINK_TYPE.V1)
+    expect(result).toHaveProperty('active', false)
+    expect(result).toHaveProperty('endOfSubsection', false)
   })
 })

+ 17 - 0
tests/units/services/layout/menuBuilder/cotisationsMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -102,6 +104,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -118,6 +121,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -134,6 +138,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -150,6 +155,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -166,6 +172,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -182,6 +189,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -198,6 +206,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -214,6 +223,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -230,6 +240,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -246,6 +257,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -262,6 +274,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -278,6 +291,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -294,6 +308,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -310,6 +325,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -326,6 +342,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 1 - 0
tests/units/services/layout/menuBuilder/donorsMenuBuilder.test.ts

@@ -53,6 +53,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 

+ 6 - 0
tests/units/services/layout/menuBuilder/educationalMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -86,6 +87,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -102,6 +104,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -118,6 +121,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -134,6 +138,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -151,6 +156,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 1 - 0
tests/units/services/layout/menuBuilder/equipmentMenuBuilder.test.ts

@@ -53,6 +53,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 

+ 3 - 0
tests/units/services/layout/menuBuilder/myAccessesMenuBuilder.test.ts

@@ -65,6 +65,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'Séraphin',
@@ -73,6 +74,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'Lilou',
@@ -81,6 +83,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })

+ 4 - 0
tests/units/services/layout/menuBuilder/myFamilyMenuBuilder.test.ts

@@ -96,6 +96,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'Dupuis Séraphin',
@@ -104,6 +105,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'Dubois Lilou',
@@ -112,6 +114,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'Soprano Tony',
@@ -120,6 +123,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })

+ 4 - 0
tests/units/services/layout/menuBuilder/statsMenuBuilder.test.ts

@@ -70,6 +70,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 
@@ -89,6 +90,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'accesses_quotas_courses_hebdos',
@@ -97,6 +99,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.V1,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })
@@ -114,6 +117,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.V1,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 1 - 0
tests/units/services/layout/menuBuilder/websiteAdminMenuBuilder.test.ts

@@ -73,6 +73,7 @@ describe('build', () => {
       target: '_self',
       type: MENU_LINK_TYPE.EXTERNAL,
       active: false,
+      endOfSubsection: false,
     })
   })
 })

+ 7 - 0
tests/units/services/layout/menuBuilder/websiteListMenuBuilder.test.ts

@@ -61,6 +61,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })
@@ -84,6 +85,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'parent2',
@@ -92,6 +94,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'parent3',
@@ -100,6 +103,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })
@@ -125,6 +129,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'parent1',
@@ -133,6 +138,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
       {
         label: 'parent2',
@@ -141,6 +147,7 @@ describe('build', () => {
         target: '_self',
         type: MENU_LINK_TYPE.EXTERNAL,
         active: false,
+        endOfSubsection: false,
       },
     ])
   })

+ 2 - 0
types/layout.d.ts

@@ -21,6 +21,8 @@ interface MenuItem {
   active: boolean
   /** Définit l'attribut 'target' du lien */
   target?: LINK_TARGET
+  /** Indique si l'item est à la fin d'une sous-section (bordure basse plus épaisse) */
+  endOfSubsection?: boolean
 }
 
 /**