From 13e0bd998e931204161395c80119bf5a5866f433 Mon Sep 17 00:00:00 2001 From: Maryam Mehdizadeh Date: Mon, 2 Feb 2026 11:27:18 +0800 Subject: [PATCH 1/2] feat: add config option to hide developer messages for clinical users Adds a `showDeveloperMessages` configuration option to allow hiding developer-focused messages from clinical/production deployments. Changes: - Add showDeveloperMessages field to ConfigFile interface (optional, defaults to true) - Update FALLBACK_CONFIG with showDeveloperMessages: true - Add showDeveloperMessages: true to main branch config.json - Update usePopulate hook to conditionally show pre-population issue snackbar - Keep console.warn() output for developer debugging (not visible to end users) - Add comprehensive tests for both enabled and disabled states For health-checks-pilot branch deployment: - Set showDeveloperMessages: false in config.json to hide messages like "Form partially populated, there might be pre-population issues. View console for details." Related issue: #1805 --- apps/smart-forms-app/public/config.json | 5 +- .../features/configChecker/utils/config.ts | 6 ++ .../prepopulate/hooks/usePopulate.tsx | 16 ++-- .../prepopulate/test/usePopulate.test.tsx | 74 ++++++++++++++++++- 4 files changed, 93 insertions(+), 8 deletions(-) diff --git a/apps/smart-forms-app/public/config.json b/apps/smart-forms-app/public/config.json index 6e664f82a..977f32fb6 100644 --- a/apps/smart-forms-app/public/config.json +++ b/apps/smart-forms-app/public/config.json @@ -3,5 +3,6 @@ "formsServerUrl": "https://smartforms.csiro.au/api/fhir", "defaultClientId": "a57d90e3-5f69-4b92-aa2e-2992180863c1", "launchScopes": "launch openid fhirUser online_access patient/AllergyIntolerance.cs patient/Condition.cs patient/Encounter.r patient/Immunization.cs patient/Medication.r patient/MedicationStatement.cs patient/Observation.cs patient/Patient.r patient/QuestionnaireResponse.crus user/Practitioner.r launch/questionnaire?role=http://ns.electronichealth.net.au/smart/role/new", - "registeredClientIdsUrl": "https://smartforms.csiro.au/smart-config/config.json" -} + "registeredClientIdsUrl": "https://smartforms.csiro.au/smart-config/config.json", + "showDeveloperMessages": true +} \ No newline at end of file diff --git a/apps/smart-forms-app/src/features/configChecker/utils/config.ts b/apps/smart-forms-app/src/features/configChecker/utils/config.ts index 671a384c4..e5ad4d320 100644 --- a/apps/smart-forms-app/src/features/configChecker/utils/config.ts +++ b/apps/smart-forms-app/src/features/configChecker/utils/config.ts @@ -38,6 +38,11 @@ export interface ConfigFile { // "https://example.com/fhir": "6cc9bccb-3ae2-40d7-9660-22c99534520b" // } registeredClientIdsUrl: string | null; + + // Controls whether developer-focused messages are shown. + // Set to false for clinical/production deployments to hide technical messages. + // Defaults to true if not specified (shows messages for backward compatibility). + showDeveloperMessages?: boolean; } export interface AppConfig extends ConfigFile { @@ -53,6 +58,7 @@ export const FALLBACK_CONFIG: AppConfig = { launchScopes: 'launch openid fhirUser online_access patient/AllergyIntolerance.cs patient/Condition.cs patient/Encounter.r patient/Immunization.cs patient/Medication.r patient/MedicationStatement.cs patient/Observation.cs patient/Patient.r patient/QuestionnaireResponse.crus user/Practitioner.r launch/questionnaire?role=http://ns.electronichealth.net.au/smart/role/new', registeredClientIdsUrl: null, + showDeveloperMessages: true, registeredClientIds: null }; diff --git a/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx b/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx index 34062942f..d4cf0118b 100644 --- a/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx +++ b/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx @@ -15,9 +15,10 @@ * limitations under the License. */ -import { useState } from 'react'; +import { useState, useContext } from 'react'; import CloseSnackbar from '../../../components/Snackbar/CloseSnackbar.tsx'; import { useSnackbar } from 'notistack'; +import { ConfigContext } from '../../configChecker/contexts/ConfigContext.tsx'; import { buildForm, useQuestionnaireResponseStore, @@ -44,6 +45,7 @@ function usePopulate(spinner: RendererSpinner, onStopSpinner: () => void): void const [isPopulated, setIsPopulated] = useState(false); const { enqueueSnackbar } = useSnackbar(); + const { config } = useContext(ConfigContext); // Do not run population if spinner purpose is "repopulate" if (status !== 'prepopulate') { @@ -127,10 +129,14 @@ function usePopulate(spinner: RendererSpinner, onStopSpinner: () => void): void onStopSpinner(); if (issues) { - enqueueSnackbar( - 'Form partially populated, there might be pre-population issues. View console for details.', - { action: } - ); + // Only show the snackbar message if developer messages are enabled + if (config.showDeveloperMessages ?? true) { + enqueueSnackbar( + 'Form partially populated, there might be pre-population issues. View console for details.', + { action: } + ); + } + // Always log to console - clinicians won't see this, but developers need it console.warn(issues); return; } diff --git a/apps/smart-forms-app/src/features/prepopulate/test/usePopulate.test.tsx b/apps/smart-forms-app/src/features/prepopulate/test/usePopulate.test.tsx index eeb6c7375..fa0b7d699 100644 --- a/apps/smart-forms-app/src/features/prepopulate/test/usePopulate.test.tsx +++ b/apps/smart-forms-app/src/features/prepopulate/test/usePopulate.test.tsx @@ -45,6 +45,24 @@ jest.mock('../../../components/Snackbar/CloseSnackbar', () => { }; }); +// Mock ConfigContext +const mockConfigContext = { + config: { + showDeveloperMessages: true + }, + configLoading: false, + configValid: true, + configError: null, + configErrorType: null, + currentClientId: 'test-client-id', + onSetCurrentClientId: jest.fn() +}; + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useContext: jest.fn(() => mockConfigContext) +})); + // Create mock store functions that will be used in the module mock const mockSourceQuestionnaire = jest.fn(); const mockSourceResponse = jest.fn(); @@ -373,7 +391,7 @@ describe('usePopulate', () => { }); }); - it('should handle successful population with issues', async () => { + it('should handle successful population with issues (developer messages enabled)', async () => { const issues = { resourceType: 'OperationOutcome' as const, issue: [ @@ -408,13 +426,67 @@ describe('usePopulate', () => { additionalContext: undefined }); expect(mockOnStopSpinner).toHaveBeenCalled(); + // Snackbar should be shown when developer messages are enabled expect(mockEnqueueSnackbar).toHaveBeenCalledWith( 'Form partially populated, there might be pre-population issues. View console for details.', { action: expect.anything() } ); + // Console warning should always be shown + expect(consoleSpy).toHaveBeenCalledWith(issues); + + consoleSpy.mockRestore(); + }); + + it('should handle successful population with issues (developer messages disabled)', async () => { + // Temporarily set showDeveloperMessages to false + const originalShowDeveloperMessages = mockConfigContext.config.showDeveloperMessages; + mockConfigContext.config.showDeveloperMessages = false; + + const issues = { + resourceType: 'OperationOutcome' as const, + issue: [ + { + severity: 'warning' as const, + code: 'incomplete' as const, + diagnostics: 'Some fields could not be populated' + } + ] + }; + const spinner = createSpinner(true, 'prepopulate'); + + mockPopulateQuestionnaire.mockResolvedValue({ + populateSuccess: true, + populateResult: { + populatedResponse: mockResponse, + issues + } + }); + + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); + + renderHook(() => usePopulate(spinner, mockOnStopSpinner)); + + // Wait for async operations + await new Promise((resolve) => setTimeout(resolve, 10)); + + expect(mockBuildForm).toHaveBeenCalledWith({ + questionnaire: mockQuestionnaire, + questionnaireResponse: mockResponse, + terminologyServerUrl: 'https://test-terminology-server.com', + additionalContext: undefined + }); + expect(mockOnStopSpinner).toHaveBeenCalled(); + // Snackbar should NOT be shown when developer messages are disabled + expect(mockEnqueueSnackbar).not.toHaveBeenCalledWith( + 'Form partially populated, there might be pre-population issues. View console for details.', + { action: expect.anything() } + ); + // Console warning should still be shown (developers can still see it) expect(consoleSpy).toHaveBeenCalledWith(issues); consoleSpy.mockRestore(); + // Restore original value + mockConfigContext.config.showDeveloperMessages = originalShowDeveloperMessages; }); }); From 99457a82b4b527dd5d0374aadbad9d69e09f6921 Mon Sep 17 00:00:00 2001 From: Maryam Mehdizadeh Date: Fri, 6 Feb 2026 12:53:52 +0800 Subject: [PATCH 2/2] style: fix prettier formatting in config.json --- apps/smart-forms-app/public/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smart-forms-app/public/config.json b/apps/smart-forms-app/public/config.json index 977f32fb6..6c063a838 100644 --- a/apps/smart-forms-app/public/config.json +++ b/apps/smart-forms-app/public/config.json @@ -5,4 +5,4 @@ "launchScopes": "launch openid fhirUser online_access patient/AllergyIntolerance.cs patient/Condition.cs patient/Encounter.r patient/Immunization.cs patient/Medication.r patient/MedicationStatement.cs patient/Observation.cs patient/Patient.r patient/QuestionnaireResponse.crus user/Practitioner.r launch/questionnaire?role=http://ns.electronichealth.net.au/smart/role/new", "registeredClientIdsUrl": "https://smartforms.csiro.au/smart-config/config.json", "showDeveloperMessages": true -} \ No newline at end of file +}