refactor(team): extract data request keys

This commit is contained in:
777genius 2026-05-22 09:42:02 +03:00
parent 1d2f61ad86
commit 69f7a21771
3 changed files with 106 additions and 34 deletions

View file

@ -29,6 +29,14 @@ import {
isTeamTaskNeedsFixActionable,
} from '@shared/utils/teamTaskState';
import {
getFullTeamDataRequestKey,
getTeamDataRequestKey,
getTeamDataRequestLabel,
getThinTeamDataRequestKey,
isTeamDataRequestKeyForTeam,
normalizeTeamGetDataOptions,
} from '../team/teamDataRequestKeys';
import { selectTeamDataForName } from '../team/teamDataSelectors';
import {
areInboxMessageArraysEquivalent,
@ -155,38 +163,6 @@ interface RefreshTeamDataOptions {
withDedup?: boolean;
}
type TeamDataSnapshotMode = 'full' | 'thin';
function normalizeTeamGetDataOptions(options?: TeamGetDataOptions): TeamGetDataOptions | undefined {
return options?.includeMemberBranches === false ? { includeMemberBranches: false } : undefined;
}
function shouldIncludeMemberBranches(options?: TeamGetDataOptions): boolean {
return normalizeTeamGetDataOptions(options)?.includeMemberBranches !== false;
}
function getTeamDataSnapshotMode(options?: TeamGetDataOptions): TeamDataSnapshotMode {
return shouldIncludeMemberBranches(options) ? 'full' : 'thin';
}
function getTeamDataRequestKey(teamName: string, options?: TeamGetDataOptions): string {
const normalizedOptions = normalizeTeamGetDataOptions(options);
return `${teamName}\u0000mode:${getTeamDataSnapshotMode(normalizedOptions)}`;
}
function getTeamDataRequestLabel(teamName: string, options?: TeamGetDataOptions): string {
const normalizedOptions = normalizeTeamGetDataOptions(options);
return `team:getData(${teamName},mode=${getTeamDataSnapshotMode(normalizedOptions)})`;
}
function getFullTeamDataRequestKey(teamName: string): string {
return getTeamDataRequestKey(teamName);
}
function getThinTeamDataRequestKey(teamName: string): string {
return getTeamDataRequestKey(teamName, { includeMemberBranches: false });
}
function hasFullTeamDataRequestForTeam(teamName: string): boolean {
return inFlightTeamDataRequests.has(getFullTeamDataRequestKey(teamName));
}
@ -196,9 +172,8 @@ function hasThinTeamDataRequestForTeam(teamName: string): boolean {
}
function clearTeamDataRequestsForTeam(teamName: string): void {
const prefix = `${teamName}\u0000`;
for (const key of inFlightTeamDataRequests.keys()) {
if (key.startsWith(prefix)) {
if (isTeamDataRequestKeyForTeam(key, teamName)) {
inFlightTeamDataRequests.delete(key);
}
}

View file

@ -0,0 +1,39 @@
import type { TeamGetDataOptions } from '@shared/types';
export type TeamDataSnapshotMode = 'full' | 'thin';
export function normalizeTeamGetDataOptions(
options?: TeamGetDataOptions
): TeamGetDataOptions | undefined {
return options?.includeMemberBranches === false ? { includeMemberBranches: false } : undefined;
}
export function shouldIncludeMemberBranches(options?: TeamGetDataOptions): boolean {
return normalizeTeamGetDataOptions(options)?.includeMemberBranches !== false;
}
export function getTeamDataSnapshotMode(options?: TeamGetDataOptions): TeamDataSnapshotMode {
return shouldIncludeMemberBranches(options) ? 'full' : 'thin';
}
export function getTeamDataRequestKey(teamName: string, options?: TeamGetDataOptions): string {
const normalizedOptions = normalizeTeamGetDataOptions(options);
return `${teamName}\u0000mode:${getTeamDataSnapshotMode(normalizedOptions)}`;
}
export function getTeamDataRequestLabel(teamName: string, options?: TeamGetDataOptions): string {
const normalizedOptions = normalizeTeamGetDataOptions(options);
return `team:getData(${teamName},mode=${getTeamDataSnapshotMode(normalizedOptions)})`;
}
export function getFullTeamDataRequestKey(teamName: string): string {
return getTeamDataRequestKey(teamName);
}
export function getThinTeamDataRequestKey(teamName: string): string {
return getTeamDataRequestKey(teamName, { includeMemberBranches: false });
}
export function isTeamDataRequestKeyForTeam(requestKey: string, teamName: string): boolean {
return requestKey.startsWith(`${teamName}\u0000`);
}

View file

@ -0,0 +1,58 @@
import { describe, expect, it } from 'vitest';
import {
getFullTeamDataRequestKey,
getTeamDataRequestKey,
getTeamDataRequestLabel,
getTeamDataSnapshotMode,
getThinTeamDataRequestKey,
isTeamDataRequestKeyForTeam,
normalizeTeamGetDataOptions,
shouldIncludeMemberBranches,
} from '../../../src/renderer/store/team/teamDataRequestKeys';
describe('teamDataRequestKeys', () => {
it('normalizes only the thin snapshot option and treats all other inputs as full snapshots', () => {
expect(normalizeTeamGetDataOptions()).toBeUndefined();
expect(normalizeTeamGetDataOptions({})).toBeUndefined();
expect(normalizeTeamGetDataOptions({ includeMemberBranches: true })).toBeUndefined();
expect(normalizeTeamGetDataOptions({ includeMemberBranches: false })).toEqual({
includeMemberBranches: false,
});
expect(shouldIncludeMemberBranches()).toBe(true);
expect(shouldIncludeMemberBranches({ includeMemberBranches: true })).toBe(true);
expect(shouldIncludeMemberBranches({ includeMemberBranches: false })).toBe(false);
});
it('maps normalized request options to stable full and thin snapshot modes', () => {
expect(getTeamDataSnapshotMode()).toBe('full');
expect(getTeamDataSnapshotMode({ includeMemberBranches: true })).toBe('full');
expect(getTeamDataSnapshotMode({ includeMemberBranches: false })).toBe('thin');
});
it('builds request keys that preserve the existing null-separated team/mode contract', () => {
expect(getTeamDataRequestKey('my-team')).toBe('my-team\u0000mode:full');
expect(getTeamDataRequestKey('my-team', { includeMemberBranches: true })).toBe(
'my-team\u0000mode:full'
);
expect(getTeamDataRequestKey('my-team', { includeMemberBranches: false })).toBe(
'my-team\u0000mode:thin'
);
expect(getFullTeamDataRequestKey('my-team')).toBe('my-team\u0000mode:full');
expect(getThinTeamDataRequestKey('my-team')).toBe('my-team\u0000mode:thin');
});
it('builds timeout/debug labels from the same normalized mode policy', () => {
expect(getTeamDataRequestLabel('my-team')).toBe('team:getData(my-team,mode=full)');
expect(getTeamDataRequestLabel('my-team', { includeMemberBranches: false })).toBe(
'team:getData(my-team,mode=thin)'
);
});
it('matches request keys only for the exact team prefix boundary', () => {
expect(isTeamDataRequestKeyForTeam('my-team\u0000mode:full', 'my-team')).toBe(true);
expect(isTeamDataRequestKeyForTeam('my-team-extra\u0000mode:full', 'my-team')).toBe(false);
expect(isTeamDataRequestKeyForTeam('my-team', 'my-team')).toBe(false);
});
});