mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 10:39:32 +01:00
fix(tabs): keep the case-default GET read-only, forget a stale id outside the rollback
Merge-time fix for #676 (review nits 4 and 5). sessionCreated forgot a stale case default inside the try whose catch rolls the registration back; it now does so after the try, once the session is committed, so the cleanup can never drop a committed session from the live map. caseDefaultGroup (behind GET /api/cases/:name/default-group) no longer deletes a stale id as a side effect: it reports Ungrouped and leaves the value for the next creation to forget. The two tests that expected the read to clear it now expect it to write nothing; the creation test still pins the cleanup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3ca1d4832e
commit
a3efc9b963
5 files changed
+23
-18
No files matched your search
+12
-12
@@ -584,6 +584,7 @@ export class TabLayoutService {
|
||||
const caseDefault = caseName ? this.deps.caseDefaults?.getCaseDefaultGroup(owner, caseName) : undefined;
|
||||
let staleCaseDefault = false;
|
||||
const rollback = register?.();
|
||||
let layout: TabLayout;
|
||||
try {
|
||||
const groupId = placement.tabGroupId;
|
||||
const adjust =
|
||||
@@ -600,33 +601,32 @@ export class TabLayoutService {
|
||||
return follow ? placed : pinCreatedChild(placed, sessionId, metadata);
|
||||
}
|
||||
: undefined;
|
||||
const layout = await this.getUnlocked(owner, adjust);
|
||||
// A default whose group was deleted is ignored above and forgotten here,
|
||||
// only once the creation's own write has landed.
|
||||
if (staleCaseDefault && caseName) this.deps.caseDefaults?.deleteCaseDefaultGroup(owner, caseName);
|
||||
return layout;
|
||||
layout = await this.getUnlocked(owner, adjust);
|
||||
} catch (error) {
|
||||
if (typeof rollback === 'function') rollback();
|
||||
throw error;
|
||||
}
|
||||
// A default whose group was deleted is ignored above and forgotten here, only once the
|
||||
// creation's own write has landed, and outside the rollback: the session is committed by now,
|
||||
// and nothing this cleanup does may drop it from the live map.
|
||||
if (staleCaseDefault && caseName) this.deps.caseDefaults?.deleteCaseDefaultGroup(owner, caseName);
|
||||
return layout;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A case's default session group and the owner's named groups to choose from.
|
||||
* A stored id that is no longer one of this owner's groups is forgotten and
|
||||
* reported as `null` (Ungrouped), which is also where creation would put it.
|
||||
* A stored id that is no longer one of this owner's groups is reported as
|
||||
* `null` (Ungrouped), which is also where creation would put it. Read-only:
|
||||
* the next creation for the case forgets the stale id.
|
||||
*/
|
||||
async caseDefaultGroup(owner: string, caseName: string): Promise<CaseDefaultGroupView> {
|
||||
return this.withOwner(owner, async () => {
|
||||
const { authoritative } = await this.prepareUnlocked(owner);
|
||||
const groups = authoritative.groups.map((group) => ({ id: group.id, name: group.name }));
|
||||
const stored = this.deps.caseDefaults?.getCaseDefaultGroup(owner, caseName);
|
||||
if (typeof stored === 'string' && !groups.some((group) => group.id === stored)) {
|
||||
this.deps.caseDefaults?.deleteCaseDefaultGroup(owner, caseName);
|
||||
return { groupId: null, groups };
|
||||
}
|
||||
return { groupId: typeof stored === 'string' ? stored : null, groups };
|
||||
const known = typeof stored === 'string' && groups.some((group) => group.id === stored);
|
||||
return { groupId: known ? stored : null, groups };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1717,7 +1717,8 @@ export function registerCaseRoutes(
|
||||
* The tab group new sessions of this case land in when the create request names
|
||||
* no group and no parent places them. Scoped to the caller's own tab layout: the
|
||||
* options are their groups, and a stored id that is no longer one of them reads
|
||||
* as Ungrouped (null) and is forgotten. Not admin-gated in multi-user mode: the
|
||||
* as Ungrouped (null); the read writes nothing (the next creation for the case
|
||||
* forgets it). Not admin-gated in multi-user mode: the
|
||||
* value is per owner (like the layout it points into), never server-wide.
|
||||
*/
|
||||
app.get('/api/cases/:name/default-group', async (req, reply) => {
|
||||
|
||||
Reference in new issue
Block a user