mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-18 15:00:52 +01:00
Compare commits
4 Commits
931d51a1e1
...
c71b8468df
| Author | SHA1 | Date | |
|---|---|---|---|
| c71b8468df | |||
| 3a4f482021 | |||
| 88507410ed | |||
| f38cecc84b |
@ -18,8 +18,14 @@
|
|||||||
"fs:allow-appconfig-write-recursive",
|
"fs:allow-appconfig-write-recursive",
|
||||||
"fs:allow-appdata-read-recursive",
|
"fs:allow-appdata-read-recursive",
|
||||||
"fs:allow-appdata-write-recursive",
|
"fs:allow-appdata-write-recursive",
|
||||||
|
"fs:allow-applocaldata-read-recursive",
|
||||||
|
"fs:allow-applocaldata-write-recursive",
|
||||||
"fs:allow-read-file",
|
"fs:allow-read-file",
|
||||||
|
"fs:allow-write-file",
|
||||||
"fs:allow-read-dir",
|
"fs:allow-read-dir",
|
||||||
|
"fs:allow-mkdir",
|
||||||
|
"fs:allow-exists",
|
||||||
|
"fs:allow-remove",
|
||||||
"fs:allow-resource-read-recursive",
|
"fs:allow-resource-read-recursive",
|
||||||
"fs:allow-resource-write-recursive",
|
"fs:allow-resource-write-recursive",
|
||||||
"fs:allow-download-read-recursive",
|
"fs:allow-download-read-recursive",
|
||||||
|
|||||||
105
src-tauri/database/migrations/0000_cynical_nicolaos.sql
Normal file
105
src-tauri/database/migrations/0000_cynical_nicolaos.sql
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
CREATE TABLE `haex_crdt_configs` (
|
||||||
|
`key` text PRIMARY KEY NOT NULL,
|
||||||
|
`value` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_crdt_logs` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`haex_timestamp` text,
|
||||||
|
`table_name` text,
|
||||||
|
`row_pks` text,
|
||||||
|
`op_type` text,
|
||||||
|
`column_name` text,
|
||||||
|
`new_value` text,
|
||||||
|
`old_value` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE INDEX `idx_haex_timestamp` ON `haex_crdt_logs` (`haex_timestamp`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `idx_table_row` ON `haex_crdt_logs` (`table_name`,`row_pks`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_crdt_snapshots` (
|
||||||
|
`snapshot_id` text PRIMARY KEY NOT NULL,
|
||||||
|
`created` text,
|
||||||
|
`epoch_hlc` text,
|
||||||
|
`location_url` text,
|
||||||
|
`file_size_bytes` integer
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_desktop_items` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`workspace_id` text NOT NULL,
|
||||||
|
`item_type` text NOT NULL,
|
||||||
|
`extension_id` text,
|
||||||
|
`system_window_id` text,
|
||||||
|
`position_x` integer DEFAULT 0 NOT NULL,
|
||||||
|
`position_y` integer DEFAULT 0 NOT NULL,
|
||||||
|
`haex_timestamp` text,
|
||||||
|
FOREIGN KEY (`workspace_id`) REFERENCES `haex_workspaces`(`id`) ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE cascade,
|
||||||
|
CONSTRAINT "item_reference" CHECK(("haex_desktop_items"."item_type" = 'extension' AND "haex_desktop_items"."extension_id" IS NOT NULL AND "haex_desktop_items"."system_window_id" IS NULL) OR ("haex_desktop_items"."item_type" = 'system' AND "haex_desktop_items"."system_window_id" IS NOT NULL AND "haex_desktop_items"."extension_id" IS NULL) OR ("haex_desktop_items"."item_type" = 'file' AND "haex_desktop_items"."system_window_id" IS NOT NULL AND "haex_desktop_items"."extension_id" IS NULL) OR ("haex_desktop_items"."item_type" = 'folder' AND "haex_desktop_items"."system_window_id" IS NOT NULL AND "haex_desktop_items"."extension_id" IS NULL))
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_extension_permissions` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`extension_id` text NOT NULL,
|
||||||
|
`resource_type` text,
|
||||||
|
`action` text,
|
||||||
|
`target` text,
|
||||||
|
`constraints` text,
|
||||||
|
`status` text DEFAULT 'denied' NOT NULL,
|
||||||
|
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
|
||||||
|
`updated_at` integer,
|
||||||
|
`haex_timestamp` text,
|
||||||
|
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_extension_permissions_extension_id_resource_type_action_target_unique` ON `haex_extension_permissions` (`extension_id`,`resource_type`,`action`,`target`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_extensions` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`public_key` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`version` text NOT NULL,
|
||||||
|
`author` text,
|
||||||
|
`description` text,
|
||||||
|
`entry` text DEFAULT 'index.html',
|
||||||
|
`homepage` text,
|
||||||
|
`enabled` integer DEFAULT true,
|
||||||
|
`icon` text,
|
||||||
|
`signature` text NOT NULL,
|
||||||
|
`single_instance` integer DEFAULT false,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_extensions_public_key_name_unique` ON `haex_extensions` (`public_key`,`name`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_notifications` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`alt` text,
|
||||||
|
`date` text,
|
||||||
|
`icon` text,
|
||||||
|
`image` text,
|
||||||
|
`read` integer,
|
||||||
|
`source` text,
|
||||||
|
`text` text,
|
||||||
|
`title` text,
|
||||||
|
`type` text NOT NULL,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_settings` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`key` text,
|
||||||
|
`type` text,
|
||||||
|
`value` text,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_settings_key_type_value_unique` ON `haex_settings` (`key`,`type`,`value`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_workspaces` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`device_id` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`position` integer DEFAULT 0 NOT NULL,
|
||||||
|
`background` blob,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);
|
||||||
15
src-tauri/database/migrations/0001_furry_brother_voodoo.sql
Normal file
15
src-tauri/database/migrations/0001_furry_brother_voodoo.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_haex_workspaces` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`device_id` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`position` integer DEFAULT 0 NOT NULL,
|
||||||
|
`background` text,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_haex_workspaces`("id", "device_id", "name", "position", "background", "haex_timestamp") SELECT "id", "device_id", "name", "position", "background", "haex_timestamp" FROM `haex_workspaces`;--> statement-breakpoint
|
||||||
|
DROP TABLE `haex_workspaces`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_haex_workspaces` RENAME TO `haex_workspaces`;--> statement-breakpoint
|
||||||
|
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);
|
||||||
692
src-tauri/database/migrations/meta/0000_snapshot.json
Normal file
692
src-tauri/database/migrations/meta/0000_snapshot.json
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "e3d61ad1-63be-41be-9243-41144e215f98",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"tables": {
|
||||||
|
"haex_crdt_configs": {
|
||||||
|
"name": "haex_crdt_configs",
|
||||||
|
"columns": {
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_crdt_logs": {
|
||||||
|
"name": "haex_crdt_logs",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"table_name": {
|
||||||
|
"name": "table_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"row_pks": {
|
||||||
|
"name": "row_pks",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"op_type": {
|
||||||
|
"name": "op_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"column_name": {
|
||||||
|
"name": "column_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"new_value": {
|
||||||
|
"name": "new_value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"old_value": {
|
||||||
|
"name": "old_value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_haex_timestamp": {
|
||||||
|
"name": "idx_haex_timestamp",
|
||||||
|
"columns": [
|
||||||
|
"haex_timestamp"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
},
|
||||||
|
"idx_table_row": {
|
||||||
|
"name": "idx_table_row",
|
||||||
|
"columns": [
|
||||||
|
"table_name",
|
||||||
|
"row_pks"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_crdt_snapshots": {
|
||||||
|
"name": "haex_crdt_snapshots",
|
||||||
|
"columns": {
|
||||||
|
"snapshot_id": {
|
||||||
|
"name": "snapshot_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"name": "created",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"epoch_hlc": {
|
||||||
|
"name": "epoch_hlc",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"location_url": {
|
||||||
|
"name": "location_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"file_size_bytes": {
|
||||||
|
"name": "file_size_bytes",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_extension_permissions": {
|
||||||
|
"name": "haex_extension_permissions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"resource_type": {
|
||||||
|
"name": "resource_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"name": "action",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"name": "target",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"constraints": {
|
||||||
|
"name": "constraints",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'denied'"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(CURRENT_TIMESTAMP)"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
|
||||||
|
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
|
||||||
|
"columns": [
|
||||||
|
"extension_id",
|
||||||
|
"resource_type",
|
||||||
|
"action",
|
||||||
|
"target"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_extension_permissions",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"public_key": {
|
||||||
|
"name": "public_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "author",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"entry": {
|
||||||
|
"name": "entry",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_notifications": {
|
||||||
|
"name": "haex_notifications",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"alt": {
|
||||||
|
"name": "alt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"name": "date",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"name": "image",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"read": {
|
||||||
|
"name": "read",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"name": "source",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"name": "text",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_settings": {
|
||||||
|
"name": "haex_settings",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_settings_key_type_value_unique": {
|
||||||
|
"name": "haex_settings_key_type_value_unique",
|
||||||
|
"columns": [
|
||||||
|
"key",
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_workspaces": {
|
||||||
|
"name": "haex_workspaces",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
|
"type": "blob",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
692
src-tauri/database/migrations/meta/0001_snapshot.json
Normal file
692
src-tauri/database/migrations/meta/0001_snapshot.json
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "10bec43a-4227-483e-b1c1-fd50ae32bb96",
|
||||||
|
"prevId": "e3d61ad1-63be-41be-9243-41144e215f98",
|
||||||
|
"tables": {
|
||||||
|
"haex_crdt_configs": {
|
||||||
|
"name": "haex_crdt_configs",
|
||||||
|
"columns": {
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_crdt_logs": {
|
||||||
|
"name": "haex_crdt_logs",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"table_name": {
|
||||||
|
"name": "table_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"row_pks": {
|
||||||
|
"name": "row_pks",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"op_type": {
|
||||||
|
"name": "op_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"column_name": {
|
||||||
|
"name": "column_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"new_value": {
|
||||||
|
"name": "new_value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"old_value": {
|
||||||
|
"name": "old_value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_haex_timestamp": {
|
||||||
|
"name": "idx_haex_timestamp",
|
||||||
|
"columns": [
|
||||||
|
"haex_timestamp"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
},
|
||||||
|
"idx_table_row": {
|
||||||
|
"name": "idx_table_row",
|
||||||
|
"columns": [
|
||||||
|
"table_name",
|
||||||
|
"row_pks"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_crdt_snapshots": {
|
||||||
|
"name": "haex_crdt_snapshots",
|
||||||
|
"columns": {
|
||||||
|
"snapshot_id": {
|
||||||
|
"name": "snapshot_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"name": "created",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"epoch_hlc": {
|
||||||
|
"name": "epoch_hlc",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"location_url": {
|
||||||
|
"name": "location_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"file_size_bytes": {
|
||||||
|
"name": "file_size_bytes",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_extension_permissions": {
|
||||||
|
"name": "haex_extension_permissions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"resource_type": {
|
||||||
|
"name": "resource_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"name": "action",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"name": "target",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"constraints": {
|
||||||
|
"name": "constraints",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'denied'"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "(CURRENT_TIMESTAMP)"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
|
||||||
|
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
|
||||||
|
"columns": [
|
||||||
|
"extension_id",
|
||||||
|
"resource_type",
|
||||||
|
"action",
|
||||||
|
"target"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_extension_permissions",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"public_key": {
|
||||||
|
"name": "public_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "author",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"entry": {
|
||||||
|
"name": "entry",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_notifications": {
|
||||||
|
"name": "haex_notifications",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"alt": {
|
||||||
|
"name": "alt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"name": "date",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"name": "image",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"read": {
|
||||||
|
"name": "read",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"name": "source",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"name": "text",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_settings": {
|
||||||
|
"name": "haex_settings",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_settings_key_type_value_unique": {
|
||||||
|
"name": "haex_settings_key_type_value_unique",
|
||||||
|
"columns": [
|
||||||
|
"key",
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_workspaces": {
|
||||||
|
"name": "haex_workspaces",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src-tauri/database/migrations/meta/_journal.json
Normal file
20
src-tauri/database/migrations/meta/_journal.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1762119713008,
|
||||||
|
"tag": "0000_cynical_nicolaos",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1762122405562,
|
||||||
|
"tag": "0001_furry_brother_voodoo",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-read-file","fs:allow-read-dir","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:default",{"identifier":"fs:scope","allow":[{"path":"**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:allow-is-permission-granted","notification:default","opener:allow-open-url","opener:default","os:allow-hostname","os:default","store:default"]}}
|
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-applocaldata-read-recursive","fs:allow-applocaldata-write-recursive","fs:allow-read-file","fs:allow-write-file","fs:allow-read-dir","fs:allow-mkdir","fs:allow-exists","fs:allow-remove","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:default",{"identifier":"fs:scope","allow":[{"path":"**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:allow-is-permission-granted","notification:default","opener:allow-open-url","opener:default","os:allow-hostname","os:default","store:default"]}}
|
||||||
@ -156,26 +156,40 @@ pub async fn extension_sql_execute(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Generate HLC timestamp
|
// Generate HLC timestamp
|
||||||
let hlc_timestamp = hlc_service
|
let hlc_timestamp =
|
||||||
.new_timestamp_and_persist(&tx)
|
hlc_service
|
||||||
.map_err(|e| DatabaseError::HlcError {
|
.new_timestamp_and_persist(&tx)
|
||||||
reason: e.to_string(),
|
.map_err(|e| DatabaseError::HlcError {
|
||||||
})?;
|
reason: e.to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
// Transform statement
|
// Transform statement
|
||||||
transformer.transform_execute_statement(&mut statement, &hlc_timestamp)?;
|
transformer.transform_execute_statement(&mut statement, &hlc_timestamp)?;
|
||||||
|
|
||||||
// Convert parameters to references
|
// Convert parameters to references
|
||||||
let sql_values = ValueConverter::convert_params(¶ms)?;
|
let sql_values = ValueConverter::convert_params(¶ms)?;
|
||||||
let param_refs: Vec<&dyn rusqlite::ToSql> = sql_values.iter().map(|v| v as &dyn rusqlite::ToSql).collect();
|
let param_refs: Vec<&dyn rusqlite::ToSql> = sql_values
|
||||||
|
.iter()
|
||||||
|
.map(|v| v as &dyn rusqlite::ToSql)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let result = if has_returning {
|
let result = if has_returning {
|
||||||
// Use query_internal for statements with RETURNING
|
// Use query_internal for statements with RETURNING
|
||||||
let (_, rows) = SqlExecutor::query_internal_typed(&tx, &hlc_service, &statement.to_string(), ¶m_refs)?;
|
let (_, rows) = SqlExecutor::query_internal_typed(
|
||||||
|
&tx,
|
||||||
|
&hlc_service,
|
||||||
|
&statement.to_string(),
|
||||||
|
¶m_refs,
|
||||||
|
)?;
|
||||||
rows
|
rows
|
||||||
} else {
|
} else {
|
||||||
// Use execute_internal for statements without RETURNING
|
// Use execute_internal for statements without RETURNING
|
||||||
SqlExecutor::execute_internal_typed(&tx, &hlc_service, &statement.to_string(), ¶m_refs)?;
|
SqlExecutor::execute_internal_typed(
|
||||||
|
&tx,
|
||||||
|
&hlc_service,
|
||||||
|
&statement.to_string(),
|
||||||
|
¶m_refs,
|
||||||
|
)?;
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -184,23 +198,22 @@ pub async fn extension_sql_execute(
|
|||||||
// Extract table name and remove quotes (both " and `)
|
// Extract table name and remove quotes (both " and `)
|
||||||
let raw_name = create_table_details.name.to_string();
|
let raw_name = create_table_details.name.to_string();
|
||||||
println!("DEBUG: Raw table name from AST: {raw_name:?}");
|
println!("DEBUG: Raw table name from AST: {raw_name:?}");
|
||||||
println!("DEBUG: Raw table name chars: {:?}", raw_name.chars().collect::<Vec<_>>());
|
println!(
|
||||||
|
"DEBUG: Raw table name chars: {:?}",
|
||||||
|
raw_name.chars().collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
let table_name_str = raw_name
|
let table_name_str = raw_name.trim_matches('"').trim_matches('`').to_string();
|
||||||
.trim_matches('"')
|
|
||||||
.trim_matches('`')
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
println!("DEBUG: Cleaned table name: {table_name_str:?}");
|
println!("DEBUG: Cleaned table name: {table_name_str:?}");
|
||||||
println!("DEBUG: Cleaned table name chars: {:?}", table_name_str.chars().collect::<Vec<_>>());
|
println!(
|
||||||
|
"DEBUG: Cleaned table name chars: {:?}",
|
||||||
|
table_name_str.chars().collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
println!(
|
println!("Table '{table_name_str}' created by extension, setting up CRDT triggers...");
|
||||||
"Table '{table_name_str}' created by extension, setting up CRDT triggers..."
|
|
||||||
);
|
|
||||||
trigger::setup_triggers_for_table(&tx, &table_name_str, false)?;
|
trigger::setup_triggers_for_table(&tx, &table_name_str, false)?;
|
||||||
println!(
|
println!("Triggers for table '{table_name_str}' successfully created.");
|
||||||
"Triggers for table '{table_name_str}' successfully created."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit transaction
|
// Commit transaction
|
||||||
@ -298,7 +311,6 @@ pub async fn extension_sql_select(
|
|||||||
.map_err(ExtensionError::from)
|
.map_err(ExtensionError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Validiert Parameter gegen SQL-Platzhalter
|
/// Validiert Parameter gegen SQL-Platzhalter
|
||||||
fn validate_params(sql: &str, params: &[JsonValue]) -> Result<(), DatabaseError> {
|
fn validate_params(sql: &str, params: &[JsonValue]) -> Result<(), DatabaseError> {
|
||||||
let total_placeholders = count_sql_placeholders(sql);
|
let total_placeholders = count_sql_placeholders(sql);
|
||||||
@ -335,20 +347,4 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(count_sql_placeholders("SELECT * FROM users"), 0);
|
assert_eq!(count_sql_placeholders("SELECT * FROM users"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #[test]
|
|
||||||
fn test_truncate_sql() {
|
|
||||||
let sql = "SELECT * FROM very_long_table_name";
|
|
||||||
assert_eq!(truncate_sql(sql, 10), "SELECT * F...");
|
|
||||||
assert_eq!(truncate_sql(sql, 50), sql);
|
|
||||||
} */
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_validate_params() {
|
|
||||||
let params = vec![json!(1), json!("test")];
|
|
||||||
|
|
||||||
assert!(validate_params("SELECT * FROM users WHERE id = ? AND name = ?", ¶ms).is_ok());
|
|
||||||
assert!(validate_params("SELECT * FROM users WHERE id = ?", ¶ms).is_err());
|
|
||||||
assert!(validate_params("SELECT * FROM users", ¶ms).is_err());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
},
|
},
|
||||||
"assetProtocol": {
|
"assetProtocol": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"scope": ["$APPDATA", "$RESOURCE"]
|
"scope": ["$APPDATA", "$RESOURCE", "$APPLOCALDATA/**"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -23,191 +23,198 @@
|
|||||||
:key="workspace.id"
|
:key="workspace.id"
|
||||||
class="w-full h-full"
|
class="w-full h-full"
|
||||||
>
|
>
|
||||||
<div
|
<UContextMenu :items="getWorkspaceContextMenuItems(workspace.id)">
|
||||||
class="w-full h-full relative"
|
|
||||||
@click.self.stop="handleDesktopClick"
|
|
||||||
@mousedown.left.self="handleAreaSelectStart"
|
|
||||||
@dragover.prevent="handleDragOver"
|
|
||||||
@drop.prevent="handleDrop($event, workspace.id)"
|
|
||||||
>
|
|
||||||
<!-- Grid Pattern Background -->
|
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 pointer-events-none opacity-30"
|
class="w-full h-full relative"
|
||||||
:style="{
|
:style="getWorkspaceBackgroundStyle(workspace)"
|
||||||
backgroundImage:
|
@click.self.stop="handleDesktopClick"
|
||||||
'linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px)',
|
@mousedown.left.self="handleAreaSelectStart"
|
||||||
backgroundSize: '32px 32px',
|
@dragover.prevent="handleDragOver"
|
||||||
}"
|
@drop.prevent="handleDrop($event, workspace.id)"
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Snap Dropzones (only visible when window drag near edge) -->
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="absolute left-0 top-0 bottom-0 border-blue-500 pointer-events-none backdrop-blur-sm z-50 transition-all duration-500 ease-in-out"
|
|
||||||
:class="showLeftSnapZone ? 'w-1/2 bg-blue-500/20 border-2' : 'w-0'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="absolute right-0 top-0 bottom-0 border-blue-500 pointer-events-none backdrop-blur-sm z-50 transition-all duration-500 ease-in-out"
|
|
||||||
:class="showRightSnapZone ? 'w-1/2 bg-blue-500/20 border-2' : 'w-0'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Area Selection Box -->
|
|
||||||
<div
|
|
||||||
v-if="isAreaSelecting"
|
|
||||||
class="absolute bg-blue-500/20 border-2 border-blue-500 pointer-events-none z-30"
|
|
||||||
:style="selectionBoxStyle"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Icons for this workspace -->
|
|
||||||
<HaexDesktopIcon
|
|
||||||
v-for="item in getWorkspaceIcons(workspace.id)"
|
|
||||||
:id="item.id"
|
|
||||||
:key="item.id"
|
|
||||||
:item-type="item.itemType"
|
|
||||||
:reference-id="item.referenceId"
|
|
||||||
:initial-x="item.positionX"
|
|
||||||
:initial-y="item.positionY"
|
|
||||||
:label="item.label"
|
|
||||||
:icon="item.icon"
|
|
||||||
class="no-swipe"
|
|
||||||
@position-changed="handlePositionChanged"
|
|
||||||
@drag-start="handleDragStart"
|
|
||||||
@drag-end="handleDragEnd"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Windows for this workspace -->
|
|
||||||
<template
|
|
||||||
v-for="window in getWorkspaceWindows(workspace.id)"
|
|
||||||
:key="window.id"
|
|
||||||
>
|
>
|
||||||
<!-- Overview Mode: Teleport to window preview -->
|
<!-- Grid Pattern Background -->
|
||||||
<Teleport
|
<div
|
||||||
v-if="
|
class="absolute inset-0 pointer-events-none opacity-30"
|
||||||
windowManager.showWindowOverview &&
|
:style="{
|
||||||
overviewWindowState.has(window.id)
|
backgroundImage:
|
||||||
"
|
'linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px)',
|
||||||
:to="`#window-preview-${window.id}`"
|
backgroundSize: '32px 32px',
|
||||||
>
|
}"
|
||||||
<div
|
/>
|
||||||
class="absolute origin-top-left"
|
|
||||||
:style="{
|
|
||||||
transform: `scale(${overviewWindowState.get(window.id)!.scale})`,
|
|
||||||
width: `${overviewWindowState.get(window.id)!.width}px`,
|
|
||||||
height: `${overviewWindowState.get(window.id)!.height}px`,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<HaexWindow
|
|
||||||
v-show="
|
|
||||||
windowManager.showWindowOverview || !window.isMinimized
|
|
||||||
"
|
|
||||||
:id="window.id"
|
|
||||||
v-model:x="overviewWindowState.get(window.id)!.x"
|
|
||||||
v-model:y="overviewWindowState.get(window.id)!.y"
|
|
||||||
v-model:width="overviewWindowState.get(window.id)!.width"
|
|
||||||
v-model:height="overviewWindowState.get(window.id)!.height"
|
|
||||||
:title="window.title"
|
|
||||||
:icon="window.icon"
|
|
||||||
:is-active="windowManager.isWindowActive(window.id)"
|
|
||||||
:source-x="window.sourceX"
|
|
||||||
:source-y="window.sourceY"
|
|
||||||
:source-width="window.sourceWidth"
|
|
||||||
:source-height="window.sourceHeight"
|
|
||||||
:is-opening="window.isOpening"
|
|
||||||
:is-closing="window.isClosing"
|
|
||||||
:warning-level="
|
|
||||||
window.type === 'extension' &&
|
|
||||||
availableExtensions.find(
|
|
||||||
(ext) => ext.id === window.sourceId,
|
|
||||||
)?.devServerUrl
|
|
||||||
? 'warning'
|
|
||||||
: undefined
|
|
||||||
"
|
|
||||||
class="no-swipe"
|
|
||||||
@close="windowManager.closeWindow(window.id)"
|
|
||||||
@minimize="windowManager.minimizeWindow(window.id)"
|
|
||||||
@activate="windowManager.activateWindow(window.id)"
|
|
||||||
@position-changed="
|
|
||||||
(x, y) =>
|
|
||||||
windowManager.updateWindowPosition(window.id, x, y)
|
|
||||||
"
|
|
||||||
@size-changed="
|
|
||||||
(width, height) =>
|
|
||||||
windowManager.updateWindowSize(window.id, width, height)
|
|
||||||
"
|
|
||||||
@drag-start="handleWindowDragStart(window.id)"
|
|
||||||
@drag-end="handleWindowDragEnd"
|
|
||||||
>
|
|
||||||
<!-- System Window: Render Vue Component -->
|
|
||||||
<component
|
|
||||||
:is="getSystemWindowComponent(window.sourceId)"
|
|
||||||
v-if="window.type === 'system'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Extension Window: Render iFrame -->
|
<!-- Snap Dropzones (only visible when window drag near edge) -->
|
||||||
<HaexDesktopExtensionFrame
|
|
||||||
v-else
|
|
||||||
:extension-id="window.sourceId"
|
|
||||||
:window-id="window.id"
|
|
||||||
/>
|
|
||||||
</HaexWindow>
|
|
||||||
</div>
|
|
||||||
</Teleport>
|
|
||||||
|
|
||||||
<!-- Desktop Mode: Render directly in workspace -->
|
<div
|
||||||
<HaexWindow
|
class="absolute left-0 top-0 bottom-0 border-blue-500 pointer-events-none backdrop-blur-sm z-50 transition-all duration-500 ease-in-out"
|
||||||
v-else
|
:class="
|
||||||
v-show="windowManager.showWindowOverview || !window.isMinimized"
|
showLeftSnapZone ? 'w-1/2 bg-blue-500/20 border-2' : 'w-0'
|
||||||
:id="window.id"
|
|
||||||
v-model:x="window.x"
|
|
||||||
v-model:y="window.y"
|
|
||||||
v-model:width="window.width"
|
|
||||||
v-model:height="window.height"
|
|
||||||
:title="window.title"
|
|
||||||
:icon="window.icon"
|
|
||||||
:is-active="windowManager.isWindowActive(window.id)"
|
|
||||||
:source-x="window.sourceX"
|
|
||||||
:source-y="window.sourceY"
|
|
||||||
:source-width="window.sourceWidth"
|
|
||||||
:source-height="window.sourceHeight"
|
|
||||||
:is-opening="window.isOpening"
|
|
||||||
:is-closing="window.isClosing"
|
|
||||||
:warning-level="
|
|
||||||
window.type === 'extension' &&
|
|
||||||
availableExtensions.find((ext) => ext.id === window.sourceId)
|
|
||||||
?.devServerUrl
|
|
||||||
? 'warning'
|
|
||||||
: undefined
|
|
||||||
"
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="absolute right-0 top-0 bottom-0 border-blue-500 pointer-events-none backdrop-blur-sm z-50 transition-all duration-500 ease-in-out"
|
||||||
|
:class="
|
||||||
|
showRightSnapZone ? 'w-1/2 bg-blue-500/20 border-2' : 'w-0'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Area Selection Box -->
|
||||||
|
<div
|
||||||
|
v-if="isAreaSelecting"
|
||||||
|
class="absolute bg-blue-500/20 border-2 border-blue-500 pointer-events-none z-30"
|
||||||
|
:style="selectionBoxStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Icons for this workspace -->
|
||||||
|
<HaexDesktopIcon
|
||||||
|
v-for="item in getWorkspaceIcons(workspace.id)"
|
||||||
|
:id="item.id"
|
||||||
|
:key="item.id"
|
||||||
|
:item-type="item.itemType"
|
||||||
|
:reference-id="item.referenceId"
|
||||||
|
:initial-x="item.positionX"
|
||||||
|
:initial-y="item.positionY"
|
||||||
|
:label="item.label"
|
||||||
|
:icon="item.icon"
|
||||||
class="no-swipe"
|
class="no-swipe"
|
||||||
@close="windowManager.closeWindow(window.id)"
|
@position-changed="handlePositionChanged"
|
||||||
@minimize="windowManager.minimizeWindow(window.id)"
|
@drag-start="handleDragStart"
|
||||||
@activate="windowManager.activateWindow(window.id)"
|
@drag-end="handleDragEnd"
|
||||||
@position-changed="
|
/>
|
||||||
(x, y) => windowManager.updateWindowPosition(window.id, x, y)
|
|
||||||
"
|
|
||||||
@size-changed="
|
|
||||||
(width, height) =>
|
|
||||||
windowManager.updateWindowSize(window.id, width, height)
|
|
||||||
"
|
|
||||||
@drag-start="handleWindowDragStart(window.id)"
|
|
||||||
@drag-end="handleWindowDragEnd"
|
|
||||||
>
|
|
||||||
<!-- System Window: Render Vue Component -->
|
|
||||||
<component
|
|
||||||
:is="getSystemWindowComponent(window.sourceId)"
|
|
||||||
v-if="window.type === 'system'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Extension Window: Render iFrame -->
|
<!-- Windows for this workspace -->
|
||||||
<HaexDesktopExtensionFrame
|
<template
|
||||||
|
v-for="window in getWorkspaceWindows(workspace.id)"
|
||||||
|
:key="window.id"
|
||||||
|
>
|
||||||
|
<!-- Overview Mode: Teleport to window preview -->
|
||||||
|
<Teleport
|
||||||
|
v-if="
|
||||||
|
windowManager.showWindowOverview &&
|
||||||
|
overviewWindowState.has(window.id)
|
||||||
|
"
|
||||||
|
:to="`#window-preview-${window.id}`"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="absolute origin-top-left"
|
||||||
|
:style="{
|
||||||
|
transform: `scale(${overviewWindowState.get(window.id)!.scale})`,
|
||||||
|
width: `${overviewWindowState.get(window.id)!.width}px`,
|
||||||
|
height: `${overviewWindowState.get(window.id)!.height}px`,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<HaexWindow
|
||||||
|
v-show="
|
||||||
|
windowManager.showWindowOverview || !window.isMinimized
|
||||||
|
"
|
||||||
|
:id="window.id"
|
||||||
|
v-model:x="overviewWindowState.get(window.id)!.x"
|
||||||
|
v-model:y="overviewWindowState.get(window.id)!.y"
|
||||||
|
v-model:width="overviewWindowState.get(window.id)!.width"
|
||||||
|
v-model:height="overviewWindowState.get(window.id)!.height"
|
||||||
|
:title="window.title"
|
||||||
|
:icon="window.icon"
|
||||||
|
:is-active="windowManager.isWindowActive(window.id)"
|
||||||
|
:source-x="window.sourceX"
|
||||||
|
:source-y="window.sourceY"
|
||||||
|
:source-width="window.sourceWidth"
|
||||||
|
:source-height="window.sourceHeight"
|
||||||
|
:is-opening="window.isOpening"
|
||||||
|
:is-closing="window.isClosing"
|
||||||
|
:warning-level="
|
||||||
|
window.type === 'extension' &&
|
||||||
|
availableExtensions.find(
|
||||||
|
(ext) => ext.id === window.sourceId,
|
||||||
|
)?.devServerUrl
|
||||||
|
? 'warning'
|
||||||
|
: undefined
|
||||||
|
"
|
||||||
|
class="no-swipe"
|
||||||
|
@close="windowManager.closeWindow(window.id)"
|
||||||
|
@minimize="windowManager.minimizeWindow(window.id)"
|
||||||
|
@activate="windowManager.activateWindow(window.id)"
|
||||||
|
@position-changed="
|
||||||
|
(x, y) =>
|
||||||
|
windowManager.updateWindowPosition(window.id, x, y)
|
||||||
|
"
|
||||||
|
@size-changed="
|
||||||
|
(width, height) =>
|
||||||
|
windowManager.updateWindowSize(window.id, width, height)
|
||||||
|
"
|
||||||
|
@drag-start="handleWindowDragStart(window.id)"
|
||||||
|
@drag-end="handleWindowDragEnd"
|
||||||
|
>
|
||||||
|
<!-- System Window: Render Vue Component -->
|
||||||
|
<component
|
||||||
|
:is="getSystemWindowComponent(window.sourceId)"
|
||||||
|
v-if="window.type === 'system'"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Extension Window: Render iFrame -->
|
||||||
|
<HaexDesktopExtensionFrame
|
||||||
|
v-else
|
||||||
|
:extension-id="window.sourceId"
|
||||||
|
:window-id="window.id"
|
||||||
|
/>
|
||||||
|
</HaexWindow>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- Desktop Mode: Render directly in workspace -->
|
||||||
|
<HaexWindow
|
||||||
v-else
|
v-else
|
||||||
:extension-id="window.sourceId"
|
v-show="windowManager.showWindowOverview || !window.isMinimized"
|
||||||
:window-id="window.id"
|
:id="window.id"
|
||||||
/>
|
v-model:x="window.x"
|
||||||
</HaexWindow>
|
v-model:y="window.y"
|
||||||
</template>
|
v-model:width="window.width"
|
||||||
</div>
|
v-model:height="window.height"
|
||||||
|
:title="window.title"
|
||||||
|
:icon="window.icon"
|
||||||
|
:is-active="windowManager.isWindowActive(window.id)"
|
||||||
|
:source-x="window.sourceX"
|
||||||
|
:source-y="window.sourceY"
|
||||||
|
:source-width="window.sourceWidth"
|
||||||
|
:source-height="window.sourceHeight"
|
||||||
|
:is-opening="window.isOpening"
|
||||||
|
:is-closing="window.isClosing"
|
||||||
|
:warning-level="
|
||||||
|
window.type === 'extension' &&
|
||||||
|
availableExtensions.find((ext) => ext.id === window.sourceId)
|
||||||
|
?.devServerUrl
|
||||||
|
? 'warning'
|
||||||
|
: undefined
|
||||||
|
"
|
||||||
|
class="no-swipe"
|
||||||
|
@close="windowManager.closeWindow(window.id)"
|
||||||
|
@minimize="windowManager.minimizeWindow(window.id)"
|
||||||
|
@activate="windowManager.activateWindow(window.id)"
|
||||||
|
@position-changed="
|
||||||
|
(x, y) => windowManager.updateWindowPosition(window.id, x, y)
|
||||||
|
"
|
||||||
|
@size-changed="
|
||||||
|
(width, height) =>
|
||||||
|
windowManager.updateWindowSize(window.id, width, height)
|
||||||
|
"
|
||||||
|
@drag-start="handleWindowDragStart(window.id)"
|
||||||
|
@drag-end="handleWindowDragEnd"
|
||||||
|
>
|
||||||
|
<!-- System Window: Render Vue Component -->
|
||||||
|
<component
|
||||||
|
:is="getSystemWindowComponent(window.sourceId)"
|
||||||
|
v-if="window.type === 'system'"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Extension Window: Render iFrame -->
|
||||||
|
<HaexDesktopExtensionFrame
|
||||||
|
v-else
|
||||||
|
:extension-id="window.sourceId"
|
||||||
|
:window-id="window.id"
|
||||||
|
/>
|
||||||
|
</HaexWindow>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</UContextMenu>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
@ -239,6 +246,8 @@ const {
|
|||||||
allowSwipe,
|
allowSwipe,
|
||||||
isOverviewMode,
|
isOverviewMode,
|
||||||
} = storeToRefs(workspaceStore)
|
} = storeToRefs(workspaceStore)
|
||||||
|
const { getWorkspaceBackgroundStyle, getWorkspaceContextMenuItems } =
|
||||||
|
workspaceStore
|
||||||
|
|
||||||
const { x: mouseX } = useMouse()
|
const { x: mouseX } = useMouse()
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,9 @@
|
|||||||
direction="right"
|
direction="right"
|
||||||
:title="t('launcher.title')"
|
:title="t('launcher.title')"
|
||||||
:description="t('launcher.description')"
|
:description="t('launcher.description')"
|
||||||
|
:overlay="false"
|
||||||
|
:modal="false"
|
||||||
|
:handle-only="true"
|
||||||
:ui="{
|
:ui="{
|
||||||
content: 'w-dvw max-w-md sm:max-w-fit',
|
content: 'w-dvw max-w-md sm:max-w-fit',
|
||||||
}"
|
}"
|
||||||
@ -30,7 +33,7 @@
|
|||||||
size="lg"
|
size="lg"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
:ui="{
|
:ui="{
|
||||||
base: 'size-24 flex flex-wrap text-sm items-center justify-center overflow-visible cursor-grab active:cursor-grabbing',
|
base: 'size-24 flex flex-wrap text-sm items-center justify-center overflow-visible cursor-grab',
|
||||||
leadingIcon: 'size-10',
|
leadingIcon: 'size-10',
|
||||||
label: 'w-full',
|
label: 'w-full',
|
||||||
}"
|
}"
|
||||||
@ -40,7 +43,6 @@
|
|||||||
draggable="true"
|
draggable="true"
|
||||||
@click="openItem(item)"
|
@click="openItem(item)"
|
||||||
@dragstart="handleDragStart($event, item)"
|
@dragstart="handleDragStart($event, item)"
|
||||||
@dragend="handleDragEnd"
|
|
||||||
/>
|
/>
|
||||||
</UContextMenu>
|
</UContextMenu>
|
||||||
|
|
||||||
@ -241,10 +243,6 @@ const handleDragStart = (event: DragEvent, item: LauncherItem) => {
|
|||||||
event.dataTransfer.setDragImage(dragImage, 20, 20)
|
event.dataTransfer.setDragImage(dragImage, 20, 20)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDragEnd = () => {
|
|
||||||
// Cleanup if needed
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="yaml">
|
<i18n lang="yaml">
|
||||||
|
|||||||
@ -33,13 +33,36 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="h-full"/>
|
<div class="p-2">{{ t('workspaceBackground.label') }}</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<UiButton
|
||||||
|
:label="t('workspaceBackground.choose')"
|
||||||
|
@click="selectBackgroundImage"
|
||||||
|
/>
|
||||||
|
<UiButton
|
||||||
|
v-if="currentWorkspace?.background"
|
||||||
|
:label="t('workspaceBackground.remove.label')"
|
||||||
|
color="error"
|
||||||
|
@click="removeBackgroundImage"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="h-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Locale } from 'vue-i18n'
|
import type { Locale } from 'vue-i18n'
|
||||||
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
|
import {
|
||||||
|
readFile,
|
||||||
|
writeFile,
|
||||||
|
mkdir,
|
||||||
|
exists,
|
||||||
|
remove,
|
||||||
|
} from '@tauri-apps/plugin-fs'
|
||||||
|
import { appLocalDataDir } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
const { t, setLocale } = useI18n()
|
const { t, setLocale } = useI18n()
|
||||||
|
|
||||||
@ -77,6 +100,10 @@ const { requestNotificationPermissionAsync } = useNotificationStore()
|
|||||||
const { deviceName } = storeToRefs(useDeviceStore())
|
const { deviceName } = storeToRefs(useDeviceStore())
|
||||||
const { updateDeviceNameAsync, readDeviceNameAsync } = useDeviceStore()
|
const { updateDeviceNameAsync, readDeviceNameAsync } = useDeviceStore()
|
||||||
|
|
||||||
|
const workspaceStore = useWorkspaceStore()
|
||||||
|
const { currentWorkspace } = storeToRefs(workspaceStore)
|
||||||
|
const { updateWorkspaceBackgroundAsync } = workspaceStore
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await readDeviceNameAsync()
|
await readDeviceNameAsync()
|
||||||
})
|
})
|
||||||
@ -92,6 +119,152 @@ const onUpdateDeviceNameAsync = async () => {
|
|||||||
add({ description: t('deviceName.update.error'), color: 'error' })
|
add({ description: t('deviceName.update.error'), color: 'error' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectBackgroundImage = async () => {
|
||||||
|
if (!currentWorkspace.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const selected = await open({
|
||||||
|
multiple: false,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: 'Images',
|
||||||
|
extensions: ['png', 'jpg', 'jpeg', 'webp'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!selected || typeof selected !== 'string') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the selected file (works with Android photo picker URIs)
|
||||||
|
let fileData: Uint8Array
|
||||||
|
try {
|
||||||
|
fileData = await readFile(selected)
|
||||||
|
} catch (readError) {
|
||||||
|
add({
|
||||||
|
description: `Fehler beim Lesen: ${readError instanceof Error ? readError.message : String(readError)}`,
|
||||||
|
color: 'error',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect file type from file signature
|
||||||
|
let ext = 'jpg' // default
|
||||||
|
if (fileData.length > 4) {
|
||||||
|
// PNG signature: 89 50 4E 47
|
||||||
|
if (
|
||||||
|
fileData[0] === 0x89 &&
|
||||||
|
fileData[1] === 0x50 &&
|
||||||
|
fileData[2] === 0x4e &&
|
||||||
|
fileData[3] === 0x47
|
||||||
|
) {
|
||||||
|
ext = 'png'
|
||||||
|
}
|
||||||
|
// JPEG signature: FF D8 FF
|
||||||
|
else if (
|
||||||
|
fileData[0] === 0xff &&
|
||||||
|
fileData[1] === 0xd8 &&
|
||||||
|
fileData[2] === 0xff
|
||||||
|
) {
|
||||||
|
ext = 'jpg'
|
||||||
|
}
|
||||||
|
// WebP signature: RIFF xxxx WEBP
|
||||||
|
else if (
|
||||||
|
fileData[0] === 0x52 &&
|
||||||
|
fileData[1] === 0x49 &&
|
||||||
|
fileData[2] === 0x46 &&
|
||||||
|
fileData[3] === 0x46
|
||||||
|
) {
|
||||||
|
ext = 'webp'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get app local data directory
|
||||||
|
const appDataPath = await appLocalDataDir()
|
||||||
|
|
||||||
|
// Construct target path manually to avoid path joining issues
|
||||||
|
const fileName = `workspace-${currentWorkspace.value.id}-background.${ext}`
|
||||||
|
const targetPath = `${appDataPath}/files/${fileName}`
|
||||||
|
|
||||||
|
// Create parent directory if it doesn't exist
|
||||||
|
const parentDir = `${appDataPath}/files`
|
||||||
|
try {
|
||||||
|
if (!(await exists(parentDir))) {
|
||||||
|
await mkdir(parentDir, { recursive: true })
|
||||||
|
}
|
||||||
|
} catch (mkdirError) {
|
||||||
|
add({
|
||||||
|
description: `Fehler beim Erstellen des Ordners: ${mkdirError instanceof Error ? mkdirError.message : String(mkdirError)}`,
|
||||||
|
color: 'error',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file to app data directory
|
||||||
|
try {
|
||||||
|
await writeFile(targetPath, fileData)
|
||||||
|
} catch (writeError) {
|
||||||
|
add({
|
||||||
|
description: `Fehler beim Schreiben: ${writeError instanceof Error ? writeError.message : String(writeError)}`,
|
||||||
|
color: 'error',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the absolute file path in database
|
||||||
|
try {
|
||||||
|
await updateWorkspaceBackgroundAsync(
|
||||||
|
currentWorkspace.value.id,
|
||||||
|
targetPath,
|
||||||
|
)
|
||||||
|
add({
|
||||||
|
description: t('workspaceBackground.update.success'),
|
||||||
|
color: 'success',
|
||||||
|
})
|
||||||
|
} catch (dbError) {
|
||||||
|
add({
|
||||||
|
description: `Fehler beim DB-Update: ${dbError instanceof Error ? dbError.message : String(dbError)}`,
|
||||||
|
color: 'error',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error selecting background:', error)
|
||||||
|
add({
|
||||||
|
description: `${t('workspaceBackground.update.error')}: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
color: 'error',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeBackgroundImage = async () => {
|
||||||
|
if (!currentWorkspace.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Delete the background file if it exists
|
||||||
|
if (currentWorkspace.value.background) {
|
||||||
|
try {
|
||||||
|
// The background field contains the absolute file path
|
||||||
|
if (await exists(currentWorkspace.value.background)) {
|
||||||
|
await remove(currentWorkspace.value.background)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Could not delete background file:', err)
|
||||||
|
// Continue anyway to clear the database entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateWorkspaceBackgroundAsync(currentWorkspace.value.id, null)
|
||||||
|
add({
|
||||||
|
description: t('workspaceBackground.remove.success'),
|
||||||
|
color: 'success',
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error removing background:', error)
|
||||||
|
add({ description: t('workspaceBackground.remove.error'), color: 'error' })
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="yaml">
|
<i18n lang="yaml">
|
||||||
@ -112,6 +285,16 @@ de:
|
|||||||
update:
|
update:
|
||||||
success: Gerätename wurde erfolgreich aktualisiert
|
success: Gerätename wurde erfolgreich aktualisiert
|
||||||
error: Gerätename konnte nich aktualisiert werden
|
error: Gerätename konnte nich aktualisiert werden
|
||||||
|
workspaceBackground:
|
||||||
|
label: Workspace-Hintergrund
|
||||||
|
choose: Bild auswählen
|
||||||
|
update:
|
||||||
|
success: Hintergrund erfolgreich aktualisiert
|
||||||
|
error: Fehler beim Aktualisieren des Hintergrunds
|
||||||
|
remove:
|
||||||
|
label: Hintergrund entfernen
|
||||||
|
success: Hintergrund erfolgreich entfernt
|
||||||
|
error: Fehler beim Entfernen des Hintergrunds
|
||||||
en:
|
en:
|
||||||
language: Language
|
language: Language
|
||||||
design: Design
|
design: Design
|
||||||
@ -129,4 +312,14 @@ en:
|
|||||||
update:
|
update:
|
||||||
success: Device name has been successfully updated
|
success: Device name has been successfully updated
|
||||||
error: Device name could not be updated
|
error: Device name could not be updated
|
||||||
|
workspaceBackground:
|
||||||
|
label: Workspace Background
|
||||||
|
choose: Choose Image
|
||||||
|
update:
|
||||||
|
success: Background successfully updated
|
||||||
|
error: Error updating background
|
||||||
|
remove:
|
||||||
|
label: Remove Background
|
||||||
|
success: Background successfully removed
|
||||||
|
error: Error removing background
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { integer, sqliteTable, text, index } from 'drizzle-orm/sqlite-core'
|
import { integer, sqliteTable, text, index } from 'drizzle-orm/sqlite-core'
|
||||||
import tableNames from '~/database/tableNames.json'
|
import tableNames from '@/database/tableNames.json'
|
||||||
|
|
||||||
export const haexCrdtLogs = sqliteTable(
|
export const haexCrdtLogs = sqliteTable(
|
||||||
tableNames.haex.crdt.logs.name,
|
tableNames.haex.crdt.logs.name,
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
type AnySQLiteColumn,
|
type AnySQLiteColumn,
|
||||||
type SQLiteColumnBuilderBase,
|
type SQLiteColumnBuilderBase,
|
||||||
} from 'drizzle-orm/sqlite-core'
|
} from 'drizzle-orm/sqlite-core'
|
||||||
import tableNames from '~/database/tableNames.json'
|
import tableNames from '@/database/tableNames.json'
|
||||||
|
|
||||||
const crdtColumnNames = {
|
const crdtColumnNames = {
|
||||||
haexTimestamp: 'haex_timestamp',
|
haexTimestamp: 'haex_timestamp',
|
||||||
@ -137,6 +137,7 @@ export const haexWorkspaces = sqliteTable(
|
|||||||
position: integer(tableNames.haex.workspaces.columns.position)
|
position: integer(tableNames.haex.workspaces.columns.position)
|
||||||
.notNull()
|
.notNull()
|
||||||
.default(0),
|
.default(0),
|
||||||
|
background: text(),
|
||||||
}),
|
}),
|
||||||
(table) => [unique().on(table.position)],
|
(table) => [unique().on(table.position)],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -96,8 +96,7 @@
|
|||||||
@click="handleAddWorkspace"
|
@click="handleAddWorkspace"
|
||||||
icon="i-heroicons-plus"
|
icon="i-heroicons-plus"
|
||||||
:label="t('workspaces.add')"
|
:label="t('workspaces.add')"
|
||||||
>
|
/>
|
||||||
</UButton>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UDrawer>
|
</UDrawer>
|
||||||
|
|||||||
@ -300,6 +300,7 @@ export const useWindowManagerStore = defineStore('windowManager', () => {
|
|||||||
const window = windows.value.find((w) => w.id === windowId)
|
const window = windows.value.find((w) => w.id === windowId)
|
||||||
if (window) {
|
if (window) {
|
||||||
window.zIndex = nextZIndex.value++
|
window.zIndex = nextZIndex.value++
|
||||||
|
window.isMinimized = false
|
||||||
activeWindowId.value = windowId
|
activeWindowId.value = windowId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
type SelectHaexWorkspaces,
|
type SelectHaexWorkspaces,
|
||||||
} from '~/database/schemas'
|
} from '~/database/schemas'
|
||||||
import type { Swiper } from 'swiper/types'
|
import type { Swiper } from 'swiper/types'
|
||||||
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
|
|
||||||
export type IWorkspace = SelectHaexWorkspaces
|
export type IWorkspace = SelectHaexWorkspaces
|
||||||
|
|
||||||
@ -203,12 +204,86 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => {
|
|||||||
isOverviewMode.value = false
|
isOverviewMode.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateWorkspaceBackgroundAsync = async (
|
||||||
|
workspaceId: string,
|
||||||
|
base64Image: string | null,
|
||||||
|
) => {
|
||||||
|
if (!currentVault.value?.drizzle) {
|
||||||
|
throw new Error('Kein Vault geöffnet')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await currentVault.value.drizzle
|
||||||
|
.update(haexWorkspaces)
|
||||||
|
.set({ background: base64Image })
|
||||||
|
.where(eq(haexWorkspaces.id, workspaceId))
|
||||||
|
.returning()
|
||||||
|
|
||||||
|
if (result.length > 0 && result[0]) {
|
||||||
|
const index = workspaces.value.findIndex((ws) => ws.id === workspaceId)
|
||||||
|
if (index !== -1) {
|
||||||
|
workspaces.value[index] = result[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Aktualisieren des Workspace-Hintergrunds:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getWorkspaceBackgroundStyle = (workspace: IWorkspace) => {
|
||||||
|
if (!workspace.background) return {}
|
||||||
|
|
||||||
|
// The background field contains the absolute file path
|
||||||
|
// Convert it to an asset URL
|
||||||
|
const assetUrl = convertFileSrc(workspace.background)
|
||||||
|
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${assetUrl})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getWorkspaceContextMenuItems = (workspaceId: string) => {
|
||||||
|
const windowManager = useWindowManagerStore()
|
||||||
|
|
||||||
|
return [[
|
||||||
|
{
|
||||||
|
label: 'Hintergrund ändern',
|
||||||
|
icon: 'i-mdi-image',
|
||||||
|
onSelect: async () => {
|
||||||
|
// Store the workspace ID for settings to use
|
||||||
|
currentWorkspaceIndex.value = workspaces.value.findIndex(
|
||||||
|
(ws) => ws.id === workspaceId,
|
||||||
|
)
|
||||||
|
// Get settings window info
|
||||||
|
const settingsWindow = windowManager.getAllSystemWindows()
|
||||||
|
.find((win) => win.id === 'settings')
|
||||||
|
|
||||||
|
if (settingsWindow) {
|
||||||
|
await windowManager.openWindowAsync({
|
||||||
|
type: 'system',
|
||||||
|
sourceId: settingsWindow.id,
|
||||||
|
title: settingsWindow.name,
|
||||||
|
icon: settingsWindow.icon || undefined,
|
||||||
|
workspaceId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addWorkspaceAsync,
|
addWorkspaceAsync,
|
||||||
allowSwipe,
|
allowSwipe,
|
||||||
closeWorkspaceAsync,
|
closeWorkspaceAsync,
|
||||||
currentWorkspace,
|
currentWorkspace,
|
||||||
currentWorkspaceIndex,
|
currentWorkspaceIndex,
|
||||||
|
getWorkspaceBackgroundStyle,
|
||||||
|
getWorkspaceContextMenuItems,
|
||||||
isOverviewMode,
|
isOverviewMode,
|
||||||
slideToWorkspace,
|
slideToWorkspace,
|
||||||
loadWorkspacesAsync,
|
loadWorkspacesAsync,
|
||||||
@ -218,6 +293,7 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => {
|
|||||||
switchToNext,
|
switchToNext,
|
||||||
switchToPrevious,
|
switchToPrevious,
|
||||||
switchToWorkspace,
|
switchToWorkspace,
|
||||||
|
updateWorkspaceBackgroundAsync,
|
||||||
workspaces,
|
workspaces,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user