feat: retention rules become editable, space lifecycle reaches the admin UI, membership stops lying about who owns it #333
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/cluster-c"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Deferred-items cluster C (#311 items 1, 6, 13, 14, 15, 16). Item 2 deferred to #138 by decision.
The headline finding: most of this was never a backend problem
The deferred list described seven items blocked on missing endpoints. Reading the code, four of them were already served and simply never consumed:
auditQueryhas always parsedfrom/toas RFC3339 intoaudit.Filter. Only the two inputs were missing. Recorded as "endpoint support unconfirmed".POST .../deactivate,POST .../reactivateandDELETE /api/v1/spaces/{name}have existed since #286. Recorded as "admin API unconfirmed"./admin/infoalready returnsstorageDriverandshareCount. Overview never read them.RetentionPeriodsis amap[string]string, not free text. The textarea is a serialisation of structured data, so there was no grammar to reverse-engineer — which was my stated blocker in slice D, and it was wrong.So the backend change here is one endpoint and one boolean, not seven endpoints.
Retention rules are now editable rows (item 15)
You picked the control panel over the read-only window, and building it justified the choice: the mockup's typo case is a real bug in today's UI. A mistyped prefix in the textarea is accepted in silence and protects nothing — no error, no warning, and you find out when a file you believed was held gets purged. Rows can validate the path against the instance; a textarea cannot.
Two safeguards, as agreed:
saveSettingsis untouched — it still reads$("set-retention").valueand parses it. The rows can only ever produce something that round-trips through the format the server already accepts. The textarea becomes read-only and moves into a "Rules as stored" disclosure, which is therefore literally the stored form rather than a rendering of it.Durations are a select of named windows plus Custom…, because storage is arbitrary Go durations and a fixed list would quietly make existing rules uneditable.
One endpoint, with one algorithm (item 16)
GET /api/v1/admin/retention/resolve?path=returns the server's own answer.RetentionForand the newRetentionRuleFornow share one implementation, so the endpoint and the trash sweep can never disagree about a floor. Test-first, and the test is the interesting part: it pins the segment-boundary rule, so/spaces/legalcan never silently cover/spaces/legalese, and it assertsRetentionForandRetentionRuleForalways agree.The red step is enforced in CI, not just claimed — the workflow fails if the test passes before the implementation exists.
Membership stops offering edits the IdP owns (item 1 / #129)
listMembersalready branched ons.Mgr != nilto decide whether membership comes from the directory; it just never told the client. It now returnsidpManaged, and the dialog shows the notice that has been shipping hidden since the redesign, disables Add/role/Remove, and stops rendering remove buttons. Previously the dialog offered three actions the identity provider would overwrite.Controls are disabled rather than hidden, so the notice above them explains why — a row that vanishes teaches nothing.
Space lifecycle (item 13)
Deactivate / Reactivate / Delete on each row of the admin inventory. Delete only appears once a space is deactivated, because the server returns 409 otherwise — better to show the required order than to let someone discover it as an error. Deletion is confirmed by typing the space name, since it moves every file into the trash and reserves the name for the retention window.
Not done, deliberately
/dataJSON now means handing that milestone one more thing to migrate.Gate:
go vet ./...,go test ./...(full suite green including the new settings tests and the webcheck guard),go build ./cmd/cairnd,node --checkon every script block. All new i18n keys populated in four languages.