@open-mercato/core 0.6.1-develop.3256.1.fe3dec2464 → 0.6.1-develop.3276.1.1fcd145078
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/authFixtures.js.map +1 -1
- package/dist/helpers/integration/authUi.js +10 -2
- package/dist/helpers/integration/authUi.js.map +2 -2
- package/dist/helpers/integration/salesUi.js +3 -1
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js +10 -1
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +28 -27
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +21 -3
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +6 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +4 -1
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +56 -2
- package/dist/modules/auth/backend/users/page.js.map +3 -3
- package/dist/modules/auth/commands/users.js +14 -0
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/validators.js +8 -0
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -1
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -9
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -3
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -1
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +108 -99
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +13 -5
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +10 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +15 -8
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/RolesSection.js +35 -22
- package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +73 -64
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +11 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +2 -9
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +14 -29
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +10 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +79 -95
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +49 -70
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js +1 -1
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +1 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -19
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +1 -1
- package/dist/modules/resources/components/ResourceCrudForm.js.map +1 -1
- package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -1
- package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js +11 -8
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/staff/backend/staff/profile/create/page.js +1 -1
- package/dist/modules/staff/backend/staff/profile/create/page.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +1 -1
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -1
- package/dist/modules/staff/components/TeamMemberForm.js.map +1 -1
- package/dist/modules/staff/components/TeamRoleForm.js +1 -1
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/package.json +5 -5
- package/src/helpers/integration/authFixtures.ts +1 -1
- package/src/helpers/integration/authUi.ts +11 -2
- package/src/helpers/integration/salesUi.ts +10 -1
- package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +7 -3
- package/src/modules/audit_logs/lib/display-helpers.tsx +22 -14
- package/src/modules/auth/api/users/route.ts +22 -3
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +9 -1
- package/src/modules/auth/backend/users/create/page.tsx +6 -2
- package/src/modules/auth/backend/users/page.tsx +60 -3
- package/src/modules/auth/commands/users.ts +15 -0
- package/src/modules/auth/data/validators.ts +8 -0
- package/src/modules/auth/i18n/de.json +4 -0
- package/src/modules/auth/i18n/en.json +4 -0
- package/src/modules/auth/i18n/es.json +4 -0
- package/src/modules/auth/i18n/pl.json +4 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -1
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +12 -13
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +17 -13
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -1
- package/src/modules/customers/components/PipelineSettings.tsx +95 -95
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +7 -4
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +13 -8
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +16 -12
- package/src/modules/customers/components/detail/RolesSection.tsx +34 -31
- package/src/modules/customers/components/detail/TasksSection.tsx +16 -8
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +77 -51
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +7 -3
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -7
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -54
- package/src/modules/dictionaries/components/DictionariesManager.tsx +7 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +101 -146
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +60 -103
- package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +1 -1
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +17 -17
- package/src/modules/resources/components/ResourceCrudForm.tsx +1 -1
- package/src/modules/resources/components/ResourceTypeCrudForm.tsx +1 -1
- package/src/modules/sales/components/documents/ReturnDialog.tsx +10 -7
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
- package/src/modules/staff/backend/staff/profile/create/page.tsx +1 -1
- package/src/modules/staff/components/TeamForm.tsx +1 -1
- package/src/modules/staff/components/TeamMemberForm.tsx +1 -1
- package/src/modules/staff/components/TeamRoleForm.tsx +1 -1
|
@@ -35,7 +35,9 @@ import {
|
|
|
35
35
|
type IntegrationDetailBuiltInTab,
|
|
36
36
|
} from '@open-mercato/shared/modules/integrations/types'
|
|
37
37
|
import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
|
|
38
|
-
import {
|
|
38
|
+
import { LogList, type LogListEntry } from '@open-mercato/ui/backend/LogList'
|
|
39
|
+
import { Activity, AlertTriangle, Bell, Calendar, CheckCircle2, CreditCard, FileText, FileX, HardDrive, Key, MessageSquare, RefreshCw, Settings, Truck, Webhook, XCircle, Zap } from 'lucide-react'
|
|
40
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
39
41
|
import { IntegrationScheduleTab } from '../../../../data_sync/components/IntegrationScheduleTab'
|
|
40
42
|
import {
|
|
41
43
|
buildIntegrationDetailInjectedTabs,
|
|
@@ -129,12 +131,6 @@ type HealthCheckResponse = {
|
|
|
129
131
|
latencyMs: number | null
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
const LOG_LEVEL_STYLES: Record<string, string> = {
|
|
133
|
-
info: 'bg-blue-100 text-blue-800',
|
|
134
|
-
warn: 'bg-yellow-100 text-yellow-800',
|
|
135
|
-
error: 'bg-red-100 text-red-800',
|
|
136
|
-
}
|
|
137
|
-
|
|
138
134
|
const HEALTH_STATUS_STYLES: Record<string, string> = {
|
|
139
135
|
healthy: 'bg-green-100 text-green-800',
|
|
140
136
|
degraded: 'bg-yellow-100 text-yellow-800',
|
|
@@ -337,7 +333,6 @@ export default function IntegrationDetailPage({ params }: IntegrationDetailPageP
|
|
|
337
333
|
const [logs, setLogs] = React.useState<LogEntry[]>([])
|
|
338
334
|
const [logLevel, setLogLevel] = React.useState<string>('')
|
|
339
335
|
const [isLoadingLogs, setIsLoadingLogs] = React.useState(false)
|
|
340
|
-
const [expandedLogId, setExpandedLogId] = React.useState<string | null>(null)
|
|
341
336
|
|
|
342
337
|
const [isCheckingHealth, setIsCheckingHealth] = React.useState(false)
|
|
343
338
|
const [isTogglingState, setIsTogglingState] = React.useState(false)
|
|
@@ -522,9 +517,6 @@ export default function IntegrationDetailPage({ params }: IntegrationDetailPageP
|
|
|
522
517
|
React.useEffect(() => { void loadDetail() }, [loadDetail])
|
|
523
518
|
React.useEffect(() => { void loadCredentials() }, [loadCredentials])
|
|
524
519
|
React.useEffect(() => { void loadLogs() }, [loadLogs])
|
|
525
|
-
React.useEffect(() => {
|
|
526
|
-
setExpandedLogId((current) => (current && logs.some((log) => log.id === current) ? current : null))
|
|
527
|
-
}, [logs])
|
|
528
520
|
|
|
529
521
|
const handleToggleState = React.useCallback(async (enabled: boolean) => {
|
|
530
522
|
const currentIntegrationId = resolveCurrentIntegrationId()
|
|
@@ -1210,144 +1202,107 @@ export default function IntegrationDetailPage({ params }: IntegrationDetailPageP
|
|
|
1210
1202
|
</div>
|
|
1211
1203
|
{isLoadingLogs ? (
|
|
1212
1204
|
<div className="flex justify-center py-8"><Spinner /></div>
|
|
1213
|
-
) : logs.length === 0 ? (
|
|
1214
|
-
<p className="py-4 text-sm text-muted-foreground">{t('integrations.detail.logs.empty')}</p>
|
|
1215
1205
|
) : (
|
|
1216
|
-
<
|
|
1217
|
-
<
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
{t('integrations.detail.logs.details.summary', 'Summary')}
|
|
1272
|
-
</p>
|
|
1273
|
-
<p className="mt-1 text-sm font-medium">{log.message}</p>
|
|
1274
|
-
</div>
|
|
1275
|
-
{metadataEntries.length > 0 ? (
|
|
1276
|
-
<dl className="grid gap-3 sm:grid-cols-2">
|
|
1277
|
-
{metadataEntries.map(([label, value]) => (
|
|
1278
|
-
<div key={label} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
1279
|
-
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
1280
|
-
{label}
|
|
1281
|
-
</dt>
|
|
1282
|
-
<dd className="mt-1 break-all text-sm">{value}</dd>
|
|
1283
|
-
</div>
|
|
1284
|
-
))}
|
|
1285
|
-
</dl>
|
|
1286
|
-
) : null}
|
|
1287
|
-
</section>
|
|
1288
|
-
|
|
1289
|
-
{inlineEntries.length > 0 ? (
|
|
1290
|
-
<section className="space-y-3">
|
|
1291
|
-
<p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
|
1292
|
-
{t('integrations.detail.logs.details.fields', 'Fields')}
|
|
1293
|
-
</p>
|
|
1294
|
-
<dl className="grid gap-3 sm:grid-cols-2">
|
|
1295
|
-
{inlineEntries.map(([key, value]) => (
|
|
1296
|
-
<div key={key} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
1297
|
-
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
1298
|
-
{formatLogDetailLabel(key)}
|
|
1299
|
-
</dt>
|
|
1300
|
-
<dd className="mt-1 break-words text-sm">
|
|
1301
|
-
{formatLogPrimitiveValue(value)}
|
|
1302
|
-
</dd>
|
|
1303
|
-
</div>
|
|
1304
|
-
))}
|
|
1305
|
-
</dl>
|
|
1306
|
-
</section>
|
|
1307
|
-
) : null}
|
|
1308
|
-
</div>
|
|
1309
|
-
|
|
1310
|
-
<div className="space-y-3">
|
|
1311
|
-
{nestedEntries.map(([key, value]) => (
|
|
1312
|
-
<JsonDisplay
|
|
1313
|
-
key={key}
|
|
1314
|
-
data={value}
|
|
1315
|
-
title={formatLogDetailLabel(key)}
|
|
1316
|
-
defaultExpanded
|
|
1317
|
-
maxInitialDepth={1}
|
|
1318
|
-
theme="dark"
|
|
1319
|
-
maxHeight="16rem"
|
|
1320
|
-
className="p-4"
|
|
1321
|
-
/>
|
|
1322
|
-
))}
|
|
1323
|
-
{log.payload && nestedEntries.length === 0 ? (
|
|
1324
|
-
<JsonDisplay
|
|
1325
|
-
data={log.payload}
|
|
1326
|
-
title={t('integrations.detail.logs.details.payload', 'Payload')}
|
|
1327
|
-
defaultExpanded
|
|
1328
|
-
maxInitialDepth={1}
|
|
1329
|
-
theme="dark"
|
|
1330
|
-
maxHeight="16rem"
|
|
1331
|
-
className="p-4"
|
|
1332
|
-
/>
|
|
1333
|
-
) : null}
|
|
1334
|
-
{!log.payload ? (
|
|
1335
|
-
<div className="rounded-lg border border-dashed px-4 py-6 text-sm text-muted-foreground">
|
|
1336
|
-
{t('integrations.detail.logs.details.noPayload', 'No structured payload was stored for this log entry.')}
|
|
1337
|
-
</div>
|
|
1338
|
-
) : null}
|
|
1339
|
-
</div>
|
|
1206
|
+
<LogList
|
|
1207
|
+
entries={logs.map<LogListEntry>((log) => {
|
|
1208
|
+
const metadataEntries = [
|
|
1209
|
+
['Time', new Date(log.createdAt).toLocaleString()],
|
|
1210
|
+
['Level', log.level],
|
|
1211
|
+
['Code', log.code ?? null],
|
|
1212
|
+
['Run ID', log.runId ?? null],
|
|
1213
|
+
['Entity Type', log.scopeEntityType ?? null],
|
|
1214
|
+
['Entity ID', log.scopeEntityId ?? null],
|
|
1215
|
+
].filter((entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].trim().length > 0)
|
|
1216
|
+
const { inlineEntries, nestedEntries } = splitLogPayload(log.payload)
|
|
1217
|
+
|
|
1218
|
+
return {
|
|
1219
|
+
id: log.id,
|
|
1220
|
+
time: new Date(log.createdAt).toLocaleString(),
|
|
1221
|
+
level: log.level,
|
|
1222
|
+
message: log.message,
|
|
1223
|
+
body: (
|
|
1224
|
+
<div className="grid gap-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
|
|
1225
|
+
<div className="space-y-4">
|
|
1226
|
+
<section className="space-y-3">
|
|
1227
|
+
<div>
|
|
1228
|
+
<p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
|
1229
|
+
{t('integrations.detail.logs.details.summary', 'Summary')}
|
|
1230
|
+
</p>
|
|
1231
|
+
<p className="mt-1 text-sm font-medium">{log.message}</p>
|
|
1232
|
+
</div>
|
|
1233
|
+
{metadataEntries.length > 0 ? (
|
|
1234
|
+
<dl className="grid gap-3 sm:grid-cols-2">
|
|
1235
|
+
{metadataEntries.map(([label, value]) => (
|
|
1236
|
+
<div key={label} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
1237
|
+
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
1238
|
+
{label}
|
|
1239
|
+
</dt>
|
|
1240
|
+
<dd className="mt-1 break-all text-sm">{value}</dd>
|
|
1241
|
+
</div>
|
|
1242
|
+
))}
|
|
1243
|
+
</dl>
|
|
1244
|
+
) : null}
|
|
1245
|
+
</section>
|
|
1246
|
+
|
|
1247
|
+
{inlineEntries.length > 0 ? (
|
|
1248
|
+
<section className="space-y-3">
|
|
1249
|
+
<p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
|
1250
|
+
{t('integrations.detail.logs.details.fields', 'Fields')}
|
|
1251
|
+
</p>
|
|
1252
|
+
<dl className="grid gap-3 sm:grid-cols-2">
|
|
1253
|
+
{inlineEntries.map(([key, value]) => (
|
|
1254
|
+
<div key={key} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
1255
|
+
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
1256
|
+
{formatLogDetailLabel(key)}
|
|
1257
|
+
</dt>
|
|
1258
|
+
<dd className="mt-1 break-words text-sm">
|
|
1259
|
+
{formatLogPrimitiveValue(value)}
|
|
1260
|
+
</dd>
|
|
1340
1261
|
</div>
|
|
1341
|
-
|
|
1342
|
-
</
|
|
1343
|
-
</
|
|
1262
|
+
))}
|
|
1263
|
+
</dl>
|
|
1264
|
+
</section>
|
|
1344
1265
|
) : null}
|
|
1345
|
-
</
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1266
|
+
</div>
|
|
1267
|
+
|
|
1268
|
+
<div className="space-y-3">
|
|
1269
|
+
{nestedEntries.map(([key, value]) => (
|
|
1270
|
+
<JsonDisplay
|
|
1271
|
+
key={key}
|
|
1272
|
+
data={value}
|
|
1273
|
+
title={formatLogDetailLabel(key)}
|
|
1274
|
+
defaultExpanded
|
|
1275
|
+
maxInitialDepth={1}
|
|
1276
|
+
theme="dark"
|
|
1277
|
+
maxHeight="16rem"
|
|
1278
|
+
className="p-4"
|
|
1279
|
+
/>
|
|
1280
|
+
))}
|
|
1281
|
+
{log.payload && nestedEntries.length === 0 ? (
|
|
1282
|
+
<JsonDisplay
|
|
1283
|
+
data={log.payload}
|
|
1284
|
+
title={t('integrations.detail.logs.details.payload', 'Payload')}
|
|
1285
|
+
defaultExpanded
|
|
1286
|
+
maxInitialDepth={1}
|
|
1287
|
+
theme="dark"
|
|
1288
|
+
maxHeight="16rem"
|
|
1289
|
+
className="p-4"
|
|
1290
|
+
/>
|
|
1291
|
+
) : null}
|
|
1292
|
+
{!log.payload ? (
|
|
1293
|
+
<EmptyState
|
|
1294
|
+
size="sm"
|
|
1295
|
+
icon={<FileX className="h-8 w-8" aria-hidden="true" />}
|
|
1296
|
+
title={t('integrations.detail.logs.details.noPayload', 'No structured payload was stored for this log entry.')}
|
|
1297
|
+
/>
|
|
1298
|
+
) : null}
|
|
1299
|
+
</div>
|
|
1300
|
+
</div>
|
|
1301
|
+
),
|
|
1302
|
+
}
|
|
1303
|
+
})}
|
|
1304
|
+
emptyMessage={t('integrations.detail.logs.empty')}
|
|
1305
|
+
/>
|
|
1351
1306
|
)}
|
|
1352
1307
|
</TabsContent>
|
|
1353
1308
|
) : null}
|
|
@@ -18,7 +18,8 @@ import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
|
18
18
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
19
19
|
import { Card, CardContent, CardHeader, CardTitle } from '@open-mercato/ui/primitives/card'
|
|
20
20
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
21
|
-
import {
|
|
21
|
+
import { LogList, type LogListEntry } from '@open-mercato/ui/backend/LogList'
|
|
22
|
+
import { CreditCard, HandCoins, RefreshCw, Webhook } from 'lucide-react'
|
|
22
23
|
|
|
23
24
|
type TransactionRow = {
|
|
24
25
|
id: string
|
|
@@ -102,12 +103,6 @@ const STATUS_STYLES: Record<string, string> = {
|
|
|
102
103
|
unknown: 'bg-purple-100 text-purple-800',
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
const LOG_LEVEL_STYLES: Record<string, string> = {
|
|
106
|
-
info: 'bg-blue-100 text-blue-800',
|
|
107
|
-
warn: 'bg-yellow-100 text-yellow-800',
|
|
108
|
-
error: 'bg-red-100 text-red-800',
|
|
109
|
-
}
|
|
110
|
-
|
|
111
106
|
function formatDateTime(value: string | null | undefined): string {
|
|
112
107
|
if (!value) return '—'
|
|
113
108
|
const parsed = new Date(value)
|
|
@@ -194,7 +189,6 @@ export default function PaymentTransactionsPage() {
|
|
|
194
189
|
const [detail, setDetail] = React.useState<TransactionDetail | null>(null)
|
|
195
190
|
const [isLoadingDetail, setIsLoadingDetail] = React.useState(false)
|
|
196
191
|
const [detailError, setDetailError] = React.useState<string | null>(null)
|
|
197
|
-
const [expandedLogId, setExpandedLogId] = React.useState<string | null>(null)
|
|
198
192
|
const [isRefreshingStatus, setIsRefreshingStatus] = React.useState(false)
|
|
199
193
|
const [isCapturing, setIsCapturing] = React.useState(false)
|
|
200
194
|
const { runMutation } = useGuardedMutation<{
|
|
@@ -249,7 +243,6 @@ export default function PaymentTransactionsPage() {
|
|
|
249
243
|
const call = await apiCall<TransactionDetail>(`/api/payment_gateways/transactions/${encodeURIComponent(transactionId)}`, undefined, { fallback: null })
|
|
250
244
|
if (call.ok && call.result) {
|
|
251
245
|
setDetail(call.result)
|
|
252
|
-
setExpandedLogId((current) => (current && call.result?.logs.some((log) => log.id === current) ? current : null))
|
|
253
246
|
} else {
|
|
254
247
|
setDetail(null)
|
|
255
248
|
setDetailError(t('payment_gateways.transactions.error.loadDetail', 'Failed to load transaction details'))
|
|
@@ -610,100 +603,64 @@ export default function PaymentTransactionsPage() {
|
|
|
610
603
|
|
|
611
604
|
<section className="space-y-3">
|
|
612
605
|
<h3 className="text-sm font-semibold">{t('payment_gateways.transactions.detail.logs', 'Gateway logs')}</h3>
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
<
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
))}
|
|
672
|
-
</dl>
|
|
673
|
-
) : null}
|
|
674
|
-
{inlineEntries.length > 0 ? (
|
|
675
|
-
<dl className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
676
|
-
{inlineEntries.map(([key, value]) => (
|
|
677
|
-
<div key={key} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
678
|
-
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">{formatLogDetailLabel(key)}</dt>
|
|
679
|
-
<dd className="mt-1 break-words text-sm">{formatLogPrimitiveValue(value)}</dd>
|
|
680
|
-
</div>
|
|
681
|
-
))}
|
|
682
|
-
</dl>
|
|
683
|
-
) : null}
|
|
684
|
-
{nestedEntries.map(([key, value]) => (
|
|
685
|
-
<JsonDisplay
|
|
686
|
-
key={key}
|
|
687
|
-
data={value}
|
|
688
|
-
title={formatLogDetailLabel(key)}
|
|
689
|
-
defaultExpanded
|
|
690
|
-
maxInitialDepth={1}
|
|
691
|
-
theme="dark"
|
|
692
|
-
maxHeight="16rem"
|
|
693
|
-
className="p-4"
|
|
694
|
-
/>
|
|
695
|
-
))}
|
|
696
|
-
</div>
|
|
697
|
-
</td>
|
|
698
|
-
</tr>
|
|
699
|
-
) : null}
|
|
700
|
-
</React.Fragment>
|
|
701
|
-
)
|
|
702
|
-
})}
|
|
703
|
-
</tbody>
|
|
704
|
-
</table>
|
|
705
|
-
</div>
|
|
706
|
-
)}
|
|
606
|
+
<LogList
|
|
607
|
+
entries={detail.logs.map<LogListEntry>((log) => {
|
|
608
|
+
const metadataEntries = [
|
|
609
|
+
[t('payment_gateways.transactions.log.time', 'Time'), formatDateTime(log.createdAt)],
|
|
610
|
+
[t('payment_gateways.transactions.log.level', 'Level'), t(`payment_gateways.transactions.level.${log.level}`, log.level)],
|
|
611
|
+
[t('payment_gateways.transactions.log.code', 'Code'), log.code ?? null],
|
|
612
|
+
[t('payment_gateways.transactions.log.runId', 'Run ID'), log.runId ?? null],
|
|
613
|
+
[t('payment_gateways.transactions.log.entityType', 'Entity Type'), log.scopeEntityType ?? null],
|
|
614
|
+
[t('payment_gateways.transactions.log.entityId', 'Entity ID'), log.scopeEntityId ?? null],
|
|
615
|
+
].filter((entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].trim().length > 0)
|
|
616
|
+
const { inlineEntries, nestedEntries } = splitLogPayload(log.payload)
|
|
617
|
+
|
|
618
|
+
return {
|
|
619
|
+
id: log.id,
|
|
620
|
+
time: formatDateTime(log.createdAt),
|
|
621
|
+
level: log.level,
|
|
622
|
+
levelLabel: t(`payment_gateways.transactions.level.${log.level}`, log.level),
|
|
623
|
+
message: log.message,
|
|
624
|
+
body: (
|
|
625
|
+
<div className="space-y-4">
|
|
626
|
+
{metadataEntries.length > 0 ? (
|
|
627
|
+
<dl className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
628
|
+
{metadataEntries.map(([label, value]) => (
|
|
629
|
+
<div key={label} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
630
|
+
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">{label}</dt>
|
|
631
|
+
<dd className="mt-1 break-all text-sm">{value}</dd>
|
|
632
|
+
</div>
|
|
633
|
+
))}
|
|
634
|
+
</dl>
|
|
635
|
+
) : null}
|
|
636
|
+
{inlineEntries.length > 0 ? (
|
|
637
|
+
<dl className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
638
|
+
{inlineEntries.map(([key, value]) => (
|
|
639
|
+
<div key={key} className="rounded-md border bg-muted/30 px-3 py-2">
|
|
640
|
+
<dt className="text-overline font-medium uppercase tracking-wide text-muted-foreground">{formatLogDetailLabel(key)}</dt>
|
|
641
|
+
<dd className="mt-1 break-words text-sm">{formatLogPrimitiveValue(value)}</dd>
|
|
642
|
+
</div>
|
|
643
|
+
))}
|
|
644
|
+
</dl>
|
|
645
|
+
) : null}
|
|
646
|
+
{nestedEntries.map(([key, value]) => (
|
|
647
|
+
<JsonDisplay
|
|
648
|
+
key={key}
|
|
649
|
+
data={value}
|
|
650
|
+
title={formatLogDetailLabel(key)}
|
|
651
|
+
defaultExpanded
|
|
652
|
+
maxInitialDepth={1}
|
|
653
|
+
theme="dark"
|
|
654
|
+
maxHeight="16rem"
|
|
655
|
+
className="p-4"
|
|
656
|
+
/>
|
|
657
|
+
))}
|
|
658
|
+
</div>
|
|
659
|
+
),
|
|
660
|
+
}
|
|
661
|
+
})}
|
|
662
|
+
emptyMessage={t('payment_gateways.transactions.detail.logsEmpty', 'No transaction-scoped logs are available yet.')}
|
|
663
|
+
/>
|
|
707
664
|
</section>
|
|
708
665
|
</div>
|
|
709
666
|
|
|
@@ -73,7 +73,7 @@ export function AvailabilityRuleSetForm(props: AvailabilityRuleSetFormProps) {
|
|
|
73
73
|
id: 'description',
|
|
74
74
|
label: translate('planner.availabilityRuleSets.form.fields.description', 'Description'),
|
|
75
75
|
type: 'richtext',
|
|
76
|
-
editor: '
|
|
76
|
+
editor: 'html',
|
|
77
77
|
},
|
|
78
78
|
], [translate])
|
|
79
79
|
|
|
@@ -18,7 +18,7 @@ import { apiCall, apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
|
18
18
|
import { createCrud, deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
19
19
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
20
20
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
21
|
-
import { ComboboxInput } from '@open-mercato/ui/backend/inputs'
|
|
21
|
+
import { ComboboxInput, TimePicker } from '@open-mercato/ui/backend/inputs'
|
|
22
22
|
import { DictionaryEntrySelect, type DictionarySelectLabels } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'
|
|
23
23
|
import {
|
|
24
24
|
createUnavailabilityReasonEntry,
|
|
@@ -1425,20 +1425,20 @@ export function AvailabilityRulesEditor({
|
|
|
1425
1425
|
return (
|
|
1426
1426
|
<div key={`${day.code}-${windowIndex}`} className="space-y-1">
|
|
1427
1427
|
<div className="flex flex-wrap items-center gap-2">
|
|
1428
|
-
<
|
|
1429
|
-
type="time"
|
|
1428
|
+
<TimePicker
|
|
1430
1429
|
value={window.start}
|
|
1431
|
-
onChange={(
|
|
1432
|
-
className={`
|
|
1430
|
+
onChange={(value) => handleWeeklyWindowChange(index, windowIndex, { ...window, start: value ?? '' })}
|
|
1431
|
+
className={`w-[120px] ${errorClass}`}
|
|
1433
1432
|
disabled={usingRuleSet || isReadOnly}
|
|
1433
|
+
showClearButton={false}
|
|
1434
1434
|
/>
|
|
1435
1435
|
<span className="text-sm text-muted-foreground">-</span>
|
|
1436
|
-
<
|
|
1437
|
-
type="time"
|
|
1436
|
+
<TimePicker
|
|
1438
1437
|
value={window.end}
|
|
1439
|
-
onChange={(
|
|
1440
|
-
className={`
|
|
1438
|
+
onChange={(value) => handleWeeklyWindowChange(index, windowIndex, { ...window, end: value ?? '' })}
|
|
1439
|
+
className={`w-[120px] ${errorClass}`}
|
|
1441
1440
|
disabled={usingRuleSet || isReadOnly}
|
|
1441
|
+
showClearButton={false}
|
|
1442
1442
|
/>
|
|
1443
1443
|
<Button
|
|
1444
1444
|
type="button"
|
|
@@ -1753,18 +1753,18 @@ export function AvailabilityRulesEditor({
|
|
|
1753
1753
|
return (
|
|
1754
1754
|
<div key={`${index}-${window.start}`} className="space-y-1">
|
|
1755
1755
|
<div className="flex flex-wrap items-center gap-2">
|
|
1756
|
-
<
|
|
1757
|
-
type="time"
|
|
1756
|
+
<TimePicker
|
|
1758
1757
|
value={window.start}
|
|
1759
|
-
onChange={(
|
|
1760
|
-
className={`
|
|
1758
|
+
onChange={(value) => handleEditorWindowChange(index, { ...window, start: value ?? '' })}
|
|
1759
|
+
className={`w-[120px] ${errorClass}`}
|
|
1760
|
+
showClearButton={false}
|
|
1761
1761
|
/>
|
|
1762
1762
|
<span className="text-sm text-muted-foreground">-</span>
|
|
1763
|
-
<
|
|
1764
|
-
type="time"
|
|
1763
|
+
<TimePicker
|
|
1765
1764
|
value={window.end}
|
|
1766
|
-
onChange={(
|
|
1767
|
-
className={`
|
|
1765
|
+
onChange={(value) => handleEditorWindowChange(index, { ...window, end: value ?? '' })}
|
|
1766
|
+
className={`w-[120px] ${errorClass}`}
|
|
1767
|
+
showClearButton={false}
|
|
1768
1768
|
/>
|
|
1769
1769
|
<Button
|
|
1770
1770
|
type="button"
|
|
@@ -131,7 +131,7 @@ export function useResourcesResourceFormConfig(options: {
|
|
|
131
131
|
id: 'description',
|
|
132
132
|
label: t('resources.resources.form.fields.description', 'Description'),
|
|
133
133
|
type: 'richtext',
|
|
134
|
-
editor: '
|
|
134
|
+
editor: 'html',
|
|
135
135
|
},
|
|
136
136
|
{
|
|
137
137
|
id: 'resourceTypeId',
|
|
@@ -78,7 +78,7 @@ export function ResourceTypeCrudForm({
|
|
|
78
78
|
|
|
79
79
|
const fields = React.useMemo<CrudField[]>(() => [
|
|
80
80
|
{ id: 'name', label: t('resources.resourceTypes.form.name', 'Name'), type: 'text', required: true },
|
|
81
|
-
{ id: 'description', label: t('resources.resourceTypes.form.description', 'Description'), type: 'richtext' },
|
|
81
|
+
{ id: 'description', label: t('resources.resourceTypes.form.description', 'Description'), type: 'richtext', editor: 'html' },
|
|
82
82
|
{
|
|
83
83
|
id: 'appearance',
|
|
84
84
|
label: t('resources.resourceTypes.form.appearance.label', 'Appearance'),
|