feat: add conflict dismissal functionality to team dialogs
- Introduced a conflict dismissal feature in CreateTeamDialog and LaunchTeamDialog to allow users to dismiss conflict warnings when a team is already running. - Added state management for conflict dismissal and reset logic to ensure the warning reappears when relevant conditions change. - Updated UI to include a dismiss button for better user experience in handling team conflicts.
This commit is contained in:
parent
ea4cf85e2e
commit
faf07322eb
2 changed files with 34 additions and 6 deletions
|
|
@ -28,7 +28,7 @@ import { useFileListCacheWarmer } from '@renderer/hooks/useFileListCacheWarmer';
|
|||
import { cn } from '@renderer/lib/utils';
|
||||
import { normalizePath } from '@renderer/utils/pathNormalize';
|
||||
import { getMemberColor } from '@shared/constants/memberColors';
|
||||
import { AlertTriangle, CheckCircle2, Info, Loader2 } from 'lucide-react';
|
||||
import { AlertTriangle, CheckCircle2, Info, Loader2, X } from 'lucide-react';
|
||||
|
||||
import { ExtendedContextCheckbox } from './ExtendedContextCheckbox';
|
||||
import { ProjectPathSelector } from './ProjectPathSelector';
|
||||
|
|
@ -225,6 +225,7 @@ export const CreateTeamDialog = ({
|
|||
const [launchTeam, setLaunchTeam] = useState(true);
|
||||
const [soloTeam, setSoloTeam] = useState(false);
|
||||
const [teamColor, setTeamColor] = useState('');
|
||||
const [conflictDismissed, setConflictDismissed] = useState(false);
|
||||
const [selectedModel, setSelectedModelRaw] = useState(() => {
|
||||
const stored = localStorage.getItem('team:lastSelectedModel') ?? '';
|
||||
return stored === '__default__' ? '' : stored;
|
||||
|
|
@ -250,6 +251,7 @@ export const CreateTeamDialog = ({
|
|||
setPrepareState('idle');
|
||||
setPrepareMessage(null);
|
||||
setPrepareWarnings([]);
|
||||
setConflictDismissed(false);
|
||||
};
|
||||
|
||||
const resetFormState = (): void => {
|
||||
|
|
@ -492,6 +494,11 @@ export const CreateTeamDialog = ({
|
|||
return activeTeams.find((t) => normalizePath(t.projectPath) === norm) ?? null;
|
||||
}, [activeTeams, effectiveCwd]);
|
||||
|
||||
// Reset dismiss when conflict target changes
|
||||
useEffect(() => {
|
||||
setConflictDismissed(false);
|
||||
}, [conflictingTeam?.teamName, effectiveCwd]);
|
||||
|
||||
const handleSubmit = (): void => {
|
||||
if (existingTeamNames.includes(sanitizedTeamName)) {
|
||||
setFieldErrors({ teamName: 'Team name already exists' });
|
||||
|
|
@ -565,11 +572,11 @@ export const CreateTeamDialog = ({
|
|||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{conflictingTeam ? (
|
||||
{conflictingTeam && !conflictDismissed ? (
|
||||
<div className="rounded-md border border-amber-500/40 bg-amber-500/10 p-3 text-xs">
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertTriangle className="mt-0.5 size-4 shrink-0 text-amber-400" />
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="min-w-0 flex-1 space-y-1">
|
||||
<p className="font-medium text-amber-300">
|
||||
Team “{conflictingTeam.displayName}” is already running in this
|
||||
project
|
||||
|
|
@ -579,6 +586,13 @@ export const CreateTeamDialog = ({
|
|||
same files. Consider using a different directory or a git worktree for isolation.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="shrink-0 rounded p-0.5 text-amber-400/60 transition-colors hover:text-amber-300"
|
||||
onClick={() => setConflictDismissed(true)}
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { useStore } from '@renderer/store';
|
|||
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
||||
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
||||
import { normalizePath } from '@renderer/utils/pathNormalize';
|
||||
import { AlertTriangle, CheckCircle2, Loader2, RotateCcw } from 'lucide-react';
|
||||
import { AlertTriangle, CheckCircle2, Loader2, RotateCcw, X } from 'lucide-react';
|
||||
|
||||
import { ProjectPathSelector } from './ProjectPathSelector';
|
||||
import { computeEffectiveTeamModel, TeamModelSelector } from './TeamModelSelector';
|
||||
|
|
@ -79,6 +79,7 @@ export const LaunchTeamDialog = ({
|
|||
() => localStorage.getItem('team:lastExtendedContext') === 'true'
|
||||
);
|
||||
const [clearContext, setClearContext] = useState(false);
|
||||
const [conflictDismissed, setConflictDismissed] = useState(false);
|
||||
|
||||
const setSelectedModel = (value: string): void => {
|
||||
setSelectedModelRaw(value);
|
||||
|
|
@ -100,6 +101,7 @@ export const LaunchTeamDialog = ({
|
|||
setSelectedProjectPath('');
|
||||
setCustomCwd('');
|
||||
setClearContext(false);
|
||||
setConflictDismissed(false);
|
||||
chipDraft.clearChipDraft();
|
||||
};
|
||||
|
||||
|
|
@ -245,6 +247,11 @@ export const LaunchTeamDialog = ({
|
|||
);
|
||||
}, [activeTeams, effectiveCwd, teamName]);
|
||||
|
||||
// Reset dismiss when conflict target changes (different path or different conflicting team)
|
||||
useEffect(() => {
|
||||
setConflictDismissed(false);
|
||||
}, [conflictingTeam?.teamName, effectiveCwd]);
|
||||
|
||||
const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
|
||||
const mentionSuggestions = useMemo<MentionSuggestion[]>(
|
||||
() =>
|
||||
|
|
@ -305,11 +312,11 @@ export const LaunchTeamDialog = ({
|
|||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{conflictingTeam ? (
|
||||
{conflictingTeam && !conflictDismissed ? (
|
||||
<div className="rounded-md border border-amber-500/40 bg-amber-500/10 p-3 text-xs">
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertTriangle className="mt-0.5 size-4 shrink-0 text-amber-400" />
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="min-w-0 flex-1 space-y-1">
|
||||
<p className="font-medium text-amber-300">
|
||||
Team “{conflictingTeam.displayName}” is already running in this
|
||||
project
|
||||
|
|
@ -319,6 +326,13 @@ export const LaunchTeamDialog = ({
|
|||
same files. Consider using a different directory or a git worktree for isolation.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="shrink-0 rounded p-0.5 text-amber-400/60 transition-colors hover:text-amber-300"
|
||||
onClick={() => setConflictDismissed(true)}
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
Loading…
Reference in a new issue