Skip to content

Commit 41ec59b

Browse files
Alex Holmbergclaude
authored andcommitted
feat(62.1-01): add environment fields to PlatformSession
- Add environment_id and environment_name fields to PlatformSession - Add with_environment() constructor for full context - Add is_environment_selected() method - Add clear_environment() method (keeps project, clears env) - Update display_context() to show [org/project/env] format - Update org select to include environment fields - Add comprehensive tests for environment functionality Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9e0ad9a commit 41ec59b

2 files changed

Lines changed: 129 additions & 9 deletions

File tree

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,14 @@ pub async fn run_command(command: Commands) -> Result<()> {
516516

517517
match client.get_organization(&id).await {
518518
Ok(org) => {
519-
// Create session with org only (clear any project selection)
519+
// Create session with org only (clear any project/env selection)
520520
let session = PlatformSession {
521521
project_id: None,
522522
project_name: None,
523523
org_id: Some(org.id.clone()),
524524
org_name: Some(org.name.clone()),
525+
environment_id: None,
526+
environment_name: None,
525527
last_updated: Some(chrono::Utc::now()),
526528
};
527529

src/platform/session.rs

Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use std::fs;
99
use std::io;
1010
use std::path::PathBuf;
1111

12-
/// Platform session state - tracks selected project and organization
12+
/// Platform session state - tracks selected project, organization, and environment
1313
///
1414
/// This is a separate system from conversation persistence - it tracks
15-
/// which platform project/org the user has selected for platform operations.
15+
/// which platform project/org/environment the user has selected for platform operations.
1616
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1717
pub struct PlatformSession {
1818
/// Selected platform project UUID
@@ -23,6 +23,10 @@ pub struct PlatformSession {
2323
pub org_id: Option<String>,
2424
/// Organization name
2525
pub org_name: Option<String>,
26+
/// Selected environment UUID
27+
pub environment_id: Option<String>,
28+
/// Human-readable environment name
29+
pub environment_name: Option<String>,
2630
/// When the session was last updated
2731
pub last_updated: Option<DateTime<Utc>>,
2832
}
@@ -45,16 +49,47 @@ impl PlatformSession {
4549
project_name: Some(project_name),
4650
org_id: Some(org_id),
4751
org_name: Some(org_name),
52+
environment_id: None,
53+
environment_name: None,
4854
last_updated: Some(Utc::now()),
4955
}
5056
}
5157

52-
/// Clears the selected project
58+
/// Creates a platform session with a selected project and environment
59+
pub fn with_environment(
60+
project_id: String,
61+
project_name: String,
62+
org_id: String,
63+
org_name: String,
64+
environment_id: String,
65+
environment_name: String,
66+
) -> Self {
67+
Self {
68+
project_id: Some(project_id),
69+
project_name: Some(project_name),
70+
org_id: Some(org_id),
71+
org_name: Some(org_name),
72+
environment_id: Some(environment_id),
73+
environment_name: Some(environment_name),
74+
last_updated: Some(Utc::now()),
75+
}
76+
}
77+
78+
/// Clears the selected project and environment
5379
pub fn clear(&mut self) {
5480
self.project_id = None;
5581
self.project_name = None;
5682
self.org_id = None;
5783
self.org_name = None;
84+
self.environment_id = None;
85+
self.environment_name = None;
86+
self.last_updated = Some(Utc::now());
87+
}
88+
89+
/// Clears only the selected environment (keeps project)
90+
pub fn clear_environment(&mut self) {
91+
self.environment_id = None;
92+
self.environment_name = None;
5893
self.last_updated = Some(Utc::now());
5994
}
6095

@@ -63,6 +98,11 @@ impl PlatformSession {
6398
self.project_id.is_some()
6499
}
65100

101+
/// Returns true if an environment is currently selected
102+
pub fn is_environment_selected(&self) -> bool {
103+
self.environment_id.is_some()
104+
}
105+
66106
/// Returns the path to the platform session file
67107
///
68108
/// Location: `~/.syncable/platform-session.json`
@@ -105,11 +145,13 @@ impl PlatformSession {
105145

106146
/// Returns a display string for the current context
107147
///
108-
/// Format: "[org/project]" or "[no project selected]"
148+
/// Format: "[org/project/env]", "[org/project]", or "[no project selected]"
109149
pub fn display_context(&self) -> String {
110-
match (&self.org_name, &self.project_name) {
111-
(Some(org), Some(project)) => format!("[{}/{}]", org, project),
112-
(None, Some(project)) => format!("[{}]", project),
150+
match (&self.org_name, &self.project_name, &self.environment_name) {
151+
(Some(org), Some(project), Some(env)) => format!("[{}/{}/{}]", org, project, env),
152+
(Some(org), Some(project), None) => format!("[{}/{}]", org, project),
153+
(None, Some(project), Some(env)) => format!("[{}/{}]", project, env),
154+
(None, Some(project), None) => format!("[{}]", project),
113155
_ => "[no project selected]".to_string(),
114156
}
115157
}
@@ -157,7 +199,18 @@ mod tests {
157199

158200
#[test]
159201
fn test_display_context() {
160-
// Full context
202+
// Full context with environment
203+
let session = PlatformSession::with_environment(
204+
"id".to_string(),
205+
"project".to_string(),
206+
"oid".to_string(),
207+
"org".to_string(),
208+
"env-id".to_string(),
209+
"prod".to_string(),
210+
);
211+
assert_eq!(session.display_context(), "[org/project/prod]");
212+
213+
// Project only (no env)
161214
let session = PlatformSession::with_project(
162215
"id".to_string(),
163216
"project".to_string(),
@@ -172,6 +225,8 @@ mod tests {
172225
project_name: Some("project".to_string()),
173226
org_id: None,
174227
org_name: None,
228+
environment_id: None,
229+
environment_name: None,
175230
last_updated: None,
176231
};
177232
assert_eq!(session.display_context(), "[project]");
@@ -181,6 +236,69 @@ mod tests {
181236
assert_eq!(session.display_context(), "[no project selected]");
182237
}
183238

239+
#[test]
240+
fn test_with_environment() {
241+
let session = PlatformSession::with_environment(
242+
"proj-123".to_string(),
243+
"my-project".to_string(),
244+
"org-456".to_string(),
245+
"my-org".to_string(),
246+
"env-789".to_string(),
247+
"production".to_string(),
248+
);
249+
250+
assert!(session.is_project_selected());
251+
assert!(session.is_environment_selected());
252+
assert_eq!(session.project_id, Some("proj-123".to_string()));
253+
assert_eq!(session.environment_id, Some("env-789".to_string()));
254+
assert_eq!(session.environment_name, Some("production".to_string()));
255+
assert_eq!(session.display_context(), "[my-org/my-project/production]");
256+
}
257+
258+
#[test]
259+
fn test_clear_environment() {
260+
let mut session = PlatformSession::with_environment(
261+
"proj-123".to_string(),
262+
"my-project".to_string(),
263+
"org-456".to_string(),
264+
"my-org".to_string(),
265+
"env-789".to_string(),
266+
"production".to_string(),
267+
);
268+
269+
assert!(session.is_environment_selected());
270+
271+
session.clear_environment();
272+
273+
assert!(session.is_project_selected()); // Project still selected
274+
assert!(!session.is_environment_selected()); // Environment cleared
275+
assert_eq!(session.display_context(), "[my-org/my-project]");
276+
}
277+
278+
#[test]
279+
fn test_is_environment_selected() {
280+
let session = PlatformSession::new();
281+
assert!(!session.is_environment_selected());
282+
283+
let session = PlatformSession::with_project(
284+
"proj-123".to_string(),
285+
"my-project".to_string(),
286+
"org-456".to_string(),
287+
"my-org".to_string(),
288+
);
289+
assert!(!session.is_environment_selected());
290+
291+
let session = PlatformSession::with_environment(
292+
"proj-123".to_string(),
293+
"my-project".to_string(),
294+
"org-456".to_string(),
295+
"my-org".to_string(),
296+
"env-789".to_string(),
297+
"staging".to_string(),
298+
);
299+
assert!(session.is_environment_selected());
300+
}
301+
184302
#[test]
185303
fn test_save_and_load() {
186304
// Use a temp directory for testing

0 commit comments

Comments
 (0)