Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 115 additions & 115 deletions .secrets.baseline

Large diffs are not rendered by default.

40 changes: 39 additions & 1 deletion src/frontend/src/controllers/API/queries/migration/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,42 @@ export interface MigrationStep {
error: string | null;
}

/** The steps that copy this instance's data. Each one runs a command of its own on the server. */
export type CopyStepId =
| "copy_database"
| "copy_knowledge_bases"
| "copy_files";

/** The latest run of a copy step, as the record keeps it. */
export interface MigrationCopyRun {
run_id: string;
status: "running" | "done" | "failed" | "cancelled" | "interrupted";
/** A test run says what a copy would do and never completes its step. */
dry_run: boolean;
started_by: string;
started_at: string;
finished_at: string | null;
/** The command's last word on a run that ended. */
report: {
ok: boolean;
tables_copied?: number;
rows_copied?: number;
problems?: { code: string; message: string }[];
} | null;
/** Set when the run did not end done: the command's own code and message, or `crashed`, `cancelled` or `interrupted`. */
error: { code: string; message?: string } | null;
}

/** One line of a run's event stream. The server numbers each, so a page can ask for what came after one. */
export interface CopyEvent {
event: "progress" | "item" | "report" | "error" | "decision_needed" | "end";
seq: number;
/** On `progress`: `checking`, `preparing_target` or `copying`. A line with none is copying. */
phase?: string;
done?: number;
total?: number | null;
}

export type MigrationStepId =
| "check_source"
| "connect_target"
Expand Down Expand Up @@ -58,7 +94,9 @@ export interface MigrationState {
};
record: {
target: { version?: string; set_by?: string; set_at?: string };
steps: { check_source?: MigrationStep };
steps: { check_source?: MigrationStep } & Partial<
Record<CopyStepId, MigrationCopyRun>
>;
accepted_findings: AcceptedFinding[];
/** Where the new instance keeps its data. Each part is there only when this instance needs it, and none holds a secret. */
destinations?: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { AxiosError, AxiosResponse } from "axios";
import { api, performStreamingRequest } from "../../api";
import { getURL } from "../../helpers/constants";
import type {
CopyEvent,
CopyStepId,
DestinationsRequest,
DestinationsSaved,
MigrationCheckEvent,
Expand Down Expand Up @@ -160,3 +162,62 @@ export const useConfirmBackupMutation = () =>
location,
}),
);

/** Starts a copy. It is a process of its own on the server, so it keeps going when the page is gone. */
export const useStartCopyMutation = (step: CopyStepId) => {
const client = useQueryClient();
return useMutation<unknown, AxiosError<{ detail?: MigrationError }>, void>({
mutationFn: () =>
api.post(getURL("MIGRATION", { path: `steps/${step}/runs` }), {
dry_run: false,
}),
// The record now says the run is on, or what changed for the server to refuse it.
onSettled: () => client.invalidateQueries({ queryKey: migrationKeys.all }),
});
};

/** Stops a run. The page learns that it ended from the run's own events. */
export const useStopCopyMutation = (step: CopyStepId) =>
useMutation<unknown, AxiosError, string>({
mutationFn: (runId) =>
api.delete(getURL("MIGRATION", { path: `steps/${step}/runs/${runId}` })),
});

