@open-mercato/core 0.6.1-develop.3256.1.fe3dec2464 → 0.6.1-develop.3260.1.dc719cac84
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
|
@@ -431,7 +431,13 @@ export function TasksSection({
|
|
|
431
431
|
) : null}
|
|
432
432
|
|
|
433
433
|
{!isInitialLoading && !hasTasks ? (
|
|
434
|
-
<TabEmptyState title={emptyState.title}
|
|
434
|
+
<TabEmptyState title={emptyState.title}>
|
|
435
|
+
<Button asChild variant="outline" size="sm" className="mt-2">
|
|
436
|
+
<Link href="/backend/customer-tasks">
|
|
437
|
+
{t('customers.people.detail.tasks.viewAll', 'View all tasks')}
|
|
438
|
+
</Link>
|
|
439
|
+
</Button>
|
|
440
|
+
</TabEmptyState>
|
|
435
441
|
) : null}
|
|
436
442
|
|
|
437
443
|
{!isInitialLoading && hasTasks ? (
|
|
@@ -565,13 +571,15 @@ export function TasksSection({
|
|
|
565
571
|
) : null}
|
|
566
572
|
</div>
|
|
567
573
|
) : null}
|
|
568
|
-
|
|
569
|
-
<
|
|
570
|
-
<
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
574
|
+
{!isInitialLoading && hasTasks ? (
|
|
575
|
+
<div className="flex justify-center">
|
|
576
|
+
<Button asChild variant="outline" size="sm">
|
|
577
|
+
<Link href="/backend/customer-tasks">
|
|
578
|
+
{t('customers.people.detail.tasks.viewAll', 'View all tasks')}
|
|
579
|
+
</Link>
|
|
580
|
+
</Button>
|
|
581
|
+
</div>
|
|
582
|
+
) : null}
|
|
575
583
|
</div>
|
|
576
584
|
|
|
577
585
|
<TaskDialog
|
|
@@ -1,14 +1,48 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import {
|
|
4
|
+
import { Globe, Repeat } from 'lucide-react'
|
|
5
5
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
6
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
|
+
import { DatePicker } from '@open-mercato/ui/primitives/date-picker'
|
|
9
|
+
import { TimePicker } from '@open-mercato/ui/backend/inputs/TimePicker'
|
|
10
|
+
import {
|
|
11
|
+
Select,
|
|
12
|
+
SelectContent,
|
|
13
|
+
SelectItem,
|
|
14
|
+
SelectTrigger,
|
|
15
|
+
SelectValue,
|
|
16
|
+
} from '@open-mercato/ui/primitives/select'
|
|
8
17
|
import type { ActivityType, ScheduleFieldId } from './fieldConfig'
|
|
9
18
|
import { isVisible, getFieldLabel } from './fieldConfig'
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
function parseIsoDate(value: string): Date | null {
|
|
21
|
+
if (!value) return null
|
|
22
|
+
const parts = value.split('-')
|
|
23
|
+
if (parts.length !== 3) return null
|
|
24
|
+
const [y, m, d] = parts.map((p) => parseInt(p, 10))
|
|
25
|
+
if (!Number.isFinite(y) || !Number.isFinite(m) || !Number.isFinite(d)) return null
|
|
26
|
+
const date = new Date(y, m - 1, d)
|
|
27
|
+
return Number.isNaN(date.getTime()) ? null : date
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function formatIsoDate(date: Date | null): string {
|
|
31
|
+
if (!date) return ''
|
|
32
|
+
const y = date.getFullYear()
|
|
33
|
+
const m = String(date.getMonth() + 1).padStart(2, '0')
|
|
34
|
+
const d = String(date.getDate()).padStart(2, '0')
|
|
35
|
+
return `${y}-${m}-${d}`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DURATION_OPTIONS: Array<{ value: number; key: string; fallback: string }> = [
|
|
39
|
+
{ value: 15, key: 'customers.schedule.duration.option.15min', fallback: '15 min' },
|
|
40
|
+
{ value: 30, key: 'customers.schedule.duration.option.30min', fallback: '30 min' },
|
|
41
|
+
{ value: 45, key: 'customers.schedule.duration.option.45min', fallback: '45 min' },
|
|
42
|
+
{ value: 60, key: 'customers.schedule.duration.option.1hour', fallback: '1 hour' },
|
|
43
|
+
{ value: 90, key: 'customers.schedule.duration.option.1h30m', fallback: '1h 30m' },
|
|
44
|
+
{ value: 120, key: 'customers.schedule.duration.option.2hours', fallback: '2 hours' },
|
|
45
|
+
]
|
|
12
46
|
const DAYS_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
|
13
47
|
|
|
14
48
|
interface DateTimeFieldsProps {
|
|
@@ -73,30 +107,23 @@ export function DateTimeFields({
|
|
|
73
107
|
return (
|
|
74
108
|
<>
|
|
75
109
|
{/* Date / Time / Duration */}
|
|
76
|
-
<div className="flex gap-3">
|
|
77
|
-
<div className="flex flex-[
|
|
110
|
+
<div className="flex flex-wrap gap-3">
|
|
111
|
+
<div className="flex min-w-0 flex-[1.5] flex-col gap-1.5">
|
|
78
112
|
<label className="text-overline font-semibold text-muted-foreground tracking-wider">
|
|
79
113
|
{getFieldLabel(activityType, 'date', t, 'customers.schedule.date', 'Date')}
|
|
80
114
|
<span aria-hidden="true" className="ml-1 text-status-error-foreground">*</span>
|
|
81
115
|
</label>
|
|
82
|
-
<
|
|
116
|
+
<DatePicker
|
|
117
|
+
value={parseIsoDate(date)}
|
|
118
|
+
onChange={(next) => setDate(formatIsoDate(next))}
|
|
119
|
+
placeholder={t('customers.schedule.date.placeholder', 'Pick a date')}
|
|
120
|
+
required
|
|
121
|
+
aria-describedby={dateMissing ? dateErrorId : undefined}
|
|
83
122
|
className={cn(
|
|
84
|
-
'
|
|
85
|
-
dateMissing
|
|
123
|
+
'h-10',
|
|
124
|
+
dateMissing && 'border-status-error-border',
|
|
86
125
|
)}
|
|
87
|
-
|
|
88
|
-
<Calendar className="size-3.5 text-muted-foreground" />
|
|
89
|
-
<input
|
|
90
|
-
type="date"
|
|
91
|
-
value={date}
|
|
92
|
-
onChange={(e) => setDate(e.target.value)}
|
|
93
|
-
required
|
|
94
|
-
aria-required="true"
|
|
95
|
-
aria-invalid={dateMissing ? true : undefined}
|
|
96
|
-
aria-describedby={dateMissing ? dateErrorId : undefined}
|
|
97
|
-
className="flex-1 bg-transparent text-sm text-foreground focus:outline-none"
|
|
98
|
-
/>
|
|
99
|
-
</div>
|
|
126
|
+
/>
|
|
100
127
|
{dateMissing ? (
|
|
101
128
|
<p id={dateErrorId} className="text-xs text-status-error-foreground">
|
|
102
129
|
{t('customers.activities.errors.dateRequired', 'Date is required')}
|
|
@@ -104,30 +131,23 @@ export function DateTimeFields({
|
|
|
104
131
|
) : null}
|
|
105
132
|
</div>
|
|
106
133
|
{showStartTime && (
|
|
107
|
-
<div className="flex flex-1 flex-col gap-1.5">
|
|
134
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
108
135
|
<label className="text-overline font-semibold text-muted-foreground tracking-wider">
|
|
109
136
|
{getFieldLabel(activityType, 'startTime', t, 'customers.schedule.start', 'Start')}
|
|
110
137
|
<span aria-hidden="true" className="ml-1 text-status-error-foreground">*</span>
|
|
111
138
|
</label>
|
|
112
|
-
<
|
|
139
|
+
<TimePicker
|
|
140
|
+
value={startTime || null}
|
|
141
|
+
onChange={(next) => setStartTime(next ?? '')}
|
|
142
|
+
disabled={allDay}
|
|
143
|
+
placeholder={t('customers.schedule.start.placeholder', 'Pick a time')}
|
|
113
144
|
className={cn(
|
|
114
|
-
'
|
|
115
|
-
timeMissing ? 'border-status-error-border' :
|
|
145
|
+
'py-2.5',
|
|
146
|
+
timeMissing ? 'border-status-error-border' : undefined,
|
|
116
147
|
)}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
type="time"
|
|
121
|
-
value={startTime}
|
|
122
|
-
onChange={(e) => setStartTime(e.target.value)}
|
|
123
|
-
disabled={allDay}
|
|
124
|
-
required={!allDay}
|
|
125
|
-
aria-required={!allDay}
|
|
126
|
-
aria-invalid={timeMissing ? true : undefined}
|
|
127
|
-
aria-describedby={timeMissing ? timeErrorId : undefined}
|
|
128
|
-
className="flex-1 bg-transparent text-sm text-foreground focus:outline-none disabled:opacity-50"
|
|
129
|
-
/>
|
|
130
|
-
</div>
|
|
148
|
+
showNowButton
|
|
149
|
+
showClearButton={false}
|
|
150
|
+
/>
|
|
131
151
|
{timeMissing ? (
|
|
132
152
|
<p id={timeErrorId} className="text-xs text-status-error-foreground">
|
|
133
153
|
{t('customers.activities.errors.timeRequired', 'Time is required')}
|
|
@@ -136,23 +156,29 @@ export function DateTimeFields({
|
|
|
136
156
|
</div>
|
|
137
157
|
)}
|
|
138
158
|
{showDuration && (
|
|
139
|
-
<div className="flex flex-1 flex-col gap-1.5">
|
|
159
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
140
160
|
<label className="text-overline font-semibold text-muted-foreground tracking-wider">
|
|
141
161
|
{getFieldLabel(activityType, 'duration', t, 'customers.schedule.duration', 'Duration')}
|
|
142
162
|
</label>
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
163
|
+
<Select
|
|
164
|
+
value={String(duration)}
|
|
165
|
+
onValueChange={(next) => {
|
|
166
|
+
const parsed = Number(next)
|
|
167
|
+
if (Number.isFinite(parsed)) setDuration(parsed)
|
|
168
|
+
}}
|
|
169
|
+
disabled={allDay}
|
|
170
|
+
>
|
|
171
|
+
<SelectTrigger className="h-10">
|
|
172
|
+
<SelectValue placeholder={t('customers.schedule.duration.placeholder', 'Pick duration')} />
|
|
173
|
+
</SelectTrigger>
|
|
174
|
+
<SelectContent>
|
|
175
|
+
{DURATION_OPTIONS.map((option) => (
|
|
176
|
+
<SelectItem key={option.value} value={String(option.value)}>
|
|
177
|
+
{t(option.key, option.fallback)}
|
|
178
|
+
</SelectItem>
|
|
152
179
|
))}
|
|
153
|
-
</
|
|
154
|
-
|
|
155
|
-
</div>
|
|
180
|
+
</SelectContent>
|
|
181
|
+
</Select>
|
|
156
182
|
</div>
|
|
157
183
|
)}
|
|
158
184
|
</div>
|
|
@@ -7,8 +7,10 @@ import {
|
|
|
7
7
|
Loader2,
|
|
8
8
|
Plus,
|
|
9
9
|
Search,
|
|
10
|
+
SearchX,
|
|
10
11
|
X,
|
|
11
12
|
} from 'lucide-react'
|
|
13
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
12
14
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
13
15
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
14
16
|
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
@@ -631,9 +633,11 @@ export function LinkEntityDialog<TDetails = unknown, TLinkSettings = Record<stri
|
|
|
631
633
|
{t('customers.linking.searching', 'Searching…')}
|
|
632
634
|
</div>
|
|
633
635
|
) : displayedResults.length === 0 ? (
|
|
634
|
-
<
|
|
635
|
-
|
|
636
|
-
|
|
636
|
+
<EmptyState
|
|
637
|
+
size="sm"
|
|
638
|
+
icon={<SearchX className="h-8 w-8" aria-hidden="true" />}
|
|
639
|
+
title={adapter.searchEmptyHint}
|
|
640
|
+
/>
|
|
637
641
|
) : (
|
|
638
642
|
displayedResults.map((result) => {
|
|
639
643
|
const checked = draftSet.has(result.id)
|
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
ArrowRightLeft,
|
|
32
32
|
Boxes,
|
|
33
33
|
CalendarClock,
|
|
34
|
-
CircleAlert,
|
|
35
34
|
Clock3,
|
|
36
35
|
Gauge,
|
|
37
36
|
Play,
|
|
@@ -964,17 +963,15 @@ export default function SyncRunsDashboardPage() {
|
|
|
964
963
|
|
|
965
964
|
{selectedIntegration && !selectedIntegration.isEnabled ? (
|
|
966
965
|
<Alert variant="warning">
|
|
967
|
-
<AlertDescription
|
|
968
|
-
|
|
969
|
-
<span>{t('integrations.detail.state.disabled', 'This integration is disabled. Enable it on the integration settings page before starting a sync.')}</span>
|
|
966
|
+
<AlertDescription>
|
|
967
|
+
{t('integrations.detail.state.disabled', 'This integration is disabled. Enable it on the integration settings page before starting a sync.')}
|
|
970
968
|
</AlertDescription>
|
|
971
969
|
</Alert>
|
|
972
970
|
) : null}
|
|
973
971
|
{selectedIntegration && !selectedIntegration.hasCredentials ? (
|
|
974
972
|
<Alert variant="warning">
|
|
975
|
-
<AlertDescription
|
|
976
|
-
|
|
977
|
-
<span>{t('integrations.detail.credentials.notConfigured', 'Credentials are not configured yet. Save the integration credentials before starting a sync.')}</span>
|
|
973
|
+
<AlertDescription>
|
|
974
|
+
{t('integrations.detail.credentials.notConfigured', 'Credentials are not configured yet. Save the integration credentials before starting a sync.')}
|
|
978
975
|
</AlertDescription>
|
|
979
976
|
</Alert>
|
|
980
977
|
) : null}
|
|
@@ -6,6 +6,7 @@ import { FormHeader } from '@open-mercato/ui/backend/forms'
|
|
|
6
6
|
import { Card, CardHeader, CardTitle, CardContent } from '@open-mercato/ui/primitives/card'
|
|
7
7
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
8
8
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
9
|
+
import { LogList, type LogListEntry } from '@open-mercato/ui/backend/LogList'
|
|
9
10
|
import { Progress } from '@open-mercato/ui/primitives/progress'
|
|
10
11
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
11
12
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
@@ -78,12 +79,6 @@ const STATUS_STYLES: Record<string, string> = {
|
|
|
78
79
|
paused: 'bg-orange-100 text-orange-800',
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
const LOG_LEVEL_STYLES: Record<string, string> = {
|
|
82
|
-
info: 'bg-blue-100 text-blue-800',
|
|
83
|
-
warn: 'bg-yellow-100 text-yellow-800',
|
|
84
|
-
error: 'bg-red-100 text-red-800',
|
|
85
|
-
}
|
|
86
|
-
|
|
87
82
|
type SyncRunDetailPageProps = {
|
|
88
83
|
params?: {
|
|
89
84
|
id?: string | string[]
|
|
@@ -113,7 +108,6 @@ export default function SyncRunDetailPage({ params }: SyncRunDetailPageProps) {
|
|
|
113
108
|
const [error, setError] = React.useState<string | null>(null)
|
|
114
109
|
const [logs, setLogs] = React.useState<LogEntry[]>([])
|
|
115
110
|
const [isLoadingLogs, setIsLoadingLogs] = React.useState(false)
|
|
116
|
-
const [expandedLogId, setExpandedLogId] = React.useState<string | null>(null)
|
|
117
111
|
|
|
118
112
|
const resolveCurrentRunId = React.useCallback(() => {
|
|
119
113
|
return runId ?? (
|
|
@@ -385,54 +379,25 @@ export default function SyncRunDetailPage({ params }: SyncRunDetailPageProps) {
|
|
|
385
379
|
<CardContent>
|
|
386
380
|
{isLoadingLogs ? (
|
|
387
381
|
<div className="flex justify-center py-4"><Spinner /></div>
|
|
388
|
-
) : logs.length === 0 ? (
|
|
389
|
-
<p className="text-muted-foreground text-sm">{t('data_sync.runs.detail.noLogs')}</p>
|
|
390
382
|
) : (
|
|
391
|
-
<
|
|
392
|
-
<
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
{log.level}
|
|
410
|
-
</Badge>
|
|
411
|
-
</td>
|
|
412
|
-
<td className="px-4 py-2">
|
|
413
|
-
<button
|
|
414
|
-
type="button"
|
|
415
|
-
className="w-full text-left"
|
|
416
|
-
onClick={() => setExpandedLogId((current) => current === log.id ? null : log.id)}
|
|
417
|
-
>
|
|
418
|
-
{log.message}
|
|
419
|
-
</button>
|
|
420
|
-
</td>
|
|
421
|
-
</tr>
|
|
422
|
-
{expandedLogId === log.id && log.payload ? (
|
|
423
|
-
<tr className="border-b bg-muted/30 last:border-0">
|
|
424
|
-
<td colSpan={3} className="px-4 py-4">
|
|
425
|
-
<pre className="overflow-x-auto whitespace-pre-wrap rounded-md border bg-card p-3 text-xs">
|
|
426
|
-
{JSON.stringify(log.payload, null, 2)}
|
|
427
|
-
</pre>
|
|
428
|
-
</td>
|
|
429
|
-
</tr>
|
|
430
|
-
) : null}
|
|
431
|
-
</React.Fragment>
|
|
432
|
-
))}
|
|
433
|
-
</tbody>
|
|
434
|
-
</table>
|
|
435
|
-
</div>
|
|
383
|
+
<LogList
|
|
384
|
+
entries={logs.map<LogListEntry>((log) => ({
|
|
385
|
+
id: log.id,
|
|
386
|
+
time: new Date(log.createdAt).toLocaleString(),
|
|
387
|
+
level: log.level,
|
|
388
|
+
message: log.message,
|
|
389
|
+
body: log.payload ? (
|
|
390
|
+
<pre className="overflow-x-auto whitespace-pre-wrap rounded-md border bg-card p-3 text-xs">
|
|
391
|
+
{JSON.stringify(log.payload, null, 2)}
|
|
392
|
+
</pre>
|
|
393
|
+
) : (
|
|
394
|
+
<p className="text-sm text-muted-foreground">
|
|
395
|
+
{t('data_sync.runs.detail.logs.noPayload', 'No payload recorded for this log entry.')}
|
|
396
|
+
</p>
|
|
397
|
+
),
|
|
398
|
+
}))}
|
|
399
|
+
emptyMessage={t('data_sync.runs.detail.noLogs')}
|
|
400
|
+
/>
|
|
436
401
|
)}
|
|
437
402
|
</CardContent>
|
|
438
403
|
</Card>
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { useSearchParams } from 'next/navigation'
|
|
5
|
-
import { Plus, Pencil, Trash2 } from 'lucide-react'
|
|
5
|
+
import { Book, Plus, Pencil, Trash2 } from 'lucide-react'
|
|
6
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
6
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
7
8
|
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'
|
|
8
9
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
@@ -324,9 +325,11 @@ export function DictionariesManager() {
|
|
|
324
325
|
readOnly={selectedDictionary.isInherited}
|
|
325
326
|
/>
|
|
326
327
|
) : (
|
|
327
|
-
<
|
|
328
|
-
{
|
|
329
|
-
|
|
328
|
+
<EmptyState
|
|
329
|
+
icon={<Book className="h-8 w-8" aria-hidden="true" />}
|
|
330
|
+
title={t('dictionaries.config.entries.placeholder', 'Select a dictionary to manage its entries.')}
|
|
331
|
+
className="h-full"
|
|
332
|
+
/>
|
|
330
333
|
)}
|
|
331
334
|
</div>
|
|
332
335
|
|