feat(audit): undo button for merges, hide manual games
Build, Test & Push Frontend / quality-check (push) Successful in 31s
Build, Test & Push Frontend / docker (push) Successful in 23s

The audit log shows Undo on a merge row for 30 days, with a confirm
dialog and clear errors. The details page follows a merged key to the
kept game. Hide and Show now work for manual games too. de/en texts.
This commit is contained in:
lobo committed 2026-10-02 13:39:02 +02:00
1 parent 0c300c455d
commit ae904d946a
9 files changed
+189 -57

No files matched your search

+25 -6
View File
@@ -64,7 +64,7 @@ describe('GameDetail', () => {
});
it('keeps the game shown when Core refuses', async () => {
answer({...game, source: 'STEAM', hidden: false}, {'PUT /api/library/games/220/hidden': json(409, {code: 'MANUAL_GAME'})});
answer({...game, source: 'STEAM', hidden: false}, {'PUT /api/library/games/220/hidden': json(500, {})});
renderDetail();
fireEvent.click(await screen.findByRole('button', {name: 'GAME_DETAIL.HIDE'}));
@@ -73,12 +73,19 @@ describe('GameDetail', () => {
expect(screen.queryByText('GAME_DETAIL.HIDDEN_NOTE')).toBeNull();
});
it('offers no hide for a game added by hand', async () => {
answer({...game, source: 'MANUAL', platform: 'PS5', hidden: false});
renderDetail();
it('hides a game added by hand and shows it again', async () => {
answer({...game, appid: -1942, source: 'MANUAL', platform: 'PS5', hidden: false},
{'PUT /api/library/games/-1942/hidden': echo});
renderDetail(-1942);
await screen.findByText('GAME_DETAIL.OPEN_IN_STEAM');
expect(screen.queryByRole('button', {name: 'GAME_DETAIL.HIDE'})).toBeNull();
fireEvent.click(await screen.findByRole('button', {name: 'GAME_DETAIL.HIDE'}));
expect(await screen.findByText('GAME_DETAIL.HIDDEN_NOTE')).toBeTruthy();
expect(screen.queryByText('GAME_DETAIL.OPEN_IN_STEAM')).toBeNull();
fireEvent.click(screen.getByRole('button', {name: 'GAME_DETAIL.UNHIDE'}));
await waitFor(() => expect(screen.queryByText('GAME_DETAIL.HIDDEN_NOTE')).toBeNull());
});
it('reports a broken achievement icon once and shows the empty tile', async () => {
@@ -419,4 +426,16 @@ describe('GameDetail session', () => {
expect(toast.error).not.toHaveBeenCalled();
expect(screen.queryByText('GAME_DETAIL.ERROR_LOAD')).toBeNull();
});
it('replacesTheUrlOfAMergedKeyWithTheKeptGame', async () => {
fetchRoutes({
'GET /api/users/me': json(200, {settings: {}}),
'GET /api/library/games/-7': json(200, {...game, appid: 220, source: 'STEAM'}),
'GET /api/library/games/220': json(200, {...game, appid: 220, source: 'STEAM'}),
});
const {router} = renderDetail(-7);
await waitFor(() => expect(router.state.location.pathname).toBe('/library/220'));
expect(router.state.historyAction).toBe('REPLACE');
});
});