mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-18 15:00:52 +01:00
Compare commits
3 Commits
731ae7cc47
...
v0.1.11
| Author | SHA1 | Date | |
|---|---|---|---|
| 9adee46166 | |||
| be7dff72dd | |||
| b465c117b0 |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "haex-hub",
|
"name": "haex-hub",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.9",
|
"version": "0.1.11",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nuxt build",
|
"build": "nuxt build",
|
||||||
@ -24,6 +24,7 @@
|
|||||||
"@nuxt/ui": "4.1.0",
|
"@nuxt/ui": "4.1.0",
|
||||||
"@nuxtjs/i18n": "10.0.6",
|
"@nuxtjs/i18n": "10.0.6",
|
||||||
"@pinia/nuxt": "^0.11.2",
|
"@pinia/nuxt": "^0.11.2",
|
||||||
|
"@supabase/supabase-js": "^2.79.0",
|
||||||
"@tailwindcss/vite": "^4.1.16",
|
"@tailwindcss/vite": "^4.1.16",
|
||||||
"@tauri-apps/api": "^2.9.0",
|
"@tauri-apps/api": "^2.9.0",
|
||||||
"@tauri-apps/plugin-dialog": "^2.4.2",
|
"@tauri-apps/plugin-dialog": "^2.4.2",
|
||||||
|
|||||||
69
pnpm-lock.yaml
generated
69
pnpm-lock.yaml
generated
@ -29,6 +29,9 @@ importers:
|
|||||||
'@pinia/nuxt':
|
'@pinia/nuxt':
|
||||||
specifier: ^0.11.2
|
specifier: ^0.11.2
|
||||||
version: 0.11.2(magicast@0.5.1)(pinia@3.0.3(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3)))
|
version: 0.11.2(magicast@0.5.1)(pinia@3.0.3(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3)))
|
||||||
|
'@supabase/supabase-js':
|
||||||
|
specifier: ^2.79.0
|
||||||
|
version: 2.79.0
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.16
|
specifier: ^4.1.16
|
||||||
version: 4.1.16(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
|
version: 4.1.16(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
|
||||||
@ -1894,6 +1897,30 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=9.0.0'
|
eslint: '>=9.0.0'
|
||||||
|
|
||||||
|
'@supabase/auth-js@2.79.0':
|
||||||
|
resolution: {integrity: sha512-p2GKvdbF9d/6C+dtS6iNcSicPr6eUfkvovD60HWlWsD+oOjC483DzFWrzGjNpBwnswhfMRP8Qn3rYA0VWaOfjw==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
'@supabase/functions-js@2.79.0':
|
||||||
|
resolution: {integrity: sha512-WaiU6b+Z+ZfJOjFhpMKdajt42weiFUrA6TVW5oGd6WfPGajFiKZJJIAvuK0g7KDKaYowtQrOo5+Ais+PcuZ1qA==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
'@supabase/postgrest-js@2.79.0':
|
||||||
|
resolution: {integrity: sha512-2i8EFm3/49ecjt6dk/TGVROBbtOmhryiC4NL3u0FBIrm2hqj+FvbELv1jjM6r+a6abnh+uzIV/bFsWHAa/k3/w==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
'@supabase/realtime-js@2.79.0':
|
||||||
|
resolution: {integrity: sha512-foaZujNBycAqLizUcuLyyFyDitfPnEMVO4CiKXNwaMCDVMoVX4QR6n4gpJLUC5BGzc20Mte6vSJLbk4MN90Prw==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
'@supabase/storage-js@2.79.0':
|
||||||
|
resolution: {integrity: sha512-PLSeKX1/BZhGWCT972w4TvVOCcw/xh4TsowtUBiZvPx4OdHT7dB1q0DXKwVUfKbWk5UUC+6XAq4ZU/ZCtdgn6w==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
'@supabase/supabase-js@2.79.0':
|
||||||
|
resolution: {integrity: sha512-x9ndEaBSwoRnFOOZGhh2CeV69Uz4B/EOSGCbKysDhTiYakiCAdDXaNuLPluviKU/Aot+F7BglXZDZ0YJ3GpGrw==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
'@swc/helpers@0.5.17':
|
'@swc/helpers@0.5.17':
|
||||||
resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
|
resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
|
||||||
|
|
||||||
@ -2116,6 +2143,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==}
|
resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==}
|
||||||
deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed.
|
deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed.
|
||||||
|
|
||||||
|
'@types/phoenix@1.6.6':
|
||||||
|
resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==}
|
||||||
|
|
||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
@ -7556,6 +7586,43 @@ snapshots:
|
|||||||
estraverse: 5.3.0
|
estraverse: 5.3.0
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
'@supabase/auth-js@2.79.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@supabase/functions-js@2.79.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@supabase/postgrest-js@2.79.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@supabase/realtime-js@2.79.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/phoenix': 1.6.6
|
||||||
|
'@types/ws': 8.18.1
|
||||||
|
tslib: 2.8.1
|
||||||
|
ws: 8.18.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
'@supabase/storage-js@2.79.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@supabase/supabase-js@2.79.0':
|
||||||
|
dependencies:
|
||||||
|
'@supabase/auth-js': 2.79.0
|
||||||
|
'@supabase/functions-js': 2.79.0
|
||||||
|
'@supabase/postgrest-js': 2.79.0
|
||||||
|
'@supabase/realtime-js': 2.79.0
|
||||||
|
'@supabase/storage-js': 2.79.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
'@swc/helpers@0.5.17':
|
'@swc/helpers@0.5.17':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@ -7740,6 +7807,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
parse-path: 7.1.0
|
parse-path: 7.1.0
|
||||||
|
|
||||||
|
'@types/phoenix@1.6.6': {}
|
||||||
|
|
||||||
'@types/resolve@1.20.2': {}
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
'@types/web-bluetooth@0.0.20': {}
|
'@types/web-bluetooth@0.0.20': {}
|
||||||
|
|||||||
10
src-tauri/database/migrations/0003_luxuriant_deathstrike.sql
Normal file
10
src-tauri/database/migrations/0003_luxuriant_deathstrike.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE `haex_sync_backends` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`server_url` text NOT NULL,
|
||||||
|
`enabled` integer DEFAULT true NOT NULL,
|
||||||
|
`priority` integer DEFAULT 0 NOT NULL,
|
||||||
|
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
|
||||||
|
`updated_at` integer,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
843
src-tauri/database/migrations/meta/0003_snapshot.json
Normal file
843
src-tauri/database/migrations/meta/0003_snapshot.json
Normal file
@ -0,0 +1,843 @@
|
|||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "bf82259e-9264-44e7-a60f-8cc14a1f22e2",
|
||||||
|
"prevId": "3aedf10c-2266-40f4-8549-0ff8b0588853",
|
||||||
|
"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_devices": {
|
||||||
|
"name": "haex_devices",
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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_devices_device_id_unique": {
|
||||||
|
"name": "haex_devices_device_id_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"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_device_id_key_type_unique": {
|
||||||
|
"name": "haex_settings_device_id_key_type_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_settings_device_id_haex_devices_id_fk": {
|
||||||
|
"name": "haex_settings_device_id_haex_devices_id_fk",
|
||||||
|
"tableFrom": "haex_settings",
|
||||||
|
"tableTo": "haex_devices",
|
||||||
|
"columnsFrom": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_sync_backends": {
|
||||||
|
"name": "haex_sync_backends",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"server_url": {
|
||||||
|
"name": "server_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"name": "priority",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"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": {},
|
||||||
|
"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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,6 +22,13 @@
|
|||||||
"when": 1762263814375,
|
"when": 1762263814375,
|
||||||
"tag": "0002_loose_quasimodo",
|
"tag": "0002_loose_quasimodo",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 3,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1762300795436,
|
||||||
|
"tag": "0003_luxuriant_deathstrike",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -18,6 +18,7 @@
|
|||||||
@pointerdown.left="handlePointerDown"
|
@pointerdown.left="handlePointerDown"
|
||||||
@pointermove="handlePointerMove"
|
@pointermove="handlePointerMove"
|
||||||
@pointerup="handlePointerUp"
|
@pointerup="handlePointerUp"
|
||||||
|
@dragstart.prevent
|
||||||
@click.left="handleClick"
|
@click.left="handleClick"
|
||||||
@dblclick="handleDoubleClick"
|
@dblclick="handleDoubleClick"
|
||||||
>
|
>
|
||||||
@ -176,6 +177,9 @@ const style = computed(() => ({
|
|||||||
const handlePointerDown = (e: PointerEvent) => {
|
const handlePointerDown = (e: PointerEvent) => {
|
||||||
if (!draggableEl.value || !draggableEl.value.parentElement) return
|
if (!draggableEl.value || !draggableEl.value.parentElement) return
|
||||||
|
|
||||||
|
// Prevent any text selection during drag
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
isDragging.value = true
|
isDragging.value = true
|
||||||
emit('dragStart', props.id, props.itemType, props.referenceId, iconWidth.value, iconHeight.value, x.value, y.value)
|
emit('dragStart', props.id, props.itemType, props.referenceId, iconWidth.value, iconHeight.value, x.value, y.value)
|
||||||
|
|
||||||
|
|||||||
@ -25,12 +25,13 @@
|
|||||||
>
|
>
|
||||||
<UContextMenu :items="getWorkspaceContextMenuItems(workspace.id)">
|
<UContextMenu :items="getWorkspaceContextMenuItems(workspace.id)">
|
||||||
<div
|
<div
|
||||||
class="w-full h-full relative"
|
class="w-full h-full relative select-none"
|
||||||
:style="getWorkspaceBackgroundStyle(workspace)"
|
:style="getWorkspaceBackgroundStyle(workspace)"
|
||||||
@click.self.stop="handleDesktopClick"
|
@click.self.stop="handleDesktopClick"
|
||||||
@mousedown.left.self="handleAreaSelectStart"
|
@mousedown.left.self="handleAreaSelectStart"
|
||||||
@dragover.prevent="handleDragOver"
|
@dragover.prevent="handleDragOver"
|
||||||
@drop.prevent="handleDrop($event, workspace.id)"
|
@drop.prevent="handleDrop($event, workspace.id)"
|
||||||
|
@selectstart.prevent
|
||||||
>
|
>
|
||||||
<!-- Drop Target Zone (visible during drag) -->
|
<!-- Drop Target Zone (visible during drag) -->
|
||||||
<div
|
<div
|
||||||
@ -735,6 +736,21 @@ watch(currentWorkspace, async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Reset drag state when mouse leaves the document (fixes stuck dropzone)
|
||||||
|
useEventListener(document, 'mouseleave', () => {
|
||||||
|
if (isDragging.value) {
|
||||||
|
isDragging.value = false
|
||||||
|
currentDraggedItem.id = ''
|
||||||
|
currentDraggedItem.itemType = ''
|
||||||
|
currentDraggedItem.referenceId = ''
|
||||||
|
currentDraggedItem.width = 0
|
||||||
|
currentDraggedItem.height = 0
|
||||||
|
currentDraggedItem.x = 0
|
||||||
|
currentDraggedItem.y = 0
|
||||||
|
allowSwipe.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// Load workspaces first
|
// Load workspaces first
|
||||||
await workspaceStore.loadWorkspacesAsync()
|
await workspaceStore.loadWorkspacesAsync()
|
||||||
|
|||||||
@ -205,3 +205,30 @@ export const haexDesktopItems = sqliteTable(
|
|||||||
)
|
)
|
||||||
export type InsertHaexDesktopItems = typeof haexDesktopItems.$inferInsert
|
export type InsertHaexDesktopItems = typeof haexDesktopItems.$inferInsert
|
||||||
export type SelectHaexDesktopItems = typeof haexDesktopItems.$inferSelect
|
export type SelectHaexDesktopItems = typeof haexDesktopItems.$inferSelect
|
||||||
|
|
||||||
|
export const haexSyncBackends = sqliteTable(
|
||||||
|
tableNames.haex.sync_backends.name,
|
||||||
|
withCrdtColumns({
|
||||||
|
id: text(tableNames.haex.sync_backends.columns.id)
|
||||||
|
.$defaultFn(() => crypto.randomUUID())
|
||||||
|
.primaryKey(),
|
||||||
|
name: text(tableNames.haex.sync_backends.columns.name).notNull(),
|
||||||
|
serverUrl: text(tableNames.haex.sync_backends.columns.serverUrl).notNull(),
|
||||||
|
enabled: integer(tableNames.haex.sync_backends.columns.enabled, {
|
||||||
|
mode: 'boolean',
|
||||||
|
})
|
||||||
|
.default(true)
|
||||||
|
.notNull(),
|
||||||
|
priority: integer(tableNames.haex.sync_backends.columns.priority)
|
||||||
|
.default(0)
|
||||||
|
.notNull(),
|
||||||
|
createdAt: text(tableNames.haex.sync_backends.columns.createdAt).default(
|
||||||
|
sql`(CURRENT_TIMESTAMP)`,
|
||||||
|
),
|
||||||
|
updatedAt: integer(tableNames.haex.sync_backends.columns.updatedAt, {
|
||||||
|
mode: 'timestamp',
|
||||||
|
}).$onUpdate(() => new Date()),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
export type InsertHaexSyncBackends = typeof haexSyncBackends.$inferInsert
|
||||||
|
export type SelectHaexSyncBackends = typeof haexSyncBackends.$inferSelect
|
||||||
|
|||||||
@ -102,6 +102,20 @@
|
|||||||
"haexTimestamp": "haex_timestamp"
|
"haexTimestamp": "haex_timestamp"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sync_backends": {
|
||||||
|
"name": "haex_sync_backends",
|
||||||
|
"columns": {
|
||||||
|
"id": "id",
|
||||||
|
"name": "name",
|
||||||
|
"serverUrl": "server_url",
|
||||||
|
"enabled": "enabled",
|
||||||
|
"priority": "priority",
|
||||||
|
"createdAt": "created_at",
|
||||||
|
"updatedAt": "updated_at",
|
||||||
|
|
||||||
|
"haexTimestamp": "haex_timestamp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"crdt": {
|
"crdt": {
|
||||||
"logs": {
|
"logs": {
|
||||||
|
|||||||
@ -27,24 +27,26 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
const deviceStore = useDeviceStore()
|
const deviceStore = useDeviceStore()
|
||||||
const settingsStore = useVaultSettingsStore()
|
const settingsStore = useVaultSettingsStore()
|
||||||
|
|
||||||
$i18n.setLocaleMessage('de', {
|
$i18n.setLocaleMessage('de', { desktop: de })
|
||||||
desktop: de,
|
|
||||||
})
|
|
||||||
$i18n.setLocaleMessage('en', { desktop: en })
|
$i18n.setLocaleMessage('en', { desktop: en })
|
||||||
|
|
||||||
const desktopItems = ref<IDesktopItem[]>([])
|
const desktopItems = ref<IDesktopItem[]>([])
|
||||||
const selectedItemIds = ref<Set<string>>(new Set())
|
const selectedItemIds = ref<Set<string>>(new Set())
|
||||||
|
|
||||||
// Desktop Grid Settings (stored in DB per device)
|
// Desktop Grid Settings (stored in DB per device)
|
||||||
const iconSizePreset = ref<DesktopIconSizePreset>(DesktopIconSizePreset.medium)
|
const iconSizePreset = ref<DesktopIconSizePreset>(
|
||||||
|
DesktopIconSizePreset.medium,
|
||||||
|
)
|
||||||
|
|
||||||
// Get device internal ID from DB
|
// Get device internal ID from DB
|
||||||
const getDeviceInternalIdAsync = async () => {
|
const getDeviceInternalIdAsync = async () => {
|
||||||
if (!deviceStore.deviceId || !currentVault.value?.drizzle) return undefined
|
if (!deviceStore.deviceId || !currentVault.value?.drizzle) return undefined
|
||||||
|
|
||||||
const device = await currentVault.value.drizzle.query.haexDevices.findFirst({
|
const device = await currentVault.value.drizzle.query.haexDevices.findFirst(
|
||||||
where: eq(haexDevices.deviceId, deviceStore.deviceId),
|
{
|
||||||
})
|
where: eq(haexDevices.deviceId, deviceStore.deviceId),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return device?.id ? device.id : undefined
|
return device?.id ? device.id : undefined
|
||||||
}
|
}
|
||||||
@ -54,7 +56,8 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
const deviceInternalId = await getDeviceInternalIdAsync()
|
const deviceInternalId = await getDeviceInternalIdAsync()
|
||||||
if (!deviceInternalId) return
|
if (!deviceInternalId) return
|
||||||
|
|
||||||
const preset = await settingsStore.syncDesktopIconSizeAsync(deviceInternalId)
|
const preset =
|
||||||
|
await settingsStore.syncDesktopIconSizeAsync(deviceInternalId)
|
||||||
iconSizePreset.value = preset
|
iconSizePreset.value = preset
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,44 +74,51 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
return iconSizePresetValues[iconSizePreset.value]
|
return iconSizePresetValues[iconSizePreset.value]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const iconPadding = 30
|
||||||
|
|
||||||
// Calculate grid cell size based on icon size
|
// Calculate grid cell size based on icon size
|
||||||
const gridCellSize = computed(() => {
|
const gridCellSize = computed(() => {
|
||||||
// Add padding around icon (30px extra for spacing)
|
// Add padding around icon (30px extra for spacing)
|
||||||
return effectiveIconSize.value + 30
|
return effectiveIconSize.value + iconPadding
|
||||||
})
|
})
|
||||||
|
|
||||||
// Grid offsets for start position (negative = move grid up)
|
|
||||||
const gridOffsetY = -30 // Start grid 30px higher
|
|
||||||
|
|
||||||
// Snap position to grid (centers icon in cell)
|
// Snap position to grid (centers icon in cell)
|
||||||
// iconWidth and iconHeight are optional - if provided, they're used for centering
|
// iconWidth and iconHeight are optional - if provided, they're used for centering
|
||||||
const snapToGrid = (x: number, y: number, iconWidth?: number, iconHeight?: number) => {
|
const snapToGrid = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
iconWidth?: number,
|
||||||
|
iconHeight?: number,
|
||||||
|
) => {
|
||||||
const cellSize = gridCellSize.value
|
const cellSize = gridCellSize.value
|
||||||
|
const halfCell = cellSize / 2
|
||||||
|
|
||||||
// Adjust y for grid offset
|
// Use provided dimensions or fall back to the effective icon size (not cell size!)
|
||||||
const adjustedY = Math.max(0, y - gridOffsetY)
|
const actualIconWidth = iconWidth || effectiveIconSize.value
|
||||||
|
const actualIconHeight = iconHeight || effectiveIconSize.value
|
||||||
|
|
||||||
// Calculate which grid cell the position falls into
|
// Calculate which grid cell the position falls into
|
||||||
const col = Math.floor(x / cellSize)
|
// Add half the icon size to x/y to get the center point for snapping
|
||||||
const row = Math.floor(adjustedY / cellSize)
|
const centerX = x + actualIconWidth / 2
|
||||||
|
const centerY = y + actualIconHeight / 2
|
||||||
|
|
||||||
// Use provided dimensions or fall back to cell size
|
// Find nearest grid cell center
|
||||||
const actualIconWidth = iconWidth || cellSize
|
// Grid cells are centered at: halfCell, halfCell + cellSize, halfCell + 2*cellSize, ...
|
||||||
const actualIconHeight = iconHeight || cellSize
|
// Which is: halfCell + (n * cellSize) for n = 0, 1, 2, ...
|
||||||
|
const col = Math.round((centerX - halfCell) / cellSize)
|
||||||
|
const row = Math.round((centerY - halfCell) / cellSize)
|
||||||
|
|
||||||
// Center the icon in the cell(s) it occupies
|
// Calculate the center of the target grid cell
|
||||||
const cellsWide = Math.max(1, Math.ceil(actualIconWidth / cellSize))
|
const gridCenterX = halfCell + col * cellSize
|
||||||
const cellsHigh = Math.max(1, Math.ceil(actualIconHeight / cellSize))
|
const gridCenterY = halfCell + row * cellSize
|
||||||
|
|
||||||
const totalWidth = cellsWide * cellSize
|
// Calculate the top-left position that centers the icon in the cell
|
||||||
const totalHeight = cellsHigh * cellSize
|
const snappedX = gridCenterX - actualIconWidth / 2
|
||||||
|
const snappedY = gridCenterY - actualIconHeight / 2
|
||||||
const paddingX = (totalWidth - actualIconWidth) / 2
|
|
||||||
const paddingY = (totalHeight - actualIconHeight) / 2
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: col * cellSize + paddingX,
|
x: snappedX,
|
||||||
y: row * cellSize + paddingY + gridOffsetY,
|
y: snappedY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +139,12 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
.from(haexDesktopItems)
|
.from(haexDesktopItems)
|
||||||
.where(eq(haexDesktopItems.workspaceId, currentWorkspace.value.id))
|
.where(eq(haexDesktopItems.workspaceId, currentWorkspace.value.id))
|
||||||
|
|
||||||
desktopItems.value = items.map(item => ({
|
desktopItems.value = items.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
referenceId: item.itemType === 'extension' ? item.extensionId! : item.systemWindowId!,
|
referenceId:
|
||||||
|
item.itemType === 'extension'
|
||||||
|
? item.extensionId!
|
||||||
|
: item.systemWindowId!,
|
||||||
}))
|
}))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fehler beim Laden der Desktop-Items:', error)
|
console.error('Fehler beim Laden der Desktop-Items:', error)
|
||||||
@ -160,7 +173,10 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
workspaceId: targetWorkspaceId,
|
workspaceId: targetWorkspaceId,
|
||||||
itemType: itemType,
|
itemType: itemType,
|
||||||
extensionId: itemType === 'extension' ? referenceId : null,
|
extensionId: itemType === 'extension' ? referenceId : null,
|
||||||
systemWindowId: itemType === 'system' || itemType === 'file' || itemType === 'folder' ? referenceId : null,
|
systemWindowId:
|
||||||
|
itemType === 'system' || itemType === 'file' || itemType === 'folder'
|
||||||
|
? referenceId
|
||||||
|
: null,
|
||||||
positionX: positionX,
|
positionX: positionX,
|
||||||
positionY: positionY,
|
positionY: positionY,
|
||||||
}
|
}
|
||||||
@ -173,7 +189,10 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
if (result.length > 0 && result[0]) {
|
if (result.length > 0 && result[0]) {
|
||||||
const itemWithRef = {
|
const itemWithRef = {
|
||||||
...result[0],
|
...result[0],
|
||||||
referenceId: itemType === 'extension' ? result[0].extensionId! : result[0].systemWindowId!,
|
referenceId:
|
||||||
|
itemType === 'extension'
|
||||||
|
? result[0].extensionId!
|
||||||
|
: result[0].systemWindowId!,
|
||||||
}
|
}
|
||||||
desktopItems.value.push(itemWithRef)
|
desktopItems.value.push(itemWithRef)
|
||||||
return itemWithRef
|
return itemWithRef
|
||||||
@ -184,7 +203,7 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
itemType,
|
itemType,
|
||||||
referenceId,
|
referenceId,
|
||||||
workspaceId: targetWorkspaceId,
|
workspaceId: targetWorkspaceId,
|
||||||
position: { x: positionX, y: positionY }
|
position: { x: positionX, y: positionY },
|
||||||
})
|
})
|
||||||
|
|
||||||
// Log full error details
|
// Log full error details
|
||||||
@ -221,7 +240,10 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
const item = result[0]
|
const item = result[0]
|
||||||
desktopItems.value[index] = {
|
desktopItems.value[index] = {
|
||||||
...item,
|
...item,
|
||||||
referenceId: item.itemType === 'extension' ? item.extensionId! : item.systemWindowId!,
|
referenceId:
|
||||||
|
item.itemType === 'extension'
|
||||||
|
? item.extensionId!
|
||||||
|
: item.systemWindowId!,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,16 +276,14 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
itemType: DesktopItemType,
|
itemType: DesktopItemType,
|
||||||
referenceId: string,
|
referenceId: string,
|
||||||
) => {
|
) => {
|
||||||
return desktopItems.value.find(
|
return desktopItems.value.find((item) => {
|
||||||
(item) => {
|
if (item.itemType !== itemType) return false
|
||||||
if (item.itemType !== itemType) return false
|
if (itemType === 'extension') {
|
||||||
if (itemType === 'extension') {
|
return item.extensionId === referenceId
|
||||||
return item.extensionId === referenceId
|
} else {
|
||||||
} else {
|
return item.systemWindowId === referenceId
|
||||||
return item.systemWindowId === referenceId
|
}
|
||||||
}
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const openDesktopItem = (
|
const openDesktopItem = (
|
||||||
@ -274,9 +294,9 @@ export const useDesktopStore = defineStore('desktopStore', () => {
|
|||||||
const windowManager = useWindowManagerStore()
|
const windowManager = useWindowManagerStore()
|
||||||
|
|
||||||
if (itemType === 'system') {
|
if (itemType === 'system') {
|
||||||
const systemWindow = windowManager.getAllSystemWindows().find(
|
const systemWindow = windowManager
|
||||||
(win) => win.id === referenceId,
|
.getAllSystemWindows()
|
||||||
)
|
.find((win) => win.id === referenceId)
|
||||||
|
|
||||||
if (systemWindow) {
|
if (systemWindow) {
|
||||||
windowManager.openWindowAsync({
|
windowManager.openWindowAsync({
|
||||||
|
|||||||
130
src/stores/sync/backends.ts
Normal file
130
src/stores/sync/backends.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { eq } from 'drizzle-orm'
|
||||||
|
import {
|
||||||
|
haexSyncBackends,
|
||||||
|
type InsertHaexSyncBackends,
|
||||||
|
type SelectHaexSyncBackends,
|
||||||
|
} from '~/database/schemas'
|
||||||
|
|
||||||
|
export const useSyncBackendsStore = defineStore('syncBackendsStore', () => {
|
||||||
|
const { currentVault } = storeToRefs(useVaultStore())
|
||||||
|
|
||||||
|
const backends = ref<SelectHaexSyncBackends[]>([])
|
||||||
|
|
||||||
|
const enabledBackends = computed(() =>
|
||||||
|
backends.value.filter((b) => b.enabled),
|
||||||
|
)
|
||||||
|
|
||||||
|
const sortedBackends = computed(() =>
|
||||||
|
[...backends.value].sort((a, b) => (b.priority || 0) - (a.priority || 0)),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Load all sync backends from database
|
||||||
|
const loadBackendsAsync = async () => {
|
||||||
|
if (!currentVault.value?.drizzle) {
|
||||||
|
console.error('No vault opened')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await currentVault.value.drizzle
|
||||||
|
.select()
|
||||||
|
.from(haexSyncBackends)
|
||||||
|
|
||||||
|
backends.value = result
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load sync backends:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new sync backend
|
||||||
|
const addBackendAsync = async (backend: InsertHaexSyncBackends) => {
|
||||||
|
if (!currentVault.value?.drizzle) {
|
||||||
|
throw new Error('No vault opened')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await currentVault.value.drizzle
|
||||||
|
.insert(haexSyncBackends)
|
||||||
|
.values(backend)
|
||||||
|
.returning()
|
||||||
|
|
||||||
|
if (result.length > 0 && result[0]) {
|
||||||
|
backends.value.push(result[0])
|
||||||
|
return result[0]
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to add sync backend:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update an existing sync backend
|
||||||
|
const updateBackendAsync = async (
|
||||||
|
id: string,
|
||||||
|
updates: Partial<InsertHaexSyncBackends>,
|
||||||
|
) => {
|
||||||
|
if (!currentVault.value?.drizzle) {
|
||||||
|
throw new Error('No vault opened')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await currentVault.value.drizzle
|
||||||
|
.update(haexSyncBackends)
|
||||||
|
.set(updates)
|
||||||
|
.where(eq(haexSyncBackends.id, id))
|
||||||
|
.returning()
|
||||||
|
|
||||||
|
if (result.length > 0 && result[0]) {
|
||||||
|
const index = backends.value.findIndex((b) => b.id === id)
|
||||||
|
if (index !== -1) {
|
||||||
|
backends.value[index] = result[0]
|
||||||
|
}
|
||||||
|
return result[0]
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to update sync backend:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a sync backend
|
||||||
|
const deleteBackendAsync = async (id: string) => {
|
||||||
|
if (!currentVault.value?.drizzle) {
|
||||||
|
throw new Error('No vault opened')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await currentVault.value.drizzle
|
||||||
|
.delete(haexSyncBackends)
|
||||||
|
.where(eq(haexSyncBackends.id, id))
|
||||||
|
|
||||||
|
backends.value = backends.value.filter((b) => b.id !== id)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to delete sync backend:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable/disable a backend
|
||||||
|
const toggleBackendAsync = async (id: string, enabled: boolean) => {
|
||||||
|
return updateBackendAsync(id, { enabled })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update backend priority (for sync order)
|
||||||
|
const updatePriorityAsync = async (id: string, priority: number) => {
|
||||||
|
return updateBackendAsync(id, { priority })
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
backends,
|
||||||
|
enabledBackends,
|
||||||
|
sortedBackends,
|
||||||
|
loadBackendsAsync,
|
||||||
|
addBackendAsync,
|
||||||
|
updateBackendAsync,
|
||||||
|
deleteBackendAsync,
|
||||||
|
toggleBackendAsync,
|
||||||
|
updatePriorityAsync,
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user