diff --git a/README.md b/README.md index e6abb12..f4588a8 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,53 @@ When `upgradeInsecureRequests` is set to `true` and at least one of your URLs (s This feature was implemented in response to [issue #159](https://github.com/ImagingDataCommons/slim/issues/159) where PACS servers would return HTTP bulkdata URIs even when accessed via HTTPS. +### Messages/Popups Configuration + +Configure message popup notifications that appear at the top of the screen. By default, all message popups are enabled. + +```javascript +window.config = { + // ... other config options ... + messages: { + disabled: ['warning', 'info'], // Disable specific message types + duration: 5, // Show messages for 5 seconds + top: 100 // Show 100px from top of screen + } +} +``` + +Options: +- `disabled`: Disable specific message types or all messages +- `duration`: How long messages are shown (in seconds) +- `top`: Distance from top of screen (in pixels) + +Available message types: +- `success` - Green popups +- `error` - Red popups +- `warning` - Yellow popups +- `info` - Blue popups + +Examples: +```javascript +// Disable specific types with custom duration and position +messages: { + disabled: ['warning', 'info'], + duration: 5, // Show for 5 seconds + top: 50 // Show 50px from top +} +``` + +```javascript +// Disable all popups +messages: { + disabled: true +} +``` + +Default values if not specified: +- `duration`: 5 seconds +- `top`: 100 pixels + ## Deployment Download the latest release from [github.com/imagingdatacommons/slim/releases](https://github.com/imagingdatacommons/slim/releases) and then run the following commands to install build dependencies and build the app: diff --git a/src/AppConfig.d.ts b/src/AppConfig.d.ts index f8f48ae..08c51e3 100644 --- a/src/AppConfig.d.ts +++ b/src/AppConfig.d.ts @@ -95,4 +95,9 @@ export default interface AppConfig { enableServerSelection?: boolean mode?: string preload?: boolean + messages?: { + disabled?: boolean | string[] + top?: number + duration?: number + } } diff --git a/src/index.tsx b/src/index.tsx index 3814766..585644f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -26,8 +26,67 @@ if (config.mode === 'dark') { App = React.lazy(async () => await import('./AppLight')) } +const isMessageTypeDisabled = ({ type }: { type: string }): boolean => { + const { messages } = config + if (messages === undefined) return false + if (typeof messages.disabled === 'boolean') { + return messages.disabled + } + return Array.isArray(messages.disabled) && messages.disabled.includes(type) +} + +// Store original message methods +const originalMessage = { ...message } + +const createMessageConfig = (content: string | object): object => { + const duration = config.messages?.duration ?? 5 + + if (typeof content === 'object' && content !== null) { + return { + ...content, + duration + } + } + + return { + content, + duration + } +} + +/** Create a proxy to control antd message */ +const messageProxy = new Proxy(originalMessage, { + get (target, prop: PropertyKey) { + // Handle config method separately + if (prop === 'config') { + return message.config.bind(message) + } + + // Handle message methods (success, error, etc) + const method = target[prop as keyof typeof target] + if (typeof method === 'function') { + return (...args: any[]) => { + const isMessageEnabled = !isMessageTypeDisabled({ type: prop as string }) + if (isMessageEnabled) { + const messageConfig = createMessageConfig(args[0]) + return (method as Function).apply(message, [messageConfig]) + } + return { then: () => {} } + } + } + + // Pass through any other properties + return Reflect.get(target, prop) + } +}) + +// Apply the proxy +Object.assign(message, messageProxy) + +// Set global config after proxy is in place message.config({ - top: 100 + top: config.messages?.top ?? 100, + duration: config.messages?.duration ?? 5 }) const container = document.getElementById('root')