fix(ci): resolve frontend validation failures
This commit is contained in:
parent
01b8161f41
commit
46df757f49
10 changed files with 126 additions and 82 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { api } from '@renderer/api';
|
||||
import { CreateTaskDialog } from '@renderer/components/team/dialogs/CreateTaskDialog';
|
||||
|
|
|
|||
|
|
@ -6,29 +6,53 @@ import {
|
|||
} from '@renderer/store/slices/teamSlice';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import type { TeamGraphData } from '../adapters/TeamGraphAdapter';
|
||||
import type { AppState } from '@renderer/store/types';
|
||||
|
||||
export function useGraphMemberPopoverContext(teamName: string, memberName: string) {
|
||||
interface GraphMemberPopoverContext {
|
||||
teamData:
|
||||
| (NonNullable<ReturnType<typeof selectTeamDataForName>> & {
|
||||
members: ReturnType<typeof selectResolvedMembersForTeamName>;
|
||||
messageFeed: [];
|
||||
})
|
||||
| null;
|
||||
teamMembers: ReturnType<typeof selectResolvedMembersForTeamName>;
|
||||
spawnEntry: AppState['memberSpawnStatusesByTeam'][string][string] | undefined;
|
||||
leadActivity: AppState['leadActivityByTeam'][string] | undefined;
|
||||
progress: ReturnType<typeof getCurrentProvisioningProgressForTeam> | null;
|
||||
memberSpawnSnapshot: AppState['memberSpawnSnapshotsByTeam'][string] | undefined;
|
||||
memberSpawnStatuses: AppState['memberSpawnStatusesByTeam'][string] | undefined;
|
||||
}
|
||||
|
||||
function selectGraphMemberPopoverContext(
|
||||
state: AppState,
|
||||
teamName: string,
|
||||
memberName: string
|
||||
): GraphMemberPopoverContext {
|
||||
const snapshot = teamName ? selectTeamDataForName(state, teamName) : null;
|
||||
const teamMembers = teamName ? selectResolvedMembersForTeamName(state, teamName) : [];
|
||||
|
||||
return {
|
||||
teamData: snapshot
|
||||
? {
|
||||
...snapshot,
|
||||
members: teamMembers,
|
||||
messageFeed: [],
|
||||
}
|
||||
: null,
|
||||
teamMembers,
|
||||
spawnEntry: teamName ? state.memberSpawnStatusesByTeam[teamName]?.[memberName] : undefined,
|
||||
leadActivity: teamName ? state.leadActivityByTeam[teamName] : undefined,
|
||||
progress: teamName ? getCurrentProvisioningProgressForTeam(state, teamName) : null,
|
||||
memberSpawnSnapshot: teamName ? state.memberSpawnSnapshotsByTeam[teamName] : undefined,
|
||||
memberSpawnStatuses: teamName ? state.memberSpawnStatusesByTeam[teamName] : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function useGraphMemberPopoverContext(
|
||||
teamName: string,
|
||||
memberName: string
|
||||
): ReturnType<typeof selectGraphMemberPopoverContext> {
|
||||
return useStore(
|
||||
useShallow((state) => {
|
||||
const snapshot = teamName ? selectTeamDataForName(state, teamName) : null;
|
||||
const teamMembers = teamName ? selectResolvedMembersForTeamName(state, teamName) : [];
|
||||
|
||||
return {
|
||||
teamData: snapshot
|
||||
? {
|
||||
...snapshot,
|
||||
members: teamMembers,
|
||||
messageFeed: [],
|
||||
}
|
||||
: null,
|
||||
teamMembers,
|
||||
spawnEntry: teamName ? state.memberSpawnStatusesByTeam[teamName]?.[memberName] : undefined,
|
||||
leadActivity: teamName ? state.leadActivityByTeam[teamName] : undefined,
|
||||
progress: teamName ? getCurrentProvisioningProgressForTeam(state, teamName) : null,
|
||||
memberSpawnSnapshot: teamName ? state.memberSpawnSnapshotsByTeam[teamName] : undefined,
|
||||
memberSpawnStatuses: teamName ? state.memberSpawnStatusesByTeam[teamName] : undefined,
|
||||
};
|
||||
})
|
||||
useShallow((state) => selectGraphMemberPopoverContext(state, teamName, memberName))
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,6 +289,15 @@ export const GraphActivityHud = ({
|
|||
const handleMessageClick = useCallback((item: TimelineItem) => {
|
||||
setExpandedItem(item);
|
||||
}, []);
|
||||
const handleMessageKeyDown = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>, item: TimelineItem): void => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
handleMessageClick(item);
|
||||
}
|
||||
},
|
||||
[handleMessageClick]
|
||||
);
|
||||
|
||||
const handleMemberClick = useCallback(
|
||||
(member: ResolvedTeamMember) => {
|
||||
|
|
@ -360,6 +369,52 @@ export const GraphActivityHud = ({
|
|||
};
|
||||
}, [enabled, forwardWheelToGraph, visibleLanes]);
|
||||
|
||||
const renderLaneEntry = useCallback(
|
||||
(entry: InlineActivityEntry, index: number): React.JSX.Element => {
|
||||
const messageKey = toMessageKey(entry.message);
|
||||
const timelineItem: TimelineItem = {
|
||||
type: 'message',
|
||||
message: entry.message,
|
||||
};
|
||||
const isUnread = !entry.message.read && !readSet.has(messageKey);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={entry.graphItem.id}
|
||||
className="h-[72px] min-h-[72px] min-w-0 max-w-full cursor-pointer overflow-hidden"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => handleMessageClick(timelineItem)}
|
||||
onKeyDown={(event) => handleMessageKeyDown(event, timelineItem)}
|
||||
>
|
||||
<GraphActivityCard
|
||||
message={entry.message}
|
||||
teamName={teamName}
|
||||
messageContext={messageContext}
|
||||
teamNames={teamNames}
|
||||
teamColorByName={teamColorByName}
|
||||
isUnread={isUnread}
|
||||
zebraShade={index % 2 === 1}
|
||||
onClick={() => handleMessageClick(timelineItem)}
|
||||
onOpenTaskDetail={onOpenTaskDetail}
|
||||
onOpenMemberProfile={onOpenMemberProfile}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[
|
||||
handleMessageClick,
|
||||
handleMessageKeyDown,
|
||||
messageContext,
|
||||
onOpenMemberProfile,
|
||||
onOpenTaskDetail,
|
||||
readSet,
|
||||
teamColorByName,
|
||||
teamName,
|
||||
teamNames,
|
||||
]
|
||||
);
|
||||
|
||||
if (!enabled || !teamSnapshot || visibleLanes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -421,43 +476,7 @@ export const GraphActivityHud = ({
|
|||
No recent activity
|
||||
</div>
|
||||
) : null}
|
||||
{lane.entries.map((entry, index) => {
|
||||
const messageKey = toMessageKey(entry.message);
|
||||
const timelineItem: TimelineItem = {
|
||||
type: 'message',
|
||||
message: entry.message,
|
||||
};
|
||||
const isUnread = !entry.message.read && !readSet.has(messageKey);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={entry.graphItem.id}
|
||||
className="h-[72px] min-h-[72px] min-w-0 max-w-full cursor-pointer overflow-hidden"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => handleMessageClick(timelineItem)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
handleMessageClick(timelineItem);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<GraphActivityCard
|
||||
message={entry.message}
|
||||
teamName={teamName}
|
||||
messageContext={messageContext}
|
||||
teamNames={teamNames}
|
||||
teamColorByName={teamColorByName}
|
||||
isUnread={isUnread}
|
||||
zebraShade={index % 2 === 1}
|
||||
onClick={() => handleMessageClick(timelineItem)}
|
||||
onOpenTaskDetail={onOpenTaskDetail}
|
||||
onOpenMemberProfile={onOpenMemberProfile}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{lane.entries.map(renderLaneEntry)}
|
||||
|
||||
{lane.overflowCount > 0 ? (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ import { GraphNodePopover } from './GraphNodePopover';
|
|||
import { GraphProvisioningHud } from './GraphProvisioningHud';
|
||||
import { GraphTransientHandoffHud } from './GraphTransientHandoffHud';
|
||||
|
||||
import type { GraphDomainRef, GraphEventPort } from '@claude-teams/agent-graph';
|
||||
import type {
|
||||
GraphDomainRef,
|
||||
GraphEventPort,
|
||||
TransientHandoffCard,
|
||||
} from '@claude-teams/agent-graph';
|
||||
import type {
|
||||
MemberActivityFilter,
|
||||
MemberDetailTab,
|
||||
|
|
@ -149,7 +153,7 @@ export const TeamGraphOverlay = ({
|
|||
focusNodeIds?: ReadonlySet<string> | null;
|
||||
focusEdgeIds?: ReadonlySet<string> | null;
|
||||
}) => {
|
||||
cards: import('@claude-teams/agent-graph').TransientHandoffCard[];
|
||||
cards: TransientHandoffCard[];
|
||||
time: number;
|
||||
};
|
||||
worldToScreen?: (x: number, y: number) => { x: number; y: number };
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ import { GraphNodePopover } from './GraphNodePopover';
|
|||
import { GraphProvisioningHud } from './GraphProvisioningHud';
|
||||
import { GraphTransientHandoffHud } from './GraphTransientHandoffHud';
|
||||
|
||||
import type { GraphDomainRef, GraphEventPort } from '@claude-teams/agent-graph';
|
||||
import type {
|
||||
GraphDomainRef,
|
||||
GraphEventPort,
|
||||
TransientHandoffCard,
|
||||
} from '@claude-teams/agent-graph';
|
||||
import type {
|
||||
MemberActivityFilter,
|
||||
MemberDetailTab,
|
||||
|
|
@ -169,7 +173,7 @@ export const TeamGraphTab = ({
|
|||
focusNodeIds?: ReadonlySet<string> | null;
|
||||
focusEdgeIds?: ReadonlySet<string> | null;
|
||||
}) => {
|
||||
cards: import('@claude-teams/agent-graph').TransientHandoffCard[];
|
||||
cards: TransientHandoffCard[];
|
||||
time: number;
|
||||
};
|
||||
worldToScreen?: (x: number, y: number) => { x: number; y: number };
|
||||
|
|
|
|||
|
|
@ -15,15 +15,15 @@ import { BoardTaskExactLogSummarySelector } from '../exact/BoardTaskExactLogSumm
|
|||
import { isBoardTaskExactLogsReadEnabled } from '../exact/featureGates';
|
||||
import { getBoardTaskExactLogFileVersions } from '../exact/fileVersions';
|
||||
|
||||
import { OpenCodeTaskLogStreamSource } from './OpenCodeTaskLogStreamSource';
|
||||
import { CodexNativeTaskLogStreamSource } from './CodexNativeTaskLogStreamSource';
|
||||
import { buildCodexNativeToolSignature } from './CodexNativeTraceProjector';
|
||||
import { HistoricalBoardMcpRawProbe } from './HistoricalBoardMcpRawProbe';
|
||||
import { TaskLogTranscriptCandidateSelector } from './TaskLogTranscriptCandidateSelector';
|
||||
import {
|
||||
canonicalizeBoardTaskLogToolName,
|
||||
isBoardTaskLogMcpToolName,
|
||||
} from './boardTaskLogToolNames';
|
||||
import { CodexNativeTaskLogStreamSource } from './CodexNativeTaskLogStreamSource';
|
||||
import { buildCodexNativeToolSignature } from './CodexNativeTraceProjector';
|
||||
import { HistoricalBoardMcpRawProbe } from './HistoricalBoardMcpRawProbe';
|
||||
import { OpenCodeTaskLogStreamSource } from './OpenCodeTaskLogStreamSource';
|
||||
import { TaskLogTranscriptCandidateSelector } from './TaskLogTranscriptCandidateSelector';
|
||||
|
||||
import type { BoardTaskActivityRecord } from '../activity/BoardTaskActivityRecord';
|
||||
import type { BoardTaskExactLogDetailCandidate } from '../exact/BoardTaskExactLogTypes';
|
||||
|
|
@ -1684,12 +1684,12 @@ export class BoardTaskLogStreamService {
|
|||
const cacheKey = this.buildLayoutCacheKey(teamName, taskId);
|
||||
const generation = this.getTranscriptDiscoveryGeneration(teamName);
|
||||
const cached = this.layoutCache.get(cacheKey);
|
||||
if (cached && cached.generation === generation && cached.expiresAt > Date.now()) {
|
||||
if (cached?.generation === generation && cached.expiresAt > Date.now()) {
|
||||
return cached.layout;
|
||||
}
|
||||
|
||||
const existingInFlight = this.layoutInFlight.get(cacheKey);
|
||||
if (existingInFlight && existingInFlight.generation === generation) {
|
||||
if (existingInFlight?.generation === generation) {
|
||||
return await existingInFlight.promise;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { getTeamsBasePath } from '@main/utils/pathDecoder';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
|
||||
import { getTeamsBasePath } from '@main/utils/pathDecoder';
|
||||
|
||||
const TRACE_ROOT_SEGMENT = path.join('.member-work-sync', 'runtime-hooks', 'codex-native-traces');
|
||||
|
||||
export interface CodexNativeTraceProjection {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { getTaskDisplayId } from '@shared/utils/taskIdentity';
|
||||
import { createReadStream } from 'fs';
|
||||
import * as readline from 'readline';
|
||||
|
||||
import { getTaskDisplayId } from '@shared/utils/taskIdentity';
|
||||
|
||||
import type { TeamTask } from '@shared/types';
|
||||
|
||||
const RAW_PROBE_CONCURRENCY = process.platform === 'win32' ? 4 : 8;
|
||||
|
|
|
|||
|
|
@ -45,10 +45,5 @@ export function isReadOnlyBoardTaskLogToolName(toolName: string | undefined): bo
|
|||
}
|
||||
|
||||
export function isRecoverableHistoricalBoardTaskLogToolName(toolName: string | undefined): boolean {
|
||||
const canonical = canonicalizeBoardTaskLogToolName(toolName);
|
||||
return (
|
||||
canonical !== null &&
|
||||
(HISTORICAL_BOARD_LIFECYCLE_TOOL_NAMES.has(canonical) ||
|
||||
HISTORICAL_BOARD_ACTION_TOOL_NAMES.has(canonical))
|
||||
);
|
||||
return isBoardTaskLogMcpToolName(toolName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ import { AlertCircle, Clock, FileText, Loader2 } from 'lucide-react';
|
|||
|
||||
import type {
|
||||
BoardTaskLogActor,
|
||||
ResolvedTeamMember,
|
||||
BoardTaskLogSegment,
|
||||
BoardTaskLogStreamResponse,
|
||||
ResolvedTeamMember,
|
||||
} from '@shared/types';
|
||||
|
||||
interface TaskLogStreamSectionProps {
|
||||
|
|
|
|||
Loading…
Reference in a new issue