(() => { const { TARGET_ORIGIN, TARGET_PATHNAME, TARGET_PARAM, TARGET_PARAM_VALUE, TARGET_APP_URL, HCM_ORIGIN, HCM_WELCOME_PATHNAMES, HCM_MY_INFORMATION_APPS_GROUP_ID, WORKLIST_ORIGIN, WORKLIST_SAASUI_PATHNAME, USER_BUTTON_LABEL, ALLOWED_STAGE_TYPES, SELECTORS, IDS, CLASSES, STORAGE_KEYS, CACHE, DETAIL_SORT_KEYS, BRIDGE, API_ENDPOINTS, COMCIP_REQUEST, COMCIP_TIME_ENTRY_FRAME_ID, ACTION_TEAM_OPTIONS, ACTION_COMPLEXITY_OPTIONS, } = globalThis.ArchPanelConfig; const storageService = globalThis.ArchPanelStorageService; const chromeService = globalThis.ArchPanelChromeService; const { normalizeText, cleanString, firstNonEmptyString, normalizeString, toNumber, toIsoDateString, extractArray, mapWithConcurrency, getFieldValue, flattenDisplayRecord, isVisible, formatWholeNumber, formatCurrency, formatHours, formatWeekNumber, formatOperationalWeekLabel, formatPercent, formatProgressPercent, formatDate, getDateInputValue, formatDateInputDisplay, formatDateForTimeEntryRequest, parseTimeEntryDate, formatDateTime, getLocalDateKey, getOperationalWeekInfo, getCalendarRowWeekDate, parseDatePreservingDateOnly, decodeJwtPayload, isJwtExpired, getErrorMessage, escapeHtml, cssEscape, } = globalThis.ArchPanelUtils; const { getStoredTheme, setStoredTheme, getStoredSidebarCollapsed, setStoredSidebarCollapsed, getStoredCalendarView, setStoredCalendarView, getStoredTimeManagementSelectedDate, setStoredTimeManagementSelectedDate, } = globalThis.ArchPanelPreferencesService.create({ STORAGE_KEYS, getDateInputValue, parseDatePreservingDateOnly, }); const { applyDialogTheme, ensureStyles, applyTheme, findUserAnchor, resolveInsertionTarget, lockScroll, unlockScroll, } = globalThis.ArchPanelShellView.create({ IDS, CLASSES, USER_BUTTON_LABEL, normalizeText, isVisible, }); const { normalizeWorkload, isWonWorkload, normalizeTeamValue, teamContainsUser, stripTransientFields, createExportPayload, createDatasetSnapshot, normalizeCachedExportPayload, } = globalThis.ArchPanelWorkloadDatasetDomain.create({ ALLOWED_STAGE_TYPES, cleanString, firstNonEmptyString, normalizeString, toNumber, extractArray, formatDateTime, normalizePendingServiceRequests: (...args) => comcipRepository.normalizePendingServiceRequests(...args), }); const { buildWorkloadStartCalendar, getWeekStartDate, getCalendarAnchorDate, } = globalThis.ArchPanelWorkloadCalendarDomain.create({ getLocalDateKey, getOperationalWeekInfo, getCalendarRowWeekDate, formatOperationalWeekLabel, formatDate, parseDatePreservingDateOnly, }); const { readCachedDataset, writeCachedDataset, readCachedTaskTypePayload, writeCachedTaskTypePayload, writeCachedWorklistToken, readCachedWorklistToken, } = globalThis.ArchPanelCacheRepository.create({ CACHE, storageService, normalizeCachedExportPayload, cleanString, isJwtExpired, }); const hcmPage = globalThis.ArchPanelHcmPage.create({ HCM_MY_INFORMATION_APPS_GROUP_ID, WORKLIST_ORIGIN, WORKLIST_SAASUI_PATHNAME, IDS, cleanString, isJwtExpired, hcmTileTemplate: globalThis.ArchPanelTemplates.hcmTile, onOpenArchPanel: openModal, writeCachedWorklistToken, }); const appState = { theme: getStoredTheme(), sidebarCollapsed: getStoredSidebarCollapsed(), calendarYear: new Date().getFullYear(), calendarMonth: new Date().getMonth(), calendarView: getStoredCalendarView(), calendarAnchorDateKey: getLocalDateKey(new Date()), status: "idle", loadingMessage: "", loadingProgress: 0, errorMessage: "", dataset: null, sessionAuthHeaders: {}, detailModal: null, actionFormModal: null, rampComparisonModal: null, forecastUpdateConfirmModal: null, timeEntriesDrawer: null, timeManagementModal: null, taskTypeCache: { promise: null, }, timeManagementActivityCache: new Map(), timeManagementWeekCache: new Map(), pendingTimeManagementHighlightRowId: "", timeManagementDatePicker: { isOpen: false, year: new Date().getFullYear(), month: new Date().getMonth(), }, pendingFocusSelector: "", spaFrameLifecycleIntervalId: null, lastSpaFrameLifecycleError: "", }; let syncFrame = 0; let restoreFocusTarget = null; let closeTimer = 0; const { ensurePageBridge, fetchJson, sendComcipRequestMessage, ensureSpaFrame, handleBridgeMessage, } = globalThis.ArchPanelTransportService.create({ TARGET_ORIGIN, TARGET_APP_URL, IDS, BRIDGE, COMCIP_REQUEST, COMCIP_TIME_ENTRY_FRAME_ID, chromeService, cleanString, firstNonEmptyString, isHcmWelcomePage, getSessionAuthHeaders: () => appState.sessionAuthHeaders, setSessionAuthHeaders: (headers) => { appState.sessionAuthHeaders = headers; }, }); const createExportHtml = globalThis.ArchPanelExportHtml.createExportHtml; const { renderServiceRequestDetailTable, renderSortButton, renderOpportunityLink, renderWorkloadLink, getHeaderSummary, } = globalThis.ArchPanelRenderHelpers.create({ appState, escapeHtml, cleanString, formatWholeNumber, formatCurrency, formatDate, formatHours, }); let workbenchController = null; let modalEvents = null; function getSortedDetailItems() { return workbenchController?.getSortedDetailItems() || []; } function findWorkloadById(workloadId) { return workbenchController?.findWorkloadById(workloadId) || null; } function isTargetPage() { const currentUrl = new URL(window.location.href); return ( currentUrl.origin === TARGET_ORIGIN && currentUrl.pathname === TARGET_PATHNAME && currentUrl.searchParams.get(TARGET_PARAM) === TARGET_PARAM_VALUE ); } function isHcmWelcomePage() { const currentUrl = new URL(window.location.href); return ( isAllowedHcmOrigin(currentUrl) && HCM_WELCOME_PATHNAMES.includes(currentUrl.pathname) ); } function isAllowedHcmOrigin(url) { return url?.origin === HCM_ORIGIN; } function scheduleSync() { if (syncFrame) { return; } syncFrame = window.requestAnimationFrame(() => { syncFrame = 0; syncButton(); }); } function syncButton() { const mount = document.getElementById(IDS.mount); const hcmTile = document.getElementById(IDS.hcmTile); if (isHcmWelcomePage()) { mount?.remove(); ensureStyles(); ensureModal(); hcmPage.syncHcmTile(); ensureSpaFrame(); hcmPage.syncWorklistIframeToken(); return; } if (!isTargetPage()) { mount?.remove(); hcmTile?.remove(); removeModal(); unlockScroll(); return; } mount?.remove(); hcmTile?.remove(); removeModal(); unlockScroll(); } function createMount() { const mount = document.createElement("div"); mount.id = IDS.mount; mount.className = "arch-panel-extension-entry"; const button = document.createElement("button"); button.id = IDS.button; button.type = "button"; button.className = "arch-panel-extension-button"; button.textContent = "Arch panel"; button.setAttribute("aria-label", "Open Arch panel"); button.addEventListener("click", openModal); mount.appendChild(button); return mount; } function ensureModal() { const existingOverlay = document.getElementById(IDS.overlay); if (existingOverlay) { return existingOverlay; } const overlay = document.createElement("div"); overlay.id = IDS.overlay; overlay.className = "arch-panel-extension-overlay"; overlay.hidden = true; overlay.setAttribute("aria-hidden", "true"); overlay.addEventListener("click", modalEvents.handleOverlayClick); overlay.addEventListener("change", modalEvents.handleOverlayChange); overlay.addEventListener("input", modalEvents.handleOverlayInput); overlay.addEventListener("keydown", modalEvents.handleOverlayKeydown); overlay.addEventListener("focusin", modalEvents.handleOverlayFocusIn); overlay.addEventListener("pointerover", modalEvents.handleOverlayPointerOver); overlay.addEventListener("pointermove", modalEvents.handleOverlayPointerMove); overlay.addEventListener("pointerout", modalEvents.handleOverlayPointerOut); overlay.addEventListener("scroll", modalEvents.handleOverlayScroll, true); document.body.appendChild(overlay); renderModal(); return overlay; } function renderModal() { const overlay = document.getElementById(IDS.overlay); if (!overlay) { return; } const previousScrollState = captureModalScrollState(overlay); const activeFocusSelector = getRestorableFocusSelector(document.activeElement); const requestedFocusSelector = appState.pendingFocusSelector || activeFocusSelector; overlay.innerHTML = createModalMarkup(); applyDialogTheme(overlay, appState.theme); restoreModalScrollState(overlay, previousScrollState); window.requestAnimationFrame(() => { if (requestedFocusSelector && shouldRestoreFocusAfterRender()) { const focusTarget = overlay.querySelector(requestedFocusSelector); if (focusTarget instanceof HTMLElement) { focusTarget.focus({ preventScroll: true }); if (focusTarget instanceof HTMLInputElement) { focusTarget.select(); } } } appState.pendingFocusSelector = ""; scrollPendingTimeManagementHighlightIntoView(overlay); }); } function shouldRestoreFocusAfterRender() { if (appState.pendingFocusSelector) { return true; } return ( !appState.detailModal && !appState.actionFormModal && !appState.rampComparisonModal && !appState.forecastUpdateConfirmModal && !appState.timeManagementModal ); } function scrollPendingTimeManagementHighlightIntoView(overlay) { const rowId = cleanString(appState.pendingTimeManagementHighlightRowId); if (!rowId) { return; } appState.pendingTimeManagementHighlightRowId = ""; const row = overlay.querySelector( `.arch-panel-extension-time-management-entry-row[data-row-id="${cssEscape(rowId)}"]` ); if (row instanceof HTMLElement) { row.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest", }); } } function captureModalScrollState(overlay) { const mainShell = overlay.querySelector(".arch-panel-extension-main-shell"); const shellBody = overlay.querySelector(".arch-panel-extension-shell-body"); const dialog = overlay.querySelector(".arch-panel-extension-dialog"); const detailTable = overlay.querySelector( ".arch-panel-extension-table-wrap.is-detail" ); return { windowX: window.scrollX, windowY: window.scrollY, documentTop: document.documentElement.scrollTop, bodyTop: document.body.scrollTop, mainShellTop: mainShell ? mainShell.scrollTop : 0, shellBodyTop: shellBody ? shellBody.scrollTop : 0, dialogTop: dialog ? dialog.scrollTop : 0, detailTableTop: detailTable ? detailTable.scrollTop : 0, detailTableLeft: detailTable ? detailTable.scrollLeft : 0, }; } function restoreModalScrollState(overlay, scrollState) { const restore = () => { const mainShell = overlay.querySelector(".arch-panel-extension-main-shell"); const shellBody = overlay.querySelector(".arch-panel-extension-shell-body"); const dialog = overlay.querySelector(".arch-panel-extension-dialog"); const detailTable = overlay.querySelector( ".arch-panel-extension-table-wrap.is-detail" ); if (mainShell) { mainShell.scrollTop = scrollState.mainShellTop; } if (shellBody) { shellBody.scrollTop = scrollState.shellBodyTop; } if (dialog) { dialog.scrollTop = scrollState.dialogTop; } if (detailTable) { detailTable.scrollTop = scrollState.detailTableTop; detailTable.scrollLeft = scrollState.detailTableLeft; } document.documentElement.scrollTop = scrollState.documentTop; document.body.scrollTop = scrollState.bodyTop; window.scrollTo(scrollState.windowX, scrollState.windowY); }; window.requestAnimationFrame(() => { restore(); window.requestAnimationFrame(restore); }); } function getRestorableFocusSelector(element) { if (!(element instanceof HTMLElement)) { return ""; } const action = element.getAttribute("data-action"); if ( action === "calendar-prev" || action === "calendar-next" || action === "calendar-today" || action === "toggle-sidebar" || action === "toggle-theme" ) { return `[data-action="${action}"]`; } if (action === "calendar-view") { const calendarView = element.getAttribute("data-calendar-view"); return calendarView ? `[data-action="calendar-view"][data-calendar-view="${calendarView}"]` : `[data-action="${action}"]`; } const detailScope = element.getAttribute("data-detail-scope"); const detailValue = element.getAttribute("data-detail-value"); if (detailScope === "calendar-day" && detailValue) { return getCalendarDayFocusSelector(detailValue); } return ""; } function getCalendarDayFocusSelector(dateKey) { return `[data-action="open-detail"][data-detail-scope="calendar-day"][data-detail-value="${dateKey}"]`; } function createModalMarkup() { return ` `; } const { buildRampForecastComparisonRows, hasRampForecastMismatch, isNonZeroAmount, parseForecastMonthNumber, createForecastUpdatePayload, } = globalThis.ArchPanelRampForecastDomain.create({ toNumber, normalizeString, parseDatePreservingDateOnly, formatWeekNumber, }); const { getTimeManagementRows, isTimeManagementSaveEnabled, getTimeManagementPendingChanges, createTimeManagementRowSignature, createTimeManagementSavePayload, formatTimeManagementHourPayloadValue, getTimeManagementDayKey, getTimeManagementWeekdayName, isNonServiceRequestSrNumber, } = globalThis.ArchPanelTimeManagementDomain.create({ cleanString, normalizeString, toNumber, parseTimeEntryDate, getLocalDateKey, }); const { normalizeInfoWeekResponse, normalizeTimeManagementServiceRequests, formatTimeManagementServiceRequestLabel, mergeTimeManagementServiceRequests, normalizeTimeManagementEntryRows, normalizeTimeManagementEntryRowSelection, getActivityRequestSrNumbers, normalizeActivityRequest, normalizeActivityRequestDetails, normalizeTaskTypeRequest, getTimeManagementTaskTypeOptions, getTimeManagementActivityOptions, findTimeManagementServiceRequest, findTimeManagementServiceRequestByNumber, findOptionValue, findOptionLabel, normalizeTimeEntriesSummary, groupTimeEntriesByResourceName, getTimeEntryTimeSpent, getTimeEntryActivity, getTimeEntryTaskType, } = globalThis.ArchPanelTimeManagementData.create({ cleanString, normalizeString, firstNonEmptyString, extractArray, getFieldValue, flattenDisplayRecord, toNumber, parseTimeEntryDate, getLocalDateKey, getTimeManagementDayKey, getTimeManagementWeekdayName, createTimeManagementRowSignature, }); const workbenchRepository = globalThis.ArchPanelWorkbenchRepository.create({ TARGET_ORIGIN, API_ENDPOINTS, fetchJson, extractArray, cleanString, firstNonEmptyString, getFieldValue, decodeJwtPayload, toNumber, normalizeWorkload, isWonWorkload, normalizeTeamValue, }); const comcipRepository = globalThis.ArchPanelComcipRepository.create({ COMCIP_REQUEST, sendComcipRequest: sendComcipRequestMessage, cleanString, firstNonEmptyString, extractArray, getFieldValue, toNumber, formatDateForTimeEntryRequest, }); const { renderMainContent, renderWorkloadTableRow, } = globalThis.ArchPanelDashboardView.create({ appState, buildWorkloadStartCalendar, hasRampForecastMismatch, renderOpportunityLink, renderWorkloadLink, escapeHtml, cleanString, formatWholeNumber, formatCurrency, formatPercent, formatProgressPercent, formatDate, }); const { renderDetailModal, renderActionFormModal, renderRampComparisonModal, renderForecastUpdateConfirmModal, renderTimeEntriesDrawer, } = globalThis.ArchPanelWorkbenchModalsView.create({ appState, DETAIL_SORT_KEYS, ACTION_TEAM_OPTIONS, ACTION_COMPLEXITY_OPTIONS, getSortedDetailItems, renderServiceRequestDetailTable, renderSortButton, renderWorkloadTableRow, findWorkloadById, renderOpportunityLink, groupTimeEntriesByResourceName, getTimeEntryTimeSpent, getTimeEntryActivity, getTimeEntryTaskType, isNonZeroAmount, escapeHtml, cleanString, formatWholeNumber, formatCurrency, formatDate, formatHours, }); const { renderTimeManagementModal, } = globalThis.ArchPanelManageTimeView.create({ appState, escapeHtml, cleanString, normalizeString, formatDateInputDisplay, getDateInputValue, formatHours, getWeekStartDate, getLocalDateKey, getTimeManagementDayKey, isTimeManagementSaveEnabled, getTimeManagementRows, getTimeManagementActivityOptions, findTimeManagementServiceRequestByNumber, formatTimeManagementServiceRequestLabel, isNonServiceRequestSrNumber, findOptionValue, findOptionLabel, getTimeManagementTaskTypeOptions, formatTimeManagementHourPayloadValue, }); const manageTimeController = globalThis.ArchPanelManageTimeController.create({ appState, COMCIP_REQUEST, comcipRepository, readCachedTaskTypePayload, writeCachedTaskTypePayload, getStoredTimeManagementSelectedDate, setStoredTimeManagementSelectedDate, renderModal, cleanString, normalizeString, getDateInputValue, parseDatePreservingDateOnly, getFieldValue, extractArray, getErrorMessage, cssEscape, getTimeManagementRows, isTimeManagementSaveEnabled, getTimeManagementPendingChanges, createTimeManagementSavePayload, isNonServiceRequestSrNumber, normalizeInfoWeekResponse, normalizeTimeManagementServiceRequests, mergeTimeManagementServiceRequests, normalizeTimeManagementEntryRows, normalizeTimeManagementEntryRowSelection, getActivityRequestSrNumbers, normalizeActivityRequest, normalizeActivityRequestDetails, normalizeTaskTypeRequest, getTimeManagementTaskTypeOptions, getTimeManagementActivityOptions, findTimeManagementServiceRequest, findOptionValue, }); const { toggleTimeManagementDatePicker, shiftTimeManagementDatePickerMonth, selectTimeManagementDate, shiftTimeManagementDateByWeeks, openTimeManagementModal, loadTimeManagementData, addTimeManagementEntryRow, removeTimeManagementEntryRow, updateTimeManagementSelectedSr, updateTimeManagementField, updateTimeManagementDayHours, saveTimeManagementChanges, selectTimeManagementComboboxOption, filterTimeManagementCombobox, handleTimeManagementComboboxKeydown, refreshTaskTypeCache, } = manageTimeController; workbenchController = globalThis.ArchPanelWorkbenchController.create({ appState, IDS, DETAIL_SORT_KEYS, hcmPage, workbenchRepository, comcipRepository, readCachedDataset, writeCachedDataset, readCachedWorklistToken, setStoredCalendarView, refreshTaskTypeCache, renderModal, cleanString, normalizeString, toNumber, toIsoDateString, mapWithConcurrency, getLocalDateKey, getErrorMessage, formatWholeNumber, formatProgressPercent, formatDate, teamContainsUser, stripTransientFields, createExportPayload, createDatasetSnapshot, buildRampForecastComparisonRows, parseForecastMonthNumber, createForecastUpdatePayload, normalizeTimeEntriesSummary, getCalendarAnchorDate, }); const { refreshData, hydrateDatasetFromCache, openDetailModal, openActionFormModal, openRampComparisonModal, openForecastUpdateConfirmModal, submitForecastUpdate, openTimeEntriesDrawer, shiftCalendarPeriod, goToCurrentCalendarPeriod, setCalendarView, submitActionForm, toggleDetailSort, } = workbenchController; modalEvents = globalThis.ArchPanelModalEvents.create({ appState, renderModal, closeModal, closeDetailModal, toggleTheme, toggleSidebar, refreshData, shiftCalendarPeriod, goToCurrentCalendarPeriod, setCalendarView, downloadFile, createExportHtml, openDetailModal, openActionFormModal, openRampComparisonModal, openForecastUpdateConfirmModal, submitForecastUpdate, openTimeEntriesDrawer, openTimeManagementModal, addTimeManagementEntryRow, saveTimeManagementChanges, removeTimeManagementEntryRow, toggleTimeManagementDatePicker, shiftTimeManagementDateByWeeks, shiftTimeManagementDatePickerMonth, selectTimeManagementDate, selectTimeManagementComboboxOption, submitActionForm, toggleDetailSort, loadTimeManagementData, updateTimeManagementSelectedSr, updateTimeManagementField, updateTimeManagementDayHours, filterTimeManagementCombobox, handleTimeManagementComboboxKeydown, }); function openModal() { const overlay = ensureModal(); if (!overlay) { return; } window.clearTimeout(closeTimer); restoreFocusTarget = document.activeElement instanceof HTMLElement ? document.activeElement : null; overlay.hidden = false; overlay.setAttribute("aria-hidden", "false"); lockScroll(); window.requestAnimationFrame(() => { overlay.classList.add(CLASSES.overlayOpen); const primaryAction = overlay.querySelector("[data-action='close']"); primaryAction?.focus(); }); if (!appState.dataset && appState.status !== "loading") { void hydrateDatasetFromCache(); } } function closeModal() { const overlay = document.getElementById(IDS.overlay); if (!overlay || overlay.hidden) { return; } overlay.classList.remove(CLASSES.overlayOpen); overlay.setAttribute("aria-hidden", "true"); unlockScroll(); appState.detailModal = null; appState.actionFormModal = null; appState.rampComparisonModal = null; appState.forecastUpdateConfirmModal = null; appState.timeEntriesDrawer = null; appState.timeManagementModal = null; if (restoreFocusTarget && restoreFocusTarget.isConnected) { restoreFocusTarget.focus(); } restoreFocusTarget = null; window.clearTimeout(closeTimer); closeTimer = window.setTimeout(() => { overlay.hidden = true; }, 160); } function closeDetailModal() { if (appState.detailModal?.scope === "calendar-day" && appState.detailModal.value) { appState.pendingFocusSelector = getCalendarDayFocusSelector( appState.detailModal.value ); } appState.detailModal = null; appState.timeEntriesDrawer = null; appState.timeManagementModal = null; appState.rampComparisonModal = null; appState.forecastUpdateConfirmModal = null; } function downloadFile(filename, content, contentType) { const blob = new Blob([content], { type: contentType }); const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = filename; anchor.click(); window.setTimeout(() => { URL.revokeObjectURL(url); }, 1000); } function toggleTheme() { appState.theme = appState.theme === "dark" ? "light" : "dark"; setStoredTheme(appState.theme); renderModal(); } function toggleSidebar() { appState.sidebarCollapsed = !appState.sidebarCollapsed; setStoredSidebarCollapsed(appState.sidebarCollapsed); renderModal(); } function removeModal() { const overlay = document.getElementById(IDS.overlay); window.clearTimeout(closeTimer); restoreFocusTarget = null; if (overlay) { overlay.remove(); } } function handleGlobalKeydown(event) { if (event.key !== "Escape") { return; } if (appState.actionFormModal) { appState.actionFormModal = null; renderModal(); return; } if (appState.timeManagementModal) { appState.timeManagementModal = null; renderModal(); return; } if (appState.forecastUpdateConfirmModal) { appState.forecastUpdateConfirmModal = null; renderModal(); return; } if (appState.rampComparisonModal) { appState.rampComparisonModal = null; renderModal(); return; } if (appState.timeEntriesDrawer) { appState.timeEntriesDrawer = null; renderModal(); return; } if (appState.detailModal) { closeDetailModal(); renderModal(); return; } closeModal(); } function observePage() { const observer = new MutationObserver(() => { scheduleSync(); }); observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ["src"], }); } function observeHistory() { const { pushState, replaceState } = window.history; window.history.pushState = function pushStatePatched(...args) { const result = pushState.apply(this, args); scheduleSync(); return result; }; window.history.replaceState = function replaceStatePatched(...args) { const result = replaceState.apply(this, args); scheduleSync(); return result; }; window.addEventListener("popstate", scheduleSync); window.addEventListener("hashchange", scheduleSync); } function observeWorklistPageLoadToken() { if (!isHcmWelcomePage()) { return; } const syncLoadedToken = () => { hcmPage.syncWorklistIframeToken({ force: true }); }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", syncLoadedToken, { once: true }); } else { syncLoadedToken(); } window.addEventListener("load", syncLoadedToken); window.addEventListener("pageshow", syncLoadedToken); } function observeSpaFrameLifecycle() { if (!isHcmWelcomePage()) { return; } if (appState.spaFrameLifecycleIntervalId) { return; } const syncFrame = () => { void ensureSpaFrame().catch((error) => { appState.lastSpaFrameLifecycleError = error instanceof Error ? error.message : String(error); }); }; const stopSyncFrame = () => { if (!appState.spaFrameLifecycleIntervalId) { return; } window.clearInterval(appState.spaFrameLifecycleIntervalId); appState.spaFrameLifecycleIntervalId = null; }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", syncFrame, { once: true }); } else { syncFrame(); } window.addEventListener("load", syncFrame); window.addEventListener("pageshow", syncFrame); window.addEventListener("pagehide", stopSyncFrame); window.addEventListener("beforeunload", stopSyncFrame); appState.spaFrameLifecycleIntervalId = window.setInterval(syncFrame, 15000); } window.addEventListener("message", handleBridgeMessage); document.addEventListener("keydown", handleGlobalKeydown); void ensurePageBridge(); observePage(); observeHistory(); observeWorklistPageLoadToken(); observeSpaFrameLifecycle(); scheduleSync(); })();