@airoom/nextmin-react 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,7 +4,7 @@ import React from 'react';
|
|
|
4
4
|
import { formatCell } from '../../views/list/formatters';
|
|
5
5
|
import { summarizeObject } from '../../views/list/jsonSummary';
|
|
6
6
|
// Hide technical keys in the viewer
|
|
7
|
-
const HIDDEN_KEYS = new Set(['id', '_id', 'v', '__v', 'baseId', 'exId', '__childId']);
|
|
7
|
+
const HIDDEN_KEYS = new Set(['id', '_id', 'v', '__v', 'baseId', 'exId', '__childId', 'createdAt', 'updatedAt', 'deletedAt']);
|
|
8
8
|
// Detect password-like keys generically (no value should be visible)
|
|
9
9
|
function normKey(k) {
|
|
10
10
|
return k.toLowerCase().replace(/[^a-z]/g, '');
|
|
@@ -75,6 +75,49 @@ function humanizeLabel(key) {
|
|
|
75
75
|
const spaced = key.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/_/g, ' ');
|
|
76
76
|
return spaced.slice(0, 1).toUpperCase() + spaced.slice(1);
|
|
77
77
|
}
|
|
78
|
+
/** ---------- Date/time helpers (local timezone formatting) ---------- */
|
|
79
|
+
// Check if a field name is a date field
|
|
80
|
+
function isDateField(key) {
|
|
81
|
+
if (!key)
|
|
82
|
+
return false;
|
|
83
|
+
const k = key.toLowerCase().replace(/[^a-z]/g, '');
|
|
84
|
+
return k === 'createdat' || k === 'updatedat' || k === 'deletedat';
|
|
85
|
+
}
|
|
86
|
+
function tryParseDate(val) {
|
|
87
|
+
if (val == null)
|
|
88
|
+
return null;
|
|
89
|
+
// Already a Date
|
|
90
|
+
if (val instanceof Date)
|
|
91
|
+
return isNaN(val.getTime()) ? null : val;
|
|
92
|
+
// ONLY parse ISO-like strings, NOT numbers (to avoid phone numbers, experience years, etc.)
|
|
93
|
+
if (typeof val === 'string') {
|
|
94
|
+
const s = val.trim();
|
|
95
|
+
// Must look like an ISO date: YYYY-MM-DD or contain 'T' or end with 'Z'
|
|
96
|
+
const looksIso = /^\d{4}-\d{2}-\d{2}/.test(s) || s.includes('T') || s.endsWith('Z');
|
|
97
|
+
if (!looksIso)
|
|
98
|
+
return null;
|
|
99
|
+
const d = new Date(s);
|
|
100
|
+
return isNaN(d.getTime()) ? null : d;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
function formatDateTimeLocal(d) {
|
|
105
|
+
// Use the runtime locale and include seconds for precision
|
|
106
|
+
try {
|
|
107
|
+
return d.toLocaleString(undefined, {
|
|
108
|
+
year: 'numeric',
|
|
109
|
+
month: 'short',
|
|
110
|
+
day: '2-digit',
|
|
111
|
+
hour: '2-digit',
|
|
112
|
+
minute: '2-digit',
|
|
113
|
+
second: '2-digit',
|
|
114
|
+
hour12: true,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return d.toString();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
78
121
|
function isPrivate(attr) {
|
|
79
122
|
const a = (Array.isArray(attr) ? attr[0] : attr);
|
|
80
123
|
return !!a?.private;
|
|
@@ -171,6 +214,14 @@ function renderValue(input, key) {
|
|
|
171
214
|
const val = maybeParseJson(input);
|
|
172
215
|
if (val == null)
|
|
173
216
|
return _jsx("span", { className: "text-foreground/50", children: "\u2014" });
|
|
217
|
+
// Only parse dates for known date fields (createdAt, updatedAt, deletedAt)
|
|
218
|
+
if (isDateField(key)) {
|
|
219
|
+
const d = tryParseDate(val);
|
|
220
|
+
if (d) {
|
|
221
|
+
const iso = d.toISOString();
|
|
222
|
+
return (_jsx("time", { dateTime: iso, title: iso, className: "whitespace-pre-wrap", children: formatDateTimeLocal(d) }));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
174
225
|
// Detect images
|
|
175
226
|
const urls = extractAllImageUrls(val);
|
|
176
227
|
if (urls.length)
|