From 01c42c888b078e7e0513078175e873fa2b368dd8 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 26 Sep 2024 09:51:55 -0400 Subject: [PATCH 01/11] Expand pre-checking of file source/object store configuration. - UI for detailed display of errors. - UI option to test configuration from management menu. - API + UI for checking configuration before upgrading to new version of template. - API + UI for checking configuration before updating current template's settings. - Add an option during update/upgrade to allow forcing the update even if configuration doesn't validate - I don't allow creation of invalid things, but if there are problems with an existing thing - admins and power users should have recourse. It is their data. --- client/src/api/configTemplates.ts | 6 + client/src/api/schema/schema.ts | 154 +++++++++ .../ConfigTemplates/ActionSummary.vue | 29 ++ .../ConfigTemplates/ConfigurationTestItem.vue | 32 ++ .../ConfigurationTestSummary.vue | 21 ++ .../ConfigurationTestSummaryModal.vue | 39 +++ .../ConfigTemplates/ForceActionButton.vue | 17 + .../ConfigTemplates/InstanceDropdown.test.ts | 4 +- .../ConfigTemplates/InstanceDropdown.vue | 9 +- .../ConfigTemplates/InstanceForm.vue | 13 +- .../src/components/ConfigTemplates/routing.ts | 18 + .../ConfigTemplates/test_fixtures.ts | 16 + .../useConfigurationTesting.ts | 311 ++++++++++++++++++ .../FileSources/Instances/CreateForm.vue | 62 +--- .../FileSources/Instances/EditInstance.vue | 90 +++-- .../Instances/InstanceDropdown.vue | 2 + .../FileSources/Instances/ManageIndex.vue | 12 +- .../FileSources/Instances/UpgradeForm.vue | 74 ++--- .../FileSources/Instances/routing.ts | 17 +- .../FileSources/Instances/services.ts | 18 + .../ObjectStore/Instances/CreateForm.test.ts | 28 +- .../ObjectStore/Instances/CreateForm.vue | 68 +--- .../ObjectStore/Instances/EditInstance.vue | 96 +++--- .../Instances/InstanceDropdown.vue | 2 + .../ObjectStore/Instances/ManageIndex.vue | 12 +- .../ObjectStore/Instances/UpgradeForm.test.ts | 12 +- .../ObjectStore/Instances/UpgradeForm.vue | 74 ++--- .../ObjectStore/Instances/routing.ts | 17 +- .../ObjectStore/Instances/services.ts | 22 ++ lib/galaxy/managers/_config_templates.py | 98 +++++- lib/galaxy/managers/file_source_instances.py | 96 ++++-- lib/galaxy/managers/object_store_instances.py | 87 ++++- lib/galaxy/webapps/galaxy/api/file_sources.py | 26 ++ lib/galaxy/webapps/galaxy/api/object_store.py | 26 ++ test/integration/objectstore/test_per_user.py | 12 + .../app/managers/test_user_file_sources.py | 96 ++++++ .../app/managers/test_user_object_stores.py | 111 ++++++- test/unit/objectstore/test_template_models.py | 6 + 38 files changed, 1442 insertions(+), 391 deletions(-) create mode 100644 client/src/components/ConfigTemplates/ActionSummary.vue create mode 100644 client/src/components/ConfigTemplates/ConfigurationTestItem.vue create mode 100644 client/src/components/ConfigTemplates/ConfigurationTestSummary.vue create mode 100644 client/src/components/ConfigTemplates/ConfigurationTestSummaryModal.vue create mode 100644 client/src/components/ConfigTemplates/ForceActionButton.vue create mode 100644 client/src/components/ConfigTemplates/routing.ts create mode 100644 client/src/components/ConfigTemplates/useConfigurationTesting.ts create mode 100644 client/src/components/FileSources/Instances/services.ts create mode 100644 client/src/components/ObjectStore/Instances/services.ts diff --git a/client/src/api/configTemplates.ts b/client/src/api/configTemplates.ts index 248ea2b4b934..09b6348739e9 100644 --- a/client/src/api/configTemplates.ts +++ b/client/src/api/configTemplates.ts @@ -19,6 +19,12 @@ export type SecretData = CreateInstancePayload["secrets"]; export type PluginAspectStatus = components["schemas"]["PluginAspectStatus"]; export type PluginStatus = components["schemas"]["PluginStatus"]; +export type CreateInstancePayload = components["schemas"]["CreateInstancePayload"]; +export type UpgradeInstancePayload = components["schemas"]["UpgradeInstancePayload"]; +export type TestUpgradeInstancePayload = components["schemas"]["TestUpgradeInstancePayload"]; +export type UpdateInstancePayload = components["schemas"]["UpdateInstancePayload"]; +export type TestUpdateInstancePayload = components["schemas"]["TestUpdateInstancePayload"]; + export interface TemplateSummary { description: string | null; hidden?: boolean; diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index be56f1ba7b3e..9e22dd336329 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -925,6 +925,12 @@ export interface paths { patch?: never; trace?: never; }; + "/api/file_source_instances/{user_file_source_id}/test": { + /** Test a file source instance and return status. */ + get: operations["file_sources__instances_test_instance"]; + /** Test updating or upgrading user file source instance. */ + post: operations["file_sources__test_instances_update"]; + }; "/api/file_source_templates": { parameters: { query?: never; @@ -3363,6 +3369,12 @@ export interface paths { patch?: never; trace?: never; }; + "/api/object_store_instances/{user_object_store_id}/test": { + /** Get a persisted user object store instance. */ + get: operations["object_stores__instances_test_instance"]; + /** Test updating or upgrading user object source instance. */ + post: operations["object_stores__test_instances_update"]; + }; "/api/object_store_templates": { parameters: { query?: never; @@ -16515,6 +16527,26 @@ export interface components { */ type: "string"; }; + /** TestUpdateInstancePayload */ + TestUpdateInstancePayload: { + /** Variables */ + variables?: { + [key: string]: (string | boolean | number) | undefined; + } | null; + }; + /** TestUpgradeInstancePayload */ + TestUpgradeInstancePayload: { + /** Secrets */ + secrets: { + [key: string]: string | undefined; + }; + /** Template Version */ + template_version: number; + /** Variables */ + variables: { + [key: string]: (string | boolean | number) | undefined; + }; + }; /** ToolDataDetails */ ToolDataDetails: { /** @@ -20872,6 +20904,67 @@ export interface operations { }; }; }; + file_sources__instances_test_instance: { + /** Test a file source instance and return status. */ + parameters: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The UUID index for a persisted UserFileSourceStore object. */ + path: { + user_file_source_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["PluginStatus"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + file_sources__test_instances_update: { + /** Test updating or upgrading user file source instance. */ + parameters: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The UUID index for a persisted UserFileSourceStore object. */ + path: { + user_file_source_id: string; + }; + }; + requestBody: { + content: { + "application/json": + | components["schemas"]["TestUpgradeInstancePayload"] + | components["schemas"]["TestUpdateInstancePayload"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["PluginStatus"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; file_sources__templates_index: { parameters: { query?: never; @@ -29442,6 +29535,67 @@ export interface operations { }; }; }; + object_stores__instances_test_instance: { + /** Get a persisted user object store instance. */ + parameters: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The UUID used to identify a persisted UserObjectStore object. */ + path: { + user_object_store_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["PluginStatus"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + object_stores__test_instances_update: { + /** Test updating or upgrading user object source instance. */ + parameters: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The UUID used to identify a persisted UserObjectStore object. */ + path: { + user_object_store_id: string; + }; + }; + requestBody: { + content: { + "application/json": + | components["schemas"]["TestUpgradeInstancePayload"] + | components["schemas"]["TestUpdateInstancePayload"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["PluginStatus"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; object_stores__templates_index: { parameters: { query?: never; diff --git a/client/src/components/ConfigTemplates/ActionSummary.vue b/client/src/components/ConfigTemplates/ActionSummary.vue new file mode 100644 index 000000000000..6e4652a584fe --- /dev/null +++ b/client/src/components/ConfigTemplates/ActionSummary.vue @@ -0,0 +1,29 @@ + + + diff --git a/client/src/components/ConfigTemplates/ConfigurationTestItem.vue b/client/src/components/ConfigTemplates/ConfigurationTestItem.vue new file mode 100644 index 000000000000..3d360b35b708 --- /dev/null +++ b/client/src/components/ConfigTemplates/ConfigurationTestItem.vue @@ -0,0 +1,32 @@ + + + diff --git a/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue b/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue new file mode 100644 index 000000000000..be17f1593821 --- /dev/null +++ b/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue @@ -0,0 +1,21 @@ + + + diff --git a/client/src/components/ConfigTemplates/ConfigurationTestSummaryModal.vue b/client/src/components/ConfigTemplates/ConfigurationTestSummaryModal.vue new file mode 100644 index 000000000000..22fa8a8b4736 --- /dev/null +++ b/client/src/components/ConfigTemplates/ConfigurationTestSummaryModal.vue @@ -0,0 +1,39 @@ + + + diff --git a/client/src/components/ConfigTemplates/ForceActionButton.vue b/client/src/components/ConfigTemplates/ForceActionButton.vue new file mode 100644 index 000000000000..55d42274f388 --- /dev/null +++ b/client/src/components/ConfigTemplates/ForceActionButton.vue @@ -0,0 +1,17 @@ + + + diff --git a/client/src/components/ConfigTemplates/InstanceDropdown.test.ts b/client/src/components/ConfigTemplates/InstanceDropdown.test.ts index e29d8d883113..abfca1e3070a 100644 --- a/client/src/components/ConfigTemplates/InstanceDropdown.test.ts +++ b/client/src/components/ConfigTemplates/InstanceDropdown.test.ts @@ -19,7 +19,7 @@ describe("InstanceDropdown", () => { }); const menu = wrapper.find(".dropdown-menu"); const links = menu.findAll("button.dropdown-item"); - expect(links.length).toBe(2); + expect(links.length).toBe(3); }); it("should render a drop down with upgrade if upgrade available as an option", async () => { @@ -35,6 +35,6 @@ describe("InstanceDropdown", () => { }); const menu = wrapper.find(".dropdown-menu"); const links = menu.findAll("button.dropdown-item"); - expect(links.length).toBe(3); + expect(links.length).toBe(4); }); }); diff --git a/client/src/components/ConfigTemplates/InstanceDropdown.vue b/client/src/components/ConfigTemplates/InstanceDropdown.vue index 95bbbf863cb8..f3fc2cebddd0 100644 --- a/client/src/components/ConfigTemplates/InstanceDropdown.vue +++ b/client/src/components/ConfigTemplates/InstanceDropdown.vue @@ -1,6 +1,6 @@ @@ -53,6 +54,10 @@ const emit = defineEmits<{ Edit configuration +