@open-mercato/core 0.6.4-develop.4363.1.2f376570ae → 0.6.4-develop.4371.1.8f3030407e

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.
Files changed (68) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +66 -44
  3. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  4. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +124 -103
  5. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  6. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +5 -1
  7. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
  8. package/dist/modules/customers/data/validators.js +4 -4
  9. package/dist/modules/customers/data/validators.js.map +2 -2
  10. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +26 -4
  11. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  12. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +24 -4
  13. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  14. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +35 -6
  15. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
  16. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +67 -47
  17. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  18. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +29 -6
  19. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  20. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +29 -6
  21. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  22. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +33 -4
  23. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  24. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +33 -4
  25. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  26. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +37 -8
  27. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +3 -3
  28. package/dist/modules/workflows/backend/definitions/[id]/page.js +24 -6
  29. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  30. package/package.json +7 -7
  31. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +39 -8
  32. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +38 -6
  33. package/src/modules/catalog/i18n/de.json +2 -0
  34. package/src/modules/catalog/i18n/en.json +2 -0
  35. package/src/modules/catalog/i18n/es.json +2 -0
  36. package/src/modules/catalog/i18n/pl.json +2 -0
  37. package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +5 -1
  38. package/src/modules/customers/data/validators.ts +4 -4
  39. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +30 -4
  40. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +28 -6
  41. package/src/modules/directory/i18n/de.json +2 -0
  42. package/src/modules/directory/i18n/en.json +2 -0
  43. package/src/modules/directory/i18n/es.json +2 -0
  44. package/src/modules/directory/i18n/pl.json +2 -0
  45. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +44 -4
  46. package/src/modules/planner/i18n/de.json +1 -0
  47. package/src/modules/planner/i18n/en.json +1 -0
  48. package/src/modules/planner/i18n/es.json +1 -0
  49. package/src/modules/planner/i18n/pl.json +1 -0
  50. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +36 -7
  51. package/src/modules/sales/i18n/de.json +1 -0
  52. package/src/modules/sales/i18n/en.json +1 -0
  53. package/src/modules/sales/i18n/es.json +1 -0
  54. package/src/modules/sales/i18n/pl.json +1 -0
  55. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +33 -6
  56. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +33 -6
  57. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +44 -4
  58. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +44 -4
  59. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +44 -4
  60. package/src/modules/staff/i18n/de.json +5 -0
  61. package/src/modules/staff/i18n/en.json +5 -0
  62. package/src/modules/staff/i18n/es.json +5 -0
  63. package/src/modules/staff/i18n/pl.json +5 -0
  64. package/src/modules/workflows/backend/definitions/[id]/page.tsx +26 -3
  65. package/src/modules/workflows/i18n/de.json +1 -0
  66. package/src/modules/workflows/i18n/en.json +1 -0
  67. package/src/modules/workflows/i18n/es.json +1 -0
  68. package/src/modules/workflows/i18n/pl.json +1 -0
@@ -5,7 +5,7 @@ import { useRouter } from 'next/navigation'
5
5
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
6
  import { Badge } from '@open-mercato/ui/primitives/badge'
7
7
  import { Button } from '@open-mercato/ui/primitives/button'
