Duplicate models from the DB instead of frontend snapshots (#505)

This commit is contained in:
Gregory Schier
2026-07-14 07:43:14 -07:00
committed by GitHub
parent 6b9b3660de
commit e05feba708
9 changed files with 133 additions and 53 deletions
+11 -34
View File
@@ -1,6 +1,5 @@
import { invoke } from "@tauri-apps/api/core";
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
import { resolvedModelName } from "@yaakapp/yaak-client/lib/resolvedModelName";
import { AnyModel, ModelPayload } from "../bindings/gen_models";
import { modelStoreDataAtom } from "./atoms";
import { ExtractModel, JotaiStore, ModelStoreData } from "./types";
@@ -156,44 +155,22 @@ export async function deleteModel<M extends AnyModel["model"], T extends Extract
await trackModelWrite(invoke<string>("models_delete", { model }));
}
export function duplicateModel<M extends AnyModel["model"], T extends ExtractModel<AnyModel, M>>(
model: T | null,
) {
export async function duplicateModel<
M extends AnyModel["model"],
T extends ExtractModel<AnyModel, M>,
>(model: T | null): Promise<string> {
if (model == null) {
throw new Error("Failed to duplicate null model");
}
// If the model has an explicit (non-empty) name, try to duplicate it with a name that doesn't conflict.
// When the name is empty, keep it empty so the display falls back to the URL.
let name = "name" in model ? model.name : undefined;
if (name) {
const existingModels = listModels(model.model);
for (let i = 0; i < 100; i++) {
const hasConflict = existingModels.some((m) => {
if ("folderId" in m && "folderId" in model && model.folderId !== m.folderId) {
return false;
} else if (resolvedModelName(m) !== name) {
return false;
}
return true;
});
if (!hasConflict) {
break;
}
// Flush pending writes first, since the backend duplicates from the DB (the passed-in
// model may be a stale snapshot, eg. from the memoized sidebar tree). Conflict-free
// naming ("Foo Copy 2") is also handled by the backend.
await flushAllModelWrites();
// Name conflict. Try another one
const m: RegExpMatchArray | null = name.match(/ Copy( (?<n>\d+))?$/);
if (m != null && m.groups?.n == null) {
name = name.substring(0, m.index) + " Copy 2";
} else if (m != null && m.groups?.n != null) {
name = name.substring(0, m.index) + ` Copy ${parseInt(m.groups.n) + 1}`;
} else {
name = `${name} Copy`;
}
}
}
return trackModelWrite(invoke<string>("models_duplicate", { model: { ...model, name } }));
return trackModelWrite(
invoke<string>("models_duplicate", { modelType: model.model, modelId: model.id }),
);
}
export async function createGlobalModel<T extends Exclude<AnyModel, { workspaceId: string }>>(