@@ -137,6 +137,36 @@ def normalize_pipeline_visibility(
137137 return normalize_named_visibility (pipeline_names , stored_visibility )
138138
139139
140+ def normalize_named_order (
141+ item_names : Iterable [str ], stored_order : Iterable [str ] | None
142+ ) -> tuple [list [str ], bool ]:
143+ ordered_names = list (dict .fromkeys (item_names ))
144+ clean_stored = [
145+ name for name in (stored_order or []) if isinstance (name , str ) and name .strip ()
146+ ]
147+
148+ seen : set [str ] = set ()
149+ normalized : list [str ] = []
150+ for name in clean_stored :
151+ if name in ordered_names and name not in seen :
152+ normalized .append (name )
153+ seen .add (name )
154+
155+ for name in ordered_names :
156+ if name not in seen :
157+ normalized .append (name )
158+ seen .add (name )
159+
160+ changed = normalized != clean_stored
161+ return normalized , changed
162+
163+
164+ def normalize_pipeline_order (
165+ pipeline_names : Iterable [str ], stored_order : Iterable [str ] | None
166+ ) -> tuple [list [str ], bool ]:
167+ return normalize_named_order (pipeline_names , stored_order )
168+
169+
140170class AppSettingsStore :
141171 def __init__ (
142172 self ,
@@ -201,6 +231,23 @@ def load_pipeline_visibility(self) -> dict[str, bool]:
201231 def save_pipeline_visibility (self , visibility : Mapping [str , bool ]) -> None :
202232 self .save_named_visibility ("pipeline_visibility" , visibility )
203233
234+ def load_named_order (self , key : str ) -> list [str ]:
235+ raw_order = self .load ().get (key , [])
236+ if not isinstance (raw_order , list ):
237+ return []
238+ return [name for name in raw_order if isinstance (name , str ) and name .strip ()]
239+
240+ def save_named_order (self , key : str , order : Iterable [str ]) -> None :
241+ settings = self .load ()
242+ settings [key ] = [name for name in order if isinstance (name , str ) and name ]
243+ self .save (settings )
244+
245+ def load_pipeline_order (self ) -> list [str ]:
246+ return self .load_named_order ("pipeline_order" )
247+
248+ def save_pipeline_order (self , order : Iterable [str ]) -> None :
249+ self .save_named_order ("pipeline_order" , order )
250+
204251 def load_ui_mode (self ) -> str :
205252 mode = self .load ().get ("ui_mode" )
206253 return mode if mode in {"minimal" , "advanced" } else "minimal"
0 commit comments