8
- import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
8
+ import { LoadingMessage, ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
9
9
  import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
10
10
  import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
11
11
  import { updateCrud } from '@open-mercato/ui/backend/utils/crud'
@@ -20,11 +20,12 @@ export default function StaffMyLeaveRequestDetailPage({ params }: { params?: { i
20
20
  const router = useRouter()
21
21
  const [isLoading, setIsLoading] = React.useState(true)
22
22
  const [error, setError] = React.useState<string | null>(null)
23
+ const [isNotFound, setIsNotFound] = React.useState(false)
23
24
  const [record, setRecord] = React.useState<NormalizedLeaveRequest | null>(null)
24
25
 
25
26
  React.useEffect(() => {
26
27
  if (!id) {
27
- setError(t('staff.leaveRequests.errors.notFound', 'Leave request not found.'))
28
+ setIsNotFound(true)
28
29
  setIsLoading(false)
29
30
  return
30
31
  }
@@ -33,6 +34,7 @@ export default function StaffMyLeaveRequestDetailPage({ params }: { params?: { i
33
34
  async function load() {
34
35
  setIsLoading(true)
35
36
  setError(null)
37
+ setIsNotFound(false)
36
38
  try {
37
39
  const params = new URLSearchParams({ page: '1', pageSize: '1', ids: requestId })
38
40
  const payload = await readApiResultOrThrow<LeaveRequestsResponse>(
@@ -41,15 +43,26 @@ export default function StaffMyLeaveRequestDetailPage({ params }: { params?: { i
41
43
  { errorMessage: t('staff.leaveRequests.errors.load', 'Failed to load leave request.') },
42
44
  )
43
45
  const entry = Array.isArray(payload.items) ? payload.items[0] : null
44
- if (!entry) throw new Error(t('staff.leaveRequests.errors.notFound', 'Leave request not found.'))
46
+ if (!entry) {
47
+ if (!cancelled) {
48
+ setIsNotFound(true)
49
+ setRecord(null)
50
+ }
51
+ return
52
+ }
45
53
  if (!cancelled) {
46
54
  setRecord(normalizeLeaveRequest(entry))
47
55
  }
48
56
  } catch (err) {
49
57
  if (!cancelled) {
50
- const message = err instanceof Error ? err.message : t('staff.leaveRequests.errors.load', 'Failed to load leave request.')
51
- setError(message)
52
- setRecord(null)
58
+ if ((err as { status?: number }).status === 404) {
59
+ setIsNotFound(true)
60
+ setRecord(null)
61
+ } else {
62
+ const message = err instanceof Error ? err.message : t('staff.leaveRequests.errors.load', 'Failed to load leave request.')
63
+ setError(message)
64
+ setRecord(null)
65
+ }
53
66
  }
54
67
  } finally {
55
68
  if (!cancelled) setIsLoading(false)
@@ -93,6 +106,20 @@ const handleSubmit = React.useCallback(async (values: LeaveRequestFormValues) =>
93
106
  )
94
107
  }
95
108
 
109
+ if (isNotFound) {
110
+ return (
111
+ <Page>
112
+ <PageBody>
113
+ <RecordNotFoundState
114
+ label={t('staff.leaveRequests.errors.notFound', 'Leave request not found.')}
115
+ backHref="/backend/staff/my-leave-requests"
116
+ backLabel={t('staff.leaveRequests.actions.backToMyList', 'Back to my leave requests')}
117
+ />
118
+ </PageBody>
119
+ </Page>
120
+ )
121
+ }
122
+
96
123
  if (error || !record) {
97
124
  return (
98
125
  <Page>
@@ -17,6 +17,7 @@ import { TeamMemberForm, buildTeamMemberPayload, type TeamMemberFormValues } fro
17
17
  import { NotesSection } from '@open-mercato/ui/backend/detail'
18
18
  import { ActivitiesSection, type SectionAction } from '@open-mercato/ui/backend/detail'
19
19
  import { AddressesSection as SharedAddressesSection } from '@open-mercato/ui/backend/detail'
20
+ import { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
20
21
  import { renderDictionaryColor, renderDictionaryIcon, ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'
21
22
  import { createStaffNotesAdapter } from '@open-mercato/core/modules/staff/components/detail/notesAdapter'
22
23
  import { createStaffActivitiesAdapter } from '@open-mercato/core/modules/staff/components/detail/activitiesAdapter'
@@ -70,6 +71,8 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
70
71
  const searchParams = useSearchParams()
71
72
  const [initialValues, setInitialValues] = React.useState<TeamMemberFormValues | null>(null)
72
73
  const [memberRecord, setMemberRecord] = React.useState<TeamMemberRecord | null>(null)
74
+ const [error, setError] = React.useState<string | null>(null)
75
+ const [isNotFound, setIsNotFound] = React.useState(false)
73
76
  const [availabilityRuleSetId, setAvailabilityRuleSetId] = React.useState<string | null>(null)
74
77
  const [activePanel, setActivePanel] = React.useState<'details' | 'availability' | 'jobHistory'>('details')
75
78
  const [activeTab, setActiveTab] = React.useState<'notes' | 'activities' | 'addresses'>('notes')
@@ -194,6 +197,10 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
194
197
  const memberIdValue = memberId
195
198
  let cancelled = false
196
199
  async function loadMember() {
200
+ if (!cancelled) {
201
+ setError(null)
202
+ setIsNotFound(false)
203
+ }
197
204
  try {
198
205
  const params = new URLSearchParams({ page: '1', pageSize: '1', ids: memberIdValue })
199
206
  const payload = await readApiResultOrThrow<TeamMemberResponse>(
@@ -202,7 +209,10 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
202
209
  { errorMessage: t('staff.teamMembers.form.errors.load', 'Failed to load team member.') },
203
210
  )
204
211
  const record = Array.isArray(payload.items) ? payload.items[0] : null
205
- if (!record) throw new Error(t('staff.teamMembers.form.errors.notFound', 'Team member not found.'))
212
+ if (!record) {
213
+ if (!cancelled) setIsNotFound(true)
214
+ return
215
+ }
206
216
  const customFields = extractCustomFieldEntries(record)
207
217
  if (!cancelled) {
208
218
  const resolvedTeamId = record.teamId ?? record.team_id ?? null
@@ -227,9 +237,15 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
227
237
  : null,
228
238
  )
229
239
  }
230
- } catch (error) {
231
- const message = error instanceof Error ? error.message : t('staff.teamMembers.form.errors.load', 'Failed to load team member.')
232
- flash(message, 'error')
240
+ } catch (err) {
241
+ if (!cancelled) {
242
+ if ((err as { status?: number }).status === 404) {
243
+ setIsNotFound(true)
244
+ } else {
245
+ const message = err instanceof Error ? err.message : t('staff.teamMembers.form.errors.load', 'Failed to load team member.')
246
+ setError(message)
247
+ }
248
+ }
233
249
  }
234
250
  }
235
251
  void loadMember()
@@ -304,6 +320,30 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
304
320
  : [t('staff.teamMembers.detail.roles.unassigned', 'No roles assigned')]
305
321
  const userEmail = memberRecord?.user?.email ?? null
306
322
 
323
+ if (isNotFound) {
324
+ return (
325
+ <Page>
326
+ <PageBody>
327
+ <RecordNotFoundState
328
+ label={t('staff.teamMembers.form.errors.notFound', 'Team member not found.')}
329
+ backHref="/backend/staff/team-members"
330
+ backLabel={t('staff.teamMembers.actions.backToList', 'Back to team members')}
331
+ />
332
+ </PageBody>
333
+ </Page>
334
+ )
335
+ }
336
+
337
+ if (error && !initialValues) {
338
+ return (
339
+ <Page>
340
+ <PageBody>
341
+ <ErrorMessage label={error} />
342
+ </PageBody>
343
+ </Page>
344
+ )
345
+ }
346
+
307
347
  return (
308
348
  <Page>
309
349
  <PageBody>
@@ -3,6 +3,7 @@
3
3
  import * as React from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
5
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
+ import { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
6
7
  import { readApiResultOrThrow, apiCall } from '@open-mercato/ui/backend/utils/apiCall'
7
8
  import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
8
9
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
@@ -38,6 +39,8 @@ export default function StaffTeamRoleEditPage({ params }: { params?: { id?: stri
38
39
  const router = useRouter()
39
40
  const scopeVersion = useOrganizationScopeVersion()
40
41
  const [initialValues, setInitialValues] = React.useState<TeamRoleFormValues | null>(null)
42
+ const [error, setError] = React.useState<string | null>(null)
43
+ const [isNotFound, setIsNotFound] = React.useState(false)
41
44
  const [teams, setTeams] = React.useState<TeamRoleOption[]>([])
42
45
 
43
46
  React.useEffect(() => {
@@ -45,6 +48,10 @@ export default function StaffTeamRoleEditPage({ params }: { params?: { id?: stri
45
48
  const roleIdValue = roleId
46
49
  let cancelled = false
47
50
  async function loadRole() {
51
+ if (!cancelled) {
52
+ setError(null)
53
+ setIsNotFound(false)
54
+ }
48
55
  try {
49
56
  const params = new URLSearchParams({ page: '1', pageSize: '1', ids: roleIdValue })
50
57
  const payload = await readApiResultOrThrow<TeamRoleResponse>(
@@ -53,7 +60,10 @@ export default function StaffTeamRoleEditPage({ params }: { params?: { id?: stri
53
60
  { errorMessage: t('staff.teamRoles.errors.load', 'Failed to load team role.') },
54
61
  )
55
62
  const record = Array.isArray(payload.items) ? payload.items[0] : null
56
- if (!record) throw new Error(t('staff.teamRoles.errors.notFound', 'Team role not found.'))
63
+ if (!record) {
64
+ if (!cancelled) setIsNotFound(true)
65
+ return
66
+ }
57
67
  const customFields = extractCustomFieldEntries(record)
58
68
  const appearanceIcon = typeof record.appearanceIcon === 'string'
59
69
  ? record.appearanceIcon
@@ -79,9 +89,15 @@ export default function StaffTeamRoleEditPage({ params }: { params?: { id?: stri
79
89
  ...customFields,
80
90
  })
81
91
  }
82
- } catch (error) {
83
- const message = error instanceof Error ? error.message : t('staff.teamRoles.errors.load', 'Failed to load team role.')
84
- flash(message, 'error')
92
+ } catch (err) {
93
+ if (!cancelled) {
94
+ if ((err as { status?: number }).status === 404) {
95
+ setIsNotFound(true)
96
+ } else {
97
+ const message = err instanceof Error ? err.message : t('staff.teamRoles.errors.load', 'Failed to load team role.')
98
+ setError(message)
99
+ }
100
+ }
85
101
  }
86
102
  }
87
103
  loadRole()
@@ -131,6 +147,30 @@ export default function StaffTeamRoleEditPage({ params }: { params?: { id?: stri
131
147
  router.push('/backend/staff/team-roles')
132
148
  }, [roleId, router, t])
133
149
 
150
+ if (isNotFound) {
151
+ return (
152
+ <Page>
153
+ <PageBody>
154
+ <RecordNotFoundState
155
+ label={t('staff.teamRoles.errors.notFound', 'Team role not found.')}
156
+ backHref="/backend/staff/team-roles"
157
+ backLabel={t('staff.teamRoles.actions.backToList', 'Back to team roles')}
158
+ />
159
+ </PageBody>
160
+ </Page>
161
+ )
162
+ }
163
+
164
+ if (error && !initialValues) {
165
+ return (
166
+ <Page>
167
+ <PageBody>
168
+ <ErrorMessage label={error} />
169
+ </PageBody>
170
+ </Page>
171
+ )
172
+ }
173
+
134
174
  return (
135
175
  <Page>
136
176
  <PageBody>
@@ -5,6 +5,7 @@ import Link from 'next/link'
5
5
  import { useRouter, useSearchParams } from 'next/navigation'
6
6
  import type { ColumnDef, SortingState } from '@tanstack/react-table'
7
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
8
+ import { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
8
9
  import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
9
10
  import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
10
11
  import { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'
@@ -59,6 +60,8 @@ export default function StaffTeamEditPage({ params }: { params?: { id?: string }
59
60
  const searchParams = useSearchParams()
60
61
  const scopeVersion = useOrganizationScopeVersion()
61
62
  const [initialValues, setInitialValues] = React.useState<TeamFormValues | null>(null)
63
+ const [error, setError] = React.useState<string | null>(null)
64
+ const [isNotFound, setIsNotFound] = React.useState(false)
62
65
  const [activeTab, setActiveTab] = React.useState<'details' | 'members'>('details')
63
66
  const [memberRows, setMemberRows] = React.useState<TeamMemberRow[]>([])
64
67
  const [memberPage, setMemberPage] = React.useState(1)
@@ -168,6 +171,10 @@ export default function StaffTeamEditPage({ params }: { params?: { id?: string }
168
171
  const teamIdValue = teamId
169
172
  let cancelled = false
170
173
  async function loadTeam() {
174
+ if (!cancelled) {
175
+ setError(null)
176
+ setIsNotFound(false)
177
+ }
171
178
  try {
172
179
  const params = new URLSearchParams({ page: '1', pageSize: '1', ids: teamIdValue })
173
180
  const payload = await readApiResultOrThrow<TeamResponse>(
@@ -176,7 +183,10 @@ export default function StaffTeamEditPage({ params }: { params?: { id?: string }
176
183
  { errorMessage: t('staff.teams.errors.load', 'Failed to load team.') },
177
184
  )
178
185
  const record = Array.isArray(payload.items) ? payload.items[0] : null
179
- if (!record) throw new Error(t('staff.teams.errors.notFound', 'Team not found.'))
186
+ if (!record) {
187
+ if (!cancelled) setIsNotFound(true)
188
+ return
189
+ }
180
190
  const customFields = extractCustomFieldEntries(record)
181
191
  const isActive = typeof record.isActive === 'boolean'
182
192
  ? record.isActive
@@ -192,9 +202,15 @@ export default function StaffTeamEditPage({ params }: { params?: { id?: string }
192
202
  ...customFields,
193
203
  })
194
204
  }
195
- } catch (error) {
196
- const message = error instanceof Error ? error.message : t('staff.teams.errors.load', 'Failed to load team.')
197
- flash(message, 'error')
205
+ } catch (err) {
206
+ if (!cancelled) {
207
+ if ((err as { status?: number }).status === 404) {
208
+ setIsNotFound(true)
209
+ } else {
210
+ const message = err instanceof Error ? err.message : t('staff.teams.errors.load', 'Failed to load team.')
211
+ setError(message)
212
+ }
213
+ }
198
214
  }
199
215
  }
200
216
  loadTeam()
@@ -288,6 +304,30 @@ export default function StaffTeamEditPage({ params }: { params?: { id?: string }
288
304
  router.push('/backend/staff/teams')
289
305
  }, [teamId, router, t])
290
306
 
307
+ if (isNotFound) {
308
+ return (
309
+ <Page>
310
+ <PageBody>
311
+ <RecordNotFoundState
312
+ label={t('staff.teams.errors.notFound', 'Team not found.')}
313
+ backHref="/backend/staff/teams"
314
+ backLabel={t('staff.teams.actions.backToList', 'Back to teams')}
315
+ />
316
+ </PageBody>
317
+ </Page>
318
+ )
319
+ }
320
+
321
+ if (error && !initialValues) {
322
+ return (
323
+ <Page>
324
+ <PageBody>
325
+ <ErrorMessage label={error} />
326
+ </PageBody>
327
+ </Page>
328
+ )
329
+ }
330
+
291
331
  return (
292
332
  <Page>
293
333
  <PageBody>
@@ -214,6 +214,8 @@
214
214
  "staff.errors.unauthorized": "Nicht autorisiert",
215
215
  "staff.leaveRequests.actions.accept": "Genehmigen",
216
216
  "staff.leaveRequests.actions.add": "Neuer Antrag",
217
+ "staff.leaveRequests.actions.backToList": "Zurück zu Urlaubsanträgen",
218
+ "staff.leaveRequests.actions.backToMyList": "Zurück zu meinen Urlaubsanträgen",
217
219
  "staff.leaveRequests.actions.createProfile": "Mein Profil erstellen",
218
220
  "staff.leaveRequests.actions.refresh": "Aktualisieren",
219
221
  "staff.leaveRequests.actions.reject": "Ablehnen",
@@ -444,6 +446,7 @@
444
446
  "staff.services.table.search": "Leistungen suchen...",
445
447
  "staff.services.table.tags": "Schlagworte",
446
448
  "staff.teamMembers.actions.add": "Teammitglied hinzufügen",
449
+ "staff.teamMembers.actions.backToList": "Zurück zu Teammitgliedern",
447
450
  "staff.teamMembers.actions.delete": "Löschen",
448
451
  "staff.teamMembers.actions.deleteConfirm": "Teammitglied \"{{name}}\" löschen?",
449
452
  "staff.teamMembers.actions.edit": "Bearbeiten",
@@ -854,6 +857,7 @@
854
857
  "staff.teamMembers.tags.title": "Schlagworte",
855
858
  "staff.teamMembers.tags.updateError": "Tags konnten nicht aktualisiert werden.",
856
859
  "staff.teamRoles.actions.add": "Teamrolle hinzufügen",
860
+ "staff.teamRoles.actions.backToList": "Zurück zu Teamrollen",
857
861
  "staff.teamRoles.actions.delete": "Löschen",
858
862
  "staff.teamRoles.actions.deleteConfirm": "Teamrolle \"{{name}}\" löschen?",
859
863
  "staff.teamRoles.actions.edit": "Bearbeiten",
@@ -897,6 +901,7 @@
897
901
  "staff.teamRoles.table.search": "Rollen suchen...",
898
902
  "staff.teamRoles.table.updatedAt": "Aktualisiert",
899
903
  "staff.teams.actions.add": "Team hinzufügen",
904
+ "staff.teams.actions.backToList": "Zurück zu Teams",
900
905
  "staff.teams.actions.delete": "Löschen",
901
906
  "staff.teams.actions.deleteConfirm": "Team \"{{name}}\" löschen?",
902
907
  "staff.teams.actions.edit": "Bearbeiten",
@@ -214,6 +214,8 @@
214
214
  "staff.errors.unauthorized": "Unauthorized",
215
215
  "staff.leaveRequests.actions.accept": "Approve",
216
216
  "staff.leaveRequests.actions.add": "New request",
217
+ "staff.leaveRequests.actions.backToList": "Back to leave requests",
218
+ "staff.leaveRequests.actions.backToMyList": "Back to my leave requests",
217
219
  "staff.leaveRequests.actions.createProfile": "Create my profile",
218
220
  "staff.leaveRequests.actions.refresh": "Refresh",
219
221
  "staff.leaveRequests.actions.reject": "Reject",
@@ -444,6 +446,7 @@
444
446
  "staff.services.table.search": "Search services...",
445
447
  "staff.services.table.tags": "Tags",
446
448
  "staff.teamMembers.actions.add": "Add team member",
449
+ "staff.teamMembers.actions.backToList": "Back to team members",
447
450
  "staff.teamMembers.actions.delete": "Delete",
448
451
  "staff.teamMembers.actions.deleteConfirm": "Delete team member \"{{name}}\"?",
449
452
  "staff.teamMembers.actions.edit": "Edit",
@@ -854,6 +857,7 @@
854
857
  "staff.teamMembers.tags.title": "Tags",
855
858
  "staff.teamMembers.tags.updateError": "Failed to update tags.",
856
859
  "staff.teamRoles.actions.add": "Add team role",
860
+ "staff.teamRoles.actions.backToList": "Back to team roles",
857
861
  "staff.teamRoles.actions.delete": "Delete",
858
862
  "staff.teamRoles.actions.deleteConfirm": "Delete team role \"{{name}}\"?",
859
863
  "staff.teamRoles.actions.edit": "Edit",
@@ -897,6 +901,7 @@
897
901
  "staff.teamRoles.table.search": "Search roles...",
898
902
  "staff.teamRoles.table.updatedAt": "Updated",
899
903
  "staff.teams.actions.add": "Add team",
904
+ "staff.teams.actions.backToList": "Back to teams",
900
905
  "staff.teams.actions.delete": "Delete",
901
906
  "staff.teams.actions.deleteConfirm": "Delete team \"{{name}}\"?",
902
907
  "staff.teams.actions.edit": "Edit",
@@ -214,6 +214,8 @@
214
214
  "staff.errors.unauthorized": "No autorizado",
215
215
  "staff.leaveRequests.actions.accept": "Aprobar",
216
216
  "staff.leaveRequests.actions.add": "Nueva solicitud",
217
+ "staff.leaveRequests.actions.backToList": "Volver a solicitudes de ausencia",
218
+ "staff.leaveRequests.actions.backToMyList": "Volver a mis solicitudes de ausencia",
217
219
  "staff.leaveRequests.actions.createProfile": "Crear mi perfil",
218
220
  "staff.leaveRequests.actions.refresh": "Actualizar",
219
221
  "staff.leaveRequests.actions.reject": "Rechazar",
@@ -444,6 +446,7 @@
444
446
  "staff.services.table.search": "Buscar servicios...",
445
447
  "staff.services.table.tags": "Etiquetas",
446
448
  "staff.teamMembers.actions.add": "Agregar miembro",
449
+ "staff.teamMembers.actions.backToList": "Volver a miembros del equipo",
447
450
  "staff.teamMembers.actions.delete": "Eliminar",
448
451
  "staff.teamMembers.actions.deleteConfirm": "¿Eliminar al miembro \"{{name}}\"?",
449
452
  "staff.teamMembers.actions.edit": "Editar",
@@ -854,6 +857,7 @@
854
857
  "staff.teamMembers.tags.title": "Etiquetas",
855
858
  "staff.teamMembers.tags.updateError": "No se pudieron actualizar las etiquetas.",
856
859
  "staff.teamRoles.actions.add": "Agregar rol",
860
+ "staff.teamRoles.actions.backToList": "Volver a roles del equipo",
857
861
  "staff.teamRoles.actions.delete": "Eliminar",
858
862
  "staff.teamRoles.actions.deleteConfirm": "¿Eliminar el rol \"{{name}}\"?",
859
863
  "staff.teamRoles.actions.edit": "Editar",
@@ -897,6 +901,7 @@
897
901
  "staff.teamRoles.table.search": "Buscar roles...",
898
902
  "staff.teamRoles.table.updatedAt": "Actualizado",
899
903
  "staff.teams.actions.add": "Agregar equipo",
904
+ "staff.teams.actions.backToList": "Volver a equipos",
900
905
  "staff.teams.actions.delete": "Eliminar",
901
906
  "staff.teams.actions.deleteConfirm": "¿Eliminar el equipo \"{{name}}\"?",
902
907
  "staff.teams.actions.edit": "Editar",
@@ -214,6 +214,8 @@
214
214
  "staff.errors.unauthorized": "Brak autoryzacji",
215
215
  "staff.leaveRequests.actions.accept": "Zatwierdź",
216
216
  "staff.leaveRequests.actions.add": "Nowy wniosek",
217
+ "staff.leaveRequests.actions.backToList": "Powrót do wniosków urlopowych",
218
+ "staff.leaveRequests.actions.backToMyList": "Powrót do moich wniosków urlopowych",
217
219
  "staff.leaveRequests.actions.createProfile": "Utwórz mój profil",
218
220
  "staff.leaveRequests.actions.refresh": "Odśwież",
219
221
  "staff.leaveRequests.actions.reject": "Odrzuć",
@@ -444,6 +446,7 @@
444
446
  "staff.services.table.search": "Szukaj usług...",
445
447
  "staff.services.table.tags": "Tagi",
446
448
  "staff.teamMembers.actions.add": "Dodaj członka",
449
+ "staff.teamMembers.actions.backToList": "Powrót do członków zespołu",
447
450
  "staff.teamMembers.actions.delete": "Usuń",
448
451
  "staff.teamMembers.actions.deleteConfirm": "Usunąć członka \"{{name}}\"?",
449
452
  "staff.teamMembers.actions.edit": "Edytuj",
@@ -854,6 +857,7 @@
854
857
  "staff.teamMembers.tags.title": "Tagi",
855
858
  "staff.teamMembers.tags.updateError": "Nie udało się zaktualizować tagów.",
856
859
  "staff.teamRoles.actions.add": "Dodaj rolę",
860
+ "staff.teamRoles.actions.backToList": "Powrót do ról zespołu",
857
861
  "staff.teamRoles.actions.delete": "Usuń",
858
862
  "staff.teamRoles.actions.deleteConfirm": "Usunąć rolę \"{{name}}\"?",
859
863
  "staff.teamRoles.actions.edit": "Edytuj",
@@ -897,6 +901,7 @@
897
901
  "staff.teamRoles.table.search": "Szukaj ról...",
898
902
  "staff.teamRoles.table.updatedAt": "Zaktualizowano",
899
903
  "staff.teams.actions.add": "Dodaj zespół",
904
+ "staff.teams.actions.backToList": "Powrót do zespołów",
900
905
  "staff.teams.actions.delete": "Usuń",
901
906
  "staff.teams.actions.deleteConfirm": "Usunąć zespół \"{{name}}\"?",
902
907
  "staff.teams.actions.edit": "Edytuj",
@@ -8,6 +8,7 @@ import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
8
8
  import { Spinner } from '@open-mercato/ui/primitives/spinner'
9
9
  import { Button } from '@open-mercato/ui/primitives/button'
10
10
  import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
11
+ import { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
11
12
  import { apiFetch } from '@open-mercato/ui/backend/utils/api'
12
13
  import { readJsonSafe } from '@open-mercato/ui/backend/utils/serverErrors'
13
14
  import { formatWorkflowValidationError } from '../../../lib/format-validation-error'
@@ -49,14 +50,22 @@ export default function EditWorkflowDefinitionPage() {
49
50
  queryFn: async () => {
50
51
  const response = await apiFetch(`/api/workflows/definitions/${definitionId}`)
51
52
  if (!response.ok) {
52
- throw new Error(t('workflows.errors.fetchFailed'))
53
+ const err = new Error(t('workflows.errors.fetchFailed')) as Error & { status?: number }
54
+ err.status = response.status
55
+ throw err
53
56
  }
54
57
  const result = await response.json()
55
58
  return result.data
56
59
  },
57
60
  enabled: !!definitionId,
61
+ retry: (failureCount, err) => {
62
+ if ((err as { status?: number }).status === 404) return false
63
+ return failureCount < 2
64
+ },
58
65
  })
59
66
 
67
+ const isNotFound = (error as { status?: number } | null)?.status === 404
68
+
60
69
  const initialValues = React.useMemo(() => {
61
70
  if (definition) {
62
71
  return parseWorkflowToFormValues(definition)
@@ -209,12 +218,26 @@ export default function EditWorkflowDefinitionPage() {
209
218
  )
210
219
  }
211
220
 
221
+ if (isNotFound) {
222
+ return (
223
+ <Page>
224
+ <PageBody>
225
+ <RecordNotFoundState
226
+ label={t('workflows.errors.notFound', t('workflows.errors.loadFailed'))}
227
+ backHref="/backend/definitions"
228
+ backLabel={t('workflows.backToList')}
229
+ />
230
+ </PageBody>
231
+ </Page>
232
+ )
233
+ }
234
+
212
235
  if (error || !definition) {
213
236
  return (
214
237
  <Page>
215
238
  <PageBody>
216
- <div className="flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground">
217
- <p>{t('workflows.errors.loadFailed')}</p>
239
+ <ErrorMessage label={t('workflows.errors.loadFailed')} />
240
+ <div className="mt-4 flex justify-center">
218
241
  <Button asChild variant="outline">
219
242
  <a href="/backend/definitions">{t('workflows.backToList')}</a>
220
243
  </Button>
@@ -402,6 +402,7 @@
402
402
  "workflows.errors.createFailed": "Workflow konnte nicht erstellt werden",
403
403
  "workflows.errors.fetchFailed": "Workflow konnte nicht abgerufen werden",
404
404
  "workflows.errors.loadFailed": "Workflow konnte nicht geladen werden. Bitte versuchen Sie es erneut.",
405
+ "workflows.errors.notFound": "Workflow nicht gefunden.",
405
406
  "workflows.errors.updateFailed": "Workflow konnte nicht aktualisiert werden",
406
407
  "workflows.events.backToList": "Zurück zu Ereignissen",
407
408
  "workflows.events.detail.eventData": "Ereignisdaten",
@@ -402,6 +402,7 @@
402
402
  "workflows.errors.createFailed": "Failed to create workflow",
403
403
  "workflows.errors.fetchFailed": "Failed to fetch workflow",
404
404
  "workflows.errors.loadFailed": "Failed to load workflow. Please try again.",
405
+ "workflows.errors.notFound": "Workflow not found.",
405
406
  "workflows.errors.updateFailed": "Failed to update workflow",
406
407
  "workflows.events.backToList": "Back to Events",
407
408
  "workflows.events.detail.eventData": "Event Data",
@@ -402,6 +402,7 @@
402
402
  "workflows.errors.createFailed": "No se pudo crear el flujo de trabajo",
403
403
  "workflows.errors.fetchFailed": "No se pudo obtener el flujo de trabajo",
404
404
  "workflows.errors.loadFailed": "No se pudo cargar el flujo de trabajo. Intentalo de nuevo.",
405
+ "workflows.errors.notFound": "Flujo de trabajo no encontrado.",
405
406
  "workflows.errors.updateFailed": "No se pudo actualizar el flujo de trabajo",
406
407
  "workflows.events.backToList": "Volver a eventos",
407
408
  "workflows.events.detail.eventData": "Datos del evento",
@@ -402,6 +402,7 @@
402
402
  "workflows.errors.createFailed": "Nie udało się utworzyć przepływu",
403
403
  "workflows.errors.fetchFailed": "Nie udało się pobrać przepływu",
404
404
  "workflows.errors.loadFailed": "Nie udało się załadować przepływu. Spróbuj ponownie.",
405
+ "workflows.errors.notFound": "Nie znaleziono przepływu pracy.",
405
406
  "workflows.errors.updateFailed": "Nie udało się zaktualizować przepływu",
406
407
  "workflows.events.backToList": "Powrót do Zdarzeń",
407
408
  "workflows.events.detail.eventData": "Dane Zdarzenia",