fix: chunk upload race — always return the completed response with filepath; add campaign name to setup wizard
All checks were successful
Build and Push / build (push) Successful in 1m14s
All checks were successful
Build and Push / build (push) Successful in 1m14s
This commit is contained in:
@@ -100,6 +100,17 @@ export const campaignApi = {
|
||||
};
|
||||
|
||||
export const api = {
|
||||
// Campaign
|
||||
updateCampaign: async (id: string, body: Partial<Pick<Campaign, 'name' | 'description'>>): Promise<Campaign> => {
|
||||
const res = await fetch(`${BASE_URL}/campaigns/${encodeURIComponent(id)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to update campaign');
|
||||
return res.json();
|
||||
},
|
||||
|
||||
// Settings
|
||||
getSettings: async (): Promise<GlobalSettings> => {
|
||||
const res = await fetch(`${BASE_URL}/settings`);
|
||||
@@ -241,6 +252,7 @@ export const api = {
|
||||
};
|
||||
|
||||
let lastResult: any = null;
|
||||
let completedResult: any = null;
|
||||
for (let i = 0; i < totalChunks; i += CONCURRENCY) {
|
||||
const batch = [];
|
||||
for (let j = i; j < Math.min(i + CONCURRENCY, totalChunks); j++) {
|
||||
@@ -248,9 +260,12 @@ export const api = {
|
||||
}
|
||||
const results = await Promise.all(batch);
|
||||
lastResult = results[results.length - 1];
|
||||
if (!completedResult) {
|
||||
completedResult = results.find(r => r.status === 'completed');
|
||||
}
|
||||
onProgress(Math.round((Math.min(i + CONCURRENCY, totalChunks) / totalChunks) * 100));
|
||||
}
|
||||
return lastResult;
|
||||
return completedResult || lastResult;
|
||||
},
|
||||
|
||||
// Files
|
||||
|
||||
@@ -20,18 +20,22 @@ const DEFAULT_SETTINGS: Record<string, string> = {
|
||||
|
||||
export default function Setup({ onComplete }: { onComplete: () => void }) {
|
||||
const [step, setStep] = useState(1);
|
||||
const [campaignName, setCampaignName] = useState("Default Campaign");
|
||||
const [settings, setSettings] = useState<Record<string, string>>(DEFAULT_SETTINGS);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
// On first load, try to fetch existing settings from the "default" campaign
|
||||
// (which is always created by init_db).
|
||||
// On first load, try to fetch existing settings and name from the "default" campaign.
|
||||
useEffect(() => {
|
||||
api.getCampaignSettings('default')
|
||||
.then(data => {
|
||||
if (data) setSettings(prev => ({ ...prev, ...data }));
|
||||
})
|
||||
.catch(() => {});
|
||||
fetch('/api/campaigns/default')
|
||||
.then(r => r.ok ? r.json() : null)
|
||||
.then(c => { if (c?.name) setCampaignName(c.name); })
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
const handleNext = () => setStep(prev => prev + 1);
|
||||
@@ -41,6 +45,7 @@ export default function Setup({ onComplete }: { onComplete: () => void }) {
|
||||
setSaving(true);
|
||||
setError("");
|
||||
try {
|
||||
await api.updateCampaign('default', { name: campaignName });
|
||||
await api.updateCampaignSettings('default', settings);
|
||||
await api.updateSettings({ onboarding_completed: true });
|
||||
onComplete();
|
||||
@@ -112,7 +117,18 @@ export default function Setup({ onComplete }: { onComplete: () => void }) {
|
||||
{step === 2 && (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold mb-2">2. Summarization Engine (LLM)</h2>
|
||||
<h2 className="text-xl font-semibold mb-2">Campaign Name</h2>
|
||||
<p className="text-slate-400 text-sm mb-4">Give your campaign a name — you can change it later in Settings.</p>
|
||||
<input
|
||||
type="text"
|
||||
value={campaignName}
|
||||
onChange={e => setCampaignName(e.target.value)}
|
||||
placeholder="My Campaign"
|
||||
className="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2 text-white"
|
||||
/>
|
||||
</div>
|
||||
<div className="border-t border-slate-700 pt-4">
|
||||
<h2 className="text-xl font-semibold mb-2">Summarization Engine (LLM)</h2>
|
||||
<p className="text-slate-400 text-sm mb-4">Choose where your post-transcription formatting and smart summaries are generated.</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user