fix(team): show launch dialog loading fallback

This commit is contained in:
777genius 2026-05-25 21:29:06 +03:00
parent e88d3a1e98
commit bafd4d7194
5 changed files with 138 additions and 5 deletions

View file

@ -25,6 +25,7 @@ import {
} from 'lucide-react';
import { useShallow } from 'zustand/react/shallow';
import { LaunchTeamDialogLoadingFallback } from '../team/dialogs/LaunchTeamDialogLoadingFallback';
import { ScheduleRunLogDialog } from '../team/schedule/ScheduleRunLogDialog';
import { ScheduleRunRow } from '../team/schedule/ScheduleRunRow';
import { ScheduleStatusBadge } from '../team/schedule/ScheduleStatusBadge';
@ -588,7 +589,16 @@ export const SchedulesView = (): React.JSX.Element => {
{/* Create/Edit Dialog */}
{dialogOpen && (
<Suspense fallback={null}>
<Suspense
fallback={
<LaunchTeamDialogLoadingFallback
mode="schedule"
teamName={editingSchedule?.teamName}
isEditingSchedule={Boolean(editingSchedule)}
onClose={handleClose}
/>
}
>
<LaunchTeamDialog
mode="schedule"
open={dialogOpen}

View file

@ -85,6 +85,7 @@ import { useShallow } from 'zustand/react/shallow';
import { AddMemberDialog } from './dialogs/AddMemberDialog';
import { EditTeamDialog } from './dialogs/EditTeamDialog';
import { LaunchTeamDialogLoadingFallback } from './dialogs/LaunchTeamDialogLoadingFallback';
import { ReviewDialog } from './dialogs/ReviewDialog';
import { executeTeamRelaunch } from './dialogs/teamRelaunchFlow';
import { KanbanBoard } from './kanban/KanbanBoard';
@ -2580,7 +2581,15 @@ export const TeamDetailView = memo(function TeamDetailView({
</div>
</div>
{launchDialogOpen && (
<Suspense fallback={null}>
<Suspense
fallback={
<LaunchTeamDialogLoadingFallback
mode={launchDialogState.mode}
teamName={teamName}
onClose={closeLaunchDialog}
/>
}
>
<LaunchTeamDialog
mode={launchDialogState.mode}
open={launchDialogOpen}
@ -3418,7 +3427,15 @@ export const TeamDetailView = memo(function TeamDetailView({
</Dialog>
{launchDialogOpen && (
<Suspense fallback={null}>
<Suspense
fallback={
<LaunchTeamDialogLoadingFallback
mode={launchDialogState.mode}
teamName={teamName}
onClose={closeLaunchDialog}
/>
}
>
<LaunchTeamDialog
mode={launchDialogState.mode}
open={launchDialogOpen}

View file

@ -62,6 +62,7 @@ import {
} from 'lucide-react';
import { useShallow } from 'zustand/react/shallow';
import { LaunchTeamDialogLoadingFallback } from './dialogs/LaunchTeamDialogLoadingFallback';
import { executeTeamRelaunch } from './dialogs/teamRelaunchFlow';
import { TeamEmptyState } from './TeamEmptyState';
import { EMPTY_TEAM_FILTER, TeamListFilterPopover } from './TeamListFilterPopover';
@ -1094,7 +1095,15 @@ export const TeamListView = memo(function TeamListView(): React.JSX.Element {
);
const launchDialogElement = launchDialogOpen && (
<Suspense fallback={null}>
<Suspense
fallback={
<LaunchTeamDialogLoadingFallback
mode={launchDialogMode}
teamName={launchDialogTeamName}
onClose={() => setLaunchDialogOpen(false)}
/>
}
>
{launchDialogMode === 'relaunch' ? (
<LaunchTeamDialog
mode="relaunch"

View file

@ -0,0 +1,86 @@
import React from 'react';
import { useAppTranslation } from '@features/localization/renderer';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@renderer/components/ui/dialog';
import { Loader2 } from 'lucide-react';
type LaunchTeamDialogLoadingMode = 'launch' | 'relaunch' | 'schedule';
interface LaunchTeamDialogLoadingFallbackProps {
readonly mode: LaunchTeamDialogLoadingMode;
readonly teamName?: string;
readonly isEditingSchedule?: boolean;
readonly onClose: () => void;
}
export const LaunchTeamDialogLoadingFallback = ({
mode,
teamName,
isEditingSchedule = false,
onClose,
}: LaunchTeamDialogLoadingFallbackProps): React.JSX.Element => {
const { t } = useAppTranslation('team');
const { t: tCommon } = useAppTranslation('common');
const title =
mode === 'schedule'
? isEditingSchedule
? t('launch.title.editSchedule')
: t('launch.title.createSchedule')
: mode === 'relaunch'
? t('launch.title.relaunch')
: t('launch.title.launch');
const description =
mode === 'schedule'
? isEditingSchedule && teamName
? t('launch.description.editSchedule', { team: teamName })
: teamName
? t('launch.description.createScheduleForTeam', { team: teamName })
: t('launch.description.createSchedule')
: mode === 'relaunch'
? t('launch.description.relaunchPrefix')
: t('launch.description.launchPrefix');
return (
<Dialog
open
onOpenChange={(nextOpen) => {
if (!nextOpen) {
onClose();
}
}}
>
<DialogContent className="max-w-[52rem]">
<DialogHeader>
<DialogTitle className="text-sm">{title}</DialogTitle>
<DialogDescription className="text-xs">
{mode === 'schedule' ? (
description
) : (
<>
{description} <span className="font-mono font-medium">{teamName}</span>{' '}
{mode === 'relaunch'
? t('launch.description.relaunchSuffix')
: t('launch.description.launchSuffix')}
</>
)}
</DialogDescription>
</DialogHeader>
<div
className="flex items-center gap-2 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-overlay)] px-3 py-2 text-xs text-[var(--color-text-muted)]"
aria-live="polite"
>
<Loader2 className="size-3.5 shrink-0 animate-spin" />
<span>{tCommon('states.loading')}</span>
</div>
</DialogContent>
</Dialog>
);
};

View file

@ -19,6 +19,8 @@ import {
} from 'lucide-react';
import { useShallow } from 'zustand/react/shallow';
import { LaunchTeamDialogLoadingFallback } from '../dialogs/LaunchTeamDialogLoadingFallback';
import { ScheduleEmptyState } from './ScheduleEmptyState';
import { ScheduleRunLogDialog } from './ScheduleRunLogDialog';
import { ScheduleRunRow } from './ScheduleRunRow';
@ -311,7 +313,16 @@ export const ScheduleSection = ({ teamName }: ScheduleSectionProps): React.JSX.E
{/* Create/Edit Dialog */}
{dialogOpen && (
<Suspense fallback={null}>
<Suspense
fallback={
<LaunchTeamDialogLoadingFallback
mode="schedule"
teamName={teamName}
isEditingSchedule={Boolean(editingSchedule)}
onClose={handleClose}
/>
}
>
<LaunchTeamDialog
mode="schedule"
open={dialogOpen}