fix: preserve committed room results
This commit is contained in:
1 parent
184052fbce
commit
d0190bc11f
2 files changed
+95
-18
No files matched your search
@@ -236,6 +236,7 @@ beforeEach(() => {
|
||||
testState.auditEntries = [];
|
||||
vi.clearAllMocks();
|
||||
testState.rconSend.mockResolvedValue(true);
|
||||
testState.revalidate.mockImplementation(() => undefined);
|
||||
});
|
||||
|
||||
describe("legacy room actions through the Hotel mutation service", () => {
|
||||
@@ -449,6 +450,70 @@ describe("legacy room actions through the Hotel mutation service", () => {
|
||||
expect(revalidatePath).toHaveBeenCalledWith("/admin/rooms");
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
"item update",
|
||||
() => {
|
||||
testState.selectRows = [[itemRow()]];
|
||||
return updateRoomItem({ roomId: 7, itemId: 11, x: 4 });
|
||||
},
|
||||
"/admin/rooms/7/furni",
|
||||
],
|
||||
[
|
||||
"item delete",
|
||||
() => {
|
||||
testState.selectRows = [[itemRow()]];
|
||||
return deleteRoomItem({ roomId: 7, itemId: 11 });
|
||||
},
|
||||
"/admin/rooms/7/furni",
|
||||
],
|
||||
[
|
||||
"bulk item delete",
|
||||
() => {
|
||||
testState.selectRows = [[itemRow()]];
|
||||
return bulkDeleteRoomItems({ roomId: 7, itemIds: [11] });
|
||||
},
|
||||
"/admin/rooms/7/furni",
|
||||
],
|
||||
[
|
||||
"room update",
|
||||
() => {
|
||||
testState.selectRows = [[roomRow()]];
|
||||
return updateRoom({ id: 7, name: "After" });
|
||||
},
|
||||
"/admin/rooms/7",
|
||||
],
|
||||
[
|
||||
"room delete",
|
||||
() => {
|
||||
testState.selectRows = [[roomRow()]];
|
||||
return deleteRoom({ id: 7 });
|
||||
},
|
||||
"/admin/rooms",
|
||||
],
|
||||
])(
|
||||
"reports committed %s with refresh-needed context when revalidation fails",
|
||||
async (_name, invoke, path) => {
|
||||
testState.revalidate.mockImplementation(() => {
|
||||
throw new Error("cache unavailable");
|
||||
});
|
||||
|
||||
const result = await invoke();
|
||||
|
||||
expect(result).toMatchObject({
|
||||
ok: true,
|
||||
data: {
|
||||
committed: true,
|
||||
refreshNeeded: true,
|
||||
warning: expect.stringMatching(/saved.*refresh/i),
|
||||
},
|
||||
});
|
||||
expect(testState.committedWrites).toHaveLength(1);
|
||||
expect(testState.auditEntries).toHaveLength(1);
|
||||
expect(revalidatePath).toHaveBeenCalledWith(path);
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects invalid runtime actions before RCON delivery", async () => {
|
||||
const result = await roomRconAction({ roomId: 7, action: "explode" });
|
||||
expectFailure(result, /invalid/i);
|
||||
|
||||
+30
-18
@@ -58,17 +58,32 @@ function notifyBestEffort(payload: Parameters<typeof notify>[0]): void {
|
||||
}
|
||||
}
|
||||
|
||||
function revalidateCommittedPath(path: string): ActionResult {
|
||||
try {
|
||||
revalidatePath(path);
|
||||
return actionOk();
|
||||
} catch {
|
||||
return actionOk({
|
||||
committed: true,
|
||||
refreshNeeded: true,
|
||||
warning:
|
||||
"Changes were saved, but the page could not refresh automatically. Refresh the page before trying the action again.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateRoomItem(
|
||||
payload: Record<string, unknown>,
|
||||
): Promise<ActionResult> {
|
||||
const staff = await requirePermission(PERMS.ROOMS_EDIT);
|
||||
try {
|
||||
await executeLegacyHotelMutation(staff, "room-item.update", payload);
|
||||
revalidatePath(`/admin/rooms/${String(payload.roomId)}/furni`);
|
||||
return actionOk();
|
||||
} catch (error) {
|
||||
return actionFailure(error);
|
||||
}
|
||||
return revalidateCommittedPath(
|
||||
`/admin/rooms/${String(payload.roomId)}/furni`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function bulkDeleteRoomItems(payload: {
|
||||
@@ -78,11 +93,10 @@ export async function bulkDeleteRoomItems(payload: {
|
||||
const staff = await requirePermission(PERMS.ROOMS_EDIT);
|
||||
try {
|
||||
await executeLegacyHotelMutation(staff, "room-item.bulk-delete", payload);
|
||||
revalidatePath(`/admin/rooms/${payload.roomId}/furni`);
|
||||
return actionOk();
|
||||
} catch (error) {
|
||||
return actionFailure(error);
|
||||
}
|
||||
return revalidateCommittedPath(`/admin/rooms/${payload.roomId}/furni`);
|
||||
}
|
||||
|
||||
export async function deleteRoomItem(payload: {
|
||||
@@ -92,11 +106,10 @@ export async function deleteRoomItem(payload: {
|
||||
const staff = await requirePermission(PERMS.ROOMS_EDIT);
|
||||
try {
|
||||
await executeLegacyHotelMutation(staff, "room-item.delete", payload);
|
||||
revalidatePath(`/admin/rooms/${payload.roomId}/furni`);
|
||||
return actionOk();
|
||||
} catch (error) {
|
||||
return actionFailure(error);
|
||||
}
|
||||
return revalidateCommittedPath(`/admin/rooms/${payload.roomId}/furni`);
|
||||
}
|
||||
|
||||
export async function roomRconAction(payload: {
|
||||
@@ -124,25 +137,25 @@ export async function deleteRoom(payload: {
|
||||
id: number;
|
||||
}): Promise<ActionResult> {
|
||||
const staff = await requirePermission(PERMS.ROOMS_DELETE);
|
||||
let target = `#${payload.id}`;
|
||||
try {
|
||||
const snapshot = await executeLegacyHotelMutation(
|
||||
staff,
|
||||
"room.delete",
|
||||
payload,
|
||||
);
|
||||
notifyBestEffort({
|
||||
action: "room_delete",
|
||||
actor: staff.username,
|
||||
target:
|
||||
typeof snapshot.before?.name === "string"
|
||||
? snapshot.before.name
|
||||
: `#${payload.id}`,
|
||||
});
|
||||
revalidatePath("/admin/rooms");
|
||||
return actionOk();
|
||||
if (typeof snapshot.before?.name === "string") {
|
||||
target = snapshot.before.name;
|
||||
}
|
||||
} catch (error) {
|
||||
return actionFailure(error);
|
||||
}
|
||||
notifyBestEffort({
|
||||
action: "room_delete",
|
||||
actor: staff.username,
|
||||
target,
|
||||
});
|
||||
return revalidateCommittedPath("/admin/rooms");
|
||||
}
|
||||
|
||||
export async function updateRoom(payload: {
|
||||
@@ -155,9 +168,8 @@ export async function updateRoom(payload: {
|
||||
const staff = await requirePermission(PERMS.ROOMS_EDIT);
|
||||
try {
|
||||
await executeLegacyHotelMutation(staff, "room.update", payload);
|
||||
revalidatePath(`/admin/rooms/${payload.id}`);
|
||||
return actionOk();
|
||||
} catch (error) {
|
||||
return actionFailure(error);
|
||||
}
|
||||
return revalidateCommittedPath(`/admin/rooms/${payload.id}`);
|
||||
}
|
||||
Reference in new issue
Block a user