@open-mercato/core 0.6.1-develop.3227.1.2b7b8ab258 → 0.6.1-develop.3256.1.fe3dec2464
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/modules/catalog/ai-agents.js +4 -0
- package/dist/modules/catalog/ai-agents.js.map +2 -2
- package/dist/modules/customers/ai-agents.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +11 -1
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +11 -1
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +78 -35
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +74 -30
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +78 -35
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/commands/people.js +20 -0
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/entities/components/EncryptionManager.js +40 -17
- package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
- package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
- package/package.json +5 -5
- package/src/modules/catalog/ai-agents.ts +8 -49
- package/src/modules/customers/ai-agents.ts +4 -51
- package/src/modules/customers/api/companies/route.ts +10 -0
- package/src/modules/customers/api/people/route.ts +10 -0
- package/src/modules/customers/backend/customers/companies/page.tsx +95 -35
- package/src/modules/customers/backend/customers/deals/page.tsx +91 -30
- package/src/modules/customers/backend/customers/people/page.tsx +96 -35
- package/src/modules/customers/commands/people.ts +30 -0
- package/src/modules/customers/i18n/de.json +8 -0
- package/src/modules/customers/i18n/en.json +8 -0
- package/src/modules/customers/i18n/es.json +8 -0
- package/src/modules/customers/i18n/pl.json +8 -0
- package/src/modules/entities/components/EncryptionManager.tsx +50 -21
- package/src/modules/inbox_ops/lib/llmProvider.ts +10 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { useQuery, useMutation } from '@tanstack/react-query'
|
|
5
5
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
6
|
+
import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
|
|
6
7
|
import {
|
|
7
8
|
Select,
|
|
8
9
|
SelectContent,
|
|
@@ -14,13 +15,14 @@ import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
|
|
|
14
15
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
15
16
|
import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
17
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
17
|
-
import { useCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'
|
|
18
|
+
import { useCustomFieldDefs, type CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'
|
|
18
19
|
import { Plus, Save, Trash2 } from 'lucide-react'
|
|
19
20
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
20
21
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
21
22
|
import { getEntityFields } from '#generated/entity-fields-registry'
|
|
22
23
|
|
|
23
24
|
type EntityOption = { entityId: string; label?: string; source?: string }
|
|
25
|
+
type FieldOption = { value: string; label: string }
|
|
24
26
|
|
|
25
27
|
type EncryptionFieldRow = {
|
|
26
28
|
id: string
|
|
@@ -36,6 +38,8 @@ type EncryptionMapResponse = {
|
|
|
36
38
|
|
|
37
39
|
type CanonicalOption = { value: string; label?: string }
|
|
38
40
|
|
|
41
|
+
const EMPTY_FIELD_DEFS: CustomFieldDefDto[] = []
|
|
42
|
+
|
|
39
43
|
function normalizeToken(value: string): string {
|
|
40
44
|
return value
|
|
41
45
|
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
@@ -64,6 +68,24 @@ function normalizeFieldRows(raw: EncryptionMapResponse | undefined, options: Can
|
|
|
64
68
|
}))
|
|
65
69
|
}
|
|
66
70
|
|
|
71
|
+
function areFieldRowsEqual(a: EncryptionFieldRow[], b: EncryptionFieldRow[]): boolean {
|
|
72
|
+
if (a === b) return true
|
|
73
|
+
if (a.length !== b.length) return false
|
|
74
|
+
return a.every((row, idx) => {
|
|
75
|
+
const other = b[idx]
|
|
76
|
+
return !!other && row.id === other.id && row.field === other.field && (row.hashField ?? null) === (other.hashField ?? null)
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function areFieldOptionsEqual(a: FieldOption[], b: FieldOption[]): boolean {
|
|
81
|
+
if (a === b) return true
|
|
82
|
+
if (a.length !== b.length) return false
|
|
83
|
+
return a.every((option, idx) => {
|
|
84
|
+
const other = b[idx]
|
|
85
|
+
return !!other && option.value === other.value && option.label === other.label
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
function buildRowId(): string {
|
|
68
90
|
if (typeof crypto !== 'undefined' && crypto.randomUUID) return crypto.randomUUID()
|
|
69
91
|
return `row-${Math.random().toString(36).slice(2)}`
|
|
@@ -75,11 +97,12 @@ export function EncryptionManager() {
|
|
|
75
97
|
const [selectedEntityId, setSelectedEntityId] = React.useState('')
|
|
76
98
|
const [fields, setFields] = React.useState<EncryptionFieldRow[]>([])
|
|
77
99
|
const [isActive, setIsActive] = React.useState(true)
|
|
78
|
-
const [baseFieldOptions, setBaseFieldOptions] = React.useState<
|
|
100
|
+
const [baseFieldOptions, setBaseFieldOptions] = React.useState<FieldOption[]>([])
|
|
79
101
|
const [hasUserEdited, setHasUserEdited] = React.useState(false)
|
|
80
|
-
const { data:
|
|
102
|
+
const { data: rawFieldDefs, isLoading: loadingFieldDefs } = useCustomFieldDefs(selectedEntityId ? [selectedEntityId] : [], {
|
|
81
103
|
enabled: !!selectedEntityId,
|
|
82
104
|
})
|
|
105
|
+
const fieldDefs = rawFieldDefs ?? EMPTY_FIELD_DEFS
|
|
83
106
|
const canonicalOptions = React.useMemo<CanonicalOption[]>(() => {
|
|
84
107
|
const options: CanonicalOption[] = []
|
|
85
108
|
for (const option of baseFieldOptions) {
|
|
@@ -133,13 +156,13 @@ export function EncryptionManager() {
|
|
|
133
156
|
|
|
134
157
|
React.useEffect(() => {
|
|
135
158
|
if (!selectedEntityId) {
|
|
136
|
-
setBaseFieldOptions([])
|
|
159
|
+
setBaseFieldOptions((prev) => (prev.length ? [] : prev))
|
|
137
160
|
return
|
|
138
161
|
}
|
|
139
162
|
const parts = selectedEntityId.split(':')
|
|
140
163
|
const entitySlug = parts[1]
|
|
141
164
|
if (!entitySlug) {
|
|
142
|
-
setBaseFieldOptions([])
|
|
165
|
+
setBaseFieldOptions((prev) => (prev.length ? [] : prev))
|
|
143
166
|
return
|
|
144
167
|
}
|
|
145
168
|
|
|
@@ -147,11 +170,11 @@ export function EncryptionManager() {
|
|
|
147
170
|
const mod = getEntityFields(entitySlug)
|
|
148
171
|
if (!mod) {
|
|
149
172
|
console.warn('[encryption] No fields found for entity', entitySlug)
|
|
150
|
-
setBaseFieldOptions([])
|
|
173
|
+
setBaseFieldOptions((prev) => (prev.length ? [] : prev))
|
|
151
174
|
return
|
|
152
175
|
}
|
|
153
176
|
|
|
154
|
-
const options:
|
|
177
|
+
const options: FieldOption[] = []
|
|
155
178
|
for (const raw of Object.values(mod)) {
|
|
156
179
|
if (typeof raw !== 'string' || !raw.trim()) continue
|
|
157
180
|
const value = raw.trim()
|
|
@@ -163,7 +186,7 @@ export function EncryptionManager() {
|
|
|
163
186
|
.trim() || value
|
|
164
187
|
options.push({ value, label })
|
|
165
188
|
}
|
|
166
|
-
setBaseFieldOptions(options)
|
|
189
|
+
setBaseFieldOptions((prev) => (areFieldOptionsEqual(prev, options) ? prev : options))
|
|
167
190
|
}, [selectedEntityId])
|
|
168
191
|
|
|
169
192
|
const {
|
|
@@ -188,14 +211,16 @@ export function EncryptionManager() {
|
|
|
188
211
|
const isSameMap = signature === lastMapSignatureRef.current
|
|
189
212
|
if (isSameMap && hasUserEdited) return
|
|
190
213
|
if (!map) {
|
|
191
|
-
setFields([])
|
|
192
|
-
setIsActive(true)
|
|
214
|
+
setFields((prev) => (prev.length ? [] : prev))
|
|
215
|
+
setIsActive((prev) => (prev === true ? prev : true))
|
|
193
216
|
setHasUserEdited(false)
|
|
194
217
|
lastMapSignatureRef.current = signature
|
|
195
218
|
return
|
|
196
219
|
}
|
|
197
|
-
|
|
198
|
-
|
|
220
|
+
const nextFields = normalizeFieldRows(map, canonicalOptions)
|
|
221
|
+
setFields((prev) => (areFieldRowsEqual(prev, nextFields) ? prev : nextFields))
|
|
222
|
+
const nextIsActive = map?.isActive !== false
|
|
223
|
+
setIsActive((prev) => (prev === nextIsActive ? prev : nextIsActive))
|
|
199
224
|
setHasUserEdited(false)
|
|
200
225
|
lastMapSignatureRef.current = signature
|
|
201
226
|
}, [mapSignature, map, canonicalOptions, hasUserEdited])
|
|
@@ -267,7 +292,7 @@ export function EncryptionManager() {
|
|
|
267
292
|
<ErrorMessage
|
|
268
293
|
label={t('entities.encryption.errors.loadMap', 'Failed to load encryption map')}
|
|
269
294
|
action={(
|
|
270
|
-
<Button variant="outline" size="sm" onClick={() => void refetchMap()}>
|
|
295
|
+
<Button type="button" variant="outline" size="sm" onClick={() => void refetchMap()}>
|
|
271
296
|
{t('entities.encryption.actions.retry', 'Retry')}
|
|
272
297
|
</Button>
|
|
273
298
|
)}
|
|
@@ -348,6 +373,7 @@ export function EncryptionManager() {
|
|
|
348
373
|
</td>
|
|
349
374
|
<td className="px-3 py-2 align-top text-right">
|
|
350
375
|
<Button
|
|
376
|
+
type="button"
|
|
351
377
|
variant="ghost"
|
|
352
378
|
size="sm"
|
|
353
379
|
className="h-9 w-9 px-0"
|
|
@@ -398,7 +424,7 @@ export function EncryptionManager() {
|
|
|
398
424
|
</SelectContent>
|
|
399
425
|
</Select>
|
|
400
426
|
{entitiesError ? (
|
|
401
|
-
<p className="mt-1 text-xs text-
|
|
427
|
+
<p className="mt-1 text-xs text-status-error-text">
|
|
402
428
|
{t('entities.encryption.errors.loadEntities', 'Failed to load entities')}
|
|
403
429
|
</p>
|
|
404
430
|
) : (
|
|
@@ -407,14 +433,16 @@ export function EncryptionManager() {
|
|
|
407
433
|
</p>
|
|
408
434
|
)}
|
|
409
435
|
</div>
|
|
410
|
-
<
|
|
411
|
-
<
|
|
412
|
-
|
|
436
|
+
<div className="inline-flex items-center gap-2 text-sm">
|
|
437
|
+
<Checkbox
|
|
438
|
+
id="entities-encryption-active"
|
|
413
439
|
checked={isActive}
|
|
414
|
-
|
|
440
|
+
onCheckedChange={(checked) => setIsActive(checked === true)}
|
|
415
441
|
/>
|
|
416
|
-
|
|
417
|
-
|
|
442
|
+
<label htmlFor="entities-encryption-active">
|
|
443
|
+
{t('entities.encryption.active', 'Encryption enabled for this entity')}
|
|
444
|
+
</label>
|
|
445
|
+
</div>
|
|
418
446
|
</div>
|
|
419
447
|
</div>
|
|
420
448
|
<div className="rounded-lg border bg-background/80 p-4">
|
|
@@ -425,7 +453,7 @@ export function EncryptionManager() {
|
|
|
425
453
|
{t('entities.encryption.fields.subtitle', 'List the attributes that should be encrypted with the tenant key.')}
|
|
426
454
|
</p>
|
|
427
455
|
</div>
|
|
428
|
-
<Button variant="outline" size="sm" onClick={addField}>
|
|
456
|
+
<Button type="button" variant="outline" size="sm" onClick={addField}>
|
|
429
457
|
<Plus className="mr-2 h-4 w-4" />
|
|
430
458
|
{t('entities.encryption.actions.add', 'Add field')}
|
|
431
459
|
</Button>
|
|
@@ -434,6 +462,7 @@ export function EncryptionManager() {
|
|
|
434
462
|
</div>
|
|
435
463
|
<div className="flex justify-end">
|
|
436
464
|
<Button
|
|
465
|
+
type="button"
|
|
437
466
|
onClick={() => mutation.mutate()}
|
|
438
467
|
disabled={mutation.isPending || loadingEntities || !!entitiesError || !selectedEntityId}
|
|
439
468
|
>
|
|
@@ -163,6 +163,16 @@ export async function runExtractionWithConfiguredProvider(input: {
|
|
|
163
163
|
model = factoryResolution.model
|
|
164
164
|
modelWithProvider = `${factoryResolution.providerId}/${factoryResolution.modelId}`
|
|
165
165
|
} else {
|
|
166
|
+
// BC: Legacy OPENCODE_PROVIDER / OPENCODE_MODEL path. This branch only
|
|
167
|
+
// runs when createModelFactory throws AiModelFactoryError('no_provider_configured'),
|
|
168
|
+
// meaning none of the new-style provider env vars (ANTHROPIC_API_KEY,
|
|
169
|
+
// OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, OM_AI_PROVIDER, ...) is
|
|
170
|
+
// set. The OPENCODE_* envs are deliberately kept as BC fallbacks instead
|
|
171
|
+
// of being treated as canonical OM_AI_* values because they are scoped to
|
|
172
|
+
// the OpenCode Code Mode stack (spec
|
|
173
|
+
// 2026-04-27-ai-agents-provider-model-baseurl-overrides, R1 mitigation).
|
|
174
|
+
// Keeping this fallback alive preserves backward compatibility for existing
|
|
175
|
+
// inbox_ops deployments that have not yet migrated to the new env vars.
|
|
166
176
|
const providerId = resolveExtractionProviderId()
|
|
167
177
|
const apiKey = requireOpenCodeProviderApiKey(providerId)
|
|
168
178
|
const modelConfig = resolveOpenCodeModel(providerId, {
|