(() => {
const {
TARGET_ORIGIN,
TARGET_PATHNAME,
TARGET_PARAM,
TARGET_PARAM_VALUE,
TARGET_APP_URL,
HCM_ORIGIN,
HCM_WELCOME_PATHNAME,
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,
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,
});
const hcmPage = globalThis.ArchPanelHcmPage.create({
HCM_MY_INFORMATION_APPS_GROUP_ID,
WORKLIST_ORIGIN,
WORKLIST_SAASUI_PATHNAME,
IDS,
cleanString,
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(),
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 (
currentUrl.origin === HCM_ORIGIN &&
currentUrl.pathname === HCM_WELCOME_PATHNAME
);
}
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;
}
hcmTile?.remove();
const header = document.querySelector(SELECTORS.header);
const functionsContainer = header?.querySelector(SELECTORS.functions);
const anchor = functionsContainer ? findUserAnchor(functionsContainer) : null;
if (!header || !functionsContainer) {
return;
}
ensureStyles();
const themedMount = mount ?? createMount();
const overlay = ensureModal();
applyTheme(header, functionsContainer, anchor, themedMount, overlay);
const targetSibling = resolveInsertionTarget(
functionsContainer,
anchor,
themedMount
);
if (
themedMount.parentElement !== functionsContainer ||
themedMount.nextElementSibling !== targetSibling
) {
const verifiedTarget =
targetSibling && targetSibling.parentElement === functionsContainer
? targetSibling
: null;
if (verifiedTarget) {
functionsContainer.insertBefore(themedMount, verifiedTarget);
} else {
functionsContainer.appendChild(themedMount);
}
}
}
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);
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"
) {
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 `
${renderMainContent()}
${renderDetailModal()}
${renderActionFormModal()}
${renderRampComparisonModal()}
${renderForecastUpdateConfirmModal()}
${renderTimeEntriesDrawer()}
${renderTimeManagementModal()}
`;
}
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,
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,
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,
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();
})();