@@ -3,7 +3,8 @@ import {onMounted, onUnmounted, useTemplateRef, computed, ref, nextTick, watch}
33import  {createWorkflowStore } from  ' ./WorkflowStore.ts' 
44import  {svg } from  ' ../../svg.ts' 
55import  {confirmModal } from  ' ../../features/comp/ConfirmModal.ts' 
6- import  LabelSelector  from  ' ../LabelSelector.vue' 
6+ import  {fomanticQuery } from  ' ../../modules/fomantic/base.ts' 
7+ import  {contrastColor } from  ' ../../utils/color.ts' 
78
89const =  useTemplateRef (' elRoot' 
910
@@ -415,6 +416,27 @@ const hasAction = (actionType: any) => {
415416  return  store .selectedWorkflow ?.capabilities ?.available_actions ?.includes (actionType ); 
416417}; 
417418
419+ //  Toggle label selection for add_labels, remove_labels, or filter_labels
420+ const =  (type :  string , labelId :  any ) =>  {
421+   let  labels; 
422+   if  (type  ===  ' filter_labels'  
423+     labels  =  store .workflowFilters .labels ; 
424+   } else  { 
425+     labels  =  (store .workflowActions  as  any )[type ]; 
426+   } 
427+   const =  labels .indexOf (labelId ); 
428+   if  (index  >  - 1 ) { 
429+     labels .splice (index , 1 ); 
430+   } else  { 
431+     labels .push (labelId ); 
432+   } 
433+ }; 
434+ 
435+ //  Calculate text color based on background color for better contrast
436+ const =  (hexColor :  any ) =>  {
437+   return  contrastColor (hexColor ); 
438+ }; 
439+ 
418440const =  (item :  any ) =>  {
419441  if  (! item .isConfigured ) { 
420442    return  ' status-inactive' //  Gray dot for unconfigured 
@@ -476,6 +498,27 @@ const persistDraftState = () => {
476498  store .updateDraft (draftKey , store .workflowFilters , store .workflowActions ); 
477499}; 
478500
501+ //  Initialize Fomantic UI dropdowns for label selection
502+ const =  async  () =>  {
503+   await  nextTick (); 
504+   const =  elRoot .value ?.querySelectorAll (' .ui.dropdown'  
505+   if  (dropdowns ) { 
506+     dropdowns .forEach ((dropdown ) =>  { 
507+       fomanticQuery (dropdown ).dropdown ({ 
508+         action: ' nothing' //  Don't hide on selection for multiple selection 
509+         fullTextSearch: true , 
510+       }); 
511+     }); 
512+   } 
513+ }; 
514+ 
515+ //  Watch for edit mode changes to initialize dropdowns
516+ watch (isInEditMode , async  (newVal ) =>  {
517+   if  (newVal ) { 
518+     await  initLabelDropdowns (); 
519+   } 
520+ }); 
521+ 
479522watch (() =>  store .workflowFilters , () =>  {
480523  persistDraftState (); 
481524}, {deep: true }); 
@@ -810,12 +853,44 @@ onUnmounted(() => {
810853
811854                <div  class =" field" v-if =" hasFilter('labels')" 
812855                  <label >{{ locale.onlyIfHasLabels }}</label >
813-                   <LabelSelector 
814-                     v-model =" store.workflowFilters.labels" 
815-                     :labels =" store.projectLabels" 
816-                     :placeholder =" locale.anyLabel" 
817-                     :readonly =" !isInEditMode" 
818-                   />
856+                   <div  v-if =" isInEditMode" class =" ui fluid multiple search selection dropdown label-dropdown" 
857+                     <input  type =" hidden" :value =" store.workflowFilters.labels.join(',')" 
858+                     <i  class =" dropdown icon" 
859+                     <div  class =" text" :class =" { default: !store.workflowFilters.labels?.length }" 
860+                       <span  v-if =" !store.workflowFilters.labels?.length" span >
861+                       <template  v-else >
862+                         <span 
863+                           v-for =" labelId in store.workflowFilters.labels" :key =" labelId" 
864+                           class =" ui label" 
865+                           :style =" `background-color: ${store.projectLabels.find(l => String(l.id) === labelId)?.color}; color: ${getLabelTextColor(store.projectLabels.find(l => String(l.id) === labelId)?.color)}`" 
866+                         >
867+                           {{ store.projectLabels.find(l => String(l.id) === labelId)?.name }}
868+                         </span >
869+                       </template >
870+                     </div >
871+                     <div  class =" menu" 
872+                       <div 
873+                         class =" item" v-for =" label in store.projectLabels" :key =" label.id" 
874+                         :data-value =" String(label.id)" 
875+                         @click.prevent =" toggleLabel('filter_labels', String(label.id))" 
876+                         :class =" { active: store.workflowFilters.labels.includes(String(label.id)), selected: store.workflowFilters.labels.includes(String(label.id)) }" 
877+                       >
878+                         <span  class =" ui label" :style =" `background-color: ${label.color}; color: ${getLabelTextColor(label.color)}`" 
879+                           {{ label.name }}
880+                         </span >
881+                       </div >
882+                     </div >
883+                   </div >
884+                   <div  v-else  class =" ui labels" 
885+                     <span  v-if =" !store.workflowFilters.labels?.length" class =" text-muted" span >
886+                     <span 
887+                       v-for =" labelId in store.workflowFilters.labels" :key =" labelId" 
888+                       class =" ui label" 
889+                       :style =" `background-color: ${store.projectLabels.find(l => String(l.id) === labelId)?.color}; color: ${getLabelTextColor(store.projectLabels.find(l => String(l.id) === labelId)?.color)}`" 
890+                     >
891+                       {{ store.projectLabels.find(l => String(l.id) === labelId)?.name }}
892+                     </span >
893+                   </div >
819894                </div >
820895              </div >
821896            </div >
@@ -843,20 +918,86 @@ onUnmounted(() => {
843918
844919                <div  class =" field" v-if =" hasAction('add_labels')" 
845920                  <label >{{ locale.addLabels }}</label >
846-                   <LabelSelector 
847-                     v-model =" store.workflowActions.add_labels" 
848-                     :labels =" store.projectLabels" 
849-                     :readonly =" !isInEditMode" 
850-                   />
921+                   <div  v-if =" isInEditMode" class =" ui fluid multiple search selection dropdown label-dropdown" 
922+                     <input  type =" hidden" :value =" store.workflowActions.add_labels.join(',')" 
923+                     <i  class =" dropdown icon" 
924+                     <div  class =" text" :class =" { default: !store.workflowActions.add_labels?.length }" 
925+                       <span  v-if =" !store.workflowActions.add_labels?.length" span >
926+                       <template  v-else >
927+                         <span 
928+                           v-for =" labelId in store.workflowActions.add_labels" :key =" labelId" 
929+                           class =" ui label" 
930+                           :style =" `background-color: ${store.projectLabels.find(l => String(l.id) === labelId)?.color}; color: ${getLabelTextColor(store.projectLabels.find(l => String(l.id) === labelId)?.color)}`" 
931+                         >
932+                           {{ store.projectLabels.find(l => String(l.id) === labelId)?.name }}
933+                         </span >
934+                       </template >
935+                     </div >
936+                     <div  class =" menu" 
937+                       <div 
938+                         class =" item" v-for =" label in store.projectLabels" :key =" label.id" 
939+                         :data-value =" String(label.id)" 
940+                         @click.prevent =" toggleLabel('add_labels', String(label.id))" 
941+                         :class =" { active: store.workflowActions.add_labels.includes(String(label.id)), selected: store.workflowActions.add_labels.includes(String(label.id)) }" 
942+                       >
943+                         <span  class =" ui label" :style =" `background-color: ${label.color}; color: ${getLabelTextColor(label.color)}`" 
944+                           {{ label.name }}
945+                         </span >
946+                       </div >
947+                     </div >
948+                   </div >
949+                   <div  v-else  class =" ui labels" 
950+                     <span  v-if =" !store.workflowActions.add_labels?.length" class =" text-muted" span >
951+                     <span 
952+                       v-for =" labelId in store.workflowActions.add_labels" :key =" labelId" 
953+                       class =" ui label" 
954+                       :style =" `background-color: ${store.projectLabels.find(l => String(l.id) === labelId)?.color}; color: ${getLabelTextColor(store.projectLabels.find(l => String(l.id) === labelId)?.color)}`" 
955+                     >
956+                       {{ store.projectLabels.find(l => String(l.id) === labelId)?.name }}
957+                     </span >
958+                   </div >
851959                </div >
852960
853961                <div  class =" field" v-if =" hasAction('remove_labels')" 
854962                  <label >{{ locale.removeLabels }}</label >
855-                   <LabelSelector 
856-                     v-model =" store.workflowActions.remove_labels" 
857-                     :labels =" store.projectLabels" 
858-                     :readonly =" !isInEditMode" 
859-                   />
963+                   <div  v-if =" isInEditMode" class =" ui fluid multiple search selection dropdown label-dropdown" 
964+                     <input  type =" hidden" :value =" store.workflowActions.remove_labels.join(',')" 
965+                     <i  class =" dropdown icon" 
966+                     <div  class =" text" :class =" { default: !store.workflowActions.remove_labels?.length }" 
967+                       <span  v-if =" !store.workflowActions.remove_labels?.length" span >
968+                       <template  v-else >
969+                         <span 
970+                           v-for =" labelId in store.workflowActions.remove_labels" :key =" labelId" 
971+                           class =" ui label" 
972+                           :style =" `background-color: ${store.projectLabels.find(l => String(l.id) === labelId)?.color}; color: ${getLabelTextColor(store.projectLabels.find(l => String(l.id) === labelId)?.color)}`" 
973+                         >
974+                           {{ store.projectLabels.find(l => String(l.id) === labelId)?.name }}
975+                         </span >
976+                       </template >
977+                     </div >
978+                     <div  class =" menu" 
979+                       <div 
980+                         class =" item" v-for =" label in store.projectLabels" :key =" label.id" 
981+                         :data-value =" String(label.id)" 
982+                         @click.prevent =" toggleLabel('remove_labels', String(label.id))" 
983+                         :class =" { active: store.workflowActions.remove_labels.includes(String(label.id)), selected: store.workflowActions.remove_labels.includes(String(label.id)) }" 
984+                       >
985+                         <span  class =" ui label" :style =" `background-color: ${label.color}; color: ${getLabelTextColor(label.color)}`" 
986+                           {{ label.name }}
987+                         </span >
988+                       </div >
989+                     </div >
990+                   </div >
991+                   <div  v-else  class =" ui labels" 
992+                     <span  v-if =" !store.workflowActions.remove_labels?.length" class =" text-muted" span >
993+                     <span 
994+                       v-for =" labelId in store.workflowActions.remove_labels" :key =" labelId" 
995+                       class =" ui label" 
996+                       :style =" `background-color: ${store.projectLabels.find(l => String(l.id) === labelId)?.color}; color: ${getLabelTextColor(store.projectLabels.find(l => String(l.id) === labelId)?.color)}`" 
997+                     >
998+                       {{ store.projectLabels.find(l => String(l.id) === labelId)?.name }}
999+                     </span >
1000+                   </div >
8601001                </div >
8611002
8621003                <div  class =" field" v-if =" hasAction('issue_state')" 
@@ -1284,4 +1425,34 @@ onUnmounted(() => {
12841425  outline none ; 
12851426  box-shadow 0  0  0  0  var (--color-primary-alpha-30 ) inset ; 
12861427} 
1428+ 
1429+ /*  Label selector styles */ 
1430+ .label-dropdown.ui.dropdown  .menu  >  .item.active ,
1431+ .label-dropdown.ui.dropdown  .menu  >  .item.selected  {
1432+   background var (--color-active ); 
1433+   font-weight normal ; 
1434+ } 
1435+ 
1436+ .label-dropdown.ui.dropdown  .menu  >  .item  .ui.label  {
1437+   margin 0 ; 
1438+ } 
1439+ 
1440+ .label-dropdown.ui.dropdown  >  .text  >  .ui.label  {
1441+   margin 0.125rem  ; 
1442+ } 
1443+ 
1444+ .ui.labels  {
1445+   display flex ; 
1446+   flex-wrap wrap ; 
1447+   gap 0.5rem  ; 
1448+   align-items center ; 
1449+ } 
1450+ 
1451+ .ui.labels  .ui.label  {
1452+   margin 0 ; 
1453+ } 
1454+ 
1455+ .text-muted  {
1456+   color var (--color-text-light-2 ); 
1457+ } 
12871458style >
0 commit comments