mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 07:26:19 +00:00
Split WiredCreatorToolsView: extract types/constants/helpers into 3 sibling files
The single-file WiredCreatorToolsView.tsx was 4493 lines, which is one of the main reasons the React Compiler reports "Compilation Skipped: Existing memoization could not be preserved" on this module. Split is conservative — only the pure leading sections move out, the component itself is untouched (state, effects, JSX all stay in place). New files (sibling to the view): - WiredCreatorTools.types.ts (~233 lines): every interface and type alias declared at the top of the original file. - WiredCreatorTools.constants.ts (~225 lines): TABS, MONITOR_LOG_ORDER, poll constants, MONITOR_ERROR_INFO, INSPECTION_ELEMENTS, VARIABLES_ELEMENTS, EDITABLE_*, VARIABLE_DEFINITIONS, WIRED_FREEZE_EFFECT_IDS, TEAM_COLOR_NAMES, WEEKDAY/MONTH/DIRECTION names. The createVariableDefinition factory is kept as a local helper in this file (only used to build VARIABLE_DEFINITIONS). - WiredCreatorTools.helpers.ts (~147 lines): createEmptyMonitorSnapshot, getHotelTimeFormatter (with its module-private cache map), getHotelDateTimeParts, formatMonitorLatestOccurrence, formatMonitorHistoryOccurrence, formatVariableTimestamp, formatMonitorSource, normalizeMonitorReason. All pure (or cache-stable), no closure on component state. WiredCreatorToolsView.tsx changes: - 4493 -> 3901 lines (-592, ~13% reduction). - The four inspection-icon asset imports (furni/global/user/context) move to the constants file alongside the only consumers (INSPECTION_ELEMENTS / VARIABLES_ELEMENTS). - AvatarInfoFurni was only referenced by the extracted InspectionFurniSelection interface and is removed from the main file's api import. - New import block at the top pulls back the symbols actually used by the component body. Verification: - yarn eslint on the three new files: 0 errors / 0 warnings. - yarn eslint on WiredCreatorToolsView.tsx: 26 errors before split, 26 errors after split (identical pre-existing set; nothing new introduced). - yarn tsc --noEmit on the four files: clean (only the project-wide pre-existing TS2307 about @nitrots/nitro-renderer not being installed locally remains, same as before). This unblocks future per-tab splits (Monitor / Inspection / Variables JSX panels are still inline in the view and represent the next ~1600 lines that could move out, but require introducing a shared state context first since the current setState chain is intertwined). https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import { HotelDateTimeParts, MonitorSnapshot } from './WiredCreatorTools.types';
|
||||
|
||||
const HOTEL_TIME_FORMATTERS: Map<string, Intl.DateTimeFormat> = new Map();
|
||||
|
||||
export const createEmptyMonitorSnapshot = (): MonitorSnapshot =>
|
||||
({
|
||||
usageCurrentWindow: 0,
|
||||
usageLimitPerWindow: 0,
|
||||
isHeavy: false,
|
||||
delayedEventsPending: 0,
|
||||
delayedEventsLimit: 0,
|
||||
averageExecutionMs: 0,
|
||||
peakExecutionMs: 0,
|
||||
recursionDepthCurrent: 0,
|
||||
recursionDepthLimit: 0,
|
||||
killedRemainingSeconds: 0,
|
||||
usageWindowMs: 0,
|
||||
overloadAverageThresholdMs: 0,
|
||||
overloadPeakThresholdMs: 0,
|
||||
heavyUsageThresholdPercent: 0,
|
||||
heavyConsecutiveWindowsThreshold: 0,
|
||||
overloadConsecutiveWindowsThreshold: 0,
|
||||
heavyDelayedThresholdPercent: 0,
|
||||
logs: [],
|
||||
history: []
|
||||
});
|
||||
|
||||
export const getHotelTimeFormatter = (timeZone: string): Intl.DateTimeFormat =>
|
||||
{
|
||||
const formatterTimeZone = (timeZone || 'UTC');
|
||||
const existingFormatter = HOTEL_TIME_FORMATTERS.get(formatterTimeZone);
|
||||
|
||||
if(existingFormatter) return existingFormatter;
|
||||
|
||||
let formatter: Intl.DateTimeFormat = null;
|
||||
|
||||
try
|
||||
{
|
||||
formatter = new Intl.DateTimeFormat('en-GB', {
|
||||
timeZone: formatterTimeZone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hourCycle: 'h23'
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
formatter = new Intl.DateTimeFormat('en-GB', {
|
||||
timeZone: 'UTC',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hourCycle: 'h23'
|
||||
});
|
||||
}
|
||||
|
||||
HOTEL_TIME_FORMATTERS.set(formatterTimeZone, formatter);
|
||||
|
||||
return formatter;
|
||||
};
|
||||
|
||||
export const getHotelDateTimeParts = (epochMs: number, timeZone: string): HotelDateTimeParts =>
|
||||
{
|
||||
const normalizedEpochMs = Number.isFinite(epochMs) ? epochMs : Date.now();
|
||||
const date = new Date(normalizedEpochMs);
|
||||
const formatter = getHotelTimeFormatter(timeZone);
|
||||
const formattedParts = formatter.formatToParts(date);
|
||||
const partsMap = new Map<string, string>();
|
||||
|
||||
for(const part of formattedParts)
|
||||
{
|
||||
if(part.type === 'literal') continue;
|
||||
|
||||
partsMap.set(part.type, part.value);
|
||||
}
|
||||
|
||||
return {
|
||||
year: Number(partsMap.get('year') ?? date.getUTCFullYear()),
|
||||
month: Number(partsMap.get('month') ?? (date.getUTCMonth() + 1)),
|
||||
day: Number(partsMap.get('day') ?? date.getUTCDate()),
|
||||
hour: Number(partsMap.get('hour') ?? date.getUTCHours()),
|
||||
minute: Number(partsMap.get('minute') ?? date.getUTCMinutes()),
|
||||
second: Number(partsMap.get('second') ?? date.getUTCSeconds()),
|
||||
millisecond: (((normalizedEpochMs % 1000) + 1000) % 1000)
|
||||
};
|
||||
};
|
||||
|
||||
export const formatMonitorLatestOccurrence = (latestOccurrenceSeconds: number, nowMs: number): string =>
|
||||
{
|
||||
if(latestOccurrenceSeconds <= 0) return '/';
|
||||
|
||||
const diffMs = Math.max(0, (nowMs - (latestOccurrenceSeconds * 1000)));
|
||||
const diffSeconds = Math.floor(diffMs / 1000);
|
||||
|
||||
if(diffSeconds < 5) return 'Just now';
|
||||
if(diffSeconds < 60) return `${ diffSeconds }s ago`;
|
||||
|
||||
const diffMinutes = Math.floor(diffSeconds / 60);
|
||||
|
||||
if(diffMinutes < 60) return `${ diffMinutes }m ago`;
|
||||
|
||||
const diffHours = Math.floor(diffMinutes / 60);
|
||||
|
||||
if(diffHours < 24) return `${ diffHours }h ago`;
|
||||
|
||||
const diffDays = Math.floor(diffHours / 24);
|
||||
|
||||
return `${ diffDays }d ago`;
|
||||
};
|
||||
|
||||
export const formatMonitorHistoryOccurrence = (occurredAtSeconds: number): string =>
|
||||
{
|
||||
if(occurredAtSeconds <= 0) return '/';
|
||||
|
||||
return new Date(occurredAtSeconds * 1000).toLocaleString('en-GB');
|
||||
};
|
||||
|
||||
export const formatVariableTimestamp = (timestamp: number): string =>
|
||||
{
|
||||
if(!timestamp || (timestamp <= 0)) return '/';
|
||||
|
||||
return new Date(timestamp * 1000).toLocaleString('en-GB');
|
||||
};
|
||||
|
||||
export const formatMonitorSource = (sourceLabel: string, sourceId: number): string =>
|
||||
{
|
||||
const normalizedLabel = (sourceLabel || '').trim();
|
||||
|
||||
if(!normalizedLabel && !(sourceId > 0)) return 'Room monitor';
|
||||
if(sourceId > 0) return `${ normalizedLabel || 'wired' } (#${ sourceId })`;
|
||||
|
||||
return normalizedLabel;
|
||||
};
|
||||
|
||||
export const normalizeMonitorReason = (reason: string): string =>
|
||||
{
|
||||
const normalizedReason = (reason || '').trim();
|
||||
|
||||
return normalizedReason || 'No detailed reason was recorded for this entry.';
|
||||
};
|
||||
Reference in New Issue
Block a user