fix(web): права в шапке сервера обновляются после выдачи роли
По MEMBER_UPDATE/ROLE_* клиент перечитывал участников, роли и комнаты, но
не сводку сервера: `my_permissions` в сторе сессии оставались прежними, и
кнопки управления (🔗 приглашение, ⚙ настройки, + комната) появлялись
только после перезагрузки. Матрица 11.6 требует, чтобы права сразу меняли
доступные действия (AGENT.md 11.6).
- в ветках `MEMBER_UPDATE`/`MEMBER_REMOVE` и `ROLE_*` вызывается
`addGuildFromRest` — сводка сервера перечитывается и мержится;
- vitest: кнопки появляются по событию (тест падает без правки).
This commit is contained in:
@@ -295,6 +295,9 @@ export function dispatchGatewayEvent(event: GatewayDispatch): void {
|
|||||||
if (guildId !== null) {
|
if (guildId !== null) {
|
||||||
void invalidateMembershipQueries(guildId);
|
void invalidateMembershipQueries(guildId);
|
||||||
session.scheduleGuildChannelsReload(guildId);
|
session.scheduleGuildChannelsReload(guildId);
|
||||||
|
// Свои права после выдачи роли обновляет только сводка сервера: без
|
||||||
|
// неё кнопки управления в шапке появлялись лишь после перезагрузки.
|
||||||
|
void addGuildFromRest(guildId);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -305,6 +308,8 @@ export function dispatchGatewayEvent(event: GatewayDispatch): void {
|
|||||||
if (role !== null) {
|
if (role !== null) {
|
||||||
void invalidateMembershipQueries(role.guild_id);
|
void invalidateMembershipQueries(role.guild_id);
|
||||||
session.scheduleGuildChannelsReload(role.guild_id);
|
session.scheduleGuildChannelsReload(role.guild_id);
|
||||||
|
// Права роли могли измениться и у меня: обновляем сводку сервера.
|
||||||
|
void addGuildFromRest(role.guild_id);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ const user = makeUser();
|
|||||||
|
|
||||||
const channels = [{ id: 'c-general', name: 'общий', type: 'text' as const, position: 0 }];
|
const channels = [{ id: 'c-general', name: 'общий', type: 'text' as const, position: 0 }];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Права, которые отдаёт REST-сводка сервера: тест выдачи роли меняет их и
|
||||||
|
* проверяет, что клиент перечитал сводку по событию MEMBER_UPDATE.
|
||||||
|
*/
|
||||||
|
let restPermissions: string[] | null = null;
|
||||||
|
|
||||||
function guildSummary(overrides: Record<string, unknown> = {}) {
|
function guildSummary(overrides: Record<string, unknown> = {}) {
|
||||||
return {
|
return {
|
||||||
id: 'g-1',
|
id: 'g-1',
|
||||||
@@ -79,7 +85,17 @@ function routes(guild: Record<string, unknown> = guildDetail()): FetchRoute[] {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
response: () => json({ guild: guildDetail({ icon_file_id: '777', banner_file_id: '555' }) }),
|
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/users/@me', response: () => json({ user }) },
|
||||||
{ match: '/api/v1/instance', response: () => json({ instance: { name: 'glchat-test' } }) },
|
{ match: '/api/v1/instance', response: () => json({ instance: { name: 'glchat-test' } }) },
|
||||||
{ match: '/api/v1/guilds/g-1/members', response: () => json({ members: [] }) },
|
{ match: '/api/v1/guilds/g-1/members', response: () => json({ members: [] }) },
|
||||||
@@ -122,6 +138,7 @@ async function bootApp(guild: Record<string, unknown> = guildDetail()) {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetStores();
|
resetStores();
|
||||||
|
restPermissions = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('оформление сервера в шапке и рейке', () => {
|
describe('оформление сервера в шапке и рейке', () => {
|
||||||
@@ -217,6 +234,25 @@ describe('приглашение из шапки сервера', () => {
|
|||||||
await screen.findByTestId('guild-header');
|
await screen.findByTestId('guild-header');
|
||||||
expect(screen.queryByTestId('guild-invite')).toBeNull();
|
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('встроенные звуки интерфейса', () => {
|
describe('встроенные звуки интерфейса', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user