sidebar: click-to-rename org/company/team + strip synthetics from world viz
Two related pieces of the "kill My Workspace" cleanup, landed
together because they share the same file:
Backend
- Three tiny inline-rename endpoints:
PATCH /api/orgs/{id}/name
PATCH /api/companies/{id}/name
PATCH /api/teams/{id}/name
Each takes { name: string }, trims + rejects empty, returns 204.
Backed by rename_org / rename_company / rename_team in cm-db —
single-row UPDATEs scoped to the caller's workspace, NotFound if
the id isn't visible.
- Registered next to the existing PATCH /:id (topology) routes so
they don't collide.
Frontend
- StructureTree accepts an optional onRename and canRename.
TreeRow: click on the label text of a renamable node → the span
becomes an <input>, focus + select-all, save on Enter or blur,
cancel on Escape. The rest of the row (row chevron / row body)
still navigates + selects as before, so single-click behaviour
is preserved for everything except the name text itself.
react-hooks/set-state-in-effect avoided by resetting the draft
in the enterEdit() click handler instead of inside a useEffect.
- Dashboard passes canRename={item.level !== "claw" && !synthetic}
(claws don't have a rename endpoint yet; synthetic scaffolding
gets reified into real rows in the next commit — the wizard
auto-materialize + orphan-migration dialog).
onRename fires the corresponding PATCH and calls router.refresh()
so the label lands in every consumer of the tree.
- World viz seed: new stripSynthetics(roots) helper walks the tree
and lifts children of any synthetic container up to their
grandparent's level. worldCanvasRoots feeds through this before
narrowRoots(). Result: the Live viz no longer shows "My Workspace"
or "Teams" nodes — real agents orbit the world root directly
(which is what you were asking for). Sidebar tree still shows
them so orphaned agents remain visible until the migration lands.
This commit is contained in:
@@ -152,6 +152,27 @@ pub struct OrgDetail {
|
||||
}
|
||||
|
||||
/// `GET /api/orgs/{id}` — an org's graph + node→company bindings.
|
||||
/// `PATCH /api/orgs/{id}/name` — inline rename from the sidebar. Trims the
|
||||
/// input and rejects empty; returns 204 on success, 404 if the id isn't
|
||||
/// visible in the caller's workspace.
|
||||
#[derive(Deserialize)]
|
||||
pub struct RenameOrgRequest {
|
||||
pub name: String,
|
||||
}
|
||||
pub async fn rename_org(
|
||||
State(state): State<AppState>,
|
||||
Authed(user): Authed,
|
||||
Path(id): Path<Uuid>,
|
||||
Json(body): Json<RenameOrgRequest>,
|
||||
) -> Result<StatusCode, ApiError> {
|
||||
let name = body.name.trim();
|
||||
if name.is_empty() {
|
||||
return Err(ApiError::BadRequest);
|
||||
}
|
||||
cm_db::repo::orgs::rename_org(&state.pool, id, user.workspace_id, name).await?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
/// `DELETE /api/orgs/{id}` — remove the org (structural: companies survive, just
|
||||
/// ungrouped from it).
|
||||
pub async fn delete_org(
|
||||
|
||||
Reference in New Issue
Block a user