From cf36488e6f5dc39cefd12714d4ac2a4ecaebd349 Mon Sep 17 00:00:00 2001 From: grendervill Date: Sat, 26 Sep 2026 11:06:32 +0300 Subject: [PATCH] =?UTF-8?q?fix(web):=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=B2=20=D1=88=D0=B0=D0=BF=D0=BA=D0=B5=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=B0=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=87=D0=B8=20=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit По MEMBER_UPDATE/ROLE_* клиент перечитывал участников, роли и комнаты, но не сводку сервера: `my_permissions` в сторе сессии оставались прежними, и кнопки управления (🔗 приглашение, ⚙ настройки, + комната) появлялись только после перезагрузки. Матрица 11.6 требует, чтобы права сразу меняли доступные действия (AGENT.md 11.6). - в ветках `MEMBER_UPDATE`/`MEMBER_REMOVE` и `ROLE_*` вызывается `addGuildFromRest` — сводка сервера перечитывается и мержится; - vitest: кнопки появляются по событию (тест падает без правки). --- web/src/stores/gateway.ts | 5 ++++ web/tests/guildHeaderAndSounds.test.tsx | 38 ++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/web/src/stores/gateway.ts b/web/src/stores/gateway.ts index 05b0e65..0abd83d 100644 --- a/web/src/stores/gateway.ts +++ b/web/src/stores/gateway.ts @@ -295,6 +295,9 @@ export function dispatchGatewayEvent(event: GatewayDispatch): void { if (guildId !== null) { void invalidateMembershipQueries(guildId); session.scheduleGuildChannelsReload(guildId); + // Свои права после выдачи роли обновляет только сводка сервера: без + // неё кнопки управления в шапке появлялись лишь после перезагрузки. + void addGuildFromRest(guildId); } return; } @@ -305,6 +308,8 @@ export function dispatchGatewayEvent(event: GatewayDispatch): void { if (role !== null) { void invalidateMembershipQueries(role.guild_id); session.scheduleGuildChannelsReload(role.guild_id); + // Права роли могли измениться и у меня: обновляем сводку сервера. + void addGuildFromRest(role.guild_id); } return; } diff --git a/web/tests/guildHeaderAndSounds.test.tsx b/web/tests/guildHeaderAndSounds.test.tsx index 7579949..1028ca0 100644 --- a/web/tests/guildHeaderAndSounds.test.tsx +++ b/web/tests/guildHeaderAndSounds.test.tsx @@ -33,6 +33,12 @@ const user = makeUser(); const channels = [{ id: 'c-general', name: 'общий', type: 'text' as const, position: 0 }]; +/** + * Права, которые отдаёт REST-сводка сервера: тест выдачи роли меняет их и + * проверяет, что клиент перечитал сводку по событию MEMBER_UPDATE. + */ +let restPermissions: string[] | null = null; + function guildSummary(overrides: Record = {}) { return { id: 'g-1', @@ -79,7 +85,17 @@ function routes(guild: Record = guildDetail()): FetchRoute[] { method: 'POST', response: () => json({ guild: guildDetail({ icon_file_id: '777', banner_file_id: '555' }) }), }, - { match: '/api/v1/users/@me/guilds', response: () => json({ guilds: [guildSummary(guild)] }) }, + { + match: '/api/v1/users/@me/guilds', + response: () => + json({ + guilds: [ + guildSummary( + restPermissions === null ? guild : { ...guild, my_permissions: restPermissions }, + ), + ], + }), + }, { match: '/api/v1/users/@me', response: () => json({ user }) }, { match: '/api/v1/instance', response: () => json({ instance: { name: 'glchat-test' } }) }, { match: '/api/v1/guilds/g-1/members', response: () => json({ members: [] }) }, @@ -122,6 +138,7 @@ async function bootApp(guild: Record = guildDetail()) { beforeEach(() => { resetStores(); + restPermissions = null; }); describe('оформление сервера в шапке и рейке', () => { @@ -217,6 +234,25 @@ describe('приглашение из шапки сервера', () => { await screen.findByTestId('guild-header'); expect(screen.queryByTestId('guild-invite')).toBeNull(); }); + + it('появляет кнопки после выдачи роли, без перезагрузки', async () => { + // Роль выдали уже в открытом клиенте: сводка сервера перечитывается по + // MEMBER_UPDATE, иначе кнопки управления ждали бы перезагрузки (AGENT.md 11.6). + const { gateway } = await bootApp(guildDetail({ my_permissions: [], owner_id: 'user-9' })); + await screen.findByTestId('guild-header'); + expect(screen.queryByTestId('guild-invite')).toBeNull(); + + restPermissions = ['MANAGE_GUILD', 'CREATE_INVITES']; + act(() => { + gateway.dispatch('MEMBER_UPDATE', { guild_id: 'g-1', user_id: 'user-1' }); + }); + + await waitFor(() => { + expect(screen.getByTestId('guild-invite')).toBeInTheDocument(); + }); + expect(screen.getByLabelText('Настройки сервера')).toBeInTheDocument(); + expect(screen.getByLabelText('Создать комнату')).toBeInTheDocument(); + }); }); describe('встроенные звуки интерфейса', () => {