Skip to content

Commit bbaee67

Browse files
authored
Merge pull request #38 from datum-cloud/feat/ui-org-project
feat: add org/project selection flow and selected context plumbing
2 parents 49a36ae + a0de3ce commit bbaee67

File tree

14 files changed

+919
-16
lines changed

14 files changed

+919
-16
lines changed

Cargo.lock

Lines changed: 15 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ tokio-util = "0.7.10"
3939
tower = "0.5"
4040
tracing = "0.1.40"
4141
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
42+
tracing-appender = "0.2"
4243
data-encoding = "2.9.0"
4344
n0-error = { version = "0.1", features = ["anyhow"] }
4445
n0-future = "0.3"

lib/src/datum_cloud.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ pub struct Organization {
170170
pub r#type: String,
171171
}
172172

173+
#[derive(Debug, Clone)]
173174
pub struct OrganizationWithProjects {
174175
pub org: Organization,
175176
pub projects: Vec<Project>,

lib/src/node.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ use tracing::{Instrument, debug, error, error_span, info, instrument, warn};
2424
use ttl_cache::TtlCache;
2525

2626
use crate::{
27-
Advertisment, ProxyState, Repo, StateWrapper, TcpProxyData, config::Config,
28-
state::AdvertismentTicket,
27+
Advertisment, ProxyState, Repo, SelectedContext, StateWrapper, TcpProxyData, config::Config,
28+
datum_cloud::DatumCloudClient, state::AdvertismentTicket,
2929
};
3030

3131
const TICKET_TTL: Duration = Duration::from_secs(30);
@@ -135,6 +135,55 @@ impl ListenNode {
135135
self.state.get().proxies.iter().cloned().collect()
136136
}
137137

138+
pub fn selected_context(&self) -> Option<SelectedContext> {
139+
self.state.get().selected_context.clone()
140+
}
141+
142+
pub async fn set_selected_context(
143+
&self,
144+
selected_context: Option<SelectedContext>,
145+
) -> Result<()> {
146+
info!(
147+
selected = %selected_context
148+
.as_ref()
149+
.map_or("<none>".to_string(), SelectedContext::label),
150+
"node: updating selected context"
151+
);
152+
self.state
153+
.update(&self.repo, |state| {
154+
state.selected_context = selected_context;
155+
})
156+
.await?;
157+
Ok(())
158+
}
159+
160+
pub async fn validate_selected_context(
161+
&self,
162+
datum: &DatumCloudClient,
163+
) -> Result<Option<SelectedContext>> {
164+
let selected = self.selected_context();
165+
let Some(selected) = selected else {
166+
return Ok(None);
167+
};
168+
169+
let orgs = datum.orgs_and_projects().await?;
170+
let is_valid = orgs.iter().any(|org| {
171+
if org.org.resource_id != selected.org_id {
172+
return false;
173+
}
174+
org.projects
175+
.iter()
176+
.any(|project| project.resource_id == selected.project_id)
177+
});
178+
179+
if is_valid {
180+
Ok(Some(selected))
181+
} else {
182+
self.set_selected_context(None).await?;
183+
Ok(None)
184+
}
185+
}
186+
138187
pub fn proxy_by_id(&self, id: &str) -> Option<ProxyState> {
139188
self.state
140189
.get()

lib/src/state.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use crate::{DATUM_CONNECT_GATEWAY_DOMAIN_NAME, Repo};
1515
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
1616
pub struct State {
1717
pub proxies: Vec<ProxyState>,
18+
#[serde(default)]
19+
pub selected_context: Option<SelectedContext>,
1820
}
1921

2022
impl State {
@@ -43,6 +45,20 @@ impl State {
4345
}
4446
}
4547

48+
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
49+
pub struct SelectedContext {
50+
pub org_id: String,
51+
pub org_name: String,
52+
pub project_id: String,
53+
pub project_name: String,
54+
}
55+
56+
impl SelectedContext {
57+
pub fn label(&self) -> String {
58+
format!("{} / {}", self.org_name, self.project_name)
59+
}
60+
}
61+
4662
#[derive(Debug, Clone)]
4763
pub struct StateWrapper {
4864
inner: Arc<ArcSwap<State>>,

ui/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ tokio.workspace = true
2727
tokio-util.workspace = true
2828
tracing.workspace = true
2929
tracing-subscriber.workspace = true
30+
tracing-appender.workspace = true
3031
data-encoding.workspace = true
3132
uuid.workspace = true
3233
n0-error.workspace = true

ui/src/components/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ mod hero;
77
mod bandwidth_timeseries_chart;
88
mod button;
99
mod head;
10+
mod select_dropdown;
1011
mod splash;
1112
mod typography;
1213

1314
pub use button::Button;
1415
pub use button::ButtonKind;
1516
pub use head::Head;
17+
pub use select_dropdown::{SelectDropdown, SelectItem};
1618
pub use splash::Splash;
1719
#[allow(unused)]
1820
pub use typography::Subhead;

0 commit comments

Comments
 (0)