Skip to content

Commit e67eae4

Browse files
lawsmdclaude
andcommitted
chore(saved-projects): drop redundant rank field; use JSON array order
The `rank: u32` field on each saved project was a sort key that just reproduced the order of the JSON array — and the file is hand-edited (no in-app writer yet), so reordering meant renumbering all the ranks. Removing the field makes reordering a cut-and-paste of the `{ ... }` block, and eliminates a class of accidental-tie / off-by-one mistakes that's easy to introduce when inserting an entry into a numbered list. Behavior change is one line: `load_projects_from` no longer calls `sort_by_key(|p| p.rank)`. The picker UI (`projects_picker_menu_items` in `workspace/view.rs`) already iterated the loaded vec in order with no re-sorting, so removing the sort makes the vec's deserialization order — i.e. JSON array order — the displayed order. Backward compat is free: `serde_json` silently ignores unknown fields by default, so existing `~/.warp-oss/projects.json` files with `rank` keys continue to parse cleanly — the keys are just dropped on read. No migration needed. Renamed the `sorts_by_rank_ascending` test to `preserves_file_order` with a flipped expectation that documents the new invariant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b6bb8b6 commit e67eae4

2 files changed

Lines changed: 10 additions & 14 deletions

File tree

app/src/saved_projects/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ pub struct Project {
2121
pub name: String,
2222
pub cwd: PathBuf,
2323
pub color: String,
24-
pub rank: u32,
2524
}
2625

2726
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
@@ -31,10 +30,10 @@ pub struct ProjectsConfig {
3130
}
3231

3332
/// Reads `~/.warp-oss/projects.json` (or whatever `warp_home_projects_file_path()` resolves
34-
/// to for the current channel), expands `~` in each `cwd`, and returns the list sorted by
35-
/// `rank` ascending. Missing file or empty `projects` array → empty vec (debug-logged, not
36-
/// an error). Malformed JSON → empty vec with an error log so the picker never crashes the
37-
/// app over a typo.
33+
/// to for the current channel), expands `~` in each `cwd`, and returns the list in the
34+
/// order entries appear in the JSON `projects` array (top-of-file first). Missing file or
35+
/// empty `projects` array → empty vec (debug-logged, not an error). Malformed JSON → empty
36+
/// vec with an error log so the picker never crashes the app over a typo.
3837
pub fn load_projects() -> Vec<Project> {
3938
let Some(path) = warp_core::paths::warp_home_projects_file_path() else {
4039
return vec![];
@@ -67,7 +66,6 @@ fn load_projects_from(path: &Path) -> Vec<Project> {
6766
project.cwd = expanded;
6867
}
6968
}
70-
projects.sort_by_key(|p| p.rank);
7169
projects
7270
}
7371

app/src/saved_projects/saved_projects_test.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@ fn empty_projects_array_returns_empty() {
3131
}
3232

3333
#[test]
34-
fn sorts_by_rank_ascending() {
34+
fn preserves_file_order() {
3535
let dir = tempfile::tempdir().unwrap();
3636
let path = write_json(
3737
&dir,
3838
r##"{
3939
"projects": [
40-
{ "name": "Beta", "cwd": "/b", "color": "#aaaaaa", "rank": 3 },
41-
{ "name": "Alpha", "cwd": "/a", "color": "#bbbbbb", "rank": 1 },
42-
{ "name": "Gamma", "cwd": "/g", "color": "#cccccc", "rank": 2 }
40+
{ "name": "Beta", "cwd": "/b", "color": "#aaaaaa" },
41+
{ "name": "Alpha", "cwd": "/a", "color": "#bbbbbb" },
42+
{ "name": "Gamma", "cwd": "/g", "color": "#cccccc" }
4343
]
4444
}"##,
4545
);
4646
let projects = load_projects_from(&path);
4747
let names: Vec<&str> = projects.iter().map(|p| p.name.as_str()).collect();
48-
assert_eq!(names, vec!["Alpha", "Gamma", "Beta"]);
48+
assert_eq!(names, vec!["Beta", "Alpha", "Gamma"]);
4949
}
5050

5151
#[test]
@@ -55,7 +55,6 @@ fn round_trip_serde() {
5555
name: "Acme".into(),
5656
cwd: PathBuf::from("C:\\projects\\acme-services"),
5757
color: "#2bd7fb".into(),
58-
rank: 2,
5958
}],
6059
};
6160
let serialized = serde_json::to_string(&original).unwrap();
@@ -68,7 +67,6 @@ fn project(name: &str, cwd: &str) -> Project {
6867
name: name.into(),
6968
cwd: PathBuf::from(cwd),
7069
color: "#ff00ff".into(),
71-
rank: 0,
7270
}
7371
}
7472

@@ -124,7 +122,7 @@ fn tilde_expanded_at_load() {
124122
let dir = tempfile::tempdir().unwrap();
125123
let path = write_json(
126124
&dir,
127-
r##"{"projects": [{ "name": "Cfg", "cwd": "~/foo/bar", "color": "#999999", "rank": 1 }]}"##,
125+
r##"{"projects": [{ "name": "Cfg", "cwd": "~/foo/bar", "color": "#999999" }]}"##,
128126
);
129127
let projects = load_projects_from(&path);
130128
let cwd = &projects[0].cwd;

0 commit comments

Comments
 (0)