33 <div class =" list-header" >
44 <div class =" header-top" >
55 <!-- TODO -->
6- <button v-if =" false" class =" btn btn-outline-normal ms-2" :class =" { 'active': selectMode }" type =" button" @click =" selectMode = !selectMode" >
6+ <button v-if =" false" class =" btn btn-outline-normal ms-2" :class =" { 'active': selectMode }" type =" button"
7+ @click =" selectMode = !selectMode" >
78 {{ $t("Select") }}
89 </button >
910
2829
2930 <!-- TODO: Selection Controls -->
3031 <div v-if =" selectMode && false" class =" selection-controls px-2 pt-2" >
31- <input
32- v-model =" selectAll"
33- class =" form-check-input select-input"
34- type =" checkbox"
35- />
32+ <input v-model =" selectAll" class =" form-check-input select-input" type =" checkbox" />
3633
37- <button class =" btn-outline-normal" @click =" pauseDialog" ><font-awesome-icon icon =" pause" size =" sm" /> {{ $t("Pause") }}</button >
38- <button class =" btn-outline-normal" @click =" resumeSelected" ><font-awesome-icon icon =" play" size =" sm" /> {{ $t("Resume") }}</button >
34+ <button class =" btn-outline-normal" @click =" pauseDialog" ><font-awesome-icon icon =" pause" size =" sm" /> {{
35+ $t("Pause") }}</button >
36+ <button class =" btn-outline-normal" @click =" resumeSelected" ><font-awesome-icon icon =" play" size =" sm" />
37+ {{ $t("Resume") }}</button >
3938
4039 <span v-if =" selectedStackCount > 0" >
41- {{ $t("selectedStackCount", [ selectedStackCount ]) }}
40+ {{ $t("selectedStackCount", [selectedStackCount]) }}
4241 </span >
4342 </div >
4443 </div >
4544 <div ref =" stackList" class =" stack-list" :class =" { scrollbar: scrollbar }" :style =" stackListStyle" >
46- <div v-if =" Object.keys(sortedStackList) .length === 0" class =" text-center mt-3" >
45+ <div v-if =" agentStackList[0] && agentStackList[0].stacks .length === 0" class =" text-center mt-3" >
4746 <router-link to =" /compose" >{{ $t("addFirstStackMsg") }}</router-link >
4847 </div >
49-
50- <StackListItem
51- v-for =" (item, index) in sortedStackList"
52- :key =" index"
53- :stack =" item"
54- :isSelectMode =" selectMode"
55- :isSelected =" isSelected"
56- :select =" select"
57- :deselect =" deselect"
58- />
48+ <div class =" stack-list-inner" v-for =" (agent, index) in agentStackList" :key =" index" >
49+ <div v-if =" $root.agentCount > 1" class =" p-2 agent-select"
50+ @click =" closedAgents.set(agent.endpoint, !closedAgents.get(agent.endpoint))" >
51+ <span class =" me-1" >
52+ <font-awesome-icon v-show =" closedAgents.get(agent.endpoint)" icon =" chevron-circle-right" />
53+ <font-awesome-icon v-show =" !closedAgents.get(agent.endpoint)" icon =" chevron-circle-down" />
54+ </span >
55+ <span v-if =" agent.endpoint === 'current'" >{{ $t("currentEndpoint") }}</span >
56+ <span v-else >{{ agent.endpoint }}</span >
57+ </div >
58+ <StackListItem v-show =" $root.agentCount === 1 || !closedAgents.get(agent.endpoint)"
59+ v-for =" (item, index) in agent.stacks" :key =" index" :stack =" item" :isSelectMode =" selectMode"
60+ :isSelected =" isSelected" :select =" select" :deselect =" deselect" />
61+ </div >
5962 </div >
6063 </div >
6164
@@ -92,7 +95,8 @@ export default {
9295 status: null ,
9396 active: null ,
9497 tags: null ,
95- }
98+ },
99+ closedAgents: new Map (),
96100 };
97101 },
98102 computed: {
@@ -119,7 +123,7 @@ export default {
119123 * Returns a sorted list of stacks based on the applied filters and search text.
120124 * @returns {Array} The sorted list of stacks.
121125 */
122- sortedStackList () {
126+ agentStackList () {
123127 let result = Object .values (this .$root .completeStackList );
124128
125129 result = result .filter (stack => {
@@ -187,6 +191,29 @@ export default {
187191 return m1 .name .localeCompare (m2 .name );
188192 });
189193
194+ // Group stacks by endpoint, sorting them so the local endpoint is first
195+ // and the rest are sorted alphabetically
196+ result = [
197+ ... result .reduce ((acc , stack ) => {
198+ const endpoint = stack .endpoint || ' current' ;
199+ if (! acc .has (endpoint)) {
200+ acc .set (endpoint, []);
201+ }
202+ acc .get (endpoint).push (stack);
203+ return acc;
204+ }, new Map ()).entries ()
205+ ].map (([endpoint , stacks ]) => ({
206+ endpoint,
207+ stacks
208+ })).sort ((a , b ) => {
209+ if (a .endpoint === ' current' && b .endpoint !== ' current' ) {
210+ return - 1 ;
211+ } else if (a .endpoint !== ' current' && b .endpoint === ' current' ) {
212+ return 1 ;
213+ }
214+ return a .endpoint .localeCompare (b .endpoint );
215+ });
216+
190217 return result;
191218 },
192219
@@ -221,7 +248,7 @@ export default {
221248 },
222249 watch: {
223250 searchText () {
224- for (let stack of this .sortedStackList ) {
251+ for (let stack of this .agentStackList ) {
225252 if (! this .selectedStacks [stack .id ]) {
226253 if (this .selectAll ) {
227254 this .disableSelectAllWatcher = true ;
@@ -236,7 +263,7 @@ export default {
236263 this .selectedStacks = {};
237264
238265 if (this .selectAll ) {
239- this .sortedStackList .forEach ((item ) => {
266+ this .agentStackList .forEach ((item ) => {
240267 this .selectedStacks [item .id ] = true ;
241268 });
242269 }
@@ -331,7 +358,7 @@ export default {
331358 pauseSelected () {
332359 Object .keys (this .selectedStacks )
333360 .filter (id => this .$root .stackList [id].active )
334- .forEach (id => this .$root .getSocket ().emit (" pauseStack" , id, () => {}));
361+ .forEach (id => this .$root .getSocket ().emit (" pauseStack" , id, () => { }));
335362
336363 this .cancelSelectMode ();
337364 },
@@ -342,7 +369,7 @@ export default {
342369 resumeSelected () {
343370 Object .keys (this .selectedStacks )
344371 .filter (id => ! this .$root .stackList [id].active )
345- .forEach (id => this .$root .getSocket ().emit (" resumeStack" , id, () => {}));
372+ .forEach (id => this .$root .getSocket ().emit (" resumeStack" , id, () => { }));
346373
347374 this .cancelSelectMode ();
348375 },
@@ -444,4 +471,15 @@ export default {
444471 gap: 10px ;
445472}
446473
474+ .agent - select {
475+ cursor: pointer;
476+ font- size: 14px ;
477+ font- weight: 500 ;
478+ color: $dark- font- color3;
479+ padding- left: 10px ;
480+ padding- right: 10px ;
481+ display: flex;
482+ align- items: center;
483+ user- select: none;
484+ }
447485< / style>
0 commit comments