@@ -23,16 +23,7 @@ q-dialog(
2323 )
2424 template( #before )
2525 .q-pa-md.overflow-auto ( style ="height: 100%;" )
26- p.text-body2 ( v-if ="showSendAll" ) {{ introText }}
27- q-checkbox(
28- v-if ="showSendAll"
29- v-model ="initAllIdentities"
30- :label ="checkboxLabel"
31- color ="teal-7"
32- dense
33- )
34- q-separator.q-my-md ( v-if ="showSendAll" )
35-
26+ p.text-body2.identity-modal-lede.q-mb-md {{ mainText }}
3627 q-select(
3728 v-model ="templateName"
3829 :options ="templates"
@@ -125,6 +116,42 @@ q-dialog(
125116 @click ="addVar"
126117 )
127118
119+ q-separator.q-my-md
120+ .row.items-center.no-wrap.q-mb-sm
121+ q-icon( color ="teal-7" name ="mdi-account-multiple-outline" size ="22px" )
122+ .text-subtitle1.q-ml-sm.text-weight-medium Destinataires
123+ q-space
124+ q-badge( color ="teal-7" text-color ="white" rounded ) {{ selectedRows.length }}
125+ q-banner(
126+ v-if ="selectedRows.length === 0"
127+ dense
128+ rounded
129+ class ="bg-amber-2 text-dark"
130+ )
131+ span Aucune identité dans la sélection.
132+ .identity-modal-list-wrap.mail-template-dest-in-form (
133+ v-if ="selectedRows.length > 0"
134+ :class ="listWrapClass"
135+ )
136+ q-list( dense separator padding )
137+ q-item.identity-modal-list-item (
138+ v-for ="item in identityListItems"
139+ :key ="item.key"
140+ )
141+ q-item-section( side )
142+ q-avatar( :color ="item.avatarColor" text-color ="white" size ="36px" ) {{ item.initials }}
143+ q-item-section
144+ q-item-label.text-weight-medium ( lines ="2" ) {{ item.label }}
145+ q-item-label.text-caption.text-grey-6 ( lines ="1" style ="font-family: ui-monospace, monospace" ) {{ item.idShort }}
146+ template( v-if ="showSendAll" )
147+ q-separator.q-my-md
148+ q-checkbox(
149+ v-model ="initAllIdentities"
150+ :label ="checkboxLabel"
151+ color ="teal-7"
152+ dense
153+ )
154+
128155 template( #after )
129156 .bg-grey-1.column ( style ="min-height: 0; height: 100%; overflow: hidden;" )
130157 q-bar( flat )
@@ -154,7 +181,8 @@ q-dialog(
154181
155182 .column ( v-else style ="min-height: 0; width: 100%;" )
156183 .col.q-pa-md.overflow-auto ( style ="min-height: 0;" )
157- p.text-body2.text-weight-medium.q-mb-sm {{ mainText }}
184+ p.text-body2.identity-modal-lede.q-mb-md {{ mainText }}
185+ q-separator.q-my-md
158186 q-select(
159187 v-model ="templateName"
160188 :options ="templates"
@@ -248,13 +276,40 @@ q-dialog(
248276 )
249277
250278 q-separator.q-my-md
251- q-checkbox(
252- v-if ="showSendAll"
253- v-model ="initAllIdentities"
254- :label ="checkboxLabel"
255- color ="teal-7"
279+ .row.items-center.no-wrap.q-mb-sm
280+ q-icon( color ="teal-7" name ="mdi-account-multiple-outline" size ="22px" )
281+ .text-subtitle1.q-ml-sm.text-weight-medium Destinataires
282+ q-space
283+ q-badge( color ="teal-7" text-color ="white" rounded ) {{ selectedRows.length }}
284+ q-banner(
285+ v-if ="selectedRows.length === 0"
256286 dense
287+ rounded
288+ class ="bg-amber-2 text-dark"
257289 )
290+ span Aucune identité dans la sélection.
291+ .identity-modal-list-wrap.mail-template-dest-in-form (
292+ v-if ="selectedRows.length > 0"
293+ :class ="listWrapClass"
294+ )
295+ q-list( dense separator padding )
296+ q-item.identity-modal-list-item (
297+ v-for ="item in identityListItems"
298+ :key ="item.key"
299+ )
300+ q-item-section( side )
301+ q-avatar( :color ="item.avatarColor" text-color ="white" size ="36px" ) {{ item.initials }}
302+ q-item-section
303+ q-item-label.text-weight-medium ( lines ="2" ) {{ item.label }}
304+ q-item-label.text-caption.text-grey-6 ( lines ="1" style ="font-family: ui-monospace, monospace" ) {{ item.idShort }}
305+ template( v-if ="showSendAll" )
306+ q-separator.q-my-md
307+ q-checkbox(
308+ v-model ="initAllIdentities"
309+ :label ="checkboxLabel"
310+ color ="teal-7"
311+ dense
312+ )
258313
259314 q-separator
260315 q-card-actions.identity-modal-actions ( align ="right" )
@@ -301,21 +356,99 @@ const props = defineProps({
301356
302357defineEmits ([... useDialogPluginComponent .emits ])
303358
359+ const AVATAR_COLORS = [' orange-8' , ' teal' , ' indigo' , ' deep-orange' , ' purple' , ' cyan' , ' brown' ]
360+
361+ function idToString(id : unknown ): string {
362+ if (id == null ) return ' '
363+ if (typeof id === ' string' ) return id
364+ if (typeof id === ' object' && id !== null && ' $oid' in (id as Record <string , unknown >)) {
365+ return String ((id as Record <string , unknown >).$oid )
366+ }
367+ return String (id )
368+ }
369+
370+ function strOrJoin(v : unknown ): string {
371+ if (v == null ) return ' '
372+ if (typeof v === ' string' ) return v .trim ()
373+ if (Array .isArray (v )) {
374+ return v
375+ .map ((x ) => (typeof x === ' string' ? x .trim () : x != null ? String (x ).trim () : ' ' ))
376+ .filter (Boolean )
377+ .join (' ' )
378+ }
379+ return String (v ).trim ()
380+ }
381+
382+ function buildIdentityLabel(row : Record <string , unknown >): string {
383+ const p = row ?.inetOrgPerson as Record <string , unknown > | undefined
384+ if (p && typeof p === ' object' ) {
385+ const fromCn = strOrJoin (p .cn )
386+ if (fromCn ) return fromCn
387+ const dn = strOrJoin (p .displayName )
388+ if (dn ) return dn
389+ const gn = strOrJoin (p .givenName )
390+ const sn = strOrJoin (p .sn )
391+ if (gn || sn ) return [gn , sn ].filter (Boolean ).join (' ' )
392+ const mail = strOrJoin (p .mail )
393+ if (mail ) return mail
394+ const uid = strOrJoin (p .uid )
395+ if (uid ) return uid
396+ }
397+ const id = idToString (row ?._id )
398+ if (id ) return ` Identité ${id .length > 14 ? ` ${id .slice (0 , 14 )}… ` : id } `
399+ return ' Identité (sans identifiant)'
400+ }
401+
402+ function initialsFromLabel(label : string ): string {
403+ const t = label .trim ()
404+ if (! t ) return ' ?'
405+ const parts = t .split (/ \s + / ).filter (Boolean )
406+ if (parts .length >= 2 ) {
407+ const a = parts [0 ][0 ] || ' '
408+ const b = parts [1 ][0 ] || ' '
409+ return ` ${a }${b } ` .toUpperCase ()
410+ }
411+ if (t .length >= 2 ) return t .slice (0 , 2 ).toUpperCase ()
412+ return t .charAt (0 ).toUpperCase ()
413+ }
414+
415+ function shortId(id : string ): string {
416+ if (! id ) return ' —'
417+ if (id .length <= 22 ) return id
418+ return ` ${id .slice (0 , 10 )}…${id .slice (- 8 )} `
419+ }
420+
304421/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any -- template Pug */
305422const q = useQuasar ()
306423const splitterModel = ref (42 )
307424
308- const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent ()
425+ const selectedRows = computed (() => {
426+ const raw = props .selectedIdentities
427+ if (! Array .isArray (raw )) return [] as Record <string , unknown >[]
428+ return raw as Record <string , unknown >[]
429+ })
309430
310- const mainText = computed (
311- () => ` Vous êtes sur le point d'envoyer un mail à ${props .selectedIdentities .length } identités "${props .identityTypesName }". Voulez-vous continuer ? ` ,
312- )
431+ const listWrapClass = computed (() => (q .dark .isActive ? ' identity-modal-list-wrap--dark' : ' identity-modal-list-wrap--light' ))
432+
433+ const identityListItems = computed (() => {
434+ return selectedRows .value .map ((row , idx ) => {
435+ const label = buildIdentityLabel (row )
436+ const id = idToString (row ?._id )
437+ return {
438+ key: ` ${id || ' noid' }_${idx } ` ,
439+ label ,
440+ idShort: shortId (id ),
441+ initials: initialsFromLabel (label ),
442+ avatarColor: AVATAR_COLORS [idx % AVATAR_COLORS .length ],
443+ }
444+ })
445+ })
313446
314- const introText = computed (() => {
315- if ( showSendAll . value ) {
316- return ` Vous êtes sur le point d'envoyer un mail à ${ props . selectedIdentities . length } identités "${ props . identityTypesName }". Vous pouvez aussi choisir de l'envoyer à toutes les identités synchronisées (${ props . allIdentitiesCount }). `
317- }
318- return ` Vous êtes sur le point d'envoyer un mail à ${props . selectedIdentities . length } identités " ${props .identityTypesName }". `
447+ const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent ()
448+
449+ const mainText = computed (() => {
450+ const n = selectedRows . value . length
451+ return ` Vous êtes sur le point d'envoyer un mail à ${n } identité${ n > 1 ? ' s ' : ' ' } « ${props .identityTypesName } ». Voulez-vous continuer ? `
319452})
320453
321454const checkboxLabel = computed (() => {
@@ -324,7 +457,7 @@ const checkboxLabel = computed(() => {
324457
325458const showSendAll = computed (() => {
326459 const total = Number (props .allIdentitiesCount || 0 )
327- const selected = Array . isArray ( props . selectedIdentities ) ? props . selectedIdentities . length : 0
460+ const selected = selectedRows . value . length
328461 return total > Math .max (selected , 1 )
329462})
330463
@@ -542,7 +675,6 @@ const cancelSync = () => {
542675}
543676
544677.mail-template-card > :deep(.q-card__actions ) {
545- margin-top : auto ;
546678 flex : 0 0 auto ;
547679 width : 100% ;
548680 max-width : 100% ;
@@ -555,14 +687,58 @@ const cancelSync = () => {
555687 min-width : 0 ;
556688 width : 100% ;
557689 max-width : 100% ;
558- height : 84% ;
690+ height : 100% ;
691+ }
692+
693+ .mail-template-dest-in-form.identity-modal-list-wrap--light ,
694+ .mail-template-dest-in-form.identity-modal-list-wrap--dark {
695+ max-height : min (260px , 40vh );
559696}
560697
561698.identity-modal-header {
562699 padding : 1rem 1.25rem ;
563700 flex-shrink : 0 ;
564701}
565702
703+ .identity-modal-lede {
704+ line-height : 1.55 ;
705+ margin-bottom : 1rem ;
706+ opacity : 0.92 ;
707+ }
708+
709+ .identity-modal-list-wrap--light {
710+ background : rgba (0 , 0 , 0 , 0.03 );
711+ border : 1px solid rgba (0 , 0 , 0 , 0.08 );
712+ }
713+
714+ .identity-modal-list-wrap--dark {
715+ background : rgba (255 , 255 , 255 , 0.06 );
716+ border : 1px solid rgba (255 , 255 , 255 , 0.12 );
717+ }
718+
719+ .identity-modal-list-wrap--light ,
720+ .identity-modal-list-wrap--dark {
721+ flex : 1 1 auto ;
722+ min-height : 0 ;
723+ border-radius : 10px ;
724+ overflow-x : hidden ;
725+ overflow-y : auto ;
726+ }
727+
728+ .identity-modal-list-item {
729+ border-radius : 8px ;
730+ margin-bottom : 2px ;
731+ transition : background-color 0.15s ease ;
732+ }
733+
734+ .identity-modal-list-wrap--light .identity-modal-list-item :hover {
735+ background-color : rgba (0 , 0 , 0 , 0.04 );
736+ }
737+
738+ .identity-modal-list-wrap--dark .identity-modal-list-item :hover {
739+ background-color : rgba (255 , 255 , 255 , 0.06 );
740+ }
741+
566742.identity-modal-actions {
567743 padding : 0.5rem 1rem 1rem ;
568744 background : rgba (0 , 0 , 0 , 0.02 );
0 commit comments