Implementação do tooltip nas SRs do Manage time
This commit is contained in:
@@ -358,6 +358,11 @@
|
|||||||
overlay.addEventListener("change", modalEvents.handleOverlayChange);
|
overlay.addEventListener("change", modalEvents.handleOverlayChange);
|
||||||
overlay.addEventListener("input", modalEvents.handleOverlayInput);
|
overlay.addEventListener("input", modalEvents.handleOverlayInput);
|
||||||
overlay.addEventListener("keydown", modalEvents.handleOverlayKeydown);
|
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);
|
document.body.appendChild(overlay);
|
||||||
renderModal();
|
renderModal();
|
||||||
@@ -633,6 +638,7 @@
|
|||||||
normalizeTimeManagementEntryRowSelection,
|
normalizeTimeManagementEntryRowSelection,
|
||||||
getActivityRequestSrNumbers,
|
getActivityRequestSrNumbers,
|
||||||
normalizeActivityRequest,
|
normalizeActivityRequest,
|
||||||
|
normalizeActivityRequestDetails,
|
||||||
normalizeTaskTypeRequest,
|
normalizeTaskTypeRequest,
|
||||||
getTimeManagementTaskTypeOptions,
|
getTimeManagementTaskTypeOptions,
|
||||||
getTimeManagementActivityOptions,
|
getTimeManagementActivityOptions,
|
||||||
@@ -787,6 +793,7 @@
|
|||||||
normalizeTimeManagementEntryRowSelection,
|
normalizeTimeManagementEntryRowSelection,
|
||||||
getActivityRequestSrNumbers,
|
getActivityRequestSrNumbers,
|
||||||
normalizeActivityRequest,
|
normalizeActivityRequest,
|
||||||
|
normalizeActivityRequestDetails,
|
||||||
normalizeTaskTypeRequest,
|
normalizeTaskTypeRequest,
|
||||||
getTimeManagementTaskTypeOptions,
|
getTimeManagementTaskTypeOptions,
|
||||||
getTimeManagementActivityOptions,
|
getTimeManagementActivityOptions,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
normalizeTimeManagementEntryRowSelection,
|
normalizeTimeManagementEntryRowSelection,
|
||||||
getActivityRequestSrNumbers,
|
getActivityRequestSrNumbers,
|
||||||
normalizeActivityRequest,
|
normalizeActivityRequest,
|
||||||
|
normalizeActivityRequestDetails,
|
||||||
normalizeTaskTypeRequest,
|
normalizeTaskTypeRequest,
|
||||||
getTimeManagementTaskTypeOptions,
|
getTimeManagementTaskTypeOptions,
|
||||||
getTimeManagementActivityOptions,
|
getTimeManagementActivityOptions,
|
||||||
@@ -162,6 +163,10 @@
|
|||||||
activityPayload,
|
activityPayload,
|
||||||
serviceRequests
|
serviceRequests
|
||||||
);
|
);
|
||||||
|
const activityRequestDetailsBySr = normalizeActivityRequestDetails(
|
||||||
|
activityPayload,
|
||||||
|
serviceRequests
|
||||||
|
);
|
||||||
const taskTypes = normalizeTaskTypeRequest(taskTypePayload);
|
const taskTypes = normalizeTaskTypeRequest(taskTypePayload);
|
||||||
const rows = timeEntryRows;
|
const rows = timeEntryRows;
|
||||||
const selectedSrNumber = rows[0]?.selectedSrNumber || "";
|
const selectedSrNumber = rows[0]?.selectedSrNumber || "";
|
||||||
@@ -188,6 +193,7 @@
|
|||||||
serviceRequests,
|
serviceRequests,
|
||||||
selectedSrNumber,
|
selectedSrNumber,
|
||||||
activityOptionsBySr,
|
activityOptionsBySr,
|
||||||
|
activityRequestDetailsBySr,
|
||||||
activityRequestUrl,
|
activityRequestUrl,
|
||||||
activityRequestPayload: activityPayload,
|
activityRequestPayload: activityPayload,
|
||||||
timeEntryRows: normalizedRows,
|
timeEntryRows: normalizedRows,
|
||||||
@@ -227,6 +233,7 @@
|
|||||||
serviceRequests: [],
|
serviceRequests: [],
|
||||||
selectedSrNumber: "",
|
selectedSrNumber: "",
|
||||||
activityOptionsBySr: {},
|
activityOptionsBySr: {},
|
||||||
|
activityRequestDetailsBySr: {},
|
||||||
activityRequestUrl: "",
|
activityRequestUrl: "",
|
||||||
activityRequestPayload: null,
|
activityRequestPayload: null,
|
||||||
selectedActivityValue: "",
|
selectedActivityValue: "",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
filterTimeManagementCombobox,
|
filterTimeManagementCombobox,
|
||||||
handleTimeManagementComboboxKeydown,
|
handleTimeManagementComboboxKeydown,
|
||||||
} = dependencies;
|
} = dependencies;
|
||||||
|
let timeManagementTooltipHideTimer = 0;
|
||||||
|
|
||||||
function handleOverlayClick(event) {
|
function handleOverlayClick(event) {
|
||||||
const overlay = document.getElementById(
|
const overlay = document.getElementById(
|
||||||
@@ -70,6 +71,16 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
event.target instanceof HTMLInputElement &&
|
||||||
|
event.target.getAttribute("data-combobox-field")
|
||||||
|
) {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
positionTimeManagementCombobox(event.target);
|
||||||
|
scrollSelectedTimeManagementComboboxOptionIntoView(event.target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const actionElement = event.target.closest("[data-action]");
|
const actionElement = event.target.closest("[data-action]");
|
||||||
|
|
||||||
if (!actionElement) {
|
if (!actionElement) {
|
||||||
@@ -87,6 +98,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
action === "time-management-combobox-option" &&
|
||||||
|
event.target?.closest?.(".arch-panel-extension-service-request-tooltip")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (action === "close") {
|
if (action === "close") {
|
||||||
@@ -406,6 +424,134 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
filterTimeManagementCombobox(target);
|
filterTimeManagementCombobox(target);
|
||||||
|
positionTimeManagementCombobox(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOverlayFocusIn(event) {
|
||||||
|
const target = event.target;
|
||||||
|
|
||||||
|
if (
|
||||||
|
target instanceof HTMLInputElement &&
|
||||||
|
target.getAttribute("data-combobox-field")
|
||||||
|
) {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
clearTimeManagementComboboxTooltipOptions(
|
||||||
|
target.closest(".arch-panel-extension-combobox")
|
||||||
|
);
|
||||||
|
hideTimeManagementServiceRequestTooltipPortal();
|
||||||
|
positionTimeManagementCombobox(target);
|
||||||
|
scrollSelectedTimeManagementComboboxOptionIntoView(target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOverlayPointerOver(event) {
|
||||||
|
const portal = event.target?.closest?.(
|
||||||
|
".arch-panel-extension-service-request-tooltip-portal"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (portal instanceof HTMLElement) {
|
||||||
|
clearTimeManagementTooltipHideTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = event.target?.closest?.(
|
||||||
|
".arch-panel-extension-combobox-option.has-tooltip"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (option instanceof HTMLElement) {
|
||||||
|
setActiveTimeManagementComboboxTooltipOption(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOverlayPointerMove(event) {
|
||||||
|
if (
|
||||||
|
event.target?.closest?.(".arch-panel-extension-service-request-tooltip-portal")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = event.target?.closest?.(
|
||||||
|
".arch-panel-extension-combobox-option.has-tooltip"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (option instanceof HTMLElement) {
|
||||||
|
setActiveTimeManagementComboboxTooltipOption(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOverlayPointerOut(event) {
|
||||||
|
const portal = event.target?.closest?.(
|
||||||
|
".arch-panel-extension-service-request-tooltip-portal"
|
||||||
|
);
|
||||||
|
const nextTarget = event.relatedTarget;
|
||||||
|
|
||||||
|
if (portal instanceof HTMLElement) {
|
||||||
|
if (nextTarget instanceof Node && portal.contains(nextTarget)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleTimeManagementTooltipHide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu = event.target?.closest?.(
|
||||||
|
".arch-panel-extension-combobox-menu.has-service-request-tooltips"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!(menu instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextTarget instanceof Node && menu.contains(nextTarget)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleTimeManagementTooltipHide(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleTimeManagementTooltipHide(menu = null) {
|
||||||
|
clearTimeManagementTooltipHideTimer();
|
||||||
|
timeManagementTooltipHideTimer = window.setTimeout(() => {
|
||||||
|
const portal = getTimeManagementServiceRequestTooltipPortal(false);
|
||||||
|
const hoveredOption = menu
|
||||||
|
? menu.querySelector(".arch-panel-extension-combobox-option.has-tooltip:hover")
|
||||||
|
: document.querySelector(".arch-panel-extension-combobox-option.has-tooltip:hover");
|
||||||
|
|
||||||
|
if (
|
||||||
|
!hoveredOption &&
|
||||||
|
!(portal instanceof HTMLElement && portal.matches(":hover"))
|
||||||
|
) {
|
||||||
|
clearTimeManagementComboboxTooltipOptions(menu || document.body);
|
||||||
|
hideTimeManagementServiceRequestTooltipPortal();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearTimeManagementTooltipHideTimer() {
|
||||||
|
if (timeManagementTooltipHideTimer) {
|
||||||
|
window.clearTimeout(timeManagementTooltipHideTimer);
|
||||||
|
timeManagementTooltipHideTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOverlayScroll(event) {
|
||||||
|
const menu = event.target;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(menu instanceof HTMLElement) ||
|
||||||
|
!menu.classList.contains("arch-panel-extension-combobox-menu")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeOption = menu.querySelector(
|
||||||
|
".arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (activeOption instanceof HTMLElement) {
|
||||||
|
positionTimeManagementComboboxOptionTooltip(activeOption);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOverlayKeydown(event) {
|
function handleOverlayKeydown(event) {
|
||||||
@@ -435,6 +581,188 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleTimeManagementComboboxKeydown(event, target);
|
handleTimeManagementComboboxKeydown(event, target);
|
||||||
|
positionTimeManagementCombobox(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function positionTimeManagementCombobox(input) {
|
||||||
|
const combobox = input.closest(".arch-panel-extension-combobox");
|
||||||
|
const menu = combobox?.querySelector(".arch-panel-extension-combobox-menu");
|
||||||
|
|
||||||
|
if (!(combobox instanceof HTMLElement) || !(menu instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputRect = input.getBoundingClientRect();
|
||||||
|
const margin = 16;
|
||||||
|
const gap = 6;
|
||||||
|
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||||
|
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||||
|
const spaceBelow = viewportHeight - inputRect.bottom - margin - gap;
|
||||||
|
const spaceAbove = inputRect.top - margin - gap;
|
||||||
|
const hasServiceRequestTooltips = menu.classList.contains(
|
||||||
|
"has-service-request-tooltips"
|
||||||
|
);
|
||||||
|
const openAbove = spaceBelow < 240 && spaceAbove > spaceBelow;
|
||||||
|
const availableHeight = Math.max(180, (openAbove ? spaceAbove : spaceBelow) - 12);
|
||||||
|
const desiredHeight = hasServiceRequestTooltips ? 430 : 260;
|
||||||
|
const menuWidth = hasServiceRequestTooltips
|
||||||
|
? Math.min(1120, Math.max(inputRect.width, viewportWidth - inputRect.left - margin))
|
||||||
|
: inputRect.width;
|
||||||
|
|
||||||
|
menu.style.top = openAbove ? "auto" : `calc(100% + ${gap}px)`;
|
||||||
|
menu.style.bottom = openAbove ? `calc(100% + ${gap}px)` : "auto";
|
||||||
|
menu.style.maxHeight = `${Math.min(desiredHeight, availableHeight)}px`;
|
||||||
|
menu.style.width = `${menuWidth}px`;
|
||||||
|
menu.style.maxWidth = `calc(100vw - ${Math.max(margin * 2, inputRect.left + margin)}px)`;
|
||||||
|
|
||||||
|
const activeOption = menu.querySelector(
|
||||||
|
".arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active, .arch-panel-extension-combobox-option.has-tooltip:hover, .arch-panel-extension-combobox-option.has-tooltip:focus, .arch-panel-extension-combobox-option.has-tooltip.is-active"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (activeOption instanceof HTMLElement) {
|
||||||
|
setActiveTimeManagementComboboxTooltipOption(activeOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollSelectedTimeManagementComboboxOptionIntoView(input) {
|
||||||
|
const combobox = input.closest(".arch-panel-extension-combobox");
|
||||||
|
const menu = combobox?.querySelector(".arch-panel-extension-combobox-menu");
|
||||||
|
const selectedOption = menu?.querySelector(
|
||||||
|
".arch-panel-extension-combobox-option.is-selected:not([hidden])"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!(menu instanceof HTMLElement) || !(selectedOption instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetScrollTop =
|
||||||
|
selectedOption.offsetTop -
|
||||||
|
Math.max(0, (menu.clientHeight - selectedOption.offsetHeight) / 2);
|
||||||
|
|
||||||
|
menu.scrollTop = Math.max(0, targetScrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveTimeManagementComboboxTooltipOption(option) {
|
||||||
|
const menu = option.closest(".arch-panel-extension-combobox-menu");
|
||||||
|
|
||||||
|
if (!(menu instanceof HTMLElement) || option.hidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeManagementComboboxTooltipOptions(menu, option);
|
||||||
|
option.classList.add("is-tooltip-active");
|
||||||
|
positionTimeManagementComboboxOptionTooltip(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearTimeManagementComboboxTooltipOptions(root, exceptOption = null) {
|
||||||
|
if (!(root instanceof Element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root
|
||||||
|
.querySelectorAll(".arch-panel-extension-combobox-option.is-tooltip-active")
|
||||||
|
.forEach((item) => {
|
||||||
|
if (item !== exceptOption) {
|
||||||
|
item.classList.remove("is-tooltip-active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function positionTimeManagementComboboxOptionTooltip(option) {
|
||||||
|
const menu = option.closest(".arch-panel-extension-combobox-menu");
|
||||||
|
const tooltip = option.querySelector(
|
||||||
|
".arch-panel-extension-service-request-tooltip"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!(menu instanceof HTMLElement) || !(tooltip instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuRect = menu.getBoundingClientRect();
|
||||||
|
const optionRect = option.getBoundingClientRect();
|
||||||
|
const padding = 10;
|
||||||
|
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||||
|
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||||
|
const portal = getTimeManagementServiceRequestTooltipPortal();
|
||||||
|
|
||||||
|
if (!(portal instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tooltipWidth = Math.min(
|
||||||
|
420,
|
||||||
|
Math.max(320, Math.min(menuRect.width * 0.38, viewportWidth - padding * 2))
|
||||||
|
);
|
||||||
|
const reservedTextWidth = tooltipWidth + 28;
|
||||||
|
const maxTooltipHeight = Math.max(180, Math.min(380, viewportHeight - padding * 2));
|
||||||
|
const optionCenter = optionRect.top + optionRect.height / 2;
|
||||||
|
const availableRight = viewportWidth - optionRect.right - padding * 2;
|
||||||
|
const availableLeft = optionRect.left - padding * 2;
|
||||||
|
const verticalPadding = 12;
|
||||||
|
|
||||||
|
portal.innerHTML = tooltip.innerHTML;
|
||||||
|
portal.style.width = `${tooltipWidth}px`;
|
||||||
|
portal.style.maxHeight = `${maxTooltipHeight}px`;
|
||||||
|
portal.classList.add("is-visible");
|
||||||
|
|
||||||
|
const tooltipHeight = Math.min(
|
||||||
|
maxTooltipHeight,
|
||||||
|
Math.max(120, portal.getBoundingClientRect().height || portal.scrollHeight)
|
||||||
|
);
|
||||||
|
const preferredRight = Math.min(
|
||||||
|
menuRect.right - tooltipWidth - padding,
|
||||||
|
viewportWidth - tooltipWidth - padding
|
||||||
|
);
|
||||||
|
const preferredLeft = menuRect.left + padding;
|
||||||
|
const hasRoomOnRight = availableRight >= tooltipWidth;
|
||||||
|
const hasRoomOnLeft = availableLeft >= tooltipWidth;
|
||||||
|
const tooltipLeft = hasRoomOnRight
|
||||||
|
? optionRect.right + padding
|
||||||
|
: hasRoomOnLeft
|
||||||
|
? optionRect.left - padding - tooltipWidth
|
||||||
|
: Math.max(padding, Math.min(preferredRight, preferredLeft));
|
||||||
|
const tooltipTop = Math.max(
|
||||||
|
verticalPadding,
|
||||||
|
Math.min(
|
||||||
|
optionCenter - tooltipHeight / 2,
|
||||||
|
viewportHeight - tooltipHeight - verticalPadding
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
portal.style.top = `${tooltipTop}px`;
|
||||||
|
portal.style.left = `${tooltipLeft}px`;
|
||||||
|
portal.style.right = "auto";
|
||||||
|
portal.style.bottom = "auto";
|
||||||
|
portal.style.maxHeight = `${Math.min(maxTooltipHeight, viewportHeight - tooltipTop - verticalPadding)}px`;
|
||||||
|
menu.style.setProperty(
|
||||||
|
"--arch-service-request-tooltip-reserved-width",
|
||||||
|
`${reservedTextWidth}px`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeManagementServiceRequestTooltipPortal(createIfMissing = true) {
|
||||||
|
const overlay = document.getElementById(globalThis.ArchPanelConfig.IDS.overlay);
|
||||||
|
let portal = overlay?.querySelector(
|
||||||
|
".arch-panel-extension-service-request-tooltip-portal"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!portal && createIfMissing && overlay) {
|
||||||
|
portal = document.createElement("div");
|
||||||
|
portal.className =
|
||||||
|
"arch-panel-extension-service-request-tooltip arch-panel-extension-service-request-tooltip-portal";
|
||||||
|
portal.setAttribute("role", "tooltip");
|
||||||
|
overlay.appendChild(portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return portal;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideTimeManagementServiceRequestTooltipPortal() {
|
||||||
|
const portal = getTimeManagementServiceRequestTooltipPortal(false);
|
||||||
|
|
||||||
|
if (portal instanceof HTMLElement) {
|
||||||
|
portal.classList.remove("is-visible");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTimeManagementHourKeydown(event, input) {
|
function handleTimeManagementHourKeydown(event, input) {
|
||||||
@@ -524,6 +852,11 @@
|
|||||||
handleOverlayChange,
|
handleOverlayChange,
|
||||||
handleOverlayInput,
|
handleOverlayInput,
|
||||||
handleOverlayKeydown,
|
handleOverlayKeydown,
|
||||||
|
handleOverlayFocusIn,
|
||||||
|
handleOverlayPointerOver,
|
||||||
|
handleOverlayPointerMove,
|
||||||
|
handleOverlayPointerOut,
|
||||||
|
handleOverlayScroll,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1619,6 +1619,8 @@ body.arch-panel-extension-modal-open {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.arch-panel-extension-time-management-card {
|
.arch-panel-extension-time-management-card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
--arch-time-management-scrollbar-gutter: 16px;
|
--arch-time-management-scrollbar-gutter: 16px;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
@@ -1630,6 +1632,10 @@ body.arch-panel-extension-modal-open {
|
|||||||
border-color: rgba(217, 79, 43, 0.42);
|
border-color: rgba(217, 79, 43, 0.42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-time-management-card:has(.arch-panel-extension-combobox:focus-within) {
|
||||||
|
z-index: 40;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-time-management-toolbar {
|
.arch-panel-extension-time-management-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
@@ -1875,6 +1881,10 @@ body.arch-panel-extension-modal-open {
|
|||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-time-management-rows:has(.arch-panel-extension-combobox-option.has-tooltip:hover) {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-time-management-empty {
|
.arch-panel-extension-time-management-empty {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -1901,6 +1911,7 @@ body.arch-panel-extension-modal-open {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.arch-panel-extension-time-management-entry-row {
|
.arch-panel-extension-time-management-entry-row {
|
||||||
|
position: relative;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns:
|
grid-template-columns:
|
||||||
minmax(420px, 3.8fr)
|
minmax(420px, 3.8fr)
|
||||||
@@ -1912,6 +1923,10 @@ body.arch-panel-extension-modal-open {
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-time-management-entry-row:has(.arch-panel-extension-combobox:focus-within) {
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-time-management-entry-row.is-compact {
|
.arch-panel-extension-time-management-entry-row.is-compact {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -1950,9 +1965,14 @@ body.arch-panel-extension-modal-open {
|
|||||||
|
|
||||||
.arch-panel-extension-combobox {
|
.arch-panel-extension-combobox {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox:focus-within {
|
||||||
|
z-index: 70;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-combobox input {
|
.arch-panel-extension-combobox input {
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
@@ -1991,6 +2011,13 @@ body.arch-panel-extension-modal-open {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-value-text {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-combobox:focus-within .arch-panel-extension-combobox-value {
|
.arch-panel-extension-combobox:focus-within .arch-panel-extension-combobox-value {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -2042,9 +2069,10 @@ body.arch-panel-extension-modal-open {
|
|||||||
.arch-panel-extension-combobox-menu {
|
.arch-panel-extension-combobox-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% + 6px);
|
top: calc(100% + 6px);
|
||||||
|
bottom: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 10000;
|
z-index: 2147483000;
|
||||||
display: none;
|
display: none;
|
||||||
max-height: 260px;
|
max-height: 260px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -2055,6 +2083,15 @@ body.arch-panel-extension-modal-open {
|
|||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips {
|
||||||
|
right: auto;
|
||||||
|
width: min(1120px, calc(100vw - 72px));
|
||||||
|
max-height: min(58vh, 430px);
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
scroll-padding-block: 10px 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-combobox:focus-within .arch-panel-extension-combobox-menu {
|
.arch-panel-extension-combobox:focus-within .arch-panel-extension-combobox-menu {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
@@ -2126,12 +2163,202 @@ body.arch-panel-extension-modal-open {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip.is-selected::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-combobox-empty {
|
.arch-panel-extension-combobox-empty {
|
||||||
color: var(--wb-text-muted);
|
color: var(--wb-text-muted);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 8px 9px;
|
padding: 8px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip {
|
||||||
|
--arch-tooltip-panel: var(--wb-panel, #ffffff);
|
||||||
|
--arch-tooltip-border: var(--wb-border-strong, #c8c8c8);
|
||||||
|
--arch-tooltip-text: var(--wb-text, #1f1f1f);
|
||||||
|
--arch-tooltip-muted: var(--wb-text-muted, #6f7782);
|
||||||
|
--arch-tooltip-link: var(--wb-link, #006b9a);
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
left: 10px;
|
||||||
|
z-index: 2147483647;
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
width: 420px;
|
||||||
|
max-width: min(420px, calc(100vw - 96px));
|
||||||
|
max-height: min(360px, calc(100vh - 20px));
|
||||||
|
overflow: auto;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: auto;
|
||||||
|
border: 1px solid var(--arch-tooltip-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--arch-tooltip-panel);
|
||||||
|
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.24);
|
||||||
|
color: var(--arch-tooltip-text);
|
||||||
|
padding: 12px;
|
||||||
|
transform: translateY(4px);
|
||||||
|
transition:
|
||||||
|
opacity 120ms ease 500ms,
|
||||||
|
transform 120ms ease 500ms,
|
||||||
|
visibility 0ms linear 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip > .arch-panel-extension-service-request-tooltip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-portal.is-visible {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
transition-delay: 0ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip:hover .arch-panel-extension-service-request-tooltip,
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip:focus .arch-panel-extension-service-request-tooltip,
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active .arch-panel-extension-service-request-tooltip {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
transition-delay: 0ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip:hover)
|
||||||
|
.arch-panel-extension-combobox-option-main,
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip:focus)
|
||||||
|
.arch-panel-extension-combobox-option-main,
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active)
|
||||||
|
.arch-panel-extension-combobox-option-main {
|
||||||
|
max-width: calc(100% - var(--arch-service-request-tooltip-reserved-width, 448px));
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-title {
|
||||||
|
display: block;
|
||||||
|
color: var(--arch-tooltip-text);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(110px, 0.42fr) minmax(0, 1fr);
|
||||||
|
gap: 7px 10px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-label {
|
||||||
|
color: var(--arch-tooltip-muted);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.35;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-value {
|
||||||
|
min-width: 0;
|
||||||
|
color: var(--arch-tooltip-text);
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-excerpt {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-more {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-more summary {
|
||||||
|
width: max-content;
|
||||||
|
color: var(--arch-tooltip-link);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-more summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-more[open] summary {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip-value:has(.arch-panel-extension-service-request-tooltip-more[open])
|
||||||
|
.arch-panel-extension-service-request-tooltip-excerpt {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1180px) {
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips {
|
||||||
|
width: min(760px, calc(100vw - 48px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip {
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
left: 10px;
|
||||||
|
width: min(340px, calc(100% - 24px));
|
||||||
|
transform: translateY(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip:hover)
|
||||||
|
.arch-panel-extension-combobox-option-main,
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip:focus)
|
||||||
|
.arch-panel-extension-combobox-option-main,
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active)
|
||||||
|
.arch-panel-extension-combobox-option-main {
|
||||||
|
max-width: calc(100% - var(--arch-service-request-tooltip-reserved-width, 368px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip:hover .arch-panel-extension-service-request-tooltip,
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip:focus .arch-panel-extension-service-request-tooltip,
|
||||||
|
.arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active .arch-panel-extension-service-request-tooltip {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips {
|
||||||
|
width: min(520px, calc(100vw - 32px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip:hover)
|
||||||
|
.arch-panel-extension-combobox-option-main,
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip:focus)
|
||||||
|
.arch-panel-extension-combobox-option-main,
|
||||||
|
.arch-panel-extension-combobox-menu.has-service-request-tooltips:has(.arch-panel-extension-combobox-option.has-tooltip.is-tooltip-active)
|
||||||
|
.arch-panel-extension-combobox-option-main {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arch-panel-extension-service-request-tooltip {
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
left: 8px;
|
||||||
|
width: min(420px, calc(100vw - 48px));
|
||||||
|
max-height: min(320px, calc(100vh - 120px));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.arch-panel-extension-time-management-days {
|
.arch-panel-extension-time-management-days {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(7, minmax(110px, 1fr));
|
grid-template-columns: repeat(7, minmax(110px, 1fr));
|
||||||
|
|||||||
@@ -14,6 +14,34 @@
|
|||||||
getTimeManagementWeekdayName,
|
getTimeManagementWeekdayName,
|
||||||
createTimeManagementRowSignature,
|
createTimeManagementRowSignature,
|
||||||
} = dependencies;
|
} = dependencies;
|
||||||
|
const ACTIVITY_REQUEST_DETAIL_FIELDS = [
|
||||||
|
"SrNumber",
|
||||||
|
"ProblemDescription",
|
||||||
|
"AccountPartyUniqueName",
|
||||||
|
"ServiceNew_c",
|
||||||
|
"OptyOwner_c",
|
||||||
|
"OptyName_c",
|
||||||
|
"OptyNumber_c",
|
||||||
|
"ReportedByPartyUniqueName",
|
||||||
|
"StatusCdMeaning",
|
||||||
|
"CountryText_c",
|
||||||
|
"AssigneePersonName",
|
||||||
|
"OptyStatus_c",
|
||||||
|
];
|
||||||
|
const ACTIVITY_REQUEST_DETAIL_LABELS = {
|
||||||
|
SrNumber: "SR Number",
|
||||||
|
ProblemDescription: "Problem Description",
|
||||||
|
AccountPartyUniqueName: "Account",
|
||||||
|
ServiceNew_c: "Service",
|
||||||
|
OptyOwner_c: "Opportunity Owner",
|
||||||
|
OptyName_c: "Opportunity",
|
||||||
|
OptyNumber_c: "Opportunity Number",
|
||||||
|
ReportedByPartyUniqueName: "Reported By",
|
||||||
|
StatusCdMeaning: "Status",
|
||||||
|
CountryText_c: "Country",
|
||||||
|
AssigneePersonName: "Assignee",
|
||||||
|
OptyStatus_c: "Opportunity Status",
|
||||||
|
};
|
||||||
|
|
||||||
function normalizeInfoWeekResponse(payload) {
|
function normalizeInfoWeekResponse(payload) {
|
||||||
return extractArray(payload, ["items", "data", "results", "content"])
|
return extractArray(payload, ["items", "data", "results", "content"])
|
||||||
@@ -275,16 +303,7 @@
|
|||||||
|
|
||||||
function normalizeActivityRequest(payload, serviceRequests) {
|
function normalizeActivityRequest(payload, serviceRequests) {
|
||||||
const activityOptionsBySr = {};
|
const activityOptionsBySr = {};
|
||||||
const activityItemsBySr = new Map();
|
const activityItemsBySr = getActivityRequestItemsBySr(payload);
|
||||||
|
|
||||||
for (const item of extractArray(payload, ["items", "data", "results", "content"])) {
|
|
||||||
const srNumber = cleanString(getFieldValue(item, ["SrNumber", "srNumber"]));
|
|
||||||
const srKey = normalizeString(srNumber);
|
|
||||||
|
|
||||||
if (srKey && !activityItemsBySr.has(srKey)) {
|
|
||||||
activityItemsBySr.set(srKey, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const serviceRequest of serviceRequests || []) {
|
for (const serviceRequest of serviceRequests || []) {
|
||||||
const srNumber = cleanString(serviceRequest?.srNumber);
|
const srNumber = cleanString(serviceRequest?.srNumber);
|
||||||
@@ -300,6 +319,140 @@
|
|||||||
return activityOptionsBySr;
|
return activityOptionsBySr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeActivityRequestDetails(payload, serviceRequests) {
|
||||||
|
const detailsBySr = {};
|
||||||
|
const activityItemsBySr = getActivityRequestItemsBySr(payload);
|
||||||
|
const srNumbers = getActivityRequestDetailSrNumbers(
|
||||||
|
activityItemsBySr,
|
||||||
|
serviceRequests
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const srNumber of srNumbers) {
|
||||||
|
const srKey = normalizeString(srNumber);
|
||||||
|
const activityItem = activityItemsBySr.get(srKey);
|
||||||
|
const details = normalizeActivityRequestDetailRows(activityItem);
|
||||||
|
|
||||||
|
if (details.length) {
|
||||||
|
detailsBySr[srNumber] = details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return detailsBySr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActivityRequestItemsBySr(payload) {
|
||||||
|
const activityItemsBySr = new Map();
|
||||||
|
|
||||||
|
for (const item of extractArray(payload, ["items", "data", "results", "content"])) {
|
||||||
|
const srNumber = cleanString(getFieldValue(item, ["SrNumber", "srNumber"]));
|
||||||
|
const srKey = normalizeString(srNumber);
|
||||||
|
|
||||||
|
if (srKey && !activityItemsBySr.has(srKey)) {
|
||||||
|
activityItemsBySr.set(srKey, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activityItemsBySr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActivityRequestDetailSrNumbers(activityItemsBySr, serviceRequests) {
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
return [
|
||||||
|
...(serviceRequests || []).map((item) => cleanString(item?.srNumber)),
|
||||||
|
...Array.from(activityItemsBySr.values()).map((item) =>
|
||||||
|
cleanString(getFieldValue(item, ["SrNumber", "srNumber"]))
|
||||||
|
),
|
||||||
|
].filter((srNumber) => {
|
||||||
|
const key = normalizeString(srNumber);
|
||||||
|
|
||||||
|
if (!key || seen.has(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.add(key);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeActivityRequestDetailRows(item) {
|
||||||
|
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set();
|
||||||
|
const preferredRows = ACTIVITY_REQUEST_DETAIL_FIELDS.map((fieldName) =>
|
||||||
|
createActivityRequestDetailRow(fieldName, getActivityRequestDetailValue(item, fieldName))
|
||||||
|
).filter(Boolean);
|
||||||
|
const extraRows = flattenDisplayRecord(item)
|
||||||
|
.map(([fieldName, value]) => createActivityRequestDetailRow(fieldName, value))
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
return [...preferredRows, ...extraRows].filter((row) => {
|
||||||
|
const key = normalizeActivityRequestDetailKey(row.key);
|
||||||
|
|
||||||
|
if (!key || seen.has(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.add(key);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createActivityRequestDetailRow(fieldName, value) {
|
||||||
|
if (isActivityRequestDetailExcludedKey(fieldName) || isObjectLike(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const detailValue = cleanString(value);
|
||||||
|
|
||||||
|
if (!detailValue) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: cleanString(fieldName),
|
||||||
|
label: formatActivityRequestDetailLabel(fieldName),
|
||||||
|
value: detailValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActivityRequestDetailValue(item, fieldName) {
|
||||||
|
const lowerFirstFieldName = `${fieldName.charAt(0).toLowerCase()}${fieldName.slice(1)}`;
|
||||||
|
|
||||||
|
return getFieldValue(item, [fieldName, lowerFirstFieldName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActivityRequestDetailExcludedKey(fieldName) {
|
||||||
|
return normalizeActivityRequestDetailKey(fieldName).includes("SRACTIVITIESC");
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeActivityRequestDetailKey(fieldName) {
|
||||||
|
return normalizeString(fieldName).replace(/[^A-Z0-9]/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isObjectLike(value) {
|
||||||
|
return value && typeof value === "object";
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatActivityRequestDetailLabel(fieldName) {
|
||||||
|
const cleanFieldName = cleanString(fieldName);
|
||||||
|
const directLabel = ACTIVITY_REQUEST_DETAIL_LABELS[cleanFieldName];
|
||||||
|
|
||||||
|
if (directLabel) {
|
||||||
|
return directLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleanFieldName
|
||||||
|
.split(".")
|
||||||
|
.pop()
|
||||||
|
.replace(/_c$/i, "")
|
||||||
|
.replace(/_/g, " ")
|
||||||
|
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeSrActivityFieldOptions(item) {
|
function normalizeSrActivityFieldOptions(item) {
|
||||||
const activityText = firstNonEmptyString([
|
const activityText = firstNonEmptyString([
|
||||||
getFieldValue(item, ["SRActivities_c", "srActivities_c"]),
|
getFieldValue(item, ["SRActivities_c", "srActivities_c"]),
|
||||||
@@ -811,6 +964,7 @@
|
|||||||
normalizeTimeManagementEntryRowSelection,
|
normalizeTimeManagementEntryRowSelection,
|
||||||
getActivityRequestSrNumbers,
|
getActivityRequestSrNumbers,
|
||||||
normalizeActivityRequest,
|
normalizeActivityRequest,
|
||||||
|
normalizeActivityRequestDetails,
|
||||||
normalizeTaskTypeRequest,
|
normalizeTaskTypeRequest,
|
||||||
getTimeManagementTaskTypeOptions,
|
getTimeManagementTaskTypeOptions,
|
||||||
getTimeManagementActivityOptions,
|
getTimeManagementActivityOptions,
|
||||||
|
|||||||
@@ -228,17 +228,12 @@
|
|||||||
<div class="arch-panel-extension-time-management-entry-row is-compact${isHighlighted ? " is-duplicate-highlight" : ""}" data-row-id="${escapeHtml(rowId)}">
|
<div class="arch-panel-extension-time-management-entry-row is-compact${isHighlighted ? " is-duplicate-highlight" : ""}" data-row-id="${escapeHtml(rowId)}">
|
||||||
<input type="hidden" name="timeEntryId" value="${escapeHtml(row?.timeEntryId || "")}">
|
<input type="hidden" name="timeEntryId" value="${escapeHtml(row?.timeEntryId || "")}">
|
||||||
<label class="arch-panel-extension-form-field">
|
<label class="arch-panel-extension-form-field">
|
||||||
${renderSearchableCombobox({
|
${renderTimeManagementServiceRequestField({
|
||||||
field: "sr",
|
modal,
|
||||||
rowId,
|
rowId,
|
||||||
selectedValue: selectedSr,
|
selectedSr,
|
||||||
value: selectedSrLabel,
|
selectedSrLabel,
|
||||||
placeholder: "Search SR",
|
isNonServiceRequest,
|
||||||
options: modal.serviceRequests || [],
|
|
||||||
valueKey: "srNumber",
|
|
||||||
labelKey: "label",
|
|
||||||
fallbackLabelKey: "srTitle",
|
|
||||||
disabled: isNonServiceRequest,
|
|
||||||
})}
|
})}
|
||||||
</label>
|
</label>
|
||||||
<label class="arch-panel-extension-form-field">
|
<label class="arch-panel-extension-form-field">
|
||||||
@@ -288,6 +283,101 @@
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderTimeManagementServiceRequestField({
|
||||||
|
modal,
|
||||||
|
rowId,
|
||||||
|
selectedSr,
|
||||||
|
selectedSrLabel,
|
||||||
|
isNonServiceRequest,
|
||||||
|
}) {
|
||||||
|
return renderSearchableCombobox({
|
||||||
|
field: "sr",
|
||||||
|
rowId,
|
||||||
|
selectedValue: selectedSr,
|
||||||
|
value: selectedSrLabel,
|
||||||
|
placeholder: "Search SR",
|
||||||
|
options: modal.serviceRequests || [],
|
||||||
|
valueKey: "srNumber",
|
||||||
|
labelKey: "label",
|
||||||
|
fallbackLabelKey: "srTitle",
|
||||||
|
disabled: isNonServiceRequest,
|
||||||
|
optionTooltipHtml: (option) => {
|
||||||
|
const optionSrNumber = cleanString(option?.srNumber);
|
||||||
|
const details = getTimeManagementServiceRequestDetails(modal, optionSrNumber);
|
||||||
|
|
||||||
|
return details.length
|
||||||
|
? renderTimeManagementServiceRequestTooltip(
|
||||||
|
option?.label ||
|
||||||
|
formatTimeManagementServiceRequestLabel(option) ||
|
||||||
|
optionSrNumber,
|
||||||
|
details
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTimeManagementServiceRequestTooltip(title, details) {
|
||||||
|
return `
|
||||||
|
<span class="arch-panel-extension-service-request-tooltip" role="tooltip">
|
||||||
|
<span class="arch-panel-extension-service-request-tooltip-title">
|
||||||
|
${escapeHtml(title || "Service Request")}
|
||||||
|
</span>
|
||||||
|
<span class="arch-panel-extension-service-request-tooltip-grid">
|
||||||
|
${details
|
||||||
|
.map(
|
||||||
|
(detail) => `
|
||||||
|
<span class="arch-panel-extension-service-request-tooltip-label">
|
||||||
|
${escapeHtml(detail.label || detail.key || "")}
|
||||||
|
</span>
|
||||||
|
<span class="arch-panel-extension-service-request-tooltip-value">
|
||||||
|
${renderTimeManagementServiceRequestTooltipValue(detail)}
|
||||||
|
</span>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.join("")}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTimeManagementServiceRequestTooltipValue(detail) {
|
||||||
|
const value = cleanString(detail?.value);
|
||||||
|
|
||||||
|
if (!isLongProblemDescriptionDetail(detail, value)) {
|
||||||
|
return escapeHtml(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<span class="arch-panel-extension-service-request-tooltip-excerpt">
|
||||||
|
${escapeHtml(value.slice(0, 180).trim())}...
|
||||||
|
</span>
|
||||||
|
<details class="arch-panel-extension-service-request-tooltip-more">
|
||||||
|
<summary>ver mais</summary>
|
||||||
|
<span>${escapeHtml(value)}</span>
|
||||||
|
</details>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLongProblemDescriptionDetail(detail, value) {
|
||||||
|
const key = normalizeString(detail?.key || detail?.label).replace(/[^A-Z0-9]/g, "");
|
||||||
|
|
||||||
|
return key === "PROBLEMDESCRIPTION" && value.length > 220;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeManagementServiceRequestDetails(modal, srNumber) {
|
||||||
|
const normalizedSrNumber = normalizeString(srNumber);
|
||||||
|
const matchedSrKey = Object.keys(modal?.activityRequestDetailsBySr || {}).find(
|
||||||
|
(key) => normalizeString(key) === normalizedSrNumber
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
modal?.activityRequestDetailsBySr?.[srNumber] ||
|
||||||
|
modal?.activityRequestDetailsBySr?.[matchedSrKey] ||
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function renderTimeManagementSkeleton() {
|
function renderTimeManagementSkeleton() {
|
||||||
return `
|
return `
|
||||||
<div class="arch-panel-extension-time-management-card" aria-busy="true">
|
<div class="arch-panel-extension-time-management-card" aria-busy="true">
|
||||||
@@ -335,27 +425,62 @@
|
|||||||
fallbackLabelKey,
|
fallbackLabelKey,
|
||||||
metaKey,
|
metaKey,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
optionTooltipHtml = null,
|
||||||
}) {
|
}) {
|
||||||
const safeField = escapeHtml(field);
|
const safeField = escapeHtml(field);
|
||||||
const safeRowId = escapeHtml(rowId || "");
|
const safeRowId = escapeHtml(rowId || "");
|
||||||
const isDisabled = Boolean(disabled);
|
const isDisabled = Boolean(disabled);
|
||||||
const normalizedSelectedValue = normalizeString(selectedValue);
|
const normalizedSelectedValue = normalizeString(selectedValue);
|
||||||
|
let hasOptionTooltips = false;
|
||||||
const normalizedOptions = (options || [])
|
const normalizedOptions = (options || [])
|
||||||
.map((item) => ({
|
.map((item) => {
|
||||||
value: cleanString(item?.[valueKey]),
|
const value = cleanString(item?.[valueKey]);
|
||||||
label:
|
const label =
|
||||||
cleanString(item?.[labelKey]) ||
|
cleanString(item?.[labelKey]) ||
|
||||||
cleanString(item?.[fallbackLabelKey]) ||
|
cleanString(item?.[fallbackLabelKey]) ||
|
||||||
cleanString(item?.[valueKey]),
|
value;
|
||||||
|
|
||||||
|
return {
|
||||||
|
original: item,
|
||||||
|
value,
|
||||||
|
label,
|
||||||
meta: cleanString(item?.[metaKey]),
|
meta: cleanString(item?.[metaKey]),
|
||||||
}))
|
tooltipHtml: "",
|
||||||
.filter((item) => item.value || item.label);
|
};
|
||||||
|
})
|
||||||
|
.filter((item) => item.value || item.label)
|
||||||
|
.map((item) => {
|
||||||
|
const tooltipHtml =
|
||||||
|
typeof optionTooltipHtml === "function"
|
||||||
|
? optionTooltipHtml(item.original || item, item)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
if (tooltipHtml) {
|
||||||
|
hasOptionTooltips = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
original: item.original,
|
||||||
|
value: item.value,
|
||||||
|
label: item.label,
|
||||||
|
meta: item.meta,
|
||||||
|
tooltipHtml,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const menuClassName = [
|
||||||
|
"arch-panel-extension-combobox-menu",
|
||||||
|
hasOptionTooltips ? "has-service-request-tooltips" : "",
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<span class="arch-panel-extension-combobox${isDisabled ? " is-disabled" : ""}" data-combobox-field="${safeField}" data-row-id="${safeRowId}">
|
<span class="arch-panel-extension-combobox${isDisabled ? " is-disabled" : ""}" data-combobox-field="${safeField}" data-row-id="${safeRowId}">
|
||||||
<span class="arch-panel-extension-combobox-value" title="${escapeHtml(value || "")}">
|
<span class="arch-panel-extension-combobox-value" title="${escapeHtml(value || "")}">
|
||||||
|
<span class="arch-panel-extension-combobox-value-text">
|
||||||
${escapeHtml(value || placeholder || "")}
|
${escapeHtml(value || placeholder || "")}
|
||||||
</span>
|
</span>
|
||||||
|
</span>
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
value=""
|
value=""
|
||||||
@@ -374,7 +499,7 @@
|
|||||||
<path d="M5.23 7.21a.75.75 0 0 1 1.06.02L10 11.16l3.71-3.93a.75.75 0 1 1 1.08 1.04l-4.25 4.5a.75.75 0 0 1-1.08 0l-4.25-4.5a.75.75 0 0 1 .02-1.06Z"></path>
|
<path d="M5.23 7.21a.75.75 0 0 1 1.06.02L10 11.16l3.71-3.93a.75.75 0 1 1 1.08 1.04l-4.25 4.5a.75.75 0 0 1-1.08 0l-4.25-4.5a.75.75 0 0 1 .02-1.06Z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<span class="arch-panel-extension-combobox-menu" role="listbox">
|
<span class="${menuClassName}" role="listbox">
|
||||||
${
|
${
|
||||||
normalizedOptions.length
|
normalizedOptions.length
|
||||||
? normalizedOptions
|
? normalizedOptions
|
||||||
@@ -383,6 +508,7 @@
|
|||||||
const isSelected =
|
const isSelected =
|
||||||
normalizedSelectedValue &&
|
normalizedSelectedValue &&
|
||||||
normalizeString(item.value) === normalizedSelectedValue;
|
normalizeString(item.value) === normalizedSelectedValue;
|
||||||
|
const hasTooltip = Boolean(item.tooltipHtml);
|
||||||
const meta =
|
const meta =
|
||||||
item.meta && normalizeString(item.meta) !== normalizeString(item.label)
|
item.meta && normalizeString(item.meta) !== normalizeString(item.label)
|
||||||
? item.meta
|
? item.meta
|
||||||
@@ -390,10 +516,9 @@
|
|||||||
const optionId = `arch-panel-extension-combobox-${safeField}-${index}`;
|
const optionId = `arch-panel-extension-combobox-${safeField}-${index}`;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<button
|
<span
|
||||||
id="${optionId}"
|
id="${optionId}"
|
||||||
type="button"
|
class="arch-panel-extension-combobox-option${isSelected ? " is-selected" : ""}${hasTooltip ? " has-tooltip" : ""}"
|
||||||
class="arch-panel-extension-combobox-option${isSelected ? " is-selected" : ""}"
|
|
||||||
data-action="time-management-combobox-option"
|
data-action="time-management-combobox-option"
|
||||||
data-field="${safeField}"
|
data-field="${safeField}"
|
||||||
data-row-id="${safeRowId}"
|
data-row-id="${safeRowId}"
|
||||||
@@ -401,6 +526,7 @@
|
|||||||
data-search="${escapeHtml(`${item.label} ${item.value}`.toLowerCase())}"
|
data-search="${escapeHtml(`${item.label} ${item.value}`.toLowerCase())}"
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected="${isSelected ? "true" : "false"}"
|
aria-selected="${isSelected ? "true" : "false"}"
|
||||||
|
tabindex="-1"
|
||||||
>
|
>
|
||||||
<span class="arch-panel-extension-combobox-option-main">
|
<span class="arch-panel-extension-combobox-option-main">
|
||||||
${escapeHtml(item.label || item.value)}
|
${escapeHtml(item.label || item.value)}
|
||||||
@@ -410,7 +536,8 @@
|
|||||||
? `<span class="arch-panel-extension-combobox-option-meta">${escapeHtml(meta)}</span>`
|
? `<span class="arch-panel-extension-combobox-option-meta">${escapeHtml(meta)}</span>`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
</button>
|
${item.tooltipHtml}
|
||||||
|
</span>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user