From 64dda5bb0183b67ee1337e32817fec18413baae2 Mon Sep 17 00:00:00 2001 From: Xiaohan-Tian <157918347+Xiaohan-Tian@users.noreply.github.com> Date: Mon, 11 May 2026 23:23:11 -0700 Subject: [PATCH] fix: few minor UI and behavior adjustments --- src/components/KGOnePanel.tsx | 69 +++++++++++++------ src/components/Toolbar.tsx | 24 +++++++ .../settings/sections/GeneralSettings.tsx | 2 +- src/components/track/RegionItem.tsx | 6 +- src/components/track/TrackGridItem.tsx | 1 + src/core/KGProject.ts | 5 +- 6 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/components/KGOnePanel.tsx b/src/components/KGOnePanel.tsx index 26012dd..a0d48ce 100644 --- a/src/components/KGOnePanel.tsx +++ b/src/components/KGOnePanel.tsx @@ -329,7 +329,7 @@ const ClipTab: React.FC = ({ bpm, keySignature }) => { setGenStatus('polling'); setGenHint('Generating clip...'); - + while (true) { if (signal.aborted) return; @@ -655,7 +655,7 @@ const FullSongTab: React.FC = () => { type ResultItem = { progress: number; stage: string; status: number }; type PollResponse = { data: Array<{ status: number; result: string }>; code: number }; - + while (true) { if (signal.aborted) return; @@ -905,6 +905,19 @@ const SeparatorTab: React.FC<{ mode: KGOneMode }> = ({ mode }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + // Reset separator results whenever the active project changes + useEffect(() => { + stemAudioUrls.forEach(s => URL.revokeObjectURL(s.url)); + setStemAudioUrls([]); + setGenStatus('idle'); + setGenHint(''); + setErrorMsg(''); + setIsImporting(false); + setImportError(''); + originalRegionRef.current = null; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [projectName]); + useEffect(() => { setModel(availableSeparatorModels[0].value); }, [availableSeparatorModels]); @@ -1116,7 +1129,7 @@ const SeparatorTab: React.FC<{ mode: KGOneMode }> = ({ mode }) => { let files: string[] = []; - + while (true) { if (signal.aborted) return; @@ -1363,7 +1376,8 @@ const SeparatorTab: React.FC<{ mode: KGOneMode }> = ({ mode }) => {
Only Vocal and Instrument (Medium Accuracy) is available while not integrated with K.G.One Music Studio server. Processing in local may take long time depending on your hardware. When fallback to CPU happens, the webpage may - temporarily hang with little or no UI response until processing advances. + temporarily hang with little or no UI response until processing advances.{' '} + Learn more about K.G.One Music Studio server integration.
Provider: {localProviderLabel}
@@ -1740,7 +1754,7 @@ const RemixTab: React.FC = () => { type ResultItem = { progress: number; stage: string; status: number }; type PollResponse = { data: Array<{ status: number; result: string }>; code: number }; - + while (true) { if (signal.aborted) return; @@ -2021,7 +2035,7 @@ const RemixTab: React.FC = () => { const RepaintTab: React.FC = () => { const { selectedRegionIds, projectName, bpm, timeSignature, maxBars, - isLooping, loopingRange, refreshProjectState } = useProjectStore(); + isLooping, loopingRange, refreshProjectState } = useProjectStore(); // Form state (mirrors FullSongTab) const [caption, setCaption] = useState(''); @@ -2258,7 +2272,7 @@ const RepaintTab: React.FC = () => { type ResultItem = { progress: number; stage: string; status: number }; type PollResponse = { data: Array<{ status: number; result: string }>; code: number }; - + while (true) { if (signal.aborted) return; @@ -2573,24 +2587,37 @@ const KGOnePanel: React.FC = ({ isVisible }) => { return (
-

K.G.One Music Generator

+

{mode === 'local-separator' ? 'Music Generator' : 'K.G.One Music Generator'}

{/* Clip tab temporarily disabled, will enable in the future */} - {KGONE_TABS.map(tab => ( - - ))} + {KGONE_TABS.map(tab => { + const isDisabled = disabledTabs.has(tab); + const button = ( + + ); + return isDisabled ? ( + + {button} + + ) : button; + })}
diff --git a/src/components/Toolbar.tsx b/src/components/Toolbar.tsx index b4279be..5381f16 100644 --- a/src/components/Toolbar.tsx +++ b/src/components/Toolbar.tsx @@ -122,6 +122,30 @@ const Toolbar: React.FC = () => { return; } + // Untitled Project is ephemeral — no existing save to preserve, so rename directly + if (savedProjectName === RESERVED_PROJECT_NAME) { + const storage = KGProjectStorage.getInstance(); + const exists = await storage.exists(newName); + if (exists) { + const confirmed = await showConfirm( + `Project "${newName}" already exists. Do you want to overwrite it?` + ); + if (!confirmed) return; + setProjectName(newName); + await saveProject(newName, savedProjectName, setStatus, (finalName) => { + setSavedProjectName(finalName); + if (finalName !== newName) setProjectName(finalName); + }, true /* forceOverwrite */); + return; + } + setProjectName(newName); + await saveProject(newName, savedProjectName, setStatus, (finalName) => { + setSavedProjectName(finalName); + if (finalName !== newName) setProjectName(finalName); + }); + return; + } + // Ask whether the user wants to rename or save as a copy const choice = await showChoice( "Would you like to rename this project, or save it as a new copy?", diff --git a/src/components/settings/sections/GeneralSettings.tsx b/src/components/settings/sections/GeneralSettings.tsx index cbdc30a..8baedfd 100644 --- a/src/components/settings/sections/GeneralSettings.tsx +++ b/src/components/settings/sections/GeneralSettings.tsx @@ -591,7 +591,7 @@ const GeneralSettings: React.FC = () => { disabled={kgoneServerManaged} />
- Base URL of a running K.G.One server. Used for full-song generation, clip generation, and stem separation. + Base URL of a running K.G.One Music Studio server. Used for full-song generation, clip generation, and stem separation.
diff --git a/src/components/track/RegionItem.tsx b/src/components/track/RegionItem.tsx index 9f92bd5..ed5a17a 100644 --- a/src/components/track/RegionItem.tsx +++ b/src/components/track/RegionItem.tsx @@ -45,6 +45,7 @@ interface RegionItemProps { audioBuffer?: AudioBuffer; previewWaveformPeaks?: AudioRecordingPeak[]; isPreview?: boolean; + isAudioRegion?: boolean; } const RegionItem: React.FC = ({ @@ -71,6 +72,7 @@ const RegionItem: React.FC = ({ audioBuffer, previewWaveformPeaks, isPreview = false, + isAudioRegion = false, }) => { // Get selection state and time signature from store const { selectedRegionIds, timeSignature, bpm } = useProjectStore(); @@ -652,7 +654,7 @@ const RegionItem: React.FC = ({ return (
= ({
{name}
-
+
{!isPreview &&
{!audioRegion && (