mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
Compare commits
1 Commits
999850dab8
...
feat/limit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ccece42f0 |
@@ -756,6 +756,15 @@ export type ListRepositoriesResponses = {
|
||||
password?: string;
|
||||
path?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
backend: 'sftp';
|
||||
host: string;
|
||||
path: string;
|
||||
privateKey: string;
|
||||
user: string;
|
||||
port?: number;
|
||||
customPassword?: string;
|
||||
isExistingRepository?: boolean;
|
||||
};
|
||||
createdAt: number;
|
||||
id: string;
|
||||
@@ -763,7 +772,7 @@ export type ListRepositoriesResponses = {
|
||||
lastError: string | null;
|
||||
name: string;
|
||||
status: 'error' | 'healthy' | 'unknown' | null;
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
||||
updatedAt: number;
|
||||
}>;
|
||||
};
|
||||
@@ -823,6 +832,15 @@ export type CreateRepositoryData = {
|
||||
password?: string;
|
||||
path?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
backend: 'sftp';
|
||||
host: string;
|
||||
path: string;
|
||||
privateKey: string;
|
||||
user: string;
|
||||
port?: number;
|
||||
customPassword?: string;
|
||||
isExistingRepository?: boolean;
|
||||
};
|
||||
name: string;
|
||||
compressionMode?: 'auto' | 'better' | 'fastest' | 'max' | 'off';
|
||||
@@ -952,6 +970,15 @@ export type GetRepositoryResponses = {
|
||||
password?: string;
|
||||
path?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
backend: 'sftp';
|
||||
host: string;
|
||||
path: string;
|
||||
privateKey: string;
|
||||
user: string;
|
||||
port?: number;
|
||||
customPassword?: string;
|
||||
isExistingRepository?: boolean;
|
||||
};
|
||||
createdAt: number;
|
||||
id: string;
|
||||
@@ -959,7 +986,7 @@ export type GetRepositoryResponses = {
|
||||
lastError: string | null;
|
||||
name: string;
|
||||
status: 'error' | 'healthy' | 'unknown' | null;
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
||||
updatedAt: number;
|
||||
};
|
||||
};
|
||||
@@ -1208,6 +1235,15 @@ export type ListBackupSchedulesResponses = {
|
||||
password?: string;
|
||||
path?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
backend: 'sftp';
|
||||
host: string;
|
||||
path: string;
|
||||
privateKey: string;
|
||||
user: string;
|
||||
port?: number;
|
||||
customPassword?: string;
|
||||
isExistingRepository?: boolean;
|
||||
};
|
||||
createdAt: number;
|
||||
id: string;
|
||||
@@ -1215,7 +1251,7 @@ export type ListBackupSchedulesResponses = {
|
||||
lastError: string | null;
|
||||
name: string;
|
||||
status: 'error' | 'healthy' | 'unknown' | null;
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
||||
updatedAt: number;
|
||||
};
|
||||
repositoryId: string;
|
||||
@@ -1430,6 +1466,15 @@ export type GetBackupScheduleResponses = {
|
||||
password?: string;
|
||||
path?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
backend: 'sftp';
|
||||
host: string;
|
||||
path: string;
|
||||
privateKey: string;
|
||||
user: string;
|
||||
port?: number;
|
||||
customPassword?: string;
|
||||
isExistingRepository?: boolean;
|
||||
};
|
||||
createdAt: number;
|
||||
id: string;
|
||||
@@ -1437,7 +1482,7 @@ export type GetBackupScheduleResponses = {
|
||||
lastError: string | null;
|
||||
name: string;
|
||||
status: 'error' | 'healthy' | 'unknown' | null;
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
||||
updatedAt: number;
|
||||
};
|
||||
repositoryId: string;
|
||||
@@ -1633,6 +1678,15 @@ export type GetBackupScheduleForVolumeResponses = {
|
||||
password?: string;
|
||||
path?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
backend: 'sftp';
|
||||
host: string;
|
||||
path: string;
|
||||
privateKey: string;
|
||||
user: string;
|
||||
port?: number;
|
||||
customPassword?: string;
|
||||
isExistingRepository?: boolean;
|
||||
};
|
||||
createdAt: number;
|
||||
id: string;
|
||||
@@ -1640,7 +1694,7 @@ export type GetBackupScheduleForVolumeResponses = {
|
||||
lastError: string | null;
|
||||
name: string;
|
||||
status: 'error' | 'healthy' | 'unknown' | null;
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
||||
updatedAt: number;
|
||||
};
|
||||
repositoryId: string;
|
||||
|
||||
@@ -29,6 +29,7 @@ const internalFormSchema = type({
|
||||
frequency: "string",
|
||||
dailyTime: "string?",
|
||||
weeklyDay: "string?",
|
||||
limitUploadKbps: "number?",
|
||||
keepLast: "number?",
|
||||
keepHourly: "number?",
|
||||
keepDaily: "number?",
|
||||
@@ -86,6 +87,7 @@ const backupScheduleToFormValues = (schedule?: BackupSchedule): InternalFormValu
|
||||
weeklyDay,
|
||||
includePatterns: schedule.includePatterns || undefined,
|
||||
excludePatternsText: schedule.excludePatterns?.join("\n") || undefined,
|
||||
limitUploadKbps: schedule.limitUploadKbps || undefined,
|
||||
...schedule.retentionPolicy,
|
||||
};
|
||||
};
|
||||
@@ -247,6 +249,29 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }:
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="limitUploadKbps"
|
||||
render={({ field }) => (
|
||||
<FormItem className="md:col-span-2">
|
||||
<FormLabel>Upload speed limit (KB/s)</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="number"
|
||||
min={0}
|
||||
placeholder="Unlimited"
|
||||
onChange={(v) => field.onChange(v.target.value ? Number(v.target.value) : undefined)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Limit upload bandwidth in kilobytes per second. Leave empty for unlimited speed.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -482,6 +507,12 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }:
|
||||
{repositoriesData?.find((r) => r.id === formValues.repositoryId)?.name || "—"}
|
||||
</p>
|
||||
</div>
|
||||
{formValues.limitUploadKbps && (
|
||||
<div>
|
||||
<p className="text-xs uppercase text-muted-foreground">Upload speed limit</p>
|
||||
<p className="font-medium">{formValues.limitUploadKbps} KB/s</p>
|
||||
</div>
|
||||
)}
|
||||
{formValues.includePatterns && formValues.includePatterns.length > 0 && (
|
||||
<div>
|
||||
<p className="text-xs uppercase text-muted-foreground">Include paths</p>
|
||||
|
||||
@@ -156,6 +156,7 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
||||
retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
|
||||
includePatterns: formValues.includePatterns,
|
||||
excludePatterns: formValues.excludePatterns,
|
||||
limitUploadKbps: formValues.limitUploadKbps,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -170,6 +171,7 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
||||
retentionPolicy: schedule.retentionPolicy || undefined,
|
||||
includePatterns: schedule.includePatterns || undefined,
|
||||
excludePatterns: schedule.excludePatterns || undefined,
|
||||
limitUploadKbps: schedule.limitUploadKbps || undefined,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -90,6 +90,7 @@ export default function CreateBackup({ loaderData }: Route.ComponentProps) {
|
||||
retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
|
||||
includePatterns: formValues.includePatterns,
|
||||
excludePatterns: formValues.excludePatterns,
|
||||
limitUploadKbps: formValues.limitUploadKbps,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
1
app/drizzle/0011_lazy_havok.sql
Normal file
1
app/drizzle/0011_lazy_havok.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE `backup_schedules_table` ADD `limit_upload_kbps` integer;
|
||||
466
app/drizzle/meta/0011_snapshot.json
Normal file
466
app/drizzle/meta/0011_snapshot.json
Normal file
@@ -0,0 +1,466 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "3ad94485-0846-44f1-8430-44d75bf16f69",
|
||||
"prevId": "17f234ba-4123-4951-a39f-6002d537435f",
|
||||
"tables": {
|
||||
"backup_schedules_table": {
|
||||
"name": "backup_schedules_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"volume_id": {
|
||||
"name": "volume_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"repository_id": {
|
||||
"name": "repository_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": true
|
||||
},
|
||||
"cron_expression": {
|
||||
"name": "cron_expression",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"retention_policy": {
|
||||
"name": "retention_policy",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"exclude_patterns": {
|
||||
"name": "exclude_patterns",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "'[]'"
|
||||
},
|
||||
"include_patterns": {
|
||||
"name": "include_patterns",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "'[]'"
|
||||
},
|
||||
"limit_upload_kbps": {
|
||||
"name": "limit_upload_kbps",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"last_backup_at": {
|
||||
"name": "last_backup_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"last_backup_status": {
|
||||
"name": "last_backup_status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"last_backup_error": {
|
||||
"name": "last_backup_error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"next_backup_at": {
|
||||
"name": "next_backup_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"backup_schedules_table_volume_id_volumes_table_id_fk": {
|
||||
"name": "backup_schedules_table_volume_id_volumes_table_id_fk",
|
||||
"tableFrom": "backup_schedules_table",
|
||||
"tableTo": "volumes_table",
|
||||
"columnsFrom": [
|
||||
"volume_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"backup_schedules_table_repository_id_repositories_table_id_fk": {
|
||||
"name": "backup_schedules_table_repository_id_repositories_table_id_fk",
|
||||
"tableFrom": "backup_schedules_table",
|
||||
"tableTo": "repositories_table",
|
||||
"columnsFrom": [
|
||||
"repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"repositories_table": {
|
||||
"name": "repositories_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"config": {
|
||||
"name": "config",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"compression_mode": {
|
||||
"name": "compression_mode",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "'auto'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "'unknown'"
|
||||
},
|
||||
"last_checked": {
|
||||
"name": "last_checked",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"last_error": {
|
||||
"name": "last_error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"repositories_table_name_unique": {
|
||||
"name": "repositories_table_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"sessions_table": {
|
||||
"name": "sessions_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"sessions_table_user_id_users_table_id_fk": {
|
||||
"name": "sessions_table_user_id_users_table_id_fk",
|
||||
"tableFrom": "sessions_table",
|
||||
"tableTo": "users_table",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users_table": {
|
||||
"name": "users_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"password_hash": {
|
||||
"name": "password_hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"has_downloaded_restic_password": {
|
||||
"name": "has_downloaded_restic_password",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_table_username_unique": {
|
||||
"name": "users_table_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"volumes_table": {
|
||||
"name": "volumes_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'unmounted'"
|
||||
},
|
||||
"last_error": {
|
||||
"name": "last_error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"last_health_check": {
|
||||
"name": "last_health_check",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch())"
|
||||
},
|
||||
"config": {
|
||||
"name": "config",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"auto_remount": {
|
||||
"name": "auto_remount",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"volumes_table_name_unique": {
|
||||
"name": "volumes_table_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +1,90 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1755765658194,
|
||||
"tag": "0000_known_madelyne_pryor",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "6",
|
||||
"when": 1755775437391,
|
||||
"tag": "0001_far_frank_castle",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "6",
|
||||
"when": 1756930554198,
|
||||
"tag": "0002_cheerful_randall",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "6",
|
||||
"when": 1758653407064,
|
||||
"tag": "0003_mature_hellcat",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "6",
|
||||
"when": 1758961535488,
|
||||
"tag": "0004_wealthy_tomas",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "6",
|
||||
"when": 1759416698274,
|
||||
"tag": "0005_simple_alice",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "6",
|
||||
"when": 1760734377440,
|
||||
"tag": "0006_secret_micromacro",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "6",
|
||||
"when": 1761224911352,
|
||||
"tag": "0007_watery_sersi",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "6",
|
||||
"when": 1761414054481,
|
||||
"tag": "0008_silent_lady_bullseye",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "6",
|
||||
"when": 1762095226041,
|
||||
"tag": "0009_little_adam_warlock",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "6",
|
||||
"when": 1762610065889,
|
||||
"tag": "0010_perfect_proemial_gods",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1755765658194,
|
||||
"tag": "0000_known_madelyne_pryor",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "6",
|
||||
"when": 1755775437391,
|
||||
"tag": "0001_far_frank_castle",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "6",
|
||||
"when": 1756930554198,
|
||||
"tag": "0002_cheerful_randall",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "6",
|
||||
"when": 1758653407064,
|
||||
"tag": "0003_mature_hellcat",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "6",
|
||||
"when": 1758961535488,
|
||||
"tag": "0004_wealthy_tomas",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "6",
|
||||
"when": 1759416698274,
|
||||
"tag": "0005_simple_alice",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "6",
|
||||
"when": 1760734377440,
|
||||
"tag": "0006_secret_micromacro",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "6",
|
||||
"when": 1761224911352,
|
||||
"tag": "0007_watery_sersi",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "6",
|
||||
"when": 1761414054481,
|
||||
"tag": "0008_silent_lady_bullseye",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "6",
|
||||
"when": 1762095226041,
|
||||
"tag": "0009_little_adam_warlock",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "6",
|
||||
"when": 1762610065889,
|
||||
"tag": "0010_perfect_proemial_gods",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"version": "6",
|
||||
"when": 1763728410318,
|
||||
"tag": "0011_lazy_havok",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -83,6 +83,7 @@ export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
|
||||
}>(),
|
||||
excludePatterns: text("exclude_patterns", { mode: "json" }).$type<string[]>().default([]),
|
||||
includePatterns: text("include_patterns", { mode: "json" }).$type<string[]>().default([]),
|
||||
limitUploadKbps: int("limit_upload_kbps", { mode: "number" }),
|
||||
lastBackupAt: int("last_backup_at", { mode: "number" }),
|
||||
lastBackupStatus: text("last_backup_status").$type<"success" | "error" | "in_progress">(),
|
||||
lastBackupError: text("last_backup_error"),
|
||||
|
||||
@@ -24,6 +24,7 @@ const backupScheduleSchema = type({
|
||||
retentionPolicy: retentionPolicySchema.or("null"),
|
||||
excludePatterns: "string[] | null",
|
||||
includePatterns: "string[] | null",
|
||||
limitUploadKbps: "number | null",
|
||||
lastBackupAt: "number | null",
|
||||
lastBackupStatus: "'success' | 'error' | 'in_progress' | null",
|
||||
lastBackupError: "string | null",
|
||||
@@ -114,6 +115,7 @@ export const createBackupScheduleBody = type({
|
||||
retentionPolicy: retentionPolicySchema.optional(),
|
||||
excludePatterns: "string[]?",
|
||||
includePatterns: "string[]?",
|
||||
limitUploadKbps: "number?",
|
||||
tags: "string[]?",
|
||||
});
|
||||
|
||||
@@ -149,6 +151,7 @@ export const updateBackupScheduleBody = type({
|
||||
retentionPolicy: retentionPolicySchema.optional(),
|
||||
excludePatterns: "string[]?",
|
||||
includePatterns: "string[]?",
|
||||
limitUploadKbps: "number?",
|
||||
tags: "string[]?",
|
||||
});
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
|
||||
retentionPolicy: data.retentionPolicy ?? null,
|
||||
excludePatterns: data.excludePatterns ?? [],
|
||||
includePatterns: data.includePatterns ?? [],
|
||||
limitUploadKbps: data.limitUploadKbps ?? null,
|
||||
nextBackupAt: nextBackupAt,
|
||||
})
|
||||
.returning();
|
||||
@@ -212,9 +213,11 @@ const executeBackup = async (scheduleId: number, manual = false) => {
|
||||
exclude?: string[];
|
||||
include?: string[];
|
||||
tags?: string[];
|
||||
limitUploadKbps?: number | null;
|
||||
signal?: AbortSignal;
|
||||
} = {
|
||||
tags: [schedule.id.toString()],
|
||||
limitUploadKbps: schedule.limitUploadKbps,
|
||||
signal: abortController.signal,
|
||||
};
|
||||
|
||||
|
||||
@@ -234,6 +234,7 @@ const backup = async (
|
||||
exclude?: string[];
|
||||
include?: string[];
|
||||
tags?: string[];
|
||||
limitUploadKbps?: number | null;
|
||||
signal?: AbortSignal;
|
||||
onProgress?: (progress: BackupProgress) => void;
|
||||
},
|
||||
@@ -243,6 +244,10 @@ const backup = async (
|
||||
|
||||
const args: string[] = ["--repo", repoUrl, "backup", "--one-file-system"];
|
||||
|
||||
if (options?.limitUploadKbps) {
|
||||
args.push("--limit-upload", String(options.limitUploadKbps));
|
||||
}
|
||||
|
||||
if (options?.tags && options.tags.length > 0) {
|
||||
for (const tag of options.tags) {
|
||||
args.push("--tag", tag);
|
||||
|
||||
Reference in New Issue
Block a user