structure polish: post-reify nav + ensure-chain + TeamWizard auto-parent
Two small quality-of-life fixes on top of the reify commit:
Post-reify navigation
OrphanMigrationDialog already returned team_id in its result;
Dashboard now pushes /?team=<team_id> before router.refresh() so
the user lands on the freshly-materialized team and sees exactly
where their agents just moved. Previously they had to hunt for it
in the newly-rebuilt sidebar.
Wizard auto-materialize (POST /api/structure/ensure-chain)
cm-db: ensure_chain(pool, ws, fallback_org, fallback_company) —
fast path returns coordinates of the first org+company already
bound in this workspace (workspace's oldest org, oldest company
under it). Slow path inserts a new org+company with the
fallback names ("My Workspace" / "General") + binds them via
org_companies. Returns { org_id, company_id, created }. Small
txn — leaves the workspace consistent whether it was already
wired or not.
cm-api: POST /api/structure/ensure-chain accepts optional
fallback_org_name and fallback_company_name in the body (trimmed,
else default). Returns the ids.
CreateTeamRequest gains an optional attach_to_company_id. When
set, after build_team() completes, we look up the company
(workspace ownership check enforced by companies::get), count
its existing teams for a stable n_i node id, and insert a
company_teams binding — so the team lands under the parent
atomically instead of a follow-up round-trip.
TeamWizard now calls ensure-chain before POST /api/teams and
passes the returned company_id in attach_to_company_id. Both
calls are best-effort — if ensure-chain fails (network etc.)
we still try to create the team, and the migration dialog stays
available as the fallback UX. Wizard flow now: fresh workspace's
first team is fully wired from the moment it appears in the
tree — no synthetic "My Workspace" scaffolding ever gets
rendered around it.
The Team/Company create paths not touched here (create_team_from_claws,
company create, org create, MasterPlannerModal scaffold) still
work as before — they just won't auto-parent yet. Later commits
can wire them the same way.
This commit is contained in:
@@ -210,6 +210,58 @@ pub async fn orphan_counts(
|
||||
}))
|
||||
}
|
||||
|
||||
/// `POST /api/structure/ensure-chain` — guarantee the workspace has an
|
||||
/// org + company chain and return coordinates for it. Idempotent: reuses
|
||||
/// existing rows when present, creates placeholder ones otherwise.
|
||||
/// Wizards call this before creating a team so first-team-in-a-fresh-
|
||||
/// workspace lands under real parents instead of synthesized scaffolding.
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct EnsureChainRequest {
|
||||
/// Placeholder name used only if we have to CREATE the org.
|
||||
#[serde(default)]
|
||||
pub fallback_org_name: Option<String>,
|
||||
/// Placeholder name used only if we have to CREATE the company.
|
||||
#[serde(default)]
|
||||
pub fallback_company_name: Option<String>,
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
pub struct EnsuredChainOut {
|
||||
pub org_id: String,
|
||||
pub company_id: String,
|
||||
/// `true` when either row was freshly created by this call.
|
||||
pub created: bool,
|
||||
}
|
||||
pub async fn ensure_chain(
|
||||
State(state): State<AppState>,
|
||||
Authed(user): Authed,
|
||||
Json(body): Json<EnsureChainRequest>,
|
||||
) -> Result<Json<EnsuredChainOut>, ApiError> {
|
||||
let org_name = body
|
||||
.fallback_org_name
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or("My Workspace");
|
||||
let company_name = body
|
||||
.fallback_company_name
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or("General");
|
||||
let r = cm_db::repo::structure_reify::ensure_chain(
|
||||
&state.pool,
|
||||
user.workspace_id,
|
||||
org_name,
|
||||
company_name,
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(EnsuredChainOut {
|
||||
org_id: r.org_id.to_string(),
|
||||
company_id: r.company_id.to_string(),
|
||||
created: r.created,
|
||||
}))
|
||||
}
|
||||
|
||||
/// `POST /api/structure/reify-orphans` — create a real org+company+team
|
||||
/// chain with the provided names and re-parent every orphan into it, all
|
||||
/// in one transaction. Returns the freshly-created ids so the client can
|
||||
|
||||
Reference in New Issue
Block a user