From fddcc8fc587da1bf8ea219cdb9fe780d289f6ba9 Mon Sep 17 00:00:00 2001 From: Jeff McMillen Date: Mon, 11 Nov 2024 15:46:23 -0600 Subject: [PATCH 1/9] Task/WP-520: AppTray should use versionEnabled for list of apps instead of enabled (#991) * Changed enabled.eq.true to versionEnabled.eq.true * Searches for versionEnabled on public apps * Ensured that tests still passed * Added versionEnabled to getPrivateApps * Corrected comments --------- Co-authored-by: Jeff McMillen Co-authored-by: Jeff McMillen Co-authored-by: Sal Tijerina --- server/portal/apps/workspace/api/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/portal/apps/workspace/api/views.py b/server/portal/apps/workspace/api/views.py index 69571375f..af07ad54d 100644 --- a/server/portal/apps/workspace/api/views.py +++ b/server/portal/apps/workspace/api/views.py @@ -429,7 +429,8 @@ def get(self, request, job_uuid): class AppsTrayView(BaseApiView): def getPrivateApps(self, user): tapis = user.tapis_oauth.client - apps_listing = tapis.apps.getApps(select="version,id,notes", search="(enabled.eq.true)", listType="MINE") + # Only shows enabled versions of apps + apps_listing = tapis.apps.getApps(select="version,id,notes", search="(versionEnabled.eq.true)", listType="MINE") my_apps = list(map(lambda app: { "label": getattr(app.notes, 'label', app.id), "version": app.version, @@ -441,7 +442,8 @@ def getPrivateApps(self, user): def getPublicApps(self, user): tapis = user.tapis_oauth.client - apps_listing = tapis.apps.getApps(select="version,id,notes", search="(enabled.eq.true)", listType="SHARED_PUBLIC") + # Only shows enabled versions of apps + apps_listing = tapis.apps.getApps(select="version,id,notes", search="(versionEnabled.eq.true)", listType="SHARED_PUBLIC") categories = [] html_definitions = {} # Traverse category records in descending priority From f44a82943018b3319394beb9f6a7fd3c284b0c13 Mon Sep 17 00:00:00 2001 From: Jacob Lowe <40873986+jalowe13@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:51:55 -0600 Subject: [PATCH 2/9] Bug/WP-24: Disabling Google Drive Integration (#988) * disabling google drive integration and test assertions * Test for No Integrations Available * added test for other 3rd party apps other than google drive * Update client/src/components/DataFiles/DataFilesListing/DataFilesListingCells.jsx Co-authored-by: fnets * Update client/src/components/DataFiles/fixtures/DataFiles.systems.fixture.js Co-authored-by: fnets * copy modal filter google drive * Revert changes in opt for settings_custom.py * settings_default drive removal * test revision keep additional 3rd party test * rm vite config push * getByText and custom example revert --------- Co-authored-by: fnets Co-authored-by: Garrett Edmonds <43251554+edmondsgarrett@users.noreply.github.com> --- .../tests/ManageAccountTables.test.jsx | 27 +++++++++++++++++++ server/portal/settings/settings_default.py | 8 ------ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/client/src/components/ManageAccount/tests/ManageAccountTables.test.jsx b/client/src/components/ManageAccount/tests/ManageAccountTables.test.jsx index 548df3bbb..25194294f 100644 --- a/client/src/components/ManageAccount/tests/ManageAccountTables.test.jsx +++ b/client/src/components/ManageAccount/tests/ManageAccountTables.test.jsx @@ -156,6 +156,33 @@ describe('Third Party Apps', () => { expect(getByText('Google Drive')).toBeDefined(); expect(getByText('Disconnect')).toBeDefined(); }); + it('Shows potential 3rd party connections other than Google Drive', () => { + const testStore = mockStore({ + profile: { + ...dummyState, + data: { + ...dummyState.data, + integrations: [ + { + label: '3rd Party Service', + description: '3rd Party Service description', + activated: true, + }, + ], + }, + }, + }); + const { getByText, queryByText } = render( + + + + ); + expect(getByText(/3rd Party Apps/)).toBeInTheDocument(); + // Check that Google Drive is not rendered + expect(queryByText('Google Drive')).toBeNull(); + // Check that other integrations are rendered + expect(getByText('3rd Party Service')).toBeInTheDocument(); + }); }); describe('License Cell', () => { diff --git a/server/portal/settings/settings_default.py b/server/portal/settings/settings_default.py index 5bb0592e8..421d62e19 100644 --- a/server/portal/settings/settings_default.py +++ b/server/portal/settings/settings_default.py @@ -110,14 +110,6 @@ 'readOnly': False, 'hideSearchBar': False }, - { - 'name': 'Google Drive', - 'system': 'googledrive', - 'scheme': 'private', - 'api': 'googledrive', - 'icon': None, - 'integration': 'portal.apps.googledrive_integration' - } ] ######################## From b01a86a8e78958836dbe0717023f1e89c5c84e38 Mon Sep 17 00:00:00 2001 From: Jacob Lowe <40873986+jalowe13@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:15:30 -0600 Subject: [PATCH 3/9] Bug/WP-419 Public Data Header Left Margin (#1003) * file fix starting point * header margin styling change * linting * linting * conditional styling on combinedbreadcrumbs * remove breadcrumbs changes * PublicData contentLayoutName pass in to Section * section module readdition * whitespace dif * lint * layout as oneColumn --- client/src/components/PublicData/PublicData.jsx | 1 + client/src/components/PublicData/PublicData.module.css | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/PublicData/PublicData.jsx b/client/src/components/PublicData/PublicData.jsx index d32750e66..29afbee7e 100644 --- a/client/src/components/PublicData/PublicData.jsx +++ b/client/src/components/PublicData/PublicData.jsx @@ -119,6 +119,7 @@ const PublicDataListing = ({ canDownload, downloadCallback }) => { disabled={!canDownload} /> } + contentLayoutName="oneColumn" > Date: Thu, 21 Nov 2024 16:02:17 -0600 Subject: [PATCH 4/9] Task/WP-728: Mutation hook: Copy file (#1000) * initial typescript * saga logic move * url param undefined fix * linting * axios update * mutateAsync changes * onSuccess, onError with async * copyCalls as an array of Promises on return --- .../src/hooks/datafiles/mutations/useCopy.js | 37 ----- .../src/hooks/datafiles/mutations/useCopy.ts | 157 ++++++++++++++++++ 2 files changed, 157 insertions(+), 37 deletions(-) delete mode 100644 client/src/hooks/datafiles/mutations/useCopy.js create mode 100644 client/src/hooks/datafiles/mutations/useCopy.ts diff --git a/client/src/hooks/datafiles/mutations/useCopy.js b/client/src/hooks/datafiles/mutations/useCopy.js deleted file mode 100644 index f0e2e640c..000000000 --- a/client/src/hooks/datafiles/mutations/useCopy.js +++ /dev/null @@ -1,37 +0,0 @@ -import { useDispatch, useSelector, shallowEqual } from 'react-redux'; -import { useSelectedFiles } from 'hooks/datafiles'; - -function useCopy() { - const dispatch = useDispatch(); - - const { selectedFiles: selected } = useSelectedFiles(); - - const status = useSelector( - (state) => state.files.operationStatus.copy, - shallowEqual - ); - - const setStatus = (newStatus) => - dispatch({ - type: 'DATA_FILES_SET_OPERATION_STATUS', - payload: { operation: 'copy', status: newStatus }, - }); - - const copy = ({ srcApi, destApi, destSystem, destPath, name, callback }) => { - const filteredSelected = selected - .filter((f) => status[f.id] !== 'SUCCESS') - .map((f) => ({ ...f, api: srcApi })); - dispatch({ - type: 'DATA_FILES_COPY', - payload: { - dest: { system: destSystem, path: destPath, api: destApi, name }, - src: filteredSelected, - reloadCallback: callback, - }, - }); - }; - - return { copy, status, setStatus }; -} - -export default useCopy; diff --git a/client/src/hooks/datafiles/mutations/useCopy.ts b/client/src/hooks/datafiles/mutations/useCopy.ts new file mode 100644 index 000000000..3398feade --- /dev/null +++ b/client/src/hooks/datafiles/mutations/useCopy.ts @@ -0,0 +1,157 @@ +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; +import { useSelectedFiles } from 'hooks/datafiles'; +import Cookies from 'js-cookie'; +import { apiClient } from 'utils/apiClient'; +import { useMutation } from '@tanstack/react-query'; +import truncateMiddle from 'utils/truncateMiddle'; + +export async function copyFileUtil({ + api, + scheme, + system, + path, + filename, + filetype, + destApi, + destSystem, + destPath, + destPathName, +}: { + api: string; + scheme: string; + system: string; + path: string; + filename: string; + filetype: string; + destApi: string; + destSystem: string; + destPath: string; + destPathName: string; +}) { + let url: string, body: any; + if (api === destApi) { + url = `/api/datafiles/${api}/copy/${scheme}/${system}/${path}/`; + url = url.replace(/\/{2,}/g, '/'); + body = { + dest_system: destSystem, + dest_path: destPath, + file_name: filename, + filetype, + dest_path_name: destPathName, + }; + } else { + url = `/api/datafiles/transfer/${filetype}/`; + url = url.replace(/\/{2,}/g, '/'); + body = { + src_api: api, + dest_api: destApi, + src_system: system, + dest_system: destSystem, + src_path: path, + dest_path: destPath, + dest_path_name: destPathName, + dirname: filename, + }; + } + + const response = await apiClient.put(url, body, { + headers: { 'X-CSRFToken': Cookies.get('csrftoken') || '' }, + withCredentials: true, + }); + return response.data; +} + +function useCopy() { + const dispatch = useDispatch(); + + const { selectedFiles: selected } = useSelectedFiles(); + + const status = useSelector( + (state: any) => state.files.operationStatus.copy, + shallowEqual + ); + + const { scheme } = useSelector( + (state: any) => state.files.params.FilesListing + ); + const setStatus = (newStatus: string) => + dispatch({ + type: 'DATA_FILES_SET_OPERATION_STATUS', + payload: { operation: 'copy', status: newStatus }, + }); + + const { mutateAsync } = useMutation({ mutationFn: copyFileUtil }); + const copy = ({ + srcApi, + destApi, + destSystem, + destPath, + name, + callback, + }: { + srcApi: string; + destApi: string; + destSystem: string; + destPath: string; + name: string; + callback: any; + }) => { + const filteredSelected = selected + .filter((f: any) => status[f.id] !== 'SUCCESS') + .map((f: any) => ({ ...f, api: srcApi })); + const copyCalls: Promise[] = filteredSelected.map((file: any) => { + // Copy File + dispatch({ + type: 'DATA_FILES_SET_OPERATION_STATUS_BY_KEY', + payload: { status: 'RUNNING', key: file.id, operation: 'copy' }, + }); + return mutateAsync( + { + api: file.api, + scheme: scheme, + system: file.system, + path: file.path, + filename: file.name, + filetype: file.type, + destApi, + destSystem, + destPath, + destPathName: name, + }, + { + onSuccess: () => { + dispatch({ + type: 'DATA_FILES_SET_OPERATION_STATUS_BY_KEY', + payload: { status: 'SUCCESS', key: file.id, operation: 'copy' }, + }); + }, + onError: (error: any) => { + dispatch({ + type: 'DATA_FILES_SET_OPERATION_STATUS_BY_KEY', + payload: { status: 'ERROR', key: file.id, operation: 'copy' }, + }); + }, + } + ); + }); + // Result + Promise.all(copyCalls).then(() => { + dispatch({ + type: 'DATA_FILES_TOGGLE_MODAL', + payload: { operation: 'copy', props: {} }, + }); + dispatch({ + type: 'ADD_TOAST', + payload: { + message: `${ + copyCalls.length > 1 ? `${copyCalls.length} files` : 'File' + } copied to ${truncateMiddle(`${destPath}`, 20) || '/'}`, + }, + }); + callback(); + }); + }; + return { copy, status, setStatus }; +} + +export default useCopy; From 36bce1dd3ccee53709cbf1e1d6dadfc3c24233af Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Fri, 22 Nov 2024 10:42:52 -0600 Subject: [PATCH 5/9] WP-765: Fix job status button (#1015) --- client/src/components/Jobs/JobsStatus/JobsStatus.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Jobs/JobsStatus/JobsStatus.jsx b/client/src/components/Jobs/JobsStatus/JobsStatus.jsx index b3886feaa..c26fbcb3c 100644 --- a/client/src/components/Jobs/JobsStatus/JobsStatus.jsx +++ b/client/src/components/Jobs/JobsStatus/JobsStatus.jsx @@ -92,7 +92,7 @@ function JobsStatus({ status, fancy, jobUuid }) { return (
{fancy && color ? ( - + {userStatus} ) : ( From d11b54c895ea300d64660de3aa18af22ee9f3fb9 Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Mon, 25 Nov 2024 19:35:45 -0600 Subject: [PATCH 6/9] Update CHANGELOG.md for v3.10.0 --- CHANGELOG.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3fe09565..aadd6e56d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.10.0] + +### Added + +deps/react-18: Update React to v18 by @jarosenb in #979 +Bug/WP-50: Fix sizing of buttons "as-link" by @jmcmillenmusic in #986 +Task/WP-509: Handle file/folder download feature with large number of files by @jmcmillenmusic in #981 +Task/WP-520: AppTray should use versionEnabled for list of apps instead of enabled by @jmcmillenmusic in #991 +Bug/WP-24: Disabling Google Drive Integration by @jalowe13 in #988 +WP-730: Refactor useRename to use react-query by @jarosenb in #993 +Task/WP-728: Mutation hook: Copy file by @jalowe13 in #1000 +Task/WP-78: V3 Shared Workspaces Tests by @jalowe13 in #987 + +### Fixed + +Bug/WP-419 Public Data Header Left Margin by @jalowe13 in #1003 +WP-765: Fix job status button to show background by @chandra-tacc in #1015 + + ## [3.9.0] ### Fixed @@ -1115,7 +1134,8 @@ WP-306: Fix target path regression (#871) ## [1.0.0] - 2020-02-28 v1.0.0 Production release as of Feb 28, 2020. -[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.9.0...HEAD +[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.10.0...HEAD +[3.10.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.10.0 [3.9.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.9.0 [3.8.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.8.2 [3.8.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.8.1 From b8940754cf73814d951bd6cc68f91adebc8c03c4 Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Tue, 26 Nov 2024 07:10:28 -0600 Subject: [PATCH 7/9] Update CHANGELOG.md --- CHANGELOG.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aadd6e56d..10995c3e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,19 +11,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -deps/react-18: Update React to v18 by @jarosenb in #979 -Bug/WP-50: Fix sizing of buttons "as-link" by @jmcmillenmusic in #986 -Task/WP-509: Handle file/folder download feature with large number of files by @jmcmillenmusic in #981 -Task/WP-520: AppTray should use versionEnabled for list of apps instead of enabled by @jmcmillenmusic in #991 -Bug/WP-24: Disabling Google Drive Integration by @jalowe13 in #988 -WP-730: Refactor useRename to use react-query by @jarosenb in #993 -Task/WP-728: Mutation hook: Copy file by @jalowe13 in #1000 -Task/WP-78: V3 Shared Workspaces Tests by @jalowe13 in #987 +deps/react-18: Update React to v18 (#979) +WP-50: Fix sizing of buttons "as-link" (#986) +WP-509: Handle file/folder download feature with large number of files (#981) +WP-520: AppTray should use versionEnabled for list of apps instead of enabled (#991) +WP-24: Disabling Google Drive Integration (#988) +WP-730: Refactor useRename to use react-query (#993) +WP-728: Mutation hook: Copy file (#1000) +WP-78: V3 Shared Workspaces Tests (#987) ### Fixed -Bug/WP-419 Public Data Header Left Margin by @jalowe13 in #1003 -WP-765: Fix job status button to show background by @chandra-tacc in #1015 +WP-419 Public Data Header Left Margin (#1003) +WP-765: Fix job status button to show background (#1015) ## [3.9.0] From 16ed8e2bf67a89ac2a16d8218576d62872bcb9ce Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Tue, 26 Nov 2024 07:13:32 -0600 Subject: [PATCH 8/9] Update CHANGELOG.md --- CHANGELOG.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10995c3e0..45d0180f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,19 +11,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -deps/react-18: Update React to v18 (#979) -WP-50: Fix sizing of buttons "as-link" (#986) -WP-509: Handle file/folder download feature with large number of files (#981) -WP-520: AppTray should use versionEnabled for list of apps instead of enabled (#991) -WP-24: Disabling Google Drive Integration (#988) -WP-730: Refactor useRename to use react-query (#993) -WP-728: Mutation hook: Copy file (#1000) -WP-78: V3 Shared Workspaces Tests (#987) +- deps/react-18: Update React to v18 (#979) +- WP-50: Fix sizing of buttons "as-link" (#986) +- WP-509: Handle file/folder download feature with large number of files (#981) +- WP-520: AppTray should use versionEnabled for list of apps instead of enabled (#991) +- WP-24: Disabling Google Drive Integration (#988) +- WP-730: Refactor useRename to use react-query (#993) +- WP-728: Mutation hook: Copy file (#1000) +- WP-78: V3 Shared Workspaces Tests (#987) ### Fixed -WP-419 Public Data Header Left Margin (#1003) -WP-765: Fix job status button to show background (#1015) +- WP-419 Public Data Header Left Margin (#1003) +- WP-765: Fix job status button to show background (#1015) ## [3.9.0] From d6d9f37bb39a7ff9f49418feecef58923b957dec Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Wed, 27 Nov 2024 10:56:57 -0600 Subject: [PATCH 9/9] WP-778: Fix infinite loop for state update in useEffect (#1019) * WP-778: Fix infinite loop for state update in useEffect * remove unnecessary changes --- client/src/components/Applications/AppForm/AppForm.jsx | 8 +++----- client/src/components/_common/Form/FormField.jsx | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/client/src/components/Applications/AppForm/AppForm.jsx b/client/src/components/Applications/AppForm/AppForm.jsx index ddb106435..e2372c24c 100644 --- a/client/src/components/Applications/AppForm/AppForm.jsx +++ b/client/src/components/Applications/AppForm/AppForm.jsx @@ -152,7 +152,6 @@ const HandleDependentFieldChanges = ({ app, formStateUpdateHandler }) => { const { values, setValues } = useFormikContext(); React.useEffect(() => { if (previousValues) { - let valueUpdated = false; let updatedValues = { ...values }; // Set the current allocation @@ -171,7 +170,6 @@ const HandleDependentFieldChanges = ({ app, formStateUpdateHandler }) => { updatedValues, formStateUpdateHandler ); - valueUpdated = true; } if (previousValues.execSystemId !== values.execSystemId) { updatedValues = execSystemChangeHandler( @@ -179,16 +177,16 @@ const HandleDependentFieldChanges = ({ app, formStateUpdateHandler }) => { values, formStateUpdateHandler ); - valueUpdated = true; } if ( previousValues.execSystemLogicalQueue !== values.execSystemLogicalQueue ) { updatedValues = updateValuesForQueue(app, values); - valueUpdated = true; } - if (valueUpdated) setValues(updatedValues); + if (JSON.stringify(updatedValues) !== JSON.stringify(values)) { + setValues(updatedValues); + } } setPreviousValues(values); }, [app, values, setValues, formStateUpdateHandler]); diff --git a/client/src/components/_common/Form/FormField.jsx b/client/src/components/_common/Form/FormField.jsx index 1e5dbc7a1..412d14dea 100644 --- a/client/src/components/_common/Form/FormField.jsx +++ b/client/src/components/_common/Form/FormField.jsx @@ -138,6 +138,7 @@ const FormField = ({