diff --git a/backend/.sqlx/query-01755585cd3f6e100a66da331720286cbc09d4abf2926146b24a8c95cf21e5c8.json b/backend/.sqlx/query-01755585cd3f6e100a66da331720286cbc09d4abf2926146b24a8c95cf21e5c8.json new file mode 100644 index 0000000000..8c1ba3782c --- /dev/null +++ b/backend/.sqlx/query-01755585cd3f6e100a66da331720286cbc09d4abf2926146b24a8c95cf21e5c8.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO workspace_runnable_dependencies (app_path, runnable_path, runnable_is_flow, workspace_id) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Bool", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "01755585cd3f6e100a66da331720286cbc09d4abf2926146b24a8c95cf21e5c8" +} diff --git a/backend/.sqlx/query-09efbd7177c6172569dc29b7d9ede70315eeb4e0ef9ed3165365f257e27f5e68.json b/backend/.sqlx/query-09efbd7177c6172569dc29b7d9ede70315eeb4e0ef9ed3165365f257e27f5e68.json new file mode 100644 index 0000000000..4500681506 --- /dev/null +++ b/backend/.sqlx/query-09efbd7177c6172569dc29b7d9ede70315eeb4e0ef9ed3165365f257e27f5e68.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO workspace_runnable_dependencies (flow_path, runnable_path, runnable_is_flow, workspace_id) VALUES ($1, $2, TRUE, $3) ON CONFLICT DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "09efbd7177c6172569dc29b7d9ede70315eeb4e0ef9ed3165365f257e27f5e68" +} diff --git a/backend/.sqlx/query-171b11d66b9ec6cb7b0dd74929e233389683f8d510850487453052a317391f0f.json b/backend/.sqlx/query-171b11d66b9ec6cb7b0dd74929e233389683f8d510850487453052a317391f0f.json new file mode 100644 index 0000000000..b8f2ccca5f --- /dev/null +++ b/backend/.sqlx/query-171b11d66b9ec6cb7b0dd74929e233389683f8d510850487453052a317391f0f.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT a.path\n FROM workspace_runnable_dependencies wru \n JOIN app a\n ON wru.app_path = a.path AND wru.workspace_id = a.workspace_id\n WHERE wru.runnable_path = $1 AND wru.runnable_is_flow = $2 AND wru.workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "171b11d66b9ec6cb7b0dd74929e233389683f8d510850487453052a317391f0f" +} diff --git a/backend/.sqlx/query-1ea8c2ce29da8d1be19dfd3ecc7f84fef7557f3e3046e7188ee06f6c3a2b2add.json b/backend/.sqlx/query-1ea8c2ce29da8d1be19dfd3ecc7f84fef7557f3e3046e7188ee06f6c3a2b2add.json new file mode 100644 index 0000000000..17c406c101 --- /dev/null +++ b/backend/.sqlx/query-1ea8c2ce29da8d1be19dfd3ecc7f84fef7557f3e3046e7188ee06f6c3a2b2add.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM workspace_runnable_usage WHERE resource_path = $1 AND workspace_id = $2 and resource_kind = 'flow'", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "1ea8c2ce29da8d1be19dfd3ecc7f84fef7557f3e3046e7188ee06f6c3a2b2add" +} diff --git a/backend/.sqlx/query-44ce12725e09c1e32d82dfe9539ee42065315ac8df5fc8bd8004c0992e6f1bdb.json b/backend/.sqlx/query-44ce12725e09c1e32d82dfe9539ee42065315ac8df5fc8bd8004c0992e6f1bdb.json new file mode 100644 index 0000000000..1369de2911 --- /dev/null +++ b/backend/.sqlx/query-44ce12725e09c1e32d82dfe9539ee42065315ac8df5fc8bd8004c0992e6f1bdb.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_dependencies SET flow_path = REGEXP_REPLACE(flow_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE flow_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "44ce12725e09c1e32d82dfe9539ee42065315ac8df5fc8bd8004c0992e6f1bdb" +} diff --git a/backend/.sqlx/query-56a2fe44b73728c9aba10f3d1c7707bd1c48c58aaa5b2ae7560cbed3c8d46329.json b/backend/.sqlx/query-56a2fe44b73728c9aba10f3d1c7707bd1c48c58aaa5b2ae7560cbed3c8d46329.json new file mode 100644 index 0000000000..22870b1d2d --- /dev/null +++ b/backend/.sqlx/query-56a2fe44b73728c9aba10f3d1c7707bd1c48c58aaa5b2ae7560cbed3c8d46329.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT f.path\n FROM workspace_runnable_usage wru \n JOIN flow f\n ON wru.resource_path = f.path AND wru.workspace_id = f.workspace_id\n WHERE wru.runnable_path = $1 AND wru.runnable_is_flow = $2 AND wru.workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "56a2fe44b73728c9aba10f3d1c7707bd1c48c58aaa5b2ae7560cbed3c8d46329" +} diff --git a/backend/.sqlx/query-6aa04cc83e746ebca45959294b6184d17c5100a3f3dc9fda02b1a7acc0b73fa5.json b/backend/.sqlx/query-6aa04cc83e746ebca45959294b6184d17c5100a3f3dc9fda02b1a7acc0b73fa5.json new file mode 100644 index 0000000000..44d1cfc7a5 --- /dev/null +++ b/backend/.sqlx/query-6aa04cc83e746ebca45959294b6184d17c5100a3f3dc9fda02b1a7acc0b73fa5.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT importer_path FROM dependency_map \n WHERE workspace_id = $1 AND imported_path = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "importer_path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "6aa04cc83e746ebca45959294b6184d17c5100a3f3dc9fda02b1a7acc0b73fa5" +} diff --git a/backend/.sqlx/query-7023184bfeece73252aac9e3e89c5954f40cf46905b40b40ba97a21558a1ac01.json b/backend/.sqlx/query-7023184bfeece73252aac9e3e89c5954f40cf46905b40b40ba97a21558a1ac01.json new file mode 100644 index 0000000000..e1d8d14548 --- /dev/null +++ b/backend/.sqlx/query-7023184bfeece73252aac9e3e89c5954f40cf46905b40b40ba97a21558a1ac01.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM workspace_runnable_dependencies WHERE flow_path = $1 AND workspace_id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "7023184bfeece73252aac9e3e89c5954f40cf46905b40b40ba97a21558a1ac01" +} diff --git a/backend/.sqlx/query-808790cc01ec68be41dfeb80dc560d447fd719f2a56ea954c8cce49ffabd4245.json b/backend/.sqlx/query-808790cc01ec68be41dfeb80dc560d447fd719f2a56ea954c8cce49ffabd4245.json new file mode 100644 index 0000000000..846f94dcbb --- /dev/null +++ b/backend/.sqlx/query-808790cc01ec68be41dfeb80dc560d447fd719f2a56ea954c8cce49ffabd4245.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT f.path\n FROM workspace_runnable_dependencies wru \n JOIN flow f\n ON wru.flow_path = f.path AND wru.workspace_id = f.workspace_id\n WHERE wru.runnable_path = $1 AND wru.runnable_is_flow = $2 AND wru.workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "808790cc01ec68be41dfeb80dc560d447fd719f2a56ea954c8cce49ffabd4245" +} diff --git a/backend/.sqlx/query-894e5080e83b098839a050bb472359d6d9fdfdbffb40a2464a45056660a3a2d4.json b/backend/.sqlx/query-894e5080e83b098839a050bb472359d6d9fdfdbffb40a2464a45056660a3a2d4.json new file mode 100644 index 0000000000..7ee434f66e --- /dev/null +++ b/backend/.sqlx/query-894e5080e83b098839a050bb472359d6d9fdfdbffb40a2464a45056660a3a2d4.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO workspace_runnable_usage (resource_path, runnable_path, script_hash, runnable_is_flow, workspace_id, resource_kind) VALUES ($1, $2, $3, FALSE, $4, 'flow') ON CONFLICT DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Int8", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "894e5080e83b098839a050bb472359d6d9fdfdbffb40a2464a45056660a3a2d4" +} diff --git a/backend/.sqlx/query-9c956541e068154193243795d96cc62a0fc9d4ba56014f3e554cc2b50ce1da06.json b/backend/.sqlx/query-9c956541e068154193243795d96cc62a0fc9d4ba56014f3e554cc2b50ce1da06.json new file mode 100644 index 0000000000..690f2dedcc --- /dev/null +++ b/backend/.sqlx/query-9c956541e068154193243795d96cc62a0fc9d4ba56014f3e554cc2b50ce1da06.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_usage SET resource_path = REGEXP_REPLACE(resource_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE resource_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "9c956541e068154193243795d96cc62a0fc9d4ba56014f3e554cc2b50ce1da06" +} diff --git a/backend/.sqlx/query-a28f8697da75d7ac2c6e13dda394ee12e8cffe925bd7cc4e9d02dc90ffe200f3.json b/backend/.sqlx/query-a28f8697da75d7ac2c6e13dda394ee12e8cffe925bd7cc4e9d02dc90ffe200f3.json new file mode 100644 index 0000000000..62c2a10550 --- /dev/null +++ b/backend/.sqlx/query-a28f8697da75d7ac2c6e13dda394ee12e8cffe925bd7cc4e9d02dc90ffe200f3.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM workspace_runnable_usage WHERE resource_path = $1 AND workspace_id = $2 and resource_kind = 'app'", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "a28f8697da75d7ac2c6e13dda394ee12e8cffe925bd7cc4e9d02dc90ffe200f3" +} diff --git a/backend/.sqlx/query-ab9783a48e0f6cacd5dd86cfa21ba8354d4cd733335db3d76155b663f668b9d7.json b/backend/.sqlx/query-ab9783a48e0f6cacd5dd86cfa21ba8354d4cd733335db3d76155b663f668b9d7.json new file mode 100644 index 0000000000..7dd52db3fa --- /dev/null +++ b/backend/.sqlx/query-ab9783a48e0f6cacd5dd86cfa21ba8354d4cd733335db3d76155b663f668b9d7.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO workspace_runnable_usage (resource_path, runnable_path, runnable_is_flow, workspace_id, resource_kind) VALUES ($1, $2, TRUE, $3, 'flow') ON CONFLICT DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "ab9783a48e0f6cacd5dd86cfa21ba8354d4cd733335db3d76155b663f668b9d7" +} diff --git a/backend/.sqlx/query-aeca239a2997efc514ee56a6b3766fa5f32b5a56e28100a2487b478e5dc3eaec.json b/backend/.sqlx/query-aeca239a2997efc514ee56a6b3766fa5f32b5a56e28100a2487b478e5dc3eaec.json new file mode 100644 index 0000000000..db6ed5a29a --- /dev/null +++ b/backend/.sqlx/query-aeca239a2997efc514ee56a6b3766fa5f32b5a56e28100a2487b478e5dc3eaec.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO workspace_runnable_dependencies (flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id) VALUES ($1, $2, $3, FALSE, $4) ON CONFLICT DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Int8", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "aeca239a2997efc514ee56a6b3766fa5f32b5a56e28100a2487b478e5dc3eaec" +} diff --git a/backend/.sqlx/query-af2f780da994befd09959d3b1b077eb9b71337a9aa2a64cd2db031e64e929251.json b/backend/.sqlx/query-af2f780da994befd09959d3b1b077eb9b71337a9aa2a64cd2db031e64e929251.json new file mode 100644 index 0000000000..8ccc824ace --- /dev/null +++ b/backend/.sqlx/query-af2f780da994befd09959d3b1b077eb9b71337a9aa2a64cd2db031e64e929251.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_usage SET workspace_id = $1 WHERE workspace_id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text" + ] + }, + "nullable": [] + }, + "hash": "af2f780da994befd09959d3b1b077eb9b71337a9aa2a64cd2db031e64e929251" +} diff --git a/backend/.sqlx/query-b190ad25e22367f71c1e16e34bfbbe4303249c8d8664962d479056971f0409a2.json b/backend/.sqlx/query-b190ad25e22367f71c1e16e34bfbbe4303249c8d8664962d479056971f0409a2.json new file mode 100644 index 0000000000..def6dfdd14 --- /dev/null +++ b/backend/.sqlx/query-b190ad25e22367f71c1e16e34bfbbe4303249c8d8664962d479056971f0409a2.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM workspace_runnable_dependencies WHERE app_path = $1 AND workspace_id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "b190ad25e22367f71c1e16e34bfbbe4303249c8d8664962d479056971f0409a2" +} diff --git a/backend/.sqlx/query-baf63525ca210c22d3ad8c0b197dc6b39dabab77ae7810f553f1773995db51f1.json b/backend/.sqlx/query-baf63525ca210c22d3ad8c0b197dc6b39dabab77ae7810f553f1773995db51f1.json new file mode 100644 index 0000000000..dfc8414434 --- /dev/null +++ b/backend/.sqlx/query-baf63525ca210c22d3ad8c0b197dc6b39dabab77ae7810f553f1773995db51f1.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_usage SET runnable_path = REGEXP_REPLACE(runnable_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE runnable_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "baf63525ca210c22d3ad8c0b197dc6b39dabab77ae7810f553f1773995db51f1" +} diff --git a/backend/.sqlx/query-c14cc34a5350865b8a5b57205b6099e8f0ea697e279f6a72484ab031b7e1e952.json b/backend/.sqlx/query-c14cc34a5350865b8a5b57205b6099e8f0ea697e279f6a72484ab031b7e1e952.json new file mode 100644 index 0000000000..828dc6f04a --- /dev/null +++ b/backend/.sqlx/query-c14cc34a5350865b8a5b57205b6099e8f0ea697e279f6a72484ab031b7e1e952.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_dependencies SET runnable_path = REGEXP_REPLACE(runnable_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE runnable_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c14cc34a5350865b8a5b57205b6099e8f0ea697e279f6a72484ab031b7e1e952" +} diff --git a/backend/.sqlx/query-e19fab3d594c8b9d38f9caa8f71b16ffcb2bc8d94a8240143a913ad125ad6eb8.json b/backend/.sqlx/query-e19fab3d594c8b9d38f9caa8f71b16ffcb2bc8d94a8240143a913ad125ad6eb8.json new file mode 100644 index 0000000000..f75e6eaa56 --- /dev/null +++ b/backend/.sqlx/query-e19fab3d594c8b9d38f9caa8f71b16ffcb2bc8d94a8240143a913ad125ad6eb8.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_dependencies SET workspace_id = $1 WHERE workspace_id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text" + ] + }, + "nullable": [] + }, + "hash": "e19fab3d594c8b9d38f9caa8f71b16ffcb2bc8d94a8240143a913ad125ad6eb8" +} diff --git a/backend/.sqlx/query-f699cc3644aeb35a0588bbb3a6bf2dc0746d9f3a1bea104123188fe2921bc886.json b/backend/.sqlx/query-f699cc3644aeb35a0588bbb3a6bf2dc0746d9f3a1bea104123188fe2921bc886.json new file mode 100644 index 0000000000..d352d3d69d --- /dev/null +++ b/backend/.sqlx/query-f699cc3644aeb35a0588bbb3a6bf2dc0746d9f3a1bea104123188fe2921bc886.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_runnable_dependencies SET app_path = REGEXP_REPLACE(app_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE app_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "f699cc3644aeb35a0588bbb3a6bf2dc0746d9f3a1bea104123188fe2921bc886" +} diff --git a/backend/migrations/20250317145509_more_generic_workspace_runnable_usage.down.sql b/backend/migrations/20250317145509_more_generic_workspace_runnable_usage.down.sql new file mode 100644 index 0000000000..27f65545ae --- /dev/null +++ b/backend/migrations/20250317145509_more_generic_workspace_runnable_usage.down.sql @@ -0,0 +1,24 @@ +DROP VIEW flow_workspace_runnables; + +DELETE FROM workspace_runnable_dependencies WHERE flow_path IS NULL; + +ALTER TABLE workspace_runnable_dependencies +DROP CONSTRAINT flow_workspace_runnables_workspace_id_flow_path_fkey; + +ALTER TABLE workspace_runnable_dependencies +ADD CONSTRAINT flow_workspace_runnables_workspace_id_flow_path_fkey +FOREIGN KEY (flow_path, workspace_id) REFERENCES flow (path, workspace_id) +ON DELETE CASCADE; + +ALTER TABLE workspace_runnable_dependencies +DROP CONSTRAINT workspace_runnable_dependencies_path_exclusive; + +ALTER TABLE workspace_runnable_dependencies +DROP CONSTRAINT fk_workspace_runnable_dependencies_app_path; + +ALTER TABLE workspace_runnable_dependencies DROP COLUMN app_path; + +ALTER TABLE workspace_runnable_dependencies ALTER flow_path SET NOT NULL; + +ALTER TABLE workspace_runnable_dependencies +RENAME TO flow_workspace_runnables; diff --git a/backend/migrations/20250317145509_more_generic_workspace_runnable_usage.up.sql b/backend/migrations/20250317145509_more_generic_workspace_runnable_usage.up.sql new file mode 100644 index 0000000000..4b7b209bb5 --- /dev/null +++ b/backend/migrations/20250317145509_more_generic_workspace_runnable_usage.up.sql @@ -0,0 +1,42 @@ +-- flow_workspace_runnables only stored runnable usages by +-- flows although apps can also use runnables + +ALTER TABLE flow_workspace_runnables +RENAME TO workspace_runnable_dependencies; + +ALTER TABLE workspace_runnable_dependencies ALTER flow_path DROP NOT NULL; + +ALTER TABLE workspace_runnable_dependencies +ADD COLUMN app_path VARCHAR(255); + +ALTER TABLE workspace_runnable_dependencies +ADD CONSTRAINT workspace_runnable_dependencies_path_exclusive CHECK ( + (flow_path IS NOT NULL AND app_path IS NULL) OR + (flow_path IS NULL AND app_path IS NOT NULL) +); + +ALTER TABLE workspace_runnable_dependencies +ADD CONSTRAINT fk_workspace_runnable_dependencies_app_path +FOREIGN KEY (app_path, workspace_id) REFERENCES app (path, workspace_id) +ON DELETE CASCADE +ON UPDATE CASCADE; + + +ALTER TABLE workspace_runnable_dependencies +DROP CONSTRAINT flow_workspace_runnables_workspace_id_flow_path_fkey; + +ALTER TABLE workspace_runnable_dependencies +ADD CONSTRAINT flow_workspace_runnables_workspace_id_flow_path_fkey +FOREIGN KEY (flow_path, workspace_id) REFERENCES flow (path, workspace_id) +ON DELETE CASCADE +ON UPDATE CASCADE; + + +CREATE UNIQUE INDEX app_workspace_without_hash_unique_idx ON workspace_runnable_dependencies (app_path, runnable_path, runnable_is_flow, workspace_id) WHERE script_hash IS NULL; +CREATE UNIQUE INDEX app_workspace_with_hash_unique_idx ON workspace_runnable_dependencies (app_path, runnable_path, script_hash, runnable_is_flow, workspace_id) WHERE script_hash IS NOT NULL; + + +-- This is to maintain compatibility with old workers +CREATE VIEW flow_workspace_runnables AS +SELECT flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id +FROM workspace_runnable_dependencies; \ No newline at end of file diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 5339ed86af..3d73899486 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -4774,6 +4774,25 @@ paths: items: $ref: "#/components/schemas/ScriptHistory" + /w/{workspace}/scripts/list_paths_from_workspace_runnable/{path}: + get: + summary: list script paths using provided script as a relative import + operationId: listScriptPathsFromWorkspaceRunnable + tags: + - script + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: list of script paths + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/scripts/get_latest_version/{path}: get: summary: get scripts's latest version (hash) @@ -5934,6 +5953,26 @@ paths: schema: $ref: "#/components/schemas/AppHistory" + /w/{workspace}/apps/list_paths_from_workspace_runnable/{runnable_kind}/{path}: + get: + summary: list app paths from workspace runnable + operationId: listAppPathsFromWorkspaceRunnable + tags: + - app + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/RunnableKind" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: list of app paths + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/apps/history_update/a/{id}/v/{version}: post: summary: update app history diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index 0a8878fad6..78159218c7 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -12,7 +12,7 @@ use crate::{ db::{ApiAuthed, DB}, resources::get_resource_value_interpolated_internal, users::{require_owner_of_path, OptAuthed}, - utils::WithStarredInfoQuery, + utils::{RunnableKind, WithStarredInfoQuery}, webhook_util::{WebhookMessage, WebhookShared}, HTTP_CLIENT, }; @@ -89,6 +89,10 @@ pub fn workspaced_service() -> Router { .route("/history/p/*path", get(get_app_history)) .route("/get_latest_version/*path", get(get_latest_version)) .route("/history_update/a/:id/v/:version", post(update_app_history)) + .route( + "/list_paths_from_workspace_runnable/:runnable_kind/*path", + get(list_paths_from_workspace_runnable), + ) .route("/custom_path_exists/*custom_path", get(custom_path_exists)) } @@ -719,6 +723,28 @@ async fn get_secret_id( Ok(hx) } +async fn list_paths_from_workspace_runnable( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, StripPath)>, +) -> JsonResult> { + let mut tx = user_db.begin(&authed).await?; + let runnables = sqlx::query_scalar!( + r#"SELECT a.path + FROM workspace_runnable_dependencies wru + JOIN app a + ON wru.app_path = a.path AND wru.workspace_id = a.workspace_id + WHERE wru.runnable_path = $1 AND wru.runnable_is_flow = $2 AND wru.workspace_id = $3"#, + path.to_path(), + matches!(runnable_kind, RunnableKind::Flow), + w_id + ) + .fetch_all(&mut *tx) + .await?; + tx.commit().await?; + Ok(Json(runnables)) +} + async fn create_app( authed: ApiAuthed, Extension(user_db): Extension, diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index beaec364f6..95a2145bcf 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -336,10 +336,10 @@ async fn list_paths_from_workspace_runnable( let mut tx = user_db.begin(&authed).await?; let runnables = sqlx::query_scalar!( r#"SELECT f.path - FROM flow_workspace_runnables fwr - JOIN flow f - ON fwr.flow_path = f.path AND fwr.workspace_id = f.workspace_id - WHERE fwr.runnable_path = $1 AND fwr.runnable_is_flow = $2 AND fwr.workspace_id = $3"#, + FROM workspace_runnable_dependencies wru + JOIN flow f + ON wru.flow_path = f.path AND wru.workspace_id = f.workspace_id + WHERE wru.runnable_path = $1 AND wru.runnable_is_flow = $2 AND wru.workspace_id = $3"#, path.to_path(), matches!(runnable_kind, RunnableKind::Flow), w_id diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index 3e0197fccc..f370bf33fe 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -147,6 +147,10 @@ pub fn workspaced_service() -> Router { ) .route("/history/p/*path", get(get_script_history)) .route("/get_latest_version/*path", get(get_latest_version)) + .route( + "/list_paths_from_workspace_runnable/*path", + get(list_paths_from_workspace_runnable), + ) .route( "/history_update/h/:hash/p/*path", post(update_script_history), @@ -447,6 +451,24 @@ async fn create_snapshot_script( return Ok((StatusCode::CREATED, format!("{}", script_hash.unwrap()))); } +async fn list_paths_from_workspace_runnable( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> JsonResult> { + let mut tx = user_db.begin(&authed).await?; + let runnables = sqlx::query_scalar!( + r#"SELECT importer_path FROM dependency_map + WHERE workspace_id = $1 AND imported_path = $2"#, + w_id, + path.to_path(), + ) + .fetch_all(&mut *tx) + .await?; + tx.commit().await?; + Ok(Json(runnables)) +} + async fn create_script( authed: ApiAuthed, Extension(user_db): Extension, diff --git a/backend/windmill-api/src/users.rs b/backend/windmill-api/src/users.rs index b8cac903b6..507831e78f 100644 --- a/backend/windmill-api/src/users.rs +++ b/backend/windmill-api/src/users.rs @@ -2538,7 +2538,7 @@ async fn update_username_in_workpsace<'c>( .await?; sqlx::query!( - r#"UPDATE flow_workspace_runnables SET flow_path = REGEXP_REPLACE(flow_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\1') WHERE flow_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3"#, + r#"UPDATE workspace_runnable_dependencies SET flow_path = REGEXP_REPLACE(flow_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\1') WHERE flow_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3"#, new_username, old_username, w_id @@ -2546,7 +2546,15 @@ async fn update_username_in_workpsace<'c>( .await?; sqlx::query!( - r#"UPDATE flow_workspace_runnables SET runnable_path = REGEXP_REPLACE(runnable_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\1') WHERE runnable_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3"#, + r#"UPDATE workspace_runnable_dependencies SET app_path = REGEXP_REPLACE(app_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\1') WHERE app_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3"#, + new_username, + old_username, + w_id + ).execute(&mut **tx) + .await?; + + sqlx::query!( + r#"UPDATE workspace_runnable_dependencies SET runnable_path = REGEXP_REPLACE(runnable_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\1') WHERE runnable_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3"#, new_username, old_username, w_id diff --git a/backend/windmill-api/src/workspaces_extra.rs b/backend/windmill-api/src/workspaces_extra.rs index 2f77112331..07570df5c3 100644 --- a/backend/windmill-api/src/workspaces_extra.rs +++ b/backend/windmill-api/src/workspaces_extra.rs @@ -190,7 +190,7 @@ pub(crate) async fn change_workspace_id( .await?; sqlx::query!( - "UPDATE flow_workspace_runnables SET workspace_id = $1 WHERE workspace_id = $2", + "UPDATE workspace_runnable_dependencies SET workspace_id = $1 WHERE workspace_id = $2", &rw.new_id, &old_id ) diff --git a/backend/windmill-worker/src/worker_lockfiles.rs b/backend/windmill-worker/src/worker_lockfiles.rs index 47a0d264cb..113d1714d2 100644 --- a/backend/windmill-worker/src/worker_lockfiles.rs +++ b/backend/windmill-worker/src/worker_lockfiles.rs @@ -177,7 +177,7 @@ fn try_normalize(path: &Path) -> Option { Some(ret) } -fn parse_bun_relative_imports(raw_code: &str, script_path: &str) -> error::Result> { +fn parse_ts_relative_imports(raw_code: &str, script_path: &str) -> error::Result> { let mut relative_imports = vec![]; let r = parse_expr_for_imports(raw_code)?; for import in r { @@ -209,8 +209,8 @@ pub fn extract_relative_imports( match language { #[cfg(feature = "python")] Some(ScriptLang::Python3) => parse_relative_imports(&raw_code, script_path).ok(), - Some(ScriptLang::Bun) | Some(ScriptLang::Bunnative) => { - parse_bun_relative_imports(&raw_code, script_path).ok() + Some(ScriptLang::Bun) | Some(ScriptLang::Bunnative) | Some(ScriptLang::Deno) => { + parse_ts_relative_imports(&raw_code, script_path).ok() } _ => None, } @@ -644,7 +644,7 @@ pub async fn handle_flow_dependency_job( tx = clear_dependency_parent_path(&parent_path, &job_path, &job.workspace_id, "flow", tx) .await?; sqlx::query!( - "DELETE FROM flow_workspace_runnables WHERE flow_path = $1 AND workspace_id = $2", + "DELETE FROM workspace_runnable_dependencies WHERE flow_path = $1 AND workspace_id = $2", job_path, job.workspace_id ) @@ -1013,7 +1013,7 @@ async fn lock_modules<'c>( } FlowModuleValue::Script { path, hash, .. } if !path.starts_with("hub/") => { sqlx::query!( - "INSERT INTO flow_workspace_runnables (flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id) VALUES ($1, $2, $3, FALSE, $4) ON CONFLICT DO NOTHING", + "INSERT INTO workspace_runnable_dependencies (flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id) VALUES ($1, $2, $3, FALSE, $4) ON CONFLICT DO NOTHING", job_path, path, hash.map(|h| h.0), @@ -1024,10 +1024,10 @@ async fn lock_modules<'c>( } FlowModuleValue::Flow { path, .. } => { sqlx::query!( - "INSERT INTO flow_workspace_runnables (flow_path, runnable_path, runnable_is_flow, workspace_id) VALUES ($1, $2, TRUE, $3) ON CONFLICT DO NOTHING", + "INSERT INTO workspace_runnable_dependencies (flow_path, runnable_path, runnable_is_flow, workspace_id) VALUES ($1, $2, TRUE, $3) ON CONFLICT DO NOTHING", job_path, path, - job.workspace_id + job.workspace_id, ) .execute(&mut *tx) .await?; @@ -1439,6 +1439,22 @@ async fn lock_modules_app( ) -> Result { match value { Value::Object(mut m) => { + if let (Some(Value::String(ref run_type)), Some(path), Some("runnableByPath")) = ( + m.get("runType"), + m.get("path").and_then(|s| s.as_str()), + m.get("type").and_then(|s| s.as_str()), + ) { + // No script_hash because apps don't supports script version locks yet + sqlx::query!( + "INSERT INTO workspace_runnable_dependencies (app_path, runnable_path, runnable_is_flow, workspace_id) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", + job_path, + path, + run_type == "flow", + job.workspace_id + ) + .execute(db) + .await?; + } if m.contains_key("inlineScript") { let v = m.get_mut("inlineScript").unwrap(); if let Some(v) = v.as_object_mut() { @@ -1595,6 +1611,15 @@ pub async fn handle_app_dependency_job( .clone() .ok_or_else(|| Error::internal_err("App Dependency requires script hash".to_owned()))? .0; + + sqlx::query!( + "DELETE FROM workspace_runnable_dependencies WHERE app_path = $1 AND workspace_id = $2", + job_path, + job.workspace_id + ) + .execute(db) + .await?; + let record = sqlx::query!("SELECT app_id, value FROM app_version WHERE id = $1", id) .fetch_optional(db) .await? diff --git a/frontend/src/lib/components/Path.svelte b/frontend/src/lib/components/Path.svelte index f6ea751e6c..feb23b9ea2 100644 --- a/frontend/src/lib/components/Path.svelte +++ b/frontend/src/lib/components/Path.svelte @@ -5,6 +5,7 @@ @@ -503,7 +536,65 @@
{error}
- {#if kind != 'app' && kind != 'schedule' && kind != 'http_trigger' && kind != 'websocket_trigger' && initialPath != '' && initialPath != undefined && initialPath != path} + {#if pathUsageInFlowsPromise || pathUsageInAppsPromise || pathUsageInScriptsPromise} + {#await Promise.all( [pathUsageInAppsPromise, pathUsageInFlowsPromise, pathUsageInScriptsPromise] )} + + {:then [apps, flows, scripts]} + {#if (apps && apps.length) || (flows && flows.length) || (scripts && scripts.length)} +

+ Used by {localeConcatAnd([ + ...(scripts && scripts.length ? [pluralize(scripts.length, 'script')] : []), + ...(flows && flows.length ? [pluralize(flows.length, 'flow')] : []), + ...(apps && apps.length ? [pluralize(apps.length, 'app')] : []) + ])} + +

    + {#each scripts || [] as path} +
  • {path}
  • + {/each} + {#each flows || [] as path} +
  • {path}
  • + {/each} + {#each apps || [] as path} +
  • {path}
  • + {/each} +
+ +

+ {#if displayPathChangedWarning} + + + + {/if} + {/if} + {/await} + {:else if displayPathChangedWarning} You are renaming an item that may be depended upon by other items. This may break apps, flows or resources. Find if it used elsewhere using the content search. Note that linked variables diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index dbcca70726..57c4d93312 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1163,3 +1163,9 @@ export function isObjectTooBig(obj: any): boolean { const { totalItems, maxDepth } = analyze(obj) return maxDepth > MAX_DEPTH || totalItems > MAX_ITEMS } + +export function localeConcatAnd(items: string[]) { + if (!items.length) return '' + if (items.length === 1) return items[0] + return items.slice(0, -1).join(', ') + ' and ' + items[items.length - 1] +}