fix: show loading spinner instead of hanging in open project dialog when user click open button
This commit is contained in:
@@ -29,6 +29,7 @@ import { KEY_SIGNATURE_MAP } from '../constants/coreConstants';
|
|||||||
import { KGOfflineRenderer } from '../core/audio-interface/KGOfflineRenderer';
|
import { KGOfflineRenderer } from '../core/audio-interface/KGOfflineRenderer';
|
||||||
import KGDropdown from './common/KGDropdown';
|
import KGDropdown from './common/KGDropdown';
|
||||||
import FileImportModal from './common/FileImportModal';
|
import FileImportModal from './common/FileImportModal';
|
||||||
|
import LoadingOverlay from './common/LoadingOverlay';
|
||||||
import OpenProjectModal from './common/OpenProjectModal';
|
import OpenProjectModal from './common/OpenProjectModal';
|
||||||
import { clearChatHistoryAndUI } from '../util/chatUtil';
|
import { clearChatHistoryAndUI } from '../util/chatUtil';
|
||||||
import PianoIcon from './common/icons/PianoIcon';
|
import PianoIcon from './common/icons/PianoIcon';
|
||||||
@@ -77,6 +78,7 @@ const Toolbar: React.FC = () => {
|
|||||||
|
|
||||||
// State for open project modal
|
// State for open project modal
|
||||||
const [showOpenProject, setShowOpenProject] = React.useState(false);
|
const [showOpenProject, setShowOpenProject] = React.useState(false);
|
||||||
|
const [isOpeningProject, setIsOpeningProject] = React.useState(false);
|
||||||
|
|
||||||
// Close zoom slider on click outside
|
// Close zoom slider on click outside
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -205,12 +207,7 @@ const Toolbar: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenProjectSelect = async (projectNameToLoad: string) => {
|
const handleOpenProjectSelect = async (projectNameToLoad: string) => {
|
||||||
const confirmed = await showConfirm(
|
setIsOpeningProject(true);
|
||||||
'Open this project? Any unsaved changes in the current project will be lost.'
|
|
||||||
);
|
|
||||||
if (!confirmed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const storage = KGProjectStorage.getInstance();
|
const storage = KGProjectStorage.getInstance();
|
||||||
@@ -218,18 +215,25 @@ const Toolbar: React.FC = () => {
|
|||||||
|
|
||||||
if (!loadedProject) {
|
if (!loadedProject) {
|
||||||
await showAlert(`Project "${projectNameToLoad}" not found.`);
|
await showAlert(`Project "${projectNameToLoad}" not found.`);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await loadProjectFromData(loadedProject, `Project "${projectNameToLoad}"`, projectNameToLoad);
|
await loadProjectFromData(loadedProject, `Project "${projectNameToLoad}"`, projectNameToLoad);
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading project:", error);
|
console.error("Error loading project:", error);
|
||||||
await showAlert(`An error occurred while loading the project: ${error}`);
|
await showAlert(`An error occurred while loading the project: ${error}`);
|
||||||
return false;
|
} finally {
|
||||||
|
setIsOpeningProject(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleConfirmOpenProject = async (_projectNameToLoad: string) => {
|
||||||
|
const confirmed = await showConfirm(
|
||||||
|
'Open this project? Any unsaved changes in the current project will be lost.'
|
||||||
|
);
|
||||||
|
return confirmed;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSaveProject = async () => {
|
const handleSaveProject = async () => {
|
||||||
if (DEBUG_MODE.TOOLBAR) {
|
if (DEBUG_MODE.TOOLBAR) {
|
||||||
console.log("user clicked save button");
|
console.log("user clicked save button");
|
||||||
@@ -1207,9 +1211,15 @@ const Toolbar: React.FC = () => {
|
|||||||
description="Drag and drop your project file here"
|
description="Drag and drop your project file here"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<LoadingOverlay
|
||||||
|
visible={isOpeningProject}
|
||||||
|
message="Opening project..."
|
||||||
|
/>
|
||||||
|
|
||||||
{showOpenProject && (
|
{showOpenProject && (
|
||||||
<OpenProjectModal
|
<OpenProjectModal
|
||||||
onClose={() => setShowOpenProject(false)}
|
onClose={() => setShowOpenProject(false)}
|
||||||
|
onConfirmOpenProject={handleConfirmOpenProject}
|
||||||
onOpenProject={handleOpenProjectSelect}
|
onOpenProject={handleOpenProjectSelect}
|
||||||
currentProjectName={savedProjectName}
|
currentProjectName={savedProjectName}
|
||||||
onCreateNewProject={createNewProject}
|
onCreateNewProject={createNewProject}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import { showAlert, showConfirm, showPrompt } from '../../util/dialogUtil';
|
|||||||
|
|
||||||
interface OpenProjectModalProps {
|
interface OpenProjectModalProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onOpenProject: (projectName: string) => Promise<boolean>;
|
onConfirmOpenProject: (projectName: string) => Promise<boolean>;
|
||||||
|
onOpenProject: (projectName: string) => Promise<void>;
|
||||||
currentProjectName: string | null;
|
currentProjectName: string | null;
|
||||||
onCreateNewProject: () => void;
|
onCreateNewProject: () => void;
|
||||||
}
|
}
|
||||||
@@ -44,12 +45,19 @@ const formatDate = (timestamp: number): string => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const OpenProjectModal: React.FC<OpenProjectModalProps> = ({ onClose, onOpenProject, currentProjectName, onCreateNewProject }) => {
|
const OpenProjectModal: React.FC<OpenProjectModalProps> = ({
|
||||||
|
onClose,
|
||||||
|
onConfirmOpenProject,
|
||||||
|
onOpenProject,
|
||||||
|
currentProjectName,
|
||||||
|
onCreateNewProject
|
||||||
|
}) => {
|
||||||
const [projects, setProjects] = useState<ProjectMeta[]>([]);
|
const [projects, setProjects] = useState<ProjectMeta[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [filter, setFilter] = useState('');
|
const [filter, setFilter] = useState('');
|
||||||
const [isClosing, setIsClosing] = useState(false);
|
const [isClosing, setIsClosing] = useState(false);
|
||||||
const mouseDownOnOverlay = useRef(false);
|
const mouseDownOnOverlay = useRef(false);
|
||||||
|
const pendingOpenProjectName = useRef<string | null>(null);
|
||||||
|
|
||||||
const [sortField, setSortField] = useState<SortField>('updatedAt');
|
const [sortField, setSortField] = useState<SortField>('updatedAt');
|
||||||
const [sortDirection, setSortDirection] = useState<SortDirection>('desc');
|
const [sortDirection, setSortDirection] = useState<SortDirection>('desc');
|
||||||
@@ -61,9 +69,16 @@ const OpenProjectModal: React.FC<OpenProjectModalProps> = ({ onClose, onOpenProj
|
|||||||
const handleAnimationEnd = useCallback((e: React.AnimationEvent) => {
|
const handleAnimationEnd = useCallback((e: React.AnimationEvent) => {
|
||||||
if (e.target !== e.currentTarget) return;
|
if (e.target !== e.currentTarget) return;
|
||||||
if (!isClosing) return;
|
if (!isClosing) return;
|
||||||
|
|
||||||
|
const projectNameToOpen = pendingOpenProjectName.current;
|
||||||
|
pendingOpenProjectName.current = null;
|
||||||
setIsClosing(false);
|
setIsClosing(false);
|
||||||
onClose();
|
onClose();
|
||||||
}, [isClosing, onClose]);
|
|
||||||
|
if (projectNameToOpen) {
|
||||||
|
void onOpenProject(projectNameToOpen);
|
||||||
|
}
|
||||||
|
}, [isClosing, onClose, onOpenProject]);
|
||||||
|
|
||||||
const fetchProjects = useCallback(async (mode: ViewMode) => {
|
const fetchProjects = useCallback(async (mode: ViewMode) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@@ -121,10 +136,11 @@ const OpenProjectModal: React.FC<OpenProjectModalProps> = ({ onClose, onOpenProj
|
|||||||
}, [projects, filter, sortField, sortDirection]);
|
}, [projects, filter, sortField, sortDirection]);
|
||||||
|
|
||||||
const handleOpen = async (projectName: string) => {
|
const handleOpen = async (projectName: string) => {
|
||||||
const opened = await onOpenProject(projectName);
|
const confirmed = await onConfirmOpenProject(projectName);
|
||||||
if (opened) {
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
pendingOpenProjectName.current = projectName;
|
||||||
startClose();
|
startClose();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDuplicate = async (e: React.MouseEvent, projectName: string) => {
|
const handleDuplicate = async (e: React.MouseEvent, projectName: string) => {
|
||||||
@@ -141,11 +157,12 @@ const OpenProjectModal: React.FC<OpenProjectModalProps> = ({ onClose, onOpenProj
|
|||||||
try {
|
try {
|
||||||
const storage = KGProjectStorage.getInstance();
|
const storage = KGProjectStorage.getInstance();
|
||||||
const finalName = await storage.resolveUniqueName(trimmed);
|
const finalName = await storage.resolveUniqueName(trimmed);
|
||||||
|
const confirmed = await onConfirmOpenProject(finalName);
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
await storage.duplicate(projectName, finalName);
|
await storage.duplicate(projectName, finalName);
|
||||||
const opened = await onOpenProject(finalName);
|
pendingOpenProjectName.current = finalName;
|
||||||
if (opened) {
|
|
||||||
startClose();
|
startClose();
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error duplicating project:', error);
|
console.error('Error duplicating project:', error);
|
||||||
await showAlert(`Failed to duplicate project: ${error}`);
|
await showAlert(`Failed to duplicate project: ${error}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user