@open-mercato/core 0.6.7-develop.6706.1.b3a4c759bb → 0.6.7-develop.6725.1.07a748cfc2
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/auth/api/admin/nav.js +14 -4
- package/dist/modules/auth/api/admin/nav.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +8 -19
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +31 -14
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/customers/api/utils.js +12 -18
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/cli.js +11 -4
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +4 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +14 -10
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/batch/route.js +4 -2
- package/dist/modules/dashboards/api/widgets/data/batch/route.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/route.js +20 -2
- package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
- package/dist/modules/dashboards/lib/aggregations.js +76 -40
- package/dist/modules/dashboards/lib/aggregations.js.map +2 -2
- package/dist/modules/dashboards/lib/exactDecimal.js +69 -0
- package/dist/modules/dashboards/lib/exactDecimal.js.map +7 -0
- package/dist/modules/dashboards/services/widgetDataService.js +228 -5
- package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureGuard.js +3 -2
- package/dist/modules/feature_toggles/components/FeatureGuard.js.map +2 -2
- package/dist/modules/feature_toggles/components/hooks/staleTime.js +5 -0
- package/dist/modules/feature_toggles/components/hooks/staleTime.js.map +7 -0
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagBoolean.js +5 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagBoolean.js.map +2 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagJson.js +5 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagJson.js.map +2 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagNumber.js +5 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagNumber.js.map +2 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagString.js +5 -2
- package/dist/modules/feature_toggles/components/hooks/useFeatureFlagString.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/route.js +16 -1
- package/dist/modules/inbox_ops/api/proposals/route.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/search-reindex-proposal-created.js +32 -0
- package/dist/modules/inbox_ops/subscribers/search-reindex-proposal-created.js.map +7 -0
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +0 -5
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +2 -2
- package/dist/modules/integrations/widgets/injection/external-ids/widget.js +14 -0
- package/dist/modules/integrations/widgets/injection/external-ids/widget.js.map +7 -0
- package/dist/modules/messages/lib/searchLookup.js +8 -16
- package/dist/modules/messages/lib/searchLookup.js.map +2 -2
- package/dist/modules/query_index/api/openapi.js +13 -1
- package/dist/modules/query_index/api/openapi.js.map +2 -2
- package/dist/modules/query_index/api/status.js +165 -105
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +128 -41
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/lib/batch.js +11 -4
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/document.js +12 -5
- package/dist/modules/query_index/lib/document.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +36 -4
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +1 -1
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +7 -4
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +14 -3
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +22 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/useSalesChannelsEnabled.js +2 -35
- package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +2 -2
- package/dist/modules/sales/data/validators.js +25 -4
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/admin/nav.ts +24 -4
- package/src/modules/auth/api/users/route.ts +8 -28
- package/src/modules/auth/lib/backendChrome.tsx +51 -13
- package/src/modules/customers/api/utils.ts +12 -31
- package/src/modules/customers/cli.ts +11 -4
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +4 -0
- package/src/modules/customers/components/formConfig.tsx +12 -8
- package/src/modules/dashboards/api/widgets/data/batch/route.ts +4 -0
- package/src/modules/dashboards/api/widgets/data/route.ts +21 -0
- package/src/modules/dashboards/lib/aggregations.ts +122 -43
- package/src/modules/dashboards/lib/exactDecimal.ts +96 -0
- package/src/modules/dashboards/services/widgetDataService.ts +342 -4
- package/src/modules/feature_toggles/components/FeatureGuard.tsx +9 -2
- package/src/modules/feature_toggles/components/hooks/staleTime.ts +5 -0
- package/src/modules/feature_toggles/components/hooks/useFeatureFlagBoolean.ts +13 -1
- package/src/modules/feature_toggles/components/hooks/useFeatureFlagJson.ts +12 -3
- package/src/modules/feature_toggles/components/hooks/useFeatureFlagNumber.ts +10 -1
- package/src/modules/feature_toggles/components/hooks/useFeatureFlagString.ts +10 -1
- package/src/modules/inbox_ops/api/proposals/route.ts +20 -1
- package/src/modules/inbox_ops/subscribers/search-reindex-proposal-created.ts +39 -0
- package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +0 -5
- package/src/modules/integrations/widgets/injection/external-ids/widget.ts +13 -0
- package/src/modules/messages/lib/searchLookup.ts +11 -34
- package/src/modules/query_index/api/openapi.ts +12 -0
- package/src/modules/query_index/api/status.ts +238 -136
- package/src/modules/query_index/components/QueryIndexesTable.tsx +192 -46
- package/src/modules/query_index/i18n/de.json +5 -3
- package/src/modules/query_index/i18n/en.json +5 -3
- package/src/modules/query_index/i18n/es.json +5 -3
- package/src/modules/query_index/i18n/pl.json +5 -3
- package/src/modules/query_index/lib/batch.ts +11 -4
- package/src/modules/query_index/lib/document.ts +35 -4
- package/src/modules/query_index/lib/engine.ts +53 -5
- package/src/modules/query_index/lib/indexer.ts +1 -1
- package/src/modules/query_index/lib/search-tokens.ts +13 -4
- package/src/modules/sales/api/documents/factory.ts +28 -3
- package/src/modules/sales/commands/documents.ts +26 -2
- package/src/modules/sales/components/useSalesChannelsEnabled.ts +2 -48
- package/src/modules/sales/data/validators.ts +50 -5
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import { useQuery } from '@tanstack/react-query'
|
|
4
4
|
import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
5
|
+
import { FEATURE_FLAG_STALE_TIME_MS } from './staleTime'
|
|
5
6
|
|
|
6
7
|
export type UseFeatureFlagStringOptions = {
|
|
7
8
|
id: string
|
|
9
|
+
/**
|
|
10
|
+
* Value used while the check is in flight and whenever the toggle cannot be
|
|
11
|
+
* resolved (undefined toggle, type mismatch, network or permission failure).
|
|
12
|
+
* Defaults to `null`.
|
|
13
|
+
*/
|
|
14
|
+
defaultValue?: string | null
|
|
8
15
|
}
|
|
9
16
|
|
|
10
17
|
export type UseFeatureFlagStringResult = {
|
|
@@ -21,6 +28,7 @@ type Result<T> = {
|
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
export function useFeatureFlagString(options: UseFeatureFlagStringOptions): UseFeatureFlagStringResult {
|
|
31
|
+
const defaultValue = options.defaultValue ?? null
|
|
24
32
|
const query = useQuery({
|
|
25
33
|
queryKey: ['featureToggles', 'check', 'string', options?.id],
|
|
26
34
|
queryFn: async () => {
|
|
@@ -37,9 +45,10 @@ export function useFeatureFlagString(options: UseFeatureFlagStringOptions): UseF
|
|
|
37
45
|
return result
|
|
38
46
|
},
|
|
39
47
|
enabled: !!options.id,
|
|
48
|
+
staleTime: FEATURE_FLAG_STALE_TIME_MS,
|
|
40
49
|
})
|
|
41
50
|
|
|
42
|
-
const value = query.data?.ok ? query.data.value :
|
|
51
|
+
const value = query.data?.ok ? query.data.value : defaultValue
|
|
43
52
|
const isLoading = query.isLoading
|
|
44
53
|
|
|
45
54
|
return {
|
|
@@ -4,6 +4,8 @@ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
|
4
4
|
import type { FilterQuery } from '@mikro-orm/postgresql'
|
|
5
5
|
import { findAndCountWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
6
6
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
7
|
+
import { findEntityIdsBySearchTokens, type SearchTokenDatabase } from '@open-mercato/shared/lib/search/tokenLookup'
|
|
8
|
+
import { E } from '#generated/entities.ids.generated'
|
|
7
9
|
import { InboxProposal, InboxEmail, InboxProposalAction, InboxDiscrepancy, type InboxProposalCategory } from '../../data/entities'
|
|
8
10
|
import { proposalListQuerySchema } from '../../data/validators'
|
|
9
11
|
import { resolveRequestContext, UnauthorizedError } from '../routeHelpers'
|
|
@@ -47,7 +49,24 @@ export async function GET(req: Request) {
|
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
if (query.search) {
|
|
50
|
-
|
|
52
|
+
// `summary` is covered by the inbox_ops encryption map, so an ILIKE alone
|
|
53
|
+
// compares the pattern against ciphertext and matches nothing once
|
|
54
|
+
// encryption is on. Union it with the token index, which stores hashes of
|
|
55
|
+
// the plaintext. Issue #2990.
|
|
56
|
+
const searchOr: FilterQuery<InboxProposal>[] = [
|
|
57
|
+
{ summary: { $ilike: `%${escapeLikePattern(query.search)}%` } },
|
|
58
|
+
]
|
|
59
|
+
const tokenMatch = await findEntityIdsBySearchTokens({
|
|
60
|
+
db: ctx.em.getKysely<SearchTokenDatabase>(),
|
|
61
|
+
entityType: E.inbox_ops.inbox_proposal,
|
|
62
|
+
query: query.search,
|
|
63
|
+
fields: ['summary'],
|
|
64
|
+
scope: { tenantId: ctx.tenantId, organizationId: ctx.organizationId },
|
|
65
|
+
})
|
|
66
|
+
if (tokenMatch.matched && tokenMatch.ids.length) {
|
|
67
|
+
searchOr.push({ id: { $in: tokenMatch.ids } })
|
|
68
|
+
}
|
|
69
|
+
where.$or = searchOr
|
|
51
70
|
}
|
|
52
71
|
|
|
53
72
|
const offset = (query.page - 1) * query.pageSize
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const metadata = {
|
|
2
|
+
event: 'inbox_ops.proposal.created',
|
|
3
|
+
persistent: false,
|
|
4
|
+
id: 'inbox_ops:query-index-reindex-proposal-created',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type Payload = {
|
|
8
|
+
proposalId?: string
|
|
9
|
+
tenantId?: string | null
|
|
10
|
+
organizationId?: string | null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type EventBus = { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> }
|
|
14
|
+
type HandlerContext = { resolve: <T = unknown>(name: string) => T }
|
|
15
|
+
|
|
16
|
+
export default async function handle(payload: Payload, ctx: HandlerContext): Promise<void> {
|
|
17
|
+
const recordId = typeof payload.proposalId === 'string' ? payload.proposalId : null
|
|
18
|
+
const tenantId = typeof payload.tenantId === 'string' ? payload.tenantId : null
|
|
19
|
+
if (!recordId || !tenantId) return
|
|
20
|
+
|
|
21
|
+
let eventBus: EventBus | null = null
|
|
22
|
+
try {
|
|
23
|
+
eventBus = ctx.resolve<EventBus>('eventBus')
|
|
24
|
+
} catch {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await eventBus.emitEvent('query_index.upsert_one', {
|
|
29
|
+
entityType: 'inbox_ops:inbox_proposal',
|
|
30
|
+
recordId,
|
|
31
|
+
organizationId: payload.organizationId ?? null,
|
|
32
|
+
tenantId,
|
|
33
|
+
crudAction: 'created',
|
|
34
|
+
coverageBaseDelta: 1,
|
|
35
|
+
}, {
|
|
36
|
+
tenantId,
|
|
37
|
+
organizationId: payload.organizationId ?? null,
|
|
38
|
+
}).catch(() => undefined)
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'
|
|
2
|
+
import ExternalIdsWidget from './widget.client'
|
|
3
|
+
|
|
4
|
+
const widget: InjectionWidgetModule = {
|
|
5
|
+
metadata: {
|
|
6
|
+
id: 'integrations.injection.external-ids',
|
|
7
|
+
title: 'External IDs',
|
|
8
|
+
features: ['integrations.view'],
|
|
9
|
+
},
|
|
10
|
+
Widget: ExternalIdsWidget,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default widget
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'
|
|
2
|
+
import type { Kysely } from 'kysely'
|
|
3
|
+
import { findEntityIdsBySearchTokensCompat, type SearchTokenDatabase } from '@open-mercato/shared/lib/search/tokenLookup'
|
|
5
4
|
|
|
6
|
-
function getDb(em: EntityManager): Kysely<
|
|
7
|
-
return em.getKysely<
|
|
5
|
+
function getDb(em: EntityManager): Kysely<SearchTokenDatabase> {
|
|
6
|
+
return em.getKysely<SearchTokenDatabase>()
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
export async function findMessageIdsBySearchTokens({
|
|
@@ -20,33 +19,11 @@ export async function findMessageIdsBySearchTokens({
|
|
|
20
19
|
organizationId: string | null
|
|
21
20
|
fields?: string[]
|
|
22
21
|
}): Promise<string[] | null> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
let searchQuery = db
|
|
31
|
-
.selectFrom('search_tokens')
|
|
32
|
-
.select('entity_id')
|
|
33
|
-
.where('entity_type', '=', 'messages:message')
|
|
34
|
-
.where('field', 'in', fields)
|
|
35
|
-
.where('token_hash', 'in', tokens.hashes)
|
|
36
|
-
.where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)
|
|
37
|
-
|
|
38
|
-
if (organizationId) {
|
|
39
|
-
searchQuery = searchQuery.where('organization_id', '=', organizationId)
|
|
40
|
-
} else {
|
|
41
|
-
searchQuery = searchQuery.where(sql<boolean>`organization_id is not distinct from ${null}`)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const rows = await searchQuery
|
|
45
|
-
.groupBy('entity_id')
|
|
46
|
-
.having(sql<boolean>`count(distinct token_hash) >= ${tokens.hashes.length}`)
|
|
47
|
-
.execute()
|
|
48
|
-
|
|
49
|
-
return rows
|
|
50
|
-
.map((row: { entity_id?: unknown }) => (typeof row.entity_id === 'string' ? row.entity_id : null))
|
|
51
|
-
.filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)
|
|
22
|
+
return findEntityIdsBySearchTokensCompat({
|
|
23
|
+
db: getDb(em),
|
|
24
|
+
entityType: 'messages:message',
|
|
25
|
+
query,
|
|
26
|
+
fields,
|
|
27
|
+
scope: { tenantId, organizationId },
|
|
28
|
+
})
|
|
52
29
|
}
|
|
@@ -37,13 +37,25 @@ export const queryIndexJobSchema = z.object({
|
|
|
37
37
|
|
|
38
38
|
export const queryIndexStatusItemSchema = z.object({
|
|
39
39
|
entityId: z.string(),
|
|
40
|
+
/** Human label. Code-defined entities have no label registry, so this mirrors `entityId`. */
|
|
40
41
|
label: z.string(),
|
|
41
42
|
baseCount: z.number().int().nonnegative().nullable(),
|
|
42
43
|
indexCount: z.number().int().nonnegative().nullable(),
|
|
43
44
|
vectorCount: z.number().int().nonnegative().nullable().optional(),
|
|
45
|
+
/** The entity declares `buildSource`, i.e. it is configured for vector search. */
|
|
44
46
|
vectorEnabled: z.boolean().optional(),
|
|
47
|
+
/** Additive: vector indexing can actually run (auto-indexing on, provider reachable, tenant opted in). */
|
|
48
|
+
vectorIndexingActive: z.boolean().optional(),
|
|
49
|
+
fulltextCount: z.number().int().nonnegative().nullable().optional(),
|
|
50
|
+
fulltextEnabled: z.boolean().optional(),
|
|
51
|
+
/** Additive: the entity has active custom field definitions in the current scope. */
|
|
52
|
+
hasCustomFields: z.boolean().optional(),
|
|
53
|
+
/** Aggregate health: query index in sync AND, when vector-configured, vector coverage complete. */
|
|
45
54
|
ok: z.boolean(),
|
|
55
|
+
/** Additive: query index alone is in sync with the base table, independent of vector/fulltext. */
|
|
56
|
+
queryIndexOk: z.boolean().optional(),
|
|
46
57
|
job: queryIndexJobSchema,
|
|
58
|
+
refreshedAt: z.string().datetime().nullable().optional(),
|
|
47
59
|
})
|
|
48
60
|
|
|
49
61
|
export const queryIndexErrorLogSchema = z.object({
|