Reestruturação dos arquivos e pastas do código da extensão

This commit is contained in:
Paulo Porto
2026-05-13 23:40:29 -03:00
parent f196067b21
commit c989088ab1
33 changed files with 13154 additions and 11866 deletions

463
src/shared/utils.js Normal file
View File

@@ -0,0 +1,463 @@
(() => {
function normalizeText(value) {
return String(value || "").replace(/\s+/g, " ").trim();
}
function cleanString(value) {
return normalizeText(value);
}
function firstNonEmptyString(values) {
for (const value of values) {
const normalized = cleanString(value);
if (normalized) {
return normalized;
}
}
return "";
}
function normalizeString(value) {
return normalizeText(value).toUpperCase();
}
function toNumber(value) {
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
const numeric = Number.parseFloat(String(value ?? "").replace(/,/g, ""));
return Number.isFinite(numeric) ? numeric : 0;
}
function toIsoDateString(value) {
const normalized = cleanString(value);
if (!normalized) {
return "";
}
const date = new Date(`${normalized}T12:00:00.000Z`);
return Number.isNaN(date.getTime()) ? normalized : date.toISOString();
}
function extractArray(value, candidateKeys = []) {
if (Array.isArray(value)) {
return value;
}
if (!value || typeof value !== "object") {
return [];
}
for (const key of candidateKeys) {
if (Array.isArray(value[key])) {
return value[key];
}
}
for (const nestedValue of Object.values(value)) {
if (Array.isArray(nestedValue)) {
return nestedValue;
}
if (nestedValue && typeof nestedValue === "object") {
const nestedArray = extractArray(nestedValue, candidateKeys);
if (nestedArray.length > 0) {
return nestedArray;
}
}
}
return [];
}
async function mapWithConcurrency(items, concurrency, mapper) {
const results = new Array(items.length);
let nextIndex = 0;
async function worker() {
while (nextIndex < items.length) {
const currentIndex = nextIndex;
nextIndex += 1;
results[currentIndex] = await mapper(items[currentIndex], currentIndex);
}
}
const workerCount = Math.min(concurrency, items.length || 1);
await Promise.all(Array.from({ length: workerCount }, () => worker()));
return results;
}
function getFieldValue(source, paths) {
if (!source || typeof source !== "object") {
return "";
}
for (const path of paths) {
if (Object.prototype.hasOwnProperty.call(source, path)) {
return source[path];
}
const parts = String(path).split(".");
let current = source;
for (const part of parts) {
if (!current || typeof current !== "object") {
current = "";
break;
}
current = current[part];
}
if (current !== undefined && current !== null && current !== "") {
return current;
}
}
return "";
}
function flattenDisplayRecord(value, prefix = "", output = []) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
if (prefix) {
output.push([prefix, value]);
}
return output;
}
for (const [key, nestedValue] of Object.entries(value)) {
const nextKey = prefix ? `${prefix}.${key}` : key;
if (
nestedValue &&
typeof nestedValue === "object" &&
!Array.isArray(nestedValue)
) {
flattenDisplayRecord(nestedValue, nextKey, output);
} else {
output.push([nextKey, nestedValue]);
}
}
return output;
}
function isVisible(element) {
const style = window.getComputedStyle(element);
const rect = element.getBoundingClientRect();
return (
style.display !== "none" &&
style.visibility !== "hidden" &&
Number.parseFloat(style.opacity || "1") > 0 &&
rect.width > 0 &&
rect.height > 0
);
}
function formatWholeNumber(value) {
return new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
}).format(value);
}
function formatCurrency(value) {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
}).format(value || 0);
}
function formatHours(value) {
return new Intl.NumberFormat("pt-BR", {
maximumFractionDigits: 2,
}).format(toNumber(value));
}
function formatWeekNumber(value) {
return String(toNumber(value)).padStart(2, "0");
}
function formatOperationalWeekLabel(weekInfo) {
if (!weekInfo) {
return "";
}
return `FY${formatWeekNumber(weekInfo.fiscalYear % 100)}-Q${
weekInfo.quarter
}-W${formatWeekNumber(weekInfo.weekNumber)}`;
}
function formatPercent(value) {
return new Intl.NumberFormat("en-US", {
maximumFractionDigits: 1,
}).format(value || 0) + "%";
}
function formatProgressPercent(value) {
return new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
}).format(value || 0) + "%";
}
function formatDate(value) {
if (!value) {
return "";
}
const date = parseDatePreservingDateOnly(value);
if (Number.isNaN(date.getTime())) {
return String(value);
}
return new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
}).format(date);
}
function getDateInputValue(value) {
const date = parseDatePreservingDateOnly(value);
if (Number.isNaN(date.getTime())) {
return "";
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
function formatDateInputDisplay(value) {
const date = parseDatePreservingDateOnly(value);
if (Number.isNaN(date.getTime())) {
return cleanString(value);
}
const day = String(date.getDate()).padStart(2, "0");
const month = String(date.getMonth() + 1).padStart(2, "0");
const year = date.getFullYear();
return `${day}/${month}/${year}`;
}
function formatDateForTimeEntryRequest(value) {
const date = parseDatePreservingDateOnly(value);
if (Number.isNaN(date.getTime())) {
return "";
}
const day = String(date.getDate()).padStart(2, "0");
const month = new Intl.DateTimeFormat("en-US", { month: "short" })
.format(date)
.toUpperCase();
const year = date.getFullYear();
return `${day}-${month}-${year}`;
}
function parseTimeEntryDate(value) {
const text = cleanString(value);
const match = text.match(/^(\d{1,2})-([A-Z]{3})-(\d{4})$/i);
if (!match) {
return parseDatePreservingDateOnly(text);
}
const monthIndex = [
"JAN",
"FEB",
"MAR",
"APR",
"MAY",
"JUN",
"JUL",
"AUG",
"SEP",
"OCT",
"NOV",
"DEC",
].indexOf(match[2].toUpperCase());
if (monthIndex < 0) {
return new Date(Number.NaN);
}
return new Date(Number(match[3]), monthIndex, Number(match[1]));
}
function formatDateTime(value) {
if (!value) {
return "";
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return String(value);
}
return new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short",
}).format(date);
}
function getLocalDateKey(value) {
if (!value) {
return "";
}
const date = parseDatePreservingDateOnly(value);
if (Number.isNaN(date.getTime())) {
return "";
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
function getOperationalWeekInfo(value) {
const date = parseDatePreservingDateOnly(value);
if (Number.isNaN(date.getTime())) {
return null;
}
const operationalYearStart = new Date(date.getFullYear(), 5, 1);
if (date < operationalYearStart) {
operationalYearStart.setFullYear(operationalYearStart.getFullYear() - 1);
}
const normalizedDate = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate()
);
const normalizedStart = new Date(
operationalYearStart.getFullYear(),
operationalYearStart.getMonth(),
operationalYearStart.getDate()
);
const daysSinceStart = Math.floor(
(normalizedDate.getTime() - normalizedStart.getTime()) / 86400000
);
const monthsSinceStart =
(normalizedDate.getFullYear() - normalizedStart.getFullYear()) * 12 +
normalizedDate.getMonth() -
normalizedStart.getMonth();
return {
fiscalYear: operationalYearStart.getFullYear() + 1,
quarter: Math.floor(monthsSinceStart / 3) + 1,
weekNumber: Math.floor(daysSinceStart / 7) + 1,
};
}
function getCalendarRowWeekDate(rowStartDate) {
const weekDate = new Date(rowStartDate);
if (weekDate.getDay() === 0) {
weekDate.setDate(weekDate.getDate() + 1);
}
return weekDate;
}
function parseDatePreservingDateOnly(value) {
if (value instanceof Date) {
return value;
}
if (typeof value === "string") {
const dateOnlyMatch = value.trim().match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (dateOnlyMatch) {
return new Date(
Number(dateOnlyMatch[1]),
Number(dateOnlyMatch[2]) - 1,
Number(dateOnlyMatch[3])
);
}
}
return new Date(value);
}
function getErrorMessage(error) {
if (error instanceof Error) {
return error.message;
}
return "Unexpected error while fetching live data.";
}
function escapeHtml(value) {
return String(value ?? "")
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
function cssEscape(value) {
if (window.CSS?.escape) {
return window.CSS.escape(String(value || ""));
}
return String(value || "").replace(/["\\]/g, "\\$&");
}
globalThis.ArchPanelUtils = Object.freeze({
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,
});
})();