From 4c8b2ee5e9be43832633d786d99f1dde83795d90 Mon Sep 17 00:00:00 2001 From: Asim Regmi <54924215+asimregmi@users.noreply.github.com> Date: Wed, 6 Dec 2023 11:24:45 -0600 Subject: [PATCH 1/9] Task/WP-352: filter incomplete users in backend (#910) * filter incomplete users in the backend * removed ununsed console.log * Adding server side unit tests for filtering incomplete users only * removed query:null to preserver query param value * fixed typo * oops...fixed type * reset offset to 0 when toggle incomplete only --------- Co-authored-by: Sal Tijerina Co-authored-by: Chandra Y --- .../components/Onboarding/OnboardingAdmin.jsx | 32 +++++++++------- .../Onboarding/OnboardingAdmin.module.scss | 38 ++++++++++++++----- .../OnboardingAdminSearchbar.module.scss | 8 +++- .../Onboarding/OnboardingStatus.jsx | 5 +++ .../components/_common/Pill/Pill.module.scss | 5 +++ client/src/redux/sagas/onboarding.sagas.js | 19 ++++++++-- .../src/redux/sagas/onboarding.sagas.test.js | 9 ++++- server/portal/apps/onboarding/api/views.py | 5 +++ .../apps/onboarding/api/views_unit_test.py | 15 ++++++++ 9 files changed, 107 insertions(+), 29 deletions(-) diff --git a/client/src/components/Onboarding/OnboardingAdmin.jsx b/client/src/components/Onboarding/OnboardingAdmin.jsx index f4b91790f..d373d0365 100644 --- a/client/src/components/Onboarding/OnboardingAdmin.jsx +++ b/client/src/components/Onboarding/OnboardingAdmin.jsx @@ -237,17 +237,21 @@ const OnboardingAdmin = () => { const [showIncompleteOnly, setShowIncompleteOnly] = useState(false); const toggleShowIncomplete = () => { + dispatch({ + type: 'FETCH_ONBOARDING_ADMIN_LIST', + payload: { + offset: 0, + limit, + query, + showIncompleteOnly: !showIncompleteOnly, // Toggle the parameter + }, + }); setShowIncompleteOnly((prev) => !prev); }; const { users, offset, limit, total, query, loading, error } = useSelector( (state) => state.onboarding.admin ); - - const filteredUsers = users.filter((user) => - showIncompleteOnly ? !user.setupComplete : true - ); - const paginationCallback = useCallback( (page) => { dispatch({ @@ -256,10 +260,11 @@ const OnboardingAdmin = () => { offset: (page - 1) * limit, limit, query, + showIncompleteOnly, }, }); }, - [offset, limit, query] + [offset, limit, query, showIncompleteOnly] ); const viewLogCallback = useCallback( @@ -276,7 +281,7 @@ const OnboardingAdmin = () => { useEffect(() => { dispatch({ type: 'FETCH_ONBOARDING_ADMIN_LIST', - payload: { offset, limit, query: null }, + payload: { offset, limit, query: null, showIncompleteOnly }, }); }, [dispatch]); @@ -294,6 +299,7 @@ const OnboardingAdmin = () => { ); } + return (
@@ -302,7 +308,7 @@ const OnboardingAdmin = () => {
- {filteredUsers.length === 0 && ( + {users.length === 0 && (
No users to show.
)}
- {filteredUsers.length > 0 && ( + {users.length > 0 && ( )}
- {filteredUsers.length > 0 && ( + {users.length > 0 && (
td:not(.has-wrappable-content):not(.status) { @include truncate-with-ellipsis; } -.user:nth-child(even) > td:not(.staffwait):not(.name) { - background-color: #c6c6c61a; +.user:nth-child(4n), +.user:nth-child(4n-1) > td:not(.staffwait) { + background-color: #f4f4f4; } .username { diff --git a/client/src/components/Onboarding/OnboardingAdminSearchbar.module.scss b/client/src/components/Onboarding/OnboardingAdminSearchbar.module.scss index e59240406..04e2e6eb3 100644 --- a/client/src/components/Onboarding/OnboardingAdminSearchbar.module.scss +++ b/client/src/components/Onboarding/OnboardingAdminSearchbar.module.scss @@ -17,7 +17,13 @@ /* WARN: Non-standard un-documented first-party breakpoint */ @media (max-width: 1700px) { .query-fieldset { - width: 460px; + width: 360px; + } +} + +@media (max-width: 768px) { + .query-fieldset { + width: 260px; } } /* FP-563: Support count in status message */ diff --git a/client/src/components/Onboarding/OnboardingStatus.jsx b/client/src/components/Onboarding/OnboardingStatus.jsx index 7f2deaeae..9818a1644 100644 --- a/client/src/components/Onboarding/OnboardingStatus.jsx +++ b/client/src/components/Onboarding/OnboardingStatus.jsx @@ -22,6 +22,9 @@ const getContents = (step) => { case 'completed': type = 'success'; break; + case null: + type = 'unavailable'; + break; default: type = 'normal'; } @@ -38,6 +41,8 @@ const getContents = (step) => { case 'failed': case 'error': return Unsuccessful; + case null: + return Unavailable; case 'completed': return Completed; case 'processing': diff --git a/client/src/components/_common/Pill/Pill.module.scss b/client/src/components/_common/Pill/Pill.module.scss index 9119ae2b5..147efb735 100644 --- a/client/src/components/_common/Pill/Pill.module.scss +++ b/client/src/components/_common/Pill/Pill.module.scss @@ -39,3 +39,8 @@ .is-normal { background-color: var(--global-color-accent--normal); } + +.is-unavailable { + background-color: transparent; + color: inherit; +} diff --git a/client/src/redux/sagas/onboarding.sagas.js b/client/src/redux/sagas/onboarding.sagas.js index 750edb6fc..0c0d07e10 100644 --- a/client/src/redux/sagas/onboarding.sagas.js +++ b/client/src/redux/sagas/onboarding.sagas.js @@ -3,8 +3,13 @@ import { fetchUtil } from 'utils/fetchUtil'; import Cookies from 'js-cookie'; // Admin listing of all users -export async function fetchOnboardingAdminList(offset, limit, q) { - const params = { offset, limit }; +export async function fetchOnboardingAdminList( + offset, + limit, + q, + showIncompleteOnly +) { + const params = { offset, limit, showIncompleteOnly }; if (q) { params.q = q; } @@ -18,8 +23,14 @@ export async function fetchOnboardingAdminList(offset, limit, q) { export function* getOnboardingAdminList(action) { yield put({ type: 'FETCH_ONBOARDING_ADMIN_LIST_PROCESSING' }); try { - const { offset, limit, query } = action.payload; - const result = yield call(fetchOnboardingAdminList, offset, limit, query); + const { offset, limit, query, showIncompleteOnly } = action.payload; + const result = yield call( + fetchOnboardingAdminList, + offset, + limit, + query, + showIncompleteOnly + ); yield put({ type: 'FETCH_ONBOARDING_ADMIN_LIST_SUCCESS', payload: { diff --git a/client/src/redux/sagas/onboarding.sagas.test.js b/client/src/redux/sagas/onboarding.sagas.test.js index 39e669b3f..6da3a8ea0 100644 --- a/client/src/redux/sagas/onboarding.sagas.test.js +++ b/client/src/redux/sagas/onboarding.sagas.test.js @@ -23,14 +23,19 @@ jest.mock('cross-fetch'); describe('getOnboardingAdminList Saga', () => { it('should fetch list of onboarding users and transform state', () => expectSaga(getOnboardingAdminList, { - payload: { offset: 0, limit: 25, query: 'query' }, + payload: { + offset: 0, + limit: 25, + query: 'query', + showIncompleteOnly: true, + }, }) .withReducer(onboarding) .provide([ [matchers.call.fn(fetchOnboardingAdminList), onboardingAdminFixture], ]) .put({ type: 'FETCH_ONBOARDING_ADMIN_LIST_PROCESSING' }) - .call(fetchOnboardingAdminList, 0, 25, 'query') + .call(fetchOnboardingAdminList, 0, 25, 'query', true) .put({ type: 'FETCH_ONBOARDING_ADMIN_LIST_SUCCESS', payload: { diff --git a/server/portal/apps/onboarding/api/views.py b/server/portal/apps/onboarding/api/views.py index a0759d8b6..73750b82b 100644 --- a/server/portal/apps/onboarding/api/views.py +++ b/server/portal/apps/onboarding/api/views.py @@ -264,8 +264,13 @@ def get(self, request): if q: query = q_to_model_queries(q) results = results.filter(query) + show_incomplete_only = request.GET.get('showIncompleteOnly', 'False').lower() + # Filter users based on the showIncompleteOnly parameter + if show_incomplete_only == 'true': + results = results.filter(profile__setup_complete=False) # Get users, with most recently joined users that do not have setup_complete, first results = results.order_by('-date_joined', 'profile__setup_complete', 'last_name', 'first_name') + # Uncomment this line to simulate many user results # results = list(results) * 105 total = len(results) diff --git a/server/portal/apps/onboarding/api/views_unit_test.py b/server/portal/apps/onboarding/api/views_unit_test.py index dd3ebab7c..0d1622ea9 100644 --- a/server/portal/apps/onboarding/api/views_unit_test.py +++ b/server/portal/apps/onboarding/api/views_unit_test.py @@ -234,11 +234,19 @@ def test_get(client, authenticated_staff, regular_user, mock_steps): authenticated_staff.profile.setup_complete = True authenticated_staff.profile.save() + # Make a request without 'showIncompleteOnly' parameter response = client.get("/api/onboarding/admin/") result = json.loads(response.content) users = result["users"] + # Make a request with 'showIncompleteOnly' parameter set to true + response_incomplete_users = client.get("/api/onboarding/admin/?showIncompleteOnly=true") + result_incomplete_users = json.loads(response_incomplete_users.content) + + users_incomplete = result_incomplete_users["users"] + + # Assertions without 'showIncompleteOnly' # The first result should be the regular_user, since they have not completed setup assert users[0]["username"] == regular_user.username @@ -248,6 +256,13 @@ def test_get(client, authenticated_staff, regular_user, mock_steps): # There should be two users returned assert len(users) == 2 + # Assertions with 'showIncompleteOnly=true' + assert users_incomplete[0]["username"] == regular_user.username + assert users_incomplete[0]['steps'][0]['step'] == "portal.apps.onboarding.steps.test_steps.MockStep" + + # There should be one user since only one user has setup_complete = True + assert len(users_incomplete) == 1 + def test_get_search(client, authenticated_staff, regular_user, mock_steps): response = client.get("/api/onboarding/admin/?q=Firstname") From 877a639799b6e31de957d5744cae00808df4f459 Mon Sep 17 00:00:00 2001 From: Sal Tijerina Date: Wed, 6 Dec 2023 14:41:48 -0600 Subject: [PATCH 2/9] hotfix: handle 401 unauthorized Tapis error for pushing keys (#915) --- .../components/DataFiles/DataFilesTable/DataFilesTable.jsx | 2 +- server/portal/apps/workspace/api/views.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/components/DataFiles/DataFilesTable/DataFilesTable.jsx b/client/src/components/DataFiles/DataFilesTable/DataFilesTable.jsx index ee09d5567..7b247ce26 100644 --- a/client/src/components/DataFiles/DataFilesTable/DataFilesTable.jsx +++ b/client/src/components/DataFiles/DataFilesTable/DataFilesTable.jsx @@ -105,7 +105,7 @@ const DataFilesTablePlaceholder = ({ section, data }) => { . ); - if (err === '500') { + if (err === '500' || err === '401') { if (downSystems.includes(currSystemHost)) { return (
diff --git a/server/portal/apps/workspace/api/views.py b/server/portal/apps/workspace/api/views.py index 9e263e08a..bec3f5b35 100644 --- a/server/portal/apps/workspace/api/views.py +++ b/server/portal/apps/workspace/api/views.py @@ -11,7 +11,7 @@ from django.urls import reverse from django.db.models.functions import Coalesce from django.core.exceptions import ObjectDoesNotExist, PermissionDenied -from tapipy.errors import BaseTapyException, InternalServerError +from tapipy.errors import BaseTapyException, InternalServerError, UnauthorizedError from portal.views.base import BaseApiView from portal.exceptions.api import ApiException from portal.apps.licenses.models import LICENSE_TYPES, get_license_info @@ -107,7 +107,7 @@ def get(self, request, *args, **kwargs): try: tapis.files.listFiles(systemId=system_id, path="/") - except InternalServerError: + except (InternalServerError, UnauthorizedError): success = _test_listing_with_existing_keypair(system_def, request.user) data['systemNeedsKeys'] = not success data['pushKeysSystem'] = system_def @@ -300,7 +300,7 @@ def post(self, request, *args, **kwargs): for system_id in list(set([job_post['archiveSystemId'], job_post['execSystemId']])): try: tapis.files.listFiles(systemId=system_id, path="/") - except InternalServerError: + except (InternalServerError, UnauthorizedError): system_def = tapis.systems.getSystem(systemId=system_id) success = _test_listing_with_existing_keypair(system_def, request.user) if not success: From 0127770c350e64f8f633b60adb9fc9d19c979ef5 Mon Sep 17 00:00:00 2001 From: Sal Tijerina Date: Wed, 6 Dec 2023 16:16:18 -0600 Subject: [PATCH 3/9] Hotfix/401 unauthorized push keys (#916) * hotfix: handle 401 unauthorized Tapis error for pushing keys * include UnauthorizedError for datafiles error handling --- .../_common/SystemsPushKeysModal/SystemsPushKeysModal.jsx | 2 +- client/src/redux/sagas/datafiles.sagas.js | 2 +- server/portal/apps/datafiles/views.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/components/_common/SystemsPushKeysModal/SystemsPushKeysModal.jsx b/client/src/components/_common/SystemsPushKeysModal/SystemsPushKeysModal.jsx index 68d771f88..1f40759f9 100644 --- a/client/src/components/_common/SystemsPushKeysModal/SystemsPushKeysModal.jsx +++ b/client/src/components/_common/SystemsPushKeysModal/SystemsPushKeysModal.jsx @@ -110,7 +110,7 @@ const SystemsPushKeysModal = () => { label="TACC Token" required disabled={submitting} - autocomplete="off" + autoComplete="off" /> diff --git a/client/src/redux/sagas/datafiles.sagas.js b/client/src/redux/sagas/datafiles.sagas.js index 2ef66a565..1ccb630af 100644 --- a/client/src/redux/sagas/datafiles.sagas.js +++ b/client/src/redux/sagas/datafiles.sagas.js @@ -168,7 +168,7 @@ export function* fetchFiles(action) { }, }); // If listing returns 500, body should contain a system def for key pushing. - yield e.status === 500 && + yield (e.status === 500 || e.status === 401) && put({ type: 'SET_SYSTEM', payload: { diff --git a/server/portal/apps/datafiles/views.py b/server/portal/apps/datafiles/views.py index 06e72e13d..69fa02fdb 100644 --- a/server/portal/apps/datafiles/views.py +++ b/server/portal/apps/datafiles/views.py @@ -4,7 +4,7 @@ from django.conf import settings from django.http import JsonResponse, HttpResponseForbidden from requests.exceptions import HTTPError -from tapipy.errors import InternalServerError +from tapipy.errors import InternalServerError, UnauthorizedError from portal.views.base import BaseApiView from portal.libs.agave.utils import service_account from portal.apps.datafiles.handlers.tapis_handlers import (tapis_get_handler, @@ -109,11 +109,11 @@ def get(self, request, operation=None, scheme=None, system=None, path='/'): operation in NOTIFY_ACTIONS and \ notify(request.user.username, operation, 'success', {'response': response}) - except InternalServerError as e: + except (InternalServerError, UnauthorizedError) as e: error_status = e.response.status_code error_json = e.response.json() operation in NOTIFY_ACTIONS and notify(request.user.username, operation, 'error', {}) - if error_status == 500: + if error_status == 500 or error_status == 401: logger.info(e) # In case of 500 determine cause system = client.systems.getSystem(systemId=system) From afed1815d3f4ec6d247b05c94647ca8055e8ab60 Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Thu, 7 Dec 2023 07:53:19 -0600 Subject: [PATCH 4/9] Update CHANGELOG.md for 3.4.2 hotfix ### Fixed - WP-402: handle 401 unauthorized Tapis error for pushing keys (#915, #916) --- CHANGELOG.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb7821883..5ac4e7c3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [3.4.2] - 2023-12-07: Fix push key handling +### Fixed + +- WP-402: handle 401 unauthorized Tapis error for pushing keys (#915, #916) + +## [3.4.1] - 2023-12-05: Fix web hook and impersonation bug +### Fixed + +- WP-400: Fix impersonate url (#912) +- Bug: Fix websockets via ASGI_APPLICATION setting (#913) + + ## [3.4.0] - 2023-11-27: Django upgrade to 4 and bug fixes ### Changed @@ -1006,7 +1019,9 @@ 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.4.0...HEAD +[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.4.2...HEAD +[3.4.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.2 +[3.4.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.1 [3.4.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.0 [3.3.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.3.2 [3.3.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.3.1 From c089760225e502f9628e00e89a40658686a3c5e4 Mon Sep 17 00:00:00 2001 From: Sal Tijerina Date: Mon, 11 Dec 2023 12:35:33 -0600 Subject: [PATCH 5/9] use archiveSystemId set in app definition as default (#917) --- .../src/components/Applications/AppForm/AppForm.jsx | 11 ++++++++--- .../components/Applications/AppForm/AppForm.test.js | 11 ++++++++++- .../AppForm/fixtures/AppForm.app.fixture.js | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/client/src/components/Applications/AppForm/AppForm.jsx b/client/src/components/Applications/AppForm/AppForm.jsx index e90801b4a..df1b4b2c2 100644 --- a/client/src/components/Applications/AppForm/AppForm.jsx +++ b/client/src/components/Applications/AppForm/AppForm.jsx @@ -274,7 +274,7 @@ export const AppSchemaForm = ({ app }) => { coresPerNode: app.definition.jobAttributes.coresPerNode, maxMinutes: app.definition.jobAttributes.maxMinutes, archiveSystemId: - defaultSystem || app.definition.jobAttributes.archiveSystemId, + app.definition.jobAttributes.archiveSystemId || defaultSystem, archiveSystemDir: app.definition.jobAttributes.archiveSystemDir, archiveOnAppError: true, appId: app.definition.id, @@ -785,14 +785,19 @@ export const AppSchemaForm = ({ app }) => { description="System into which output files are archived after application execution." name="archiveSystemId" type="text" - placeholder={defaultSystem} + placeholder={ + app.definition.archiveSystemId || defaultSystem + } /> ) : null} diff --git a/client/src/components/Applications/AppForm/AppForm.test.js b/client/src/components/Applications/AppForm/AppForm.test.js index 2a6b119df..a70c63263 100644 --- a/client/src/components/Applications/AppForm/AppForm.test.js +++ b/client/src/components/Applications/AppForm/AppForm.test.js @@ -72,11 +72,20 @@ describe('AppSchemaForm', () => { ...initialMockState, }); - const { getByText } = renderAppSchemaFormComponent(store, { + const { getByText, container } = renderAppSchemaFormComponent(store, { ...helloWorldAppFixture, }); + + const archiveSystemId = container.querySelector( + 'input[name="archiveSystemId"]' + ); await waitFor(() => { expect(getByText(/TACC-ACI/)).toBeDefined(); + + // use app definition default archive system + expect(archiveSystemId.value).toBe( + helloWorldAppFixture.definition.jobAttributes.archiveSystemId + ); }); }); diff --git a/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js b/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js index 1458448ea..263cb67e2 100644 --- a/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js +++ b/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js @@ -26,7 +26,7 @@ export const helloWorldAppFixture = { execSystemInputDir: '${JobWorkingDir}', execSystemOutputDir: '${JobWorkingDir}/output', execSystemLogicalQueue: 'development', - archiveSystemId: 'cloud.data', + archiveSystemId: 'frontera', archiveSystemDir: 'HOST_EVAL($HOME)/tapis-jobs-archive/${JobCreateDate}/${JobName}-${JobUUID}', archiveOnAppError: true, From 4f511f5150cc3c7fbf7948b2de571d40833da48e Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Mon, 11 Dec 2023 13:15:15 -0600 Subject: [PATCH 6/9] Changelog for hotfix 3.4.3 --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ac4e7c3a..9e594b724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.4.3] - 2023-12-11: Fix push key handling +### Fixed + +- WP-408: use archiveSystemId set in app definition as default (#917) + + ## [3.4.2] - 2023-12-07: Fix push key handling ### Fixed @@ -1019,7 +1025,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.4.2...HEAD +[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.4.3...HEAD +[3.4.3]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.3 [3.4.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.2 [3.4.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.1 [3.4.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.4.0 From dda1cc78eac737a623c8966f0e16de03bd9bb7bc Mon Sep 17 00:00:00 2001 From: Asim Regmi <54924215+asimregmi@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:52:51 -0600 Subject: [PATCH 7/9] Task/WP-358: sort apps inside category before rendering (#914) * sort apps inside category before rendering --------- Co-authored-by: Sal Tijerina Co-authored-by: Chandra Y --- server/portal/apps/workspace/api/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/portal/apps/workspace/api/views.py b/server/portal/apps/workspace/api/views.py index bec3f5b35..406ad7d96 100644 --- a/server/portal/apps/workspace/api/views.py +++ b/server/portal/apps/workspace/api/views.py @@ -459,6 +459,7 @@ def getPublicApps(self, user): categoryResult["apps"].append(app) + categoryResult["apps"] = sorted(categoryResult["apps"], key=lambda app: app['label'] or app['appId']) categories.append(categoryResult) return categories, html_definitions From 700c52f9f5cdb5f3f5a4a3a55a98c6f104e108ca Mon Sep 17 00:00:00 2001 From: Taylor Grafft Date: Tue, 12 Dec 2023 14:20:59 -0600 Subject: [PATCH 8/9] task/WP-367: Adding Public Data CMS Nav and fixing search bar root bug (#918) * task/WP-367: Adding Public Data CMS Nav and fixing search bar root bug * refactoring section name code for readability --------- Co-authored-by: Taylor Grafft Co-authored-by: Taylor Grafft Co-authored-by: Sal Tijerina --- .../DataFilesListing/DataFilesListing.jsx | 31 +++++++++++++++---- .../src/components/PublicData/PublicData.jsx | 6 ++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/client/src/components/DataFiles/DataFilesListing/DataFilesListing.jsx b/client/src/components/DataFiles/DataFilesListing/DataFilesListing.jsx index 2abd8e6a0..53d2e2616 100644 --- a/client/src/components/DataFiles/DataFilesListing/DataFilesListing.jsx +++ b/client/src/components/DataFiles/DataFilesListing/DataFilesListing.jsx @@ -153,13 +153,32 @@ const DataFilesListing = ({ api, scheme, system, path, isPublic }) => { const systemDisplayName = useSystemDisplayName({ scheme, system, path }); const homeDir = selectedSystem?.homeDir; - // Check if the current path is the home directory itself - const isAtHomeDir = path.replace(/^\/+/, '') === homeDir?.replace(/^\/+/, ''); + // Check if the current path is the root directory + const isRootDir = path === '/' || path === ''; - // Determine the sectionName based on the path (if homeDir, use systemDisplayName--else use current dir) - const sectionName = isAtHomeDir - ? systemDisplayName - : getCurrentDirectory(path); + // Adjusted check for home directory + const isAtHomeDir = + isRootDir || path.replace(/^\/+/, '') === homeDir?.replace(/^\/+/, ''); + + // Determine the sectionName with added handling for root directory + function determineSectionName( + isAtHomeDir, + isRootDir, + systemDisplayName, + path + ) { + if (isAtHomeDir) { + return isRootDir ? 'Root' : systemDisplayName; + } + return getCurrentDirectory(path); + } + + const sectionName = determineSectionName( + isAtHomeDir, + isRootDir, + systemDisplayName, + path + ); return ( <> diff --git a/client/src/components/PublicData/PublicData.jsx b/client/src/components/PublicData/PublicData.jsx index 40724764f..fa5e76da3 100644 --- a/client/src/components/PublicData/PublicData.jsx +++ b/client/src/components/PublicData/PublicData.jsx @@ -18,6 +18,8 @@ import DataFilesShowPathModal from '../DataFiles/DataFilesModals/DataFilesShowPa import { ToolbarButton } from '../DataFiles/DataFilesToolbar/DataFilesToolbar'; import styles from './PublicData.module.css'; +import dropdownStyles from '../../styles/components/dropdown-menu.css'; +import CombinedBreadcrumbs from '../DataFiles/CombinedBreadcrumbs/CombinedBreadcrumbs'; const PublicData = () => { const history = useHistory(); @@ -98,9 +100,9 @@ const PublicDataListing = ({ canDownload, downloadCallback }) => {
Date: Tue, 12 Dec 2023 14:40:58 -0600 Subject: [PATCH 9/9] WI-15: Add health check for site status (#919) * WI-15: Add health check for site status /core/health-check endpoint will provide ping status to validate nginx, uwsgi, django worker is up or not. * Remove used import * fix more lint errors --- server/portal/urls.py | 5 +++++ server/portal/views/unit_test.py | 7 +++++++ server/portal/views/views.py | 7 ++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/server/portal/urls.py b/server/portal/urls.py index 118071507..f19e91166 100644 --- a/server/portal/urls.py +++ b/server/portal/urls.py @@ -27,6 +27,7 @@ from django.views.generic.base import TemplateView from django.urls import path, re_path, include from impersonate import views as impersonate_views +from portal.views.views import health_check admin.autodiscover() urlpatterns = [ @@ -112,4 +113,8 @@ # version check. path('version/', portal_version), + # health check + path('core/health-check', health_check) + + ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/server/portal/views/unit_test.py b/server/portal/views/unit_test.py index cf3882ef8..f4ffbbf69 100644 --- a/server/portal/views/unit_test.py +++ b/server/portal/views/unit_test.py @@ -6,6 +6,7 @@ import requests import json + # route to be used for testing purposes API_ROUTE = '/api/system-monitor/' @@ -110,3 +111,9 @@ def test_exception(client, api_method_mock): response = client.get(API_ROUTE) assert response.status_code == 500 assert json.loads(response.content) == {'message': 'Something went wrong here...'} + + +def test_health_check(client): + response = client.get('/core/health-check') + assert response.status_code == 200 + assert json.loads(response.content) == {'status': 'healthy'} diff --git a/server/portal/views/views.py b/server/portal/views/views.py index cc4c2b90a..6c65764a2 100644 --- a/server/portal/views/views.py +++ b/server/portal/views/views.py @@ -1,5 +1,5 @@ import logging -from django.http import HttpResponse +from django.http import HttpResponse, JsonResponse logger = logging.getLogger(__name__) @@ -23,3 +23,8 @@ def project_version(request): version = 'UNKNOWN' return HttpResponse(version, content_type='text/plain') + + +def health_check(request): + health_status = {'status': 'healthy'} + return JsonResponse(health_status)