From cd6c8ae8e3a1e7e9f71fb160af7c97c5c635f7a3 Mon Sep 17 00:00:00 2001 From: Jose Francisco Date: Thu, 7 Dec 2023 20:08:41 +0000 Subject: [PATCH] (chore) Change offline setup to event based part-1 --- .../offline-ready-modal.component.tsx | 64 +++++++------------ .../apps/esm-offline-tools-app/src/index.ts | 2 + .../offline-actions-mode-button.component.tsx | 64 +++++++++++-------- packages/framework/esm-globals/src/types.ts | 4 +- packages/framework/esm-offline/src/mode.ts | 9 +++ packages/framework/esm-offline/src/public.ts | 1 + packages/shell/esm-app-shell/src/apps.ts | 30 --------- packages/shell/esm-app-shell/src/run.ts | 4 +- 8 files changed, 74 insertions(+), 104 deletions(-) diff --git a/packages/apps/esm-offline-tools-app/src/components/offline-ready-modal.component.tsx b/packages/apps/esm-offline-tools-app/src/components/offline-ready-modal.component.tsx index 363b83eab..ada179593 100644 --- a/packages/apps/esm-offline-tools-app/src/components/offline-ready-modal.component.tsx +++ b/packages/apps/esm-offline-tools-app/src/components/offline-ready-modal.component.tsx @@ -4,10 +4,10 @@ import { ModalFooter, ModalHeader, Button, - ProgressBar, + InlineLoading, } from "@carbon/react"; import { useTranslation } from "react-i18next"; -import { showToast } from "@openmrs/esm-framework"; +import { getCurrentOfflineMode, showToast } from "@openmrs/esm-framework"; export interface OfflineActionsProgressModalProps { items?: Array; @@ -19,40 +19,29 @@ const OfflineReadyModal: React.FC = ({ items, }) => { const { t } = useTranslation(); - const [progress, setProgress] = useState(0); + const [isRunning, setIsRunning] = useState(true); const [abortController, setAbortController] = useState( () => new AbortController() ); - async function runAsyncFunctionsInParallel(asyncFunctions) { - const totalFunctions = asyncFunctions.length; + async function dispatchOfflineEvent() { + //TODO CHANGE MODE + let mode = getCurrentOfflineMode().active; + window.dispatchEvent( + new CustomEvent(`openmrs:offline-${mode ? "enabled" : "disabled"}`, { + detail: getCurrentOfflineMode(), + }) + ); - if (totalFunctions === 0) { - console.warn("No tasks to run."); - setProgress(100); - return; - } - - let completedFunctions = 0; - - const promises = asyncFunctions.map(async (asyncFunction) => { - await asyncFunction(abortController); - completedFunctions++; - const progress = (completedFunctions / totalFunctions) * 100; - setProgress(progress); - }); - - await Promise.all(promises); - - console.warn("All tasks completed!"); + setIsRunning(false); } useEffect(() => { - runAsyncFunctionsInParallel(items || []); + dispatchOfflineEvent(); }, [abortController, items]); const handleClose = useCallback(() => { - if (progress < 100) { + if (isRunning) { abortController.abort(); showToast({ @@ -74,7 +63,7 @@ const OfflineReadyModal: React.FC = ({ }); closeModal(true); } - }, [abortController, closeModal, progress, t]); + }, [abortController, closeModal, isRunning, t]); return ( <> @@ -83,25 +72,18 @@ const OfflineReadyModal: React.FC = ({ closeModal={handleClose} /> - + {isRunning && ( + + )} - - diff --git a/packages/apps/esm-offline-tools-app/src/index.ts b/packages/apps/esm-offline-tools-app/src/index.ts index face214c8..bd696e78c 100644 --- a/packages/apps/esm-offline-tools-app/src/index.ts +++ b/packages/apps/esm-offline-tools-app/src/index.ts @@ -133,6 +133,8 @@ export function startupApp() { setupOffline(); setupSynchronizingOfflineActionsNotifications(); + // registerOfflineHandler(setupOffline); + registerBreadcrumbs([ { path: `${window.spaBase}/${routes.offlineTools}`, diff --git a/packages/apps/esm-offline-tools-app/src/offline-actions/offline-actions-mode-button.component.tsx b/packages/apps/esm-offline-tools-app/src/offline-actions/offline-actions-mode-button.component.tsx index 6f275e88b..c9a88aeea 100644 --- a/packages/apps/esm-offline-tools-app/src/offline-actions/offline-actions-mode-button.component.tsx +++ b/packages/apps/esm-offline-tools-app/src/offline-actions/offline-actions-mode-button.component.tsx @@ -23,20 +23,13 @@ const OfflineActionsModeButton: React.FC = () => { const [active, setActive] = useState(() => getCurrentOfflineMode().active); const toggle = useCallback(() => { - if (window.installedModules && window.installedModules.length > 0) { - const dispose = showModal("offline-tools-offline-ready-modal", { - items: window.installedModules - .filter((app) => app.length >= 3) - .map((app) => app[2]), - closeModal: (result) => { - setActive(result); - setCurrentOfflineMode(result ? "on" : "off"); - dispose(); - }, - }); - } else { - console.warn("No installed modules found."); - } + const dispose = showModal("offline-tools-offline-ready-modal", { + closeModal: (result) => { + setActive(result); + setCurrentOfflineMode(result ? "on" : "off"); + dispose(); + }, + }); }, [setActive]); const handleRefresh = useCallback(() => { @@ -44,20 +37,37 @@ const OfflineActionsModeButton: React.FC = () => { }, [toggle]); return ( -
-
- - - {t("offlineReady", "Offline Ready")} - + isOnline && ( +
+
+ + + {t("offlineReady", "Offline Ready")} + +
+ + {active && ( + + )} + + {!active && ( + + )}
- -
+ ) ); }; diff --git a/packages/framework/esm-globals/src/types.ts b/packages/framework/esm-globals/src/types.ts index 5831aa18a..1c5d616a1 100644 --- a/packages/framework/esm-globals/src/types.ts +++ b/packages/framework/esm-globals/src/types.ts @@ -54,7 +54,7 @@ declare global { /** * Gets the installed modules, which are tuples consisting of the module's name and exports. */ - installedModules: Array<[string, OpenmrsAppRoutes, OfflineReadyFunction]>; + installedModules: Array<[string, OpenmrsAppRoutes]>; /** * The i18next instance for the app. */ @@ -62,8 +62,6 @@ declare global { } } -export type OfflineReadyFunction = (abortController: AbortController) => void; - export type SpaEnvironment = "production" | "development" | "test"; export interface ImportMap { diff --git a/packages/framework/esm-offline/src/mode.ts b/packages/framework/esm-offline/src/mode.ts index 6f821c7ed..2109b35a2 100644 --- a/packages/framework/esm-offline/src/mode.ts +++ b/packages/framework/esm-offline/src/mode.ts @@ -36,6 +36,7 @@ async function isPrivateBrowsing() { } export type OfflineMode = "on" | "off" | "unavailable"; +export type OfflineHandler = () => void | Promise; export interface OfflineModeResult { current: OfflineMode; @@ -68,6 +69,14 @@ export function setCurrentOfflineMode(mode: OfflineMode) { } } +export function registerOfflineHandler(setupOffline: OfflineHandler) { + window.addEventListener("openmrs:offline-enabled", setupOffline); + const offlineMode = getCurrentOfflineMode(); + if (offlineMode.active) { + setupOffline(); + } +} + export async function activateOfflineCapability() { const isPrivate = await isPrivateBrowsing(); diff --git a/packages/framework/esm-offline/src/public.ts b/packages/framework/esm-offline/src/public.ts index c161daad2..28fe3d542 100644 --- a/packages/framework/esm-offline/src/public.ts +++ b/packages/framework/esm-offline/src/public.ts @@ -2,6 +2,7 @@ export { type OfflineMode, type OfflineModeResult, getCurrentOfflineMode, + registerOfflineHandler, } from "./mode"; export * from "./offline-patient-data"; export * from "./service-worker-messaging"; diff --git a/packages/shell/esm-app-shell/src/apps.ts b/packages/shell/esm-app-shell/src/apps.ts index 2b3d26268..8d65ab5fd 100644 --- a/packages/shell/esm-app-shell/src/apps.ts +++ b/packages/shell/esm-app-shell/src/apps.ts @@ -147,36 +147,6 @@ function getLoader( }; } -//TODO: MOCK asyncTask -const OFFLINE_READY_FUNCTION = "offlineReady"; - -const asyncTask = async (abortController) => { - return new Promise((resolve, reject) => { - const timeoutId = setTimeout(() => { - console.warn("Task completed"); - resolve("Task completed"); - }, Math.floor(Math.random() * (7000 - 1000 + 1)) + 1000); - abortController.signal.addEventListener("abort", () => { - clearTimeout(timeoutId); - console.warn("Operation aborted"); - reject("Operation aborted"); - }); - }); -}; - -/** - * This function creates a loader function suitable for use in either a single-spa - * application or parcel. - * - * This function returns a function responsible for executing the actions required - * to prepare the module for offline mode. - */ - -export function getOfflineReadyLoader(appName: string) { - //TODO dynamic import - return asyncTask; -} - /** * This is the main entry-point for registering an app with the app shell. * Each app has a name and should have a `routes.json` file that defines it's diff --git a/packages/shell/esm-app-shell/src/run.ts b/packages/shell/esm-app-shell/src/run.ts index ee4427517..a5a742632 100644 --- a/packages/shell/esm-app-shell/src/run.ts +++ b/packages/shell/esm-app-shell/src/run.ts @@ -36,7 +36,6 @@ import { finishRegisteringAllApps, registerApp, tryRegisterExtension, - getOfflineReadyLoader, } from "./apps"; import { setupI18n } from "./locale"; import { appName, getCoreExtensions } from "./ui"; @@ -92,8 +91,7 @@ async function setupApps() { const modules: typeof window.installedModules = []; const registrationPromises = Object.entries(routes).map( async ([module, routes]) => { - const offlineLoader = getOfflineReadyLoader(module); - modules.push([module, routes, offlineLoader]); + modules.push([module, routes]); registerApp(module, routes); } );