/**
* Hands over each event of a run that comes after the one numbered `after`, as it happens, down to its end.
* Resolves with the refusal when the server has no such run, or status 0 if the connection fails.
* Aborting the controller stops nothing on the server.
*/
export async function followCopy({
step,
runId,
after,
controller,
onEvent,
}: {
step: CopyStepId;
runId: string;
after: number;
controller: AbortController;
onEvent: (event: CopyEvent) => void;
}): Promise<{ status: number } | undefined> {
let refused: { status: number } | undefined;
await performStreamingRequest({
method: "GET",
url: `${getURL("MIGRATION", { path: `steps/${step}/runs/${runId}/events` })}?after=${after}`,
buildController: controller,
onError: (status) => {
refused = { status };
},
onData: async (data) => {
// A refusal answers with one JSON error body in place of the events. Let it end on its own:
// returning false would abort the caller's controller, which every later attempt shares.
if (!refused) onEvent(data as CopyEvent);
return true;
},
onNetworkError: () => {
if (!controller.signal.aborted) refused ??= { status: 0 };
},
});
return refused;
}
20 changes: 20 additions & 0 deletions src/frontend/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,26 @@
"settings.migration.backup.location.help": "Erforderlich. Geben Sie an, wo die Sicherung liegt, damit sie wiedergefunden wird, etwa ein Bucket mit Ordner oder der Name eines anderen Rechners. Langflow prüft die Angabe nicht.",
"settings.migration.backup.action": "Ich habe alles gesichert",
"settings.migration.backup.done": "Gesichert am {{time}} nach {{location}}.",
"settings.migration.copy.starting": "Wird gestartet…",
"settings.migration.copy.checking": "Es wird geprüft, was zu kopieren ist…",
"settings.migration.copy.preparing": "Die neue Datenbank wird vorbereitet…",
"settings.migration.copy.again": "Erneut kopieren",
"settings.migration.copy.stale": "Diese Kopie ist veraltet und zählt nicht mehr. Kopieren Sie erneut.",
"settings.migration.copy.stopTitle": "Kopieren stoppen?",
"settings.migration.copyDb.body": "Kopiert alle Tabellen in einem Durchgang. Wenn etwas fehlschlägt, bleibt nichts erhalten und Sie können erneut kopieren.",
"settings.migration.copyDb.progress": "Zeilen: {{done}} von {{total}}",
"settings.migration.copyDb.stopBody": "Von einer gestoppten Kopie bleibt nichts erhalten.",
"settings.migration.copyDb.done": "Tabellen: {{tables}}. Zeilen: {{rows}}.",
"settings.migration.error.interrupted": "Vor dem Abschluss gestoppt. Führen Sie den Schritt erneut aus.",
"settings.migration.error.crashed": "Der Schritt wurde mit einem Fehler beendet. Führen Sie ihn erneut aus. Wenn das wieder passiert, laden Sie das Migrationsprotokoll herunter.",
"settings.migration.error.runningElsewhere": "Ein anderer Schritt läuft gerade. Warten Sie, bis er abgeschlossen ist.",
"settings.migration.error.destinationChanged": "Das Ziel wurde nach dieser Kopie geändert. Kopieren Sie erneut.",
"settings.migration.error.enterAgain": "Langflow hat die Passwörter und Schlüssel der neuen Instanz nicht mehr. Geben Sie sie unter „{{step}}“ erneut ein.",
"settings.migration.error.targetUnreachable": "Die Datenbank der neuen Instanz ist nicht erreichbar. Prüfen Sie „{{step}}“ und versuchen Sie es erneut.",
"settings.migration.error.dbTargetNotEmpty": "Die Datenbank der neuen Instanz ist nicht leer. Verwenden Sie eine neue, leere Datenbank, ändern Sie sie unter „{{step}}“ und kopieren Sie erneut.",
"settings.migration.error.dbCountMismatch": "Die Datenbank der neuen Instanz enthält eine frühere Kopie, die nicht mehr zu dieser Instanz passt. Erneutes Kopieren in diese Datenbank behebt das nicht. Speichern Sie unter „{{step}}“ eine neue, leere Datenbank und kopieren Sie erneut.",
"settings.migration.error.orphansNoRule": "Einige Zeilen verweisen auf gelöschte Elemente und lassen sich nicht sicher auslassen. Laden Sie das Migrationsprotokoll herunter und wenden Sie sich an den Support.",
"settings.migration.error.valueRejected": "Einige Werte lassen sich nicht in PostgreSQL speichern. Laden Sie das Migrationsprotokoll herunter und wenden Sie sich an den Support.",
"settings.nav.modelProviders": "Modellanbieter",
"settings.nav.shortcuts": "Tastenkürzel",
"settings.nav.store": "Langflow-Shop",
Expand Down
20 changes: 20 additions & 0 deletions src/frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,26 @@
"settings.migration.backup.location.help": "Required. Say where you put the backup so it can be found again, for example a bucket and folder, or the name of another machine. Langflow doesn't check it.",
"settings.migration.backup.action": "I've backed up everything",
"settings.migration.backup.done": "Backed up {{time}} to {{location}}.",
"settings.migration.copy.starting": "Starting…",
"settings.migration.copy.checking": "Checking what there is to copy…",
"settings.migration.copy.preparing": "Preparing the new database…",
"settings.migration.copy.again": "Copy again",
"settings.migration.copy.stale": "This copy is out of date, so it no longer counts. Copy again.",
"settings.migration.copy.stopTitle": "Stop copying?",
"settings.migration.copyDb.body": "Copies every table in one go. If anything fails, nothing is kept and you can copy again.",
"settings.migration.copyDb.progress": "Rows: {{done}} of {{total}}",
"settings.migration.copyDb.stopBody": "Nothing from a stopped copy is kept.",
"settings.migration.copyDb.done": "Tables: {{tables}}. Rows: {{rows}}.",
"settings.migration.error.interrupted": "Stopped before it finished. Run it again.",
"settings.migration.error.crashed": "The step stopped with an error. Run it again. If it happens again, download the migration record.",
"settings.migration.error.runningElsewhere": "Another step is running. Wait for it to finish.",
"settings.migration.error.destinationChanged": "The destination changed after this copy was made. Copy again.",
"settings.migration.error.enterAgain": "Langflow no longer holds the passwords and keys of the new instance. Enter them again in '{{step}}'.",
"settings.migration.error.targetUnreachable": "Can't reach the new instance's database. Check '{{step}}', then try again.",
"settings.migration.error.dbTargetNotEmpty": "The new instance's database isn't empty. Use a new, empty database, change it in '{{step}}', then copy again.",
"settings.migration.error.dbCountMismatch": "The new instance's database holds an earlier copy that no longer matches this instance. Copying into it again can't fix that. Save a new, empty database in '{{step}}', then copy again.",
"settings.migration.error.orphansNoRule": "Some rows point at deleted items and can't be left out safely. Download the migration record and contact support.",
"settings.migration.error.valueRejected": "Some values can't be stored in PostgreSQL. Download the migration record and contact support.",
"messages.title": "Messages",
"messages.loadOlder": "Load older messages",
"messages.loadError": "Could not load messages.",
Expand Down
20 changes: 20 additions & 0 deletions src/frontend/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,26 @@
"settings.migration.backup.location.help": "Obligatorio. Indica dónde dejaste la copia de seguridad para poder encontrarla después, por ejemplo, un bucket y una carpeta, o el nombre de otra máquina. Langflow no lo comprueba.",
"settings.migration.backup.action": "He hecho copia de seguridad de todo",
"settings.migration.backup.done": "Copia de seguridad hecha el {{time}} en {{location}}.",
"settings.migration.copy.starting": "Iniciando…",
"settings.migration.copy.checking": "Comprobando qué hay que copiar…",
"settings.migration.copy.preparing": "Preparando la nueva base de datos…",
"settings.migration.copy.again": "Copiar de nuevo",
"settings.migration.copy.stale": "Esta copia está desactualizada y ya no cuenta. Copia de nuevo.",
"settings.migration.copy.stopTitle": "¿Detener la copia?",
"settings.migration.copyDb.body": "Copia todas las tablas de una vez. Si algo falla, no se conserva nada y puedes volver a copiar.",
"settings.migration.copyDb.progress": "Filas: {{done}} de {{total}}",
"settings.migration.copyDb.stopBody": "No se conserva nada de una copia detenida.",
"settings.migration.copyDb.done": "Tablas: {{tables}}. Filas: {{rows}}.",
"settings.migration.error.interrupted": "Se detuvo antes de terminar. Vuelve a ejecutarlo.",
"settings.migration.error.crashed": "El paso se detuvo con un error. Vuelve a ejecutarlo. Si ocurre de nuevo, descarga el registro de migración.",
"settings.migration.error.runningElsewhere": "Hay otro paso en ejecución. Espera a que termine.",
"settings.migration.error.destinationChanged": "El destino cambió después de hacer esta copia. Copia de nuevo.",
"settings.migration.error.enterAgain": "Langflow ya no tiene las contraseñas ni las claves de la nueva instancia. Vuelve a introducirlas en '{{step}}'.",
"settings.migration.error.targetUnreachable": "No se puede acceder a la base de datos de la nueva instancia. Revisa '{{step}}' y vuelve a intentarlo.",
"settings.migration.error.dbTargetNotEmpty": "La base de datos de la nueva instancia no está vacía. Usa una base de datos nueva y vacía, cámbiala en '{{step}}' y copia de nuevo.",
"settings.migration.error.dbCountMismatch": "La base de datos de la nueva instancia contiene una copia anterior que ya no coincide con esta instancia. Copiar de nuevo en ella no lo arregla. Guarda una base de datos nueva y vacía en '{{step}}' y copia de nuevo.",
"settings.migration.error.orphansNoRule": "Algunas filas apuntan a elementos eliminados y no se pueden omitir con seguridad. Descarga el registro de migración y contacta con soporte.",
"settings.migration.error.valueRejected": "Algunos valores no se pueden guardar en PostgreSQL. Descarga el registro de migración y contacta con soporte.",
"settings.nav.modelProviders": "Proveedores de modelos",
"settings.nav.shortcuts": "Atajos",
"settings.nav.store": "Tienda Langflow",
Expand Down
20 changes: 20 additions & 0 deletions src/frontend/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,26 @@
"settings.migration.backup.location.help": "Obligatoire. Indiquez où se trouve la sauvegarde pour pouvoir la retrouver, par exemple un bucket et un dossier, ou le nom d'une autre machine. Langflow ne le vérifie pas.",
"settings.migration.backup.action": "J'ai tout sauvegardé",
"settings.migration.backup.done": "Sauvegardé le {{time}} vers {{location}}.",
"settings.migration.copy.starting": "Démarrage…",
"settings.migration.copy.checking": "Vérification de ce qu'il y a à copier…",
"settings.migration.copy.preparing": "Préparation de la nouvelle base de données…",
"settings.migration.copy.again": "Copier à nouveau",
"settings.migration.copy.stale": "Cette copie n'est plus à jour et ne compte plus. Copiez à nouveau.",
"settings.migration.copy.stopTitle": "Arrêter la copie ?",
"settings.migration.copyDb.body": "Copie toutes les tables en une seule fois. En cas d'échec, rien n'est conservé et vous pouvez recommencer.",
"settings.migration.copyDb.progress": "Lignes : {{done}} sur {{total}}",
"settings.migration.copyDb.stopBody": "Rien n'est conservé d'une copie arrêtée.",
"settings.migration.copyDb.done": "Tables : {{tables}}. Lignes : {{rows}}.",
"settings.migration.error.interrupted": "Arrêté avant la fin. Relancez l'étape.",
"settings.migration.error.crashed": "L'étape s'est arrêtée sur une erreur. Relancez-la. Si cela se reproduit, téléchargez le journal de migration.",
"settings.migration.error.runningElsewhere": "Une autre étape est en cours. Attendez qu'elle se termine.",
"settings.migration.error.destinationChanged": "La destination a changé après cette copie. Copiez à nouveau.",
"settings.migration.error.enterAgain": "Langflow n'a plus les mots de passe ni les clés de la nouvelle instance. Saisissez-les à nouveau dans « {{step}} ».",
"settings.migration.error.targetUnreachable": "Impossible de joindre la base de données de la nouvelle instance. Vérifiez « {{step}} », puis réessayez.",
"settings.migration.error.dbTargetNotEmpty": "La base de données de la nouvelle instance n'est pas vide. Utilisez une base de données neuve et vide, modifiez-la dans « {{step}} », puis copiez à nouveau.",
"settings.migration.error.dbCountMismatch": "La base de données de la nouvelle instance contient une copie antérieure qui ne correspond plus à cette instance. Copier de nouveau dans cette base ne corrige rien. Enregistrez une base de données neuve et vide dans « {{step}} », puis copiez à nouveau.",
"settings.migration.error.orphansNoRule": "Certaines lignes renvoient à des éléments supprimés et ne peuvent pas être écartées sans risque. Téléchargez le journal de migration et contactez l'assistance.",
"settings.migration.error.valueRejected": "Certaines valeurs ne peuvent pas être stockées dans PostgreSQL. Téléchargez le journal de migration et contactez l'assistance.",
"settings.nav.modelProviders": "Fournisseurs de modèles",
"settings.nav.shortcuts": "Raccourcis",
"settings.nav.store": "Boutique Langflow",
Expand Down
20 changes: 20 additions & 0 deletions src/frontend/src/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,26 @@
"settings.migration.backup.location.help": "必須です。後で見つけられるように、バックアップの保存場所を入力します。たとえば、バケットとフォルダー、または別のマシンの名前です。Langflow は入力内容を確認しません。",
"settings.migration.backup.action": "すべてバックアップしました",
"settings.migration.backup.done": "{{time}} に {{location}} へバックアップしました。",
"settings.migration.copy.starting": "開始しています…",
"settings.migration.copy.checking": "コピーする内容を確認しています…",
"settings.migration.copy.preparing": "新しいデータベースを準備しています…",
"settings.migration.copy.again": "もう一度コピー",
"settings.migration.copy.stale": "このコピーは古くなったため、無効です。もう一度コピーしてください。",
"settings.migration.copy.stopTitle": "コピーを停止しますか?",
"settings.migration.copyDb.body": "すべてのテーブルを一度にコピーします。途中で失敗した場合は何も残らず、もう一度コピーできます。",
"settings.migration.copyDb.progress": "行: {{done}} / {{total}}",
"settings.migration.copyDb.stopBody": "停止したコピーの内容は何も残りません。",
"settings.migration.copyDb.done": "テーブル: {{tables}}。行: {{rows}}。",
"settings.migration.error.interrupted": "完了する前に停止しました。もう一度実行してください。",
"settings.migration.error.crashed": "このステップはエラーで停止しました。もう一度実行してください。再び起きた場合は、移行記録をダウンロードしてください。",
"settings.migration.error.runningElsewhere": "別のステップが実行中です。完了するまでお待ちください。",
"settings.migration.error.destinationChanged": "このコピーの後に移行先が変更されました。もう一度コピーしてください。",
"settings.migration.error.enterAgain": "新しいインスタンスのパスワードとキーは Langflow に残っていません。「{{step}}」でもう一度入力してください。",
"settings.migration.error.targetUnreachable": "新しいインスタンスのデータベースに接続できません。「{{step}}」を確認して、もう一度お試しください。",
"settings.migration.error.dbTargetNotEmpty": "新しいインスタンスのデータベースは空ではありません。新しい空のデータベースを用意し、「{{step}}」で変更してから、もう一度コピーしてください。",
"settings.migration.error.dbCountMismatch": "新しいインスタンスのデータベースには、このインスタンスと一致しなくなった以前のコピーが残っています。同じデータベースにコピーし直しても解決しません。「{{step}}」で新しい空のデータベースを保存してから、もう一度コピーしてください。",
"settings.migration.error.orphansNoRule": "一部の行は削除された項目を参照しており、安全に除外できません。移行記録をダウンロードして、サポートにお問い合わせください。",
"settings.migration.error.valueRejected": "一部の値は PostgreSQL に保存できません。移行記録をダウンロードして、サポートにお問い合わせください。",
"settings.nav.modelProviders": "モデルプロバイダー",
"settings.nav.shortcuts": "ショートカット",
"settings.nav.store": "Langflowストア",
Expand Down
Loading
Loading