@open-mercato/core 0.4.11-develop.1355.50152f3ee9 → 0.4.11-develop.1362.574a071900

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 (35) hide show
  1. package/dist/modules/customers/api/companies/route.js +141 -3
  2. package/dist/modules/customers/api/companies/route.js.map +2 -2
  3. package/dist/modules/customers/api/deals/route.js +52 -3
  4. package/dist/modules/customers/api/deals/route.js.map +2 -2
  5. package/dist/modules/customers/api/people/route.js +145 -3
  6. package/dist/modules/customers/api/people/route.js.map +2 -2
  7. package/dist/modules/customers/api/utils.js +195 -0
  8. package/dist/modules/customers/api/utils.js.map +2 -2
  9. package/dist/modules/customers/backend/customers/companies/page.js +171 -6
  10. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  11. package/dist/modules/customers/backend/customers/deals/page.js +100 -7
  12. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  13. package/dist/modules/customers/backend/customers/people/page.js +180 -7
  14. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  15. package/dist/modules/customers/commands/interactions.js +7 -0
  16. package/dist/modules/customers/commands/interactions.js.map +2 -2
  17. package/dist/modules/customers/components/detail/DealForm.js +1 -0
  18. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  19. package/dist/modules/query_index/lib/engine.js +81 -1
  20. package/dist/modules/query_index/lib/engine.js.map +2 -2
  21. package/package.json +3 -3
  22. package/src/modules/customers/api/companies/route.ts +151 -3
  23. package/src/modules/customers/api/deals/route.ts +54 -3
  24. package/src/modules/customers/api/people/route.ts +160 -3
  25. package/src/modules/customers/api/utils.ts +286 -0
  26. package/src/modules/customers/backend/customers/companies/page.tsx +184 -9
  27. package/src/modules/customers/backend/customers/deals/page.tsx +127 -35
  28. package/src/modules/customers/backend/customers/people/page.tsx +191 -10
  29. package/src/modules/customers/commands/interactions.ts +7 -0
  30. package/src/modules/customers/components/detail/DealForm.tsx +1 -0
  31. package/src/modules/customers/i18n/de.json +12 -0
  32. package/src/modules/customers/i18n/en.json +15 -3
  33. package/src/modules/customers/i18n/es.json +12 -0
  34. package/src/modules/customers/i18n/pl.json +12 -0
  35. package/src/modules/query_index/lib/engine.ts +95 -1
@@ -392,6 +392,7 @@ function EntityMultiSelect({
392
392
  onMouseDown={(event) => event.preventDefault()}
393
393
  onClick={() => addOption(option)}
394
394
  disabled={disabled}
395
+ aria-label={option.label}
395
396
  >
396
397
  <span className="flex flex-col items-start">
397
398
  <span>{option.label}</span>
@@ -218,6 +218,10 @@
218
218
  "customers.companies.list.actions.view": "Details anzeigen",
219
219
  "customers.companies.list.booleanNo": "Nein",
220
220
  "customers.companies.list.booleanYes": "Ja",
221
+ "customers.companies.list.bulkDelete.action": "Delete selected",
222
+ "customers.companies.list.bulkDelete.description": "This action cannot be undone.",
223
+ "customers.companies.list.bulkDelete.success": "{count} companies deleted",
224
+ "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
221
225
  "customers.companies.list.columns.email": "E-Mail",
222
226
  "customers.companies.list.columns.lifecycleStage": "Lebenszyklusphase",
223
227
  "customers.companies.list.columns.name": "Name",
@@ -420,6 +424,10 @@
420
424
  "customers.deals.list.actions.openInNewTab": "In neuem Tab öffnen",
421
425
  "customers.deals.list.booleanNo": "Nein",
422
426
  "customers.deals.list.booleanYes": "Ja",
427
+ "customers.deals.list.bulkDelete.action": "Delete selected",
428
+ "customers.deals.list.bulkDelete.description": "This action cannot be undone.",
429
+ "customers.deals.list.bulkDelete.success": "{count} deals deleted",
430
+ "customers.deals.list.bulkDelete.title": "Delete {count} deals?",
423
431
  "customers.deals.list.columns.companies": "Unternehmen",
424
432
  "customers.deals.list.columns.expectedClose": "Voraussichtlicher Abschluss",
425
433
  "customers.deals.list.columns.people": "Personen",
@@ -979,6 +987,10 @@
979
987
  "customers.people.list.actions.view": "Details anzeigen",
980
988
  "customers.people.list.booleanNo": "Nein",
981
989
  "customers.people.list.booleanYes": "Ja",
990
+ "customers.people.list.bulkDelete.action": "Delete selected",
991
+ "customers.people.list.bulkDelete.description": "This action cannot be undone.",
992
+ "customers.people.list.bulkDelete.success": "{count} people deleted",
993
+ "customers.people.list.bulkDelete.title": "Delete {count} people?",
982
994
  "customers.people.list.columns.email": "E-Mail",
983
995
  "customers.people.list.columns.lifecycleStage": "Lebenszyklusphase",
984
996
  "customers.people.list.columns.name": "Name",
@@ -218,6 +218,10 @@
218
218
  "customers.companies.list.actions.view": "View details",
219
219
  "customers.companies.list.booleanNo": "No",
220
220
  "customers.companies.list.booleanYes": "Yes",
221
+ "customers.companies.list.bulkDelete.action": "Delete selected",
222
+ "customers.companies.list.bulkDelete.description": "This action cannot be undone.",
223
+ "customers.companies.list.bulkDelete.success": "{count} companies deleted",
224
+ "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
221
225
  "customers.companies.list.columns.email": "Email",
222
226
  "customers.companies.list.columns.lifecycleStage": "Lifecycle stage",
223
227
  "customers.companies.list.columns.name": "Name",
@@ -242,7 +246,7 @@
242
246
  "customers.companies.list.filters.status": "Status",
243
247
  "customers.companies.list.filters.tags": "Tags",
244
248
  "customers.companies.list.noValue": "Not set",
245
- "customers.companies.list.searchPlaceholder": "Search companies",
249
+ "customers.companies.list.searchPlaceholder": "Search by name, email, phone…",
246
250
  "customers.companies.list.tags.loadError": "Failed to load tags.",
247
251
  "customers.companies.list.title": "Companies",
248
252
  "customers.config.addressFormat.description": "Choose how address forms and displays should be structured across the customer module.",
@@ -420,6 +424,10 @@
420
424
  "customers.deals.list.actions.openInNewTab": "Open in new tab",
421
425
  "customers.deals.list.booleanNo": "No",
422
426
  "customers.deals.list.booleanYes": "Yes",
427
+ "customers.deals.list.bulkDelete.action": "Delete selected",
428
+ "customers.deals.list.bulkDelete.description": "This action cannot be undone.",
429
+ "customers.deals.list.bulkDelete.success": "{count} deals deleted",
430
+ "customers.deals.list.bulkDelete.title": "Delete {count} deals?",
423
431
  "customers.deals.list.columns.companies": "Companies",
424
432
  "customers.deals.list.columns.expectedClose": "Expected close",
425
433
  "customers.deals.list.columns.people": "People",
@@ -440,7 +448,7 @@
440
448
  "customers.deals.list.filters.peoplePlaceholder": "Filter by people",
441
449
  "customers.deals.list.noValue": "Not set",
442
450
  "customers.deals.list.refresh": "Refresh",
443
- "customers.deals.list.searchPlaceholder": "Search deals…",
451
+ "customers.deals.list.searchPlaceholder": "Search by title, description…",
444
452
  "customers.deals.list.title": "Deals",
445
453
  "customers.deals.list.unnamedCompany": "Unnamed company",
446
454
  "customers.deals.list.unnamedPerson": "Unnamed person",
@@ -979,6 +987,10 @@
979
987
  "customers.people.list.actions.view": "View details",
980
988
  "customers.people.list.booleanNo": "No",
981
989
  "customers.people.list.booleanYes": "Yes",
990
+ "customers.people.list.bulkDelete.action": "Delete selected",
991
+ "customers.people.list.bulkDelete.description": "This action cannot be undone.",
992
+ "customers.people.list.bulkDelete.success": "{count} people deleted",
993
+ "customers.people.list.bulkDelete.title": "Delete {count} people?",
982
994
  "customers.people.list.columns.email": "Email",
983
995
  "customers.people.list.columns.lifecycleStage": "Lifecycle stage",
984
996
  "customers.people.list.columns.name": "Name",
@@ -1003,7 +1015,7 @@
1003
1015
  "customers.people.list.filters.status": "Status",
1004
1016
  "customers.people.list.filters.tags": "Tags",
1005
1017
  "customers.people.list.noValue": "Not set",
1006
- "customers.people.list.searchPlaceholder": "Search people",
1018
+ "customers.people.list.searchPlaceholder": "Search by name, email, phone…",
1007
1019
  "customers.people.list.title": "People",
1008
1020
  "customers.pipelines.actions.create": "Add pipeline",
1009
1021
  "customers.pipelines.actions.delete": "Delete",
@@ -218,6 +218,10 @@
218
218
  "customers.companies.list.actions.view": "Ver detalles",
219
219
  "customers.companies.list.booleanNo": "No",
220
220
  "customers.companies.list.booleanYes": "Sí",
221
+ "customers.companies.list.bulkDelete.action": "Delete selected",
222
+ "customers.companies.list.bulkDelete.description": "This action cannot be undone.",
223
+ "customers.companies.list.bulkDelete.success": "{count} companies deleted",
224
+ "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
221
225
  "customers.companies.list.columns.email": "Correo electrónico",
222
226
  "customers.companies.list.columns.lifecycleStage": "Etapa del ciclo de vida",
223
227
  "customers.companies.list.columns.name": "Nombre",
@@ -420,6 +424,10 @@
420
424
  "customers.deals.list.actions.openInNewTab": "Abrir en nueva pestaña",
421
425
  "customers.deals.list.booleanNo": "No",
422
426
  "customers.deals.list.booleanYes": "Sí",
427
+ "customers.deals.list.bulkDelete.action": "Delete selected",
428
+ "customers.deals.list.bulkDelete.description": "This action cannot be undone.",
429
+ "customers.deals.list.bulkDelete.success": "{count} deals deleted",
430
+ "customers.deals.list.bulkDelete.title": "Delete {count} deals?",
423
431
  "customers.deals.list.columns.companies": "Empresas",
424
432
  "customers.deals.list.columns.expectedClose": "Cierre esperado",
425
433
  "customers.deals.list.columns.people": "Personas",
@@ -979,6 +987,10 @@
979
987
  "customers.people.list.actions.view": "Ver detalles",
980
988
  "customers.people.list.booleanNo": "No",
981
989
  "customers.people.list.booleanYes": "Sí",
990
+ "customers.people.list.bulkDelete.action": "Delete selected",
991
+ "customers.people.list.bulkDelete.description": "This action cannot be undone.",
992
+ "customers.people.list.bulkDelete.success": "{count} people deleted",
993
+ "customers.people.list.bulkDelete.title": "Delete {count} people?",
982
994
  "customers.people.list.columns.email": "Correo electrónico",
983
995
  "customers.people.list.columns.lifecycleStage": "Etapa del ciclo de vida",
984
996
  "customers.people.list.columns.name": "Nombre",
@@ -218,6 +218,10 @@
218
218
  "customers.companies.list.actions.view": "Zobacz szczegóły",
219
219
  "customers.companies.list.booleanNo": "Nie",
220
220
  "customers.companies.list.booleanYes": "Tak",
221
+ "customers.companies.list.bulkDelete.action": "Delete selected",
222
+ "customers.companies.list.bulkDelete.description": "This action cannot be undone.",
223
+ "customers.companies.list.bulkDelete.success": "{count} companies deleted",
224
+ "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
221
225
  "customers.companies.list.columns.email": "E-mail",
222
226
  "customers.companies.list.columns.lifecycleStage": "Etap cyklu życia",
223
227
  "customers.companies.list.columns.name": "Nazwa",
@@ -420,6 +424,10 @@
420
424
  "customers.deals.list.actions.openInNewTab": "Otwórz w nowej karcie",
421
425
  "customers.deals.list.booleanNo": "Nie",
422
426
  "customers.deals.list.booleanYes": "Tak",
427
+ "customers.deals.list.bulkDelete.action": "Delete selected",
428
+ "customers.deals.list.bulkDelete.description": "This action cannot be undone.",
429
+ "customers.deals.list.bulkDelete.success": "{count} deals deleted",
430
+ "customers.deals.list.bulkDelete.title": "Delete {count} deals?",
423
431
  "customers.deals.list.columns.companies": "Firmy",
424
432
  "customers.deals.list.columns.expectedClose": "Planowana finalizacja",
425
433
  "customers.deals.list.columns.people": "Osoby",
@@ -979,6 +987,10 @@
979
987
  "customers.people.list.actions.view": "Zobacz szczegóły",
980
988
  "customers.people.list.booleanNo": "Nie",
981
989
  "customers.people.list.booleanYes": "Tak",
990
+ "customers.people.list.bulkDelete.action": "Delete selected",
991
+ "customers.people.list.bulkDelete.description": "This action cannot be undone.",
992
+ "customers.people.list.bulkDelete.success": "{count} people deleted",
993
+ "customers.people.list.bulkDelete.title": "Delete {count} people?",
982
994
  "customers.people.list.columns.email": "E-mail",
983
995
  "customers.people.list.columns.lifecycleStage": "Etap cyklu życia",
984
996
  "customers.people.list.columns.name": "Nazwa",
@@ -445,6 +445,7 @@ export class HybridQueryEngine implements QueryEngine {
445
445
  ? await this.searchSourcesHaveTokens(searchSources, opts.tenantId ?? null, orgScope)
446
446
  : false
447
447
  const searchRuntime: SearchRuntime = { ...searchRuntimeBase, searchSources, enabled: searchEnabled && hasSearchTokens }
448
+ const joinSearchAvailability = new Map<string, boolean>()
448
449
  const searchFilters = normalizeFilters(opts.filters).filter((filter) => filter.op === 'like' || filter.op === 'ilike')
449
450
  if (searchFilters.length) {
450
451
  this.logSearchDebug('search:init', {
@@ -591,7 +592,10 @@ export class HybridQueryEngine implements QueryEngine {
591
592
  )
592
593
  }
593
594
 
594
- for (const filter of baseFilters) {
595
+ const regularBaseFilters = baseFilters.filter((filter) => !filter.orGroup)
596
+ const orGroupFilters = baseFilters.filter((filter) => filter.orGroup)
597
+
598
+ for (const filter of regularBaseFilters) {
595
599
  const fieldName = String(filter.field)
596
600
  const baseField = resolveBaseColumn(fieldName)
597
601
  if (!baseField) {
@@ -640,6 +644,61 @@ export class HybridQueryEngine implements QueryEngine {
640
644
  }
641
645
  }
642
646
 
647
+ const applyOrGroupedBaseFilters = (target: ResultBuilder | null): ResultBuilder | null => {
648
+ if (!target || orGroupFilters.length === 0) return target
649
+ const groups = new Map<string, BaseFilter[]>()
650
+ for (const filter of orGroupFilters) {
651
+ if (!filter.orGroup) continue
652
+ const existing = groups.get(filter.orGroup) ?? []
653
+ existing.push(filter)
654
+ groups.set(filter.orGroup, existing)
655
+ }
656
+ let next = target
657
+ for (const [, groupFilters] of groups) {
658
+ if (!groupFilters.length) continue
659
+ next = next.where((groupBuilder) => {
660
+ groupFilters.forEach((filter, index) => {
661
+ const fieldName = String(filter.field)
662
+ const baseField = resolveBaseColumn(fieldName)
663
+ const applyCondition = (conditionBuilder: ResultBuilder) => {
664
+ if (!baseField) {
665
+ this.applyIndexDocFilterFromAlias(
666
+ knex,
667
+ conditionBuilder,
668
+ 'ei',
669
+ entity,
670
+ fieldName,
671
+ filter.op,
672
+ filter.value,
673
+ 'b.id',
674
+ searchRuntime,
675
+ )
676
+ return
677
+ }
678
+ this.applyColumnFilter(conditionBuilder, qualify(baseField), filter, {
679
+ ...searchRuntime,
680
+ knex,
681
+ entity,
682
+ field: fieldName,
683
+ recordIdColumn: 'b.id',
684
+ })
685
+ }
686
+ if (index === 0) {
687
+ applyCondition(groupBuilder as ResultBuilder)
688
+ return
689
+ }
690
+ groupBuilder.orWhere((conditionBuilder) => {
691
+ applyCondition(conditionBuilder as ResultBuilder)
692
+ })
693
+ })
694
+ })
695
+ }
696
+ return next
697
+ }
698
+
699
+ builder = applyOrGroupedBaseFilters(builder) ?? builder
700
+ optimizedCountBuilder = applyOrGroupedBaseFilters(optimizedCountBuilder)
701
+
643
702
  const applyAliasScopes = async (target: ResultBuilder, aliasName: string) => {
644
703
  const tableName = aliasTables.get(aliasName)
645
704
  if (!tableName) return
@@ -688,6 +747,37 @@ export class HybridQueryEngine implements QueryEngine {
688
747
  }
689
748
  }
690
749
 
750
+ const applyJoinSearchFilterOp = async (
751
+ target: ResultBuilder,
752
+ filter: { column: string; op: FilterOp; value?: unknown },
753
+ _qualified: string,
754
+ join: ResolvedJoin,
755
+ ): Promise<boolean> => {
756
+ if (!searchEnabled || !join.entityId) return false
757
+ if (!['eq', 'like', 'ilike'].includes(filter.op)) return false
758
+ if (typeof filter.value !== 'string' || filter.value.trim().length === 0) return false
759
+
760
+ let searchAvailable = joinSearchAvailability.get(join.entityId)
761
+ if (searchAvailable === undefined) {
762
+ searchAvailable = await this.hasSearchTokens(String(join.entityId), opts.tenantId ?? null, orgScope)
763
+ joinSearchAvailability.set(join.entityId, searchAvailable)
764
+ }
765
+ if (!searchAvailable) return false
766
+
767
+ const tokens = tokenizeText(String(filter.value), searchConfig)
768
+ if (!tokens.hashes.length) return false
769
+
770
+ return this.applySearchTokens(target, {
771
+ knex,
772
+ entity: String(join.entityId),
773
+ field: filter.column,
774
+ hashes: tokens.hashes,
775
+ recordIdColumn: `${join.alias}.id`,
776
+ tenantId: opts.tenantId ?? null,
777
+ organizationScope: orgScope,
778
+ })
779
+ }
780
+
691
781
  await applyJoinFilters({
692
782
  knex,
693
783
  baseTable,
@@ -698,6 +788,8 @@ export class HybridQueryEngine implements QueryEngine {
698
788
  qualifyBase: (column) => qualify(column),
699
789
  applyAliasScope: (target, alias) => applyAliasScopes(target, alias),
700
790
  applyFilterOp: (target, column, op, value) => applyJoinFilterOp(target as ResultBuilder, column, op, value),
791
+ applyJoinFilterOp: (target, filter, qualified, join) =>
792
+ applyJoinSearchFilterOp(target as ResultBuilder, filter, qualified, join),
701
793
  columnExists: (tbl, column) => this.columnExists(tbl, column),
702
794
  }) as ResultBuilder
703
795
 
@@ -712,6 +804,8 @@ export class HybridQueryEngine implements QueryEngine {
712
804
  qualifyBase: (column) => qualify(column),
713
805
  applyAliasScope: (target, alias) => applyAliasScopes(target, alias),
714
806
  applyFilterOp: (target, column, op, value) => applyJoinFilterOp(target as ResultBuilder, column, op, value),
807
+ applyJoinFilterOp: (target, filter, qualified, join) =>
808
+ applyJoinSearchFilterOp(target as ResultBuilder, filter, qualified, join),
715
809
  columnExists: (tbl, column) => this.columnExists(tbl, column),
716
810
  })
717
811
  }