mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
Compare commits
1 Commits
feat/limit
...
feat/multi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
967091df22 |
@@ -756,15 +756,6 @@ export type ListRepositoriesResponses = {
|
|||||||
password?: string;
|
password?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
} | {
|
|
||||||
backend: 'sftp';
|
|
||||||
host: string;
|
|
||||||
path: string;
|
|
||||||
privateKey: string;
|
|
||||||
user: string;
|
|
||||||
port?: number;
|
|
||||||
customPassword?: string;
|
|
||||||
isExistingRepository?: boolean;
|
|
||||||
};
|
};
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -772,7 +763,7 @@ export type ListRepositoriesResponses = {
|
|||||||
lastError: string | null;
|
lastError: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
status: 'error' | 'healthy' | 'unknown' | null;
|
status: 'error' | 'healthy' | 'unknown' | null;
|
||||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
@@ -832,15 +823,6 @@ export type CreateRepositoryData = {
|
|||||||
password?: string;
|
password?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
} | {
|
|
||||||
backend: 'sftp';
|
|
||||||
host: string;
|
|
||||||
path: string;
|
|
||||||
privateKey: string;
|
|
||||||
user: string;
|
|
||||||
port?: number;
|
|
||||||
customPassword?: string;
|
|
||||||
isExistingRepository?: boolean;
|
|
||||||
};
|
};
|
||||||
name: string;
|
name: string;
|
||||||
compressionMode?: 'auto' | 'better' | 'fastest' | 'max' | 'off';
|
compressionMode?: 'auto' | 'better' | 'fastest' | 'max' | 'off';
|
||||||
@@ -970,15 +952,6 @@ export type GetRepositoryResponses = {
|
|||||||
password?: string;
|
password?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
} | {
|
|
||||||
backend: 'sftp';
|
|
||||||
host: string;
|
|
||||||
path: string;
|
|
||||||
privateKey: string;
|
|
||||||
user: string;
|
|
||||||
port?: number;
|
|
||||||
customPassword?: string;
|
|
||||||
isExistingRepository?: boolean;
|
|
||||||
};
|
};
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -986,7 +959,7 @@ export type GetRepositoryResponses = {
|
|||||||
lastError: string | null;
|
lastError: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
status: 'error' | 'healthy' | 'unknown' | null;
|
status: 'error' | 'healthy' | 'unknown' | null;
|
||||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1235,15 +1208,6 @@ export type ListBackupSchedulesResponses = {
|
|||||||
password?: string;
|
password?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
} | {
|
|
||||||
backend: 'sftp';
|
|
||||||
host: string;
|
|
||||||
path: string;
|
|
||||||
privateKey: string;
|
|
||||||
user: string;
|
|
||||||
port?: number;
|
|
||||||
customPassword?: string;
|
|
||||||
isExistingRepository?: boolean;
|
|
||||||
};
|
};
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -1251,7 +1215,7 @@ export type ListBackupSchedulesResponses = {
|
|||||||
lastError: string | null;
|
lastError: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
status: 'error' | 'healthy' | 'unknown' | null;
|
status: 'error' | 'healthy' | 'unknown' | null;
|
||||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
repositoryId: string;
|
repositoryId: string;
|
||||||
@@ -1466,15 +1430,6 @@ export type GetBackupScheduleResponses = {
|
|||||||
password?: string;
|
password?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
} | {
|
|
||||||
backend: 'sftp';
|
|
||||||
host: string;
|
|
||||||
path: string;
|
|
||||||
privateKey: string;
|
|
||||||
user: string;
|
|
||||||
port?: number;
|
|
||||||
customPassword?: string;
|
|
||||||
isExistingRepository?: boolean;
|
|
||||||
};
|
};
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -1482,7 +1437,7 @@ export type GetBackupScheduleResponses = {
|
|||||||
lastError: string | null;
|
lastError: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
status: 'error' | 'healthy' | 'unknown' | null;
|
status: 'error' | 'healthy' | 'unknown' | null;
|
||||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
repositoryId: string;
|
repositoryId: string;
|
||||||
@@ -1678,15 +1633,6 @@ export type GetBackupScheduleForVolumeResponses = {
|
|||||||
password?: string;
|
password?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
} | {
|
|
||||||
backend: 'sftp';
|
|
||||||
host: string;
|
|
||||||
path: string;
|
|
||||||
privateKey: string;
|
|
||||||
user: string;
|
|
||||||
port?: number;
|
|
||||||
customPassword?: string;
|
|
||||||
isExistingRepository?: boolean;
|
|
||||||
};
|
};
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -1694,7 +1640,7 @@ export type GetBackupScheduleForVolumeResponses = {
|
|||||||
lastError: string | null;
|
lastError: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
status: 'error' | 'healthy' | 'unknown' | null;
|
status: 'error' | 'healthy' | 'unknown' | null;
|
||||||
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp';
|
type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
repositoryId: string;
|
repositoryId: string;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ const internalFormSchema = type({
|
|||||||
frequency: "string",
|
frequency: "string",
|
||||||
dailyTime: "string?",
|
dailyTime: "string?",
|
||||||
weeklyDay: "string?",
|
weeklyDay: "string?",
|
||||||
limitUploadKbps: "number?",
|
|
||||||
keepLast: "number?",
|
keepLast: "number?",
|
||||||
keepHourly: "number?",
|
keepHourly: "number?",
|
||||||
keepDaily: "number?",
|
keepDaily: "number?",
|
||||||
@@ -87,7 +86,6 @@ const backupScheduleToFormValues = (schedule?: BackupSchedule): InternalFormValu
|
|||||||
weeklyDay,
|
weeklyDay,
|
||||||
includePatterns: schedule.includePatterns || undefined,
|
includePatterns: schedule.includePatterns || undefined,
|
||||||
excludePatternsText: schedule.excludePatterns?.join("\n") || undefined,
|
excludePatternsText: schedule.excludePatterns?.join("\n") || undefined,
|
||||||
limitUploadKbps: schedule.limitUploadKbps || undefined,
|
|
||||||
...schedule.retentionPolicy,
|
...schedule.retentionPolicy,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -249,29 +247,6 @@ 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>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -507,12 +482,6 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }:
|
|||||||
{repositoriesData?.find((r) => r.id === formValues.repositoryId)?.name || "—"}
|
{repositoriesData?.find((r) => r.id === formValues.repositoryId)?.name || "—"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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 && (
|
{formValues.includePatterns && formValues.includePatterns.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-muted-foreground">Include paths</p>
|
<p className="text-xs uppercase text-muted-foreground">Include paths</p>
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
|||||||
retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
|
retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
|
||||||
includePatterns: formValues.includePatterns,
|
includePatterns: formValues.includePatterns,
|
||||||
excludePatterns: formValues.excludePatterns,
|
excludePatterns: formValues.excludePatterns,
|
||||||
limitUploadKbps: formValues.limitUploadKbps,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -171,7 +170,6 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
|||||||
retentionPolicy: schedule.retentionPolicy || undefined,
|
retentionPolicy: schedule.retentionPolicy || undefined,
|
||||||
includePatterns: schedule.includePatterns || undefined,
|
includePatterns: schedule.includePatterns || undefined,
|
||||||
excludePatterns: schedule.excludePatterns || undefined,
|
excludePatterns: schedule.excludePatterns || undefined,
|
||||||
limitUploadKbps: schedule.limitUploadKbps || undefined,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ export default function CreateBackup({ loaderData }: Route.ComponentProps) {
|
|||||||
retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
|
retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
|
||||||
includePatterns: formValues.includePatterns,
|
includePatterns: formValues.includePatterns,
|
||||||
excludePatterns: formValues.excludePatterns,
|
excludePatterns: formValues.excludePatterns,
|
||||||
limitUploadKbps: formValues.limitUploadKbps,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE `backup_schedules_table` ADD `limit_upload_kbps` integer;
|
|
||||||
@@ -1,466 +0,0 @@
|
|||||||
{
|
|
||||||
"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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -78,13 +78,6 @@
|
|||||||
"when": 1762610065889,
|
"when": 1762610065889,
|
||||||
"tag": "0010_perfect_proemial_gods",
|
"tag": "0010_perfect_proemial_gods",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 11,
|
|
||||||
"version": "6",
|
|
||||||
"when": 1763728410318,
|
|
||||||
"tag": "0011_lazy_havok",
|
|
||||||
"breakpoints": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -67,9 +67,6 @@ export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
|
|||||||
volumeId: int("volume_id")
|
volumeId: int("volume_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => volumesTable.id, { onDelete: "cascade" }),
|
.references(() => volumesTable.id, { onDelete: "cascade" }),
|
||||||
repositoryId: text("repository_id")
|
|
||||||
.notNull()
|
|
||||||
.references(() => repositoriesTable.id, { onDelete: "cascade" }),
|
|
||||||
enabled: int("enabled", { mode: "boolean" }).notNull().default(true),
|
enabled: int("enabled", { mode: "boolean" }).notNull().default(true),
|
||||||
cronExpression: text("cron_expression").notNull(),
|
cronExpression: text("cron_expression").notNull(),
|
||||||
retentionPolicy: text("retention_policy", { mode: "json" }).$type<{
|
retentionPolicy: text("retention_policy", { mode: "json" }).$type<{
|
||||||
@@ -83,7 +80,6 @@ export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
|
|||||||
}>(),
|
}>(),
|
||||||
excludePatterns: text("exclude_patterns", { mode: "json" }).$type<string[]>().default([]),
|
excludePatterns: text("exclude_patterns", { mode: "json" }).$type<string[]>().default([]),
|
||||||
includePatterns: text("include_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" }),
|
lastBackupAt: int("last_backup_at", { mode: "number" }),
|
||||||
lastBackupStatus: text("last_backup_status").$type<"success" | "error" | "in_progress">(),
|
lastBackupStatus: text("last_backup_status").$type<"success" | "error" | "in_progress">(),
|
||||||
lastBackupError: text("last_backup_error"),
|
lastBackupError: text("last_backup_error"),
|
||||||
@@ -91,14 +87,43 @@ export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
|
|||||||
createdAt: int("created_at", { mode: "number" }).notNull().default(sql`(unixepoch())`),
|
createdAt: int("created_at", { mode: "number" }).notNull().default(sql`(unixepoch())`),
|
||||||
updatedAt: int("updated_at", { mode: "number" }).notNull().default(sql`(unixepoch())`),
|
updatedAt: int("updated_at", { mode: "number" }).notNull().default(sql`(unixepoch())`),
|
||||||
});
|
});
|
||||||
export const backupScheduleRelations = relations(backupSchedulesTable, ({ one }) => ({
|
|
||||||
|
/**
|
||||||
|
* Junction Table: Backup Schedules <-> Repositories (Many-to-Many)
|
||||||
|
*/
|
||||||
|
export const backupScheduleRepositoriesTable = sqliteTable(
|
||||||
|
"backup_schedule_repositories_table",
|
||||||
|
{
|
||||||
|
scheduleId: int("schedule_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => backupSchedulesTable.id, { onDelete: "cascade" }),
|
||||||
|
repositoryId: text("repository_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => repositoriesTable.id, { onDelete: "cascade" }),
|
||||||
|
},
|
||||||
|
(table) => ({
|
||||||
|
pk: { name: "pk_schedule_repository", columns: [table.scheduleId, table.repositoryId] },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const backupScheduleRelations = relations(backupSchedulesTable, ({ one, many }) => ({
|
||||||
volume: one(volumesTable, {
|
volume: one(volumesTable, {
|
||||||
fields: [backupSchedulesTable.volumeId],
|
fields: [backupSchedulesTable.volumeId],
|
||||||
references: [volumesTable.id],
|
references: [volumesTable.id],
|
||||||
}),
|
}),
|
||||||
|
repositories: many(backupScheduleRepositoriesTable),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const backupScheduleRepositoryRelations = relations(backupScheduleRepositoriesTable, ({ one }) => ({
|
||||||
|
schedule: one(backupSchedulesTable, {
|
||||||
|
fields: [backupScheduleRepositoriesTable.scheduleId],
|
||||||
|
references: [backupSchedulesTable.id],
|
||||||
|
}),
|
||||||
repository: one(repositoriesTable, {
|
repository: one(repositoriesTable, {
|
||||||
fields: [backupSchedulesTable.repositoryId],
|
fields: [backupScheduleRepositoriesTable.repositoryId],
|
||||||
references: [repositoriesTable.id],
|
references: [repositoriesTable.id],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type BackupSchedule = typeof backupSchedulesTable.$inferSelect;
|
export type BackupSchedule = typeof backupSchedulesTable.$inferSelect;
|
||||||
|
export type BackupScheduleRepository = typeof backupScheduleRepositoriesTable.$inferSelect;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ const backupScheduleSchema = type({
|
|||||||
retentionPolicy: retentionPolicySchema.or("null"),
|
retentionPolicy: retentionPolicySchema.or("null"),
|
||||||
excludePatterns: "string[] | null",
|
excludePatterns: "string[] | null",
|
||||||
includePatterns: "string[] | null",
|
includePatterns: "string[] | null",
|
||||||
limitUploadKbps: "number | null",
|
|
||||||
lastBackupAt: "number | null",
|
lastBackupAt: "number | null",
|
||||||
lastBackupStatus: "'success' | 'error' | 'in_progress' | null",
|
lastBackupStatus: "'success' | 'error' | 'in_progress' | null",
|
||||||
lastBackupError: "string | null",
|
lastBackupError: "string | null",
|
||||||
@@ -115,7 +114,6 @@ export const createBackupScheduleBody = type({
|
|||||||
retentionPolicy: retentionPolicySchema.optional(),
|
retentionPolicy: retentionPolicySchema.optional(),
|
||||||
excludePatterns: "string[]?",
|
excludePatterns: "string[]?",
|
||||||
includePatterns: "string[]?",
|
includePatterns: "string[]?",
|
||||||
limitUploadKbps: "number?",
|
|
||||||
tags: "string[]?",
|
tags: "string[]?",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,7 +149,6 @@ export const updateBackupScheduleBody = type({
|
|||||||
retentionPolicy: retentionPolicySchema.optional(),
|
retentionPolicy: retentionPolicySchema.optional(),
|
||||||
excludePatterns: "string[]?",
|
excludePatterns: "string[]?",
|
||||||
includePatterns: "string[]?",
|
includePatterns: "string[]?",
|
||||||
limitUploadKbps: "number?",
|
|
||||||
tags: "string[]?",
|
tags: "string[]?",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
|
|||||||
retentionPolicy: data.retentionPolicy ?? null,
|
retentionPolicy: data.retentionPolicy ?? null,
|
||||||
excludePatterns: data.excludePatterns ?? [],
|
excludePatterns: data.excludePatterns ?? [],
|
||||||
includePatterns: data.includePatterns ?? [],
|
includePatterns: data.includePatterns ?? [],
|
||||||
limitUploadKbps: data.limitUploadKbps ?? null,
|
|
||||||
nextBackupAt: nextBackupAt,
|
nextBackupAt: nextBackupAt,
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
@@ -213,11 +212,9 @@ const executeBackup = async (scheduleId: number, manual = false) => {
|
|||||||
exclude?: string[];
|
exclude?: string[];
|
||||||
include?: string[];
|
include?: string[];
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
limitUploadKbps?: number | null;
|
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
} = {
|
} = {
|
||||||
tags: [schedule.id.toString()],
|
tags: [schedule.id.toString()],
|
||||||
limitUploadKbps: schedule.limitUploadKbps,
|
|
||||||
signal: abortController.signal,
|
signal: abortController.signal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -234,7 +234,6 @@ const backup = async (
|
|||||||
exclude?: string[];
|
exclude?: string[];
|
||||||
include?: string[];
|
include?: string[];
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
limitUploadKbps?: number | null;
|
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
onProgress?: (progress: BackupProgress) => void;
|
onProgress?: (progress: BackupProgress) => void;
|
||||||
},
|
},
|
||||||
@@ -244,10 +243,6 @@ const backup = async (
|
|||||||
|
|
||||||
const args: string[] = ["--repo", repoUrl, "backup", "--one-file-system"];
|
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) {
|
if (options?.tags && options.tags.length > 0) {
|
||||||
for (const tag of options.tags) {
|
for (const tag of options.tags) {
|
||||||
args.push("--tag", tag);
|
args.push("--tag", tag);
|
||||||
|
|||||||
Reference in New Issue
Block a user