@open-mercato/core 0.6.8-develop.6917.1.af45bc96e2 → 0.6.8-develop.6924.1.a8d208fcdc
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/dist/bootstrap.js +2 -1
- package/dist/bootstrap.js.map +2 -2
- package/dist/modules/catalog/search.js +8 -0
- package/dist/modules/catalog/search.js.map +2 -2
- package/dist/modules/customer_accounts/search.js +2 -0
- package/dist/modules/customer_accounts/search.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +55 -8
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js +1 -1
- package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +2 -0
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/inbox_ops/search.js +1 -0
- package/dist/modules/inbox_ops/search.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/page.js +10 -5
- package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
- package/dist/modules/messages/search.js +2 -1
- package/dist/modules/messages/search.js.map +2 -2
- package/dist/modules/planner/search.js +1 -0
- package/dist/modules/planner/search.js.map +2 -2
- package/dist/modules/resources/search.js +2 -0
- package/dist/modules/resources/search.js.map +2 -2
- package/dist/modules/sales/search.js +24 -2
- package/dist/modules/sales/search.js.map +2 -2
- package/dist/modules/staff/search.js +4 -0
- package/dist/modules/staff/search.js.map +2 -2
- package/dist/modules/wms/search.js +4 -0
- package/dist/modules/wms/search.js.map +2 -2
- package/package.json +7 -7
- package/src/bootstrap.ts +9 -2
- package/src/modules/catalog/search.ts +8 -0
- package/src/modules/customer_accounts/search.ts +2 -0
- package/src/modules/customers/commands/deals.ts +86 -14
- package/src/modules/customers/components/detail/create/dealCustomFieldControl.tsx +1 -1
- package/src/modules/customers/components/formConfig.tsx +2 -0
- package/src/modules/inbox_ops/search.ts +1 -0
- package/src/modules/integrations/backend/integrations/page.tsx +13 -5
- package/src/modules/messages/search.ts +2 -1
- package/src/modules/planner/search.ts +1 -0
- package/src/modules/resources/search.ts +2 -0
- package/src/modules/sales/search.ts +24 -2
- package/src/modules/staff/search.ts +4 -0
- package/src/modules/wms/search.ts +4 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/inbox_ops/search.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\ntype SearchContext = SearchBuildContext & {\n tenantId: string\n}\n\nfunction assertTenantContext(ctx: SearchBuildContext): asserts ctx is SearchContext {\n if (typeof ctx.tenantId !== 'string' || ctx.tenantId.length === 0) {\n throw new Error('[search.inbox_ops] Missing tenantId in search build context')\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'inbox_ops:inbox_proposal',\n enabled: true,\n priority: 6,\n fieldPolicy: {\n searchable: ['summary', 'category'],\n excluded: ['metadata', 'participants'],\n },\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n assertTenantContext(ctx)\n const record = ctx.record\n if (!record.summary) return null\n\n const { t } = await resolveTranslations()\n const confidence = String(record.confidence ?? '')\n const status = String(record.status ?? '')\n const category = record.category ? String(record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n\n return {\n text: String(record.summary || ''),\n fields: {\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detected_language: record.detected_language,\n },\n presenter: {\n title: String(record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n },\n checksumSource: {\n summary: record.summary,\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detectedLanguage: record.detected_language,\n },\n }\n },\n formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {\n const { t } = await resolveTranslations()\n const confidence = String(ctx.record.confidence ?? '')\n const status = String(ctx.record.status ?? '')\n const category = ctx.record.category ? String(ctx.record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n return {\n title: String(ctx.record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n }\n },\n resolveUrl: async (ctx: SearchBuildContext): Promise<string | null> => {\n const id = ctx.record.id\n if (!id) return null\n return `/backend/inbox-ops/proposals/${encodeURIComponent(String(id))}`\n },\n },\n ],\n}\n\nexport const config = searchConfig\nexport default searchConfig\n"],
|
|
5
|
-
"mappings": "AAMA,SAAS,2BAA2B;AAMpC,SAAS,oBAAoB,KAAuD;AAClF,MAAI,OAAO,IAAI,aAAa,YAAY,IAAI,SAAS,WAAW,GAAG;AACjE,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,QACX,YAAY,CAAC,WAAW,UAAU;AAAA,QAClC,UAAU,CAAC,YAAY,cAAc;AAAA,MACvC;AAAA,MACA,aAAa,OAAO,QAA+D;AACjF,4BAAoB,GAAG;AACvB,cAAM,SAAS,IAAI;AACnB,YAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,OAAO,cAAc,EAAE;AACjD,cAAM,SAAS,OAAO,OAAO,UAAU,EAAE;AACzC,cAAM,WAAW,OAAO,WAAW,OAAO,OAAO,QAAQ,IAAI;AAC7D,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AAErH,eAAO;AAAA,UACL,MAAM,OAAO,OAAO,WAAW,EAAE;AAAA,UACjC,QAAQ;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,mBAAmB,OAAO;AAAA,UAC5B;AAAA,UACA,WAAW;AAAA,YACT,OAAO,OAAO,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,YACnG;AAAA,YACA,MAAM;AAAA,UACR;AAAA,UACA,gBAAgB;AAAA,YACd,SAAS,OAAO;AAAA,YAChB,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,kBAAkB,OAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MACA,cAAc,OAAO,QAAmE;AACtF,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,IAAI,OAAO,cAAc,EAAE;AACrD,cAAM,SAAS,OAAO,IAAI,OAAO,UAAU,EAAE;AAC7C,cAAM,WAAW,IAAI,OAAO,WAAW,OAAO,IAAI,OAAO,QAAQ,IAAI;AACrE,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AACrH,eAAO;AAAA,UACL,OAAO,OAAO,IAAI,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,UACvG;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,YAAY,OAAO,QAAoD;AACrE,cAAM,KAAK,IAAI,OAAO;AACtB,YAAI,CAAC,GAAI,QAAO;AAChB,eAAO,gCAAgC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,SAAS;AACtB,IAAO,iBAAQ;",
|
|
4
|
+
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\ntype SearchContext = SearchBuildContext & {\n tenantId: string\n}\n\nfunction assertTenantContext(ctx: SearchBuildContext): asserts ctx is SearchContext {\n if (typeof ctx.tenantId !== 'string' || ctx.tenantId.length === 0) {\n throw new Error('[search.inbox_ops] Missing tenantId in search build context')\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'inbox_ops:inbox_proposal',\n aclFeatures: ['inbox_ops.proposals.view'],\n enabled: true,\n priority: 6,\n fieldPolicy: {\n searchable: ['summary', 'category'],\n excluded: ['metadata', 'participants'],\n },\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n assertTenantContext(ctx)\n const record = ctx.record\n if (!record.summary) return null\n\n const { t } = await resolveTranslations()\n const confidence = String(record.confidence ?? '')\n const status = String(record.status ?? '')\n const category = record.category ? String(record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n\n return {\n text: String(record.summary || ''),\n fields: {\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detected_language: record.detected_language,\n },\n presenter: {\n title: String(record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n },\n checksumSource: {\n summary: record.summary,\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detectedLanguage: record.detected_language,\n },\n }\n },\n formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {\n const { t } = await resolveTranslations()\n const confidence = String(ctx.record.confidence ?? '')\n const status = String(ctx.record.status ?? '')\n const category = ctx.record.category ? String(ctx.record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n return {\n title: String(ctx.record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n }\n },\n resolveUrl: async (ctx: SearchBuildContext): Promise<string | null> => {\n const id = ctx.record.id\n if (!id) return null\n return `/backend/inbox-ops/proposals/${encodeURIComponent(String(id))}`\n },\n },\n ],\n}\n\nexport const config = searchConfig\nexport default searchConfig\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,2BAA2B;AAMpC,SAAS,oBAAoB,KAAuD;AAClF,MAAI,OAAO,IAAI,aAAa,YAAY,IAAI,SAAS,WAAW,GAAG;AACjE,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,aAAa,CAAC,0BAA0B;AAAA,MACxC,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,QACX,YAAY,CAAC,WAAW,UAAU;AAAA,QAClC,UAAU,CAAC,YAAY,cAAc;AAAA,MACvC;AAAA,MACA,aAAa,OAAO,QAA+D;AACjF,4BAAoB,GAAG;AACvB,cAAM,SAAS,IAAI;AACnB,YAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,OAAO,cAAc,EAAE;AACjD,cAAM,SAAS,OAAO,OAAO,UAAU,EAAE;AACzC,cAAM,WAAW,OAAO,WAAW,OAAO,OAAO,QAAQ,IAAI;AAC7D,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AAErH,eAAO;AAAA,UACL,MAAM,OAAO,OAAO,WAAW,EAAE;AAAA,UACjC,QAAQ;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,mBAAmB,OAAO;AAAA,UAC5B;AAAA,UACA,WAAW;AAAA,YACT,OAAO,OAAO,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,YACnG;AAAA,YACA,MAAM;AAAA,UACR;AAAA,UACA,gBAAgB;AAAA,YACd,SAAS,OAAO;AAAA,YAChB,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,kBAAkB,OAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MACA,cAAc,OAAO,QAAmE;AACtF,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,IAAI,OAAO,cAAc,EAAE;AACrD,cAAM,SAAS,OAAO,IAAI,OAAO,UAAU,EAAE;AAC7C,cAAM,WAAW,IAAI,OAAO,WAAW,OAAO,IAAI,OAAO,QAAQ,IAAI;AACrE,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AACrH,eAAO;AAAA,UACL,OAAO,OAAO,IAAI,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,UACvG;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,YAAY,OAAO,QAAoD;AACrE,cAAM,KAAK,IAAI,OAAO;AACtB,YAAI,CAAC,GAAI,QAAO;AAChB,eAAO,gCAAgC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,SAAS;AACtB,IAAO,iBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -122,14 +122,19 @@ function IntegrationsMarketplacePage() {
|
|
|
122
122
|
const load = React.useCallback(async () => {
|
|
123
123
|
setIsLoading(true);
|
|
124
124
|
const fallback = { items: [], bundles: [], total: 0, page: 1, pageSize: 100, totalPages: 1 };
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
try {
|
|
126
|
+
const call = await apiCall(`/api/integrations${listQuery}`, void 0, { fallback });
|
|
127
|
+
if (!call.ok) {
|
|
128
|
+
flash(t("integrations.marketplace.loadError"), "error");
|
|
129
|
+
setIsLoading(false);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
setData(call.result ?? fallback);
|
|
133
|
+
setIsLoading(false);
|
|
134
|
+
} catch {
|
|
127
135
|
flash(t("integrations.marketplace.loadError"), "error");
|
|
128
136
|
setIsLoading(false);
|
|
129
|
-
return;
|
|
130
137
|
}
|
|
131
|
-
setData(call.result ?? fallback);
|
|
132
|
-
setIsLoading(false);
|
|
133
138
|
}, [listQuery, t]);
|
|
134
139
|
React.useEffect(() => {
|
|
135
140
|
void load();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/integrations/backend/integrations/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Card, CardHeader, CardTitle, CardContent } from '@open-mercato/ui/primitives/card'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { FilterBar, type FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Bell, Cog, CreditCard, HardDrive, LayoutGrid, MessageSquare, RefreshCw, Search, Truck, Webhook } from 'lucide-react'\nimport {\n buildIntegrationMarketplaceFilterDefs,\n getIntegrationMarketplaceCategory,\n getListQueryFromFilterValues,\n INTEGRATION_MARKETPLACE_CATEGORIES,\n normalizeIntegrationMarketplaceFilterValues,\n} from './filters'\n\ntype IntegrationAnalytics = {\n lastActivityAt: string | null\n totalCount: number\n errorCount: number\n errorRate: number\n dailyCounts: number[]\n}\n\ntype IntegrationItem = {\n id: string\n title: string\n description?: string\n category?: string\n tags?: string[]\n bundleId?: string\n author?: string\n company?: string\n version?: string\n isEnabled: boolean\n hasCredentials: boolean\n healthStatus: 'healthy' | 'degraded' | 'unhealthy' | 'unconfigured'\n analytics: IntegrationAnalytics\n stateUpdatedAt?: string | null\n}\n\ntype BundleItem = {\n id: string\n title: string\n description?: string\n icon?: string\n integrationCount: number\n enabledCount: number\n}\n\ntype ListResponse = {\n items: IntegrationItem[]\n bundles: BundleItem[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nconst CATEGORY_ICONS: Record<string, React.ElementType> = {\n all: LayoutGrid,\n payment: CreditCard,\n shipping: Truck,\n data_sync: RefreshCw,\n communication: MessageSquare,\n notification: Bell,\n storage: HardDrive,\n webhook: Webhook,\n}\n\nconst HEALTH_BADGE_CLASS: Record<string, string> = {\n healthy: 'bg-emerald-500/15 text-emerald-800 dark:text-emerald-300',\n degraded: 'bg-amber-500/15 text-amber-900 dark:text-amber-300',\n unhealthy: 'bg-destructive/15 text-destructive',\n unconfigured: 'bg-muted text-muted-foreground',\n}\n\nfunction buildListQueryString(input: {\n q?: string\n category?: string\n bundleId?: string\n isEnabled?: boolean\n healthStatus?: string\n sort?: string\n order?: string\n page?: number\n pageSize?: number\n}): string {\n const params = new URLSearchParams()\n if (input.q) params.set('q', input.q)\n if (input.category) params.set('category', input.category)\n if (input.bundleId) params.set('bundleId', input.bundleId)\n if (input.isEnabled !== undefined) params.set('isEnabled', String(input.isEnabled))\n if (input.healthStatus) params.set('healthStatus', input.healthStatus)\n if (input.sort) params.set('sort', input.sort)\n if (input.order) params.set('order', input.order)\n if (input.page != null && input.page > 1) params.set('page', String(input.page))\n if (input.pageSize != null && input.pageSize !== 100) params.set('pageSize', String(input.pageSize))\n const qs = params.toString()\n return qs ? `?${qs}` : ''\n}\n\nfunction LogSparkline({ counts, className }: { counts: number[]; className?: string }) {\n const max = Math.max(1, ...counts)\n const w = 72\n const h = 22\n const step = counts.length > 1 ? w / (counts.length - 1) : w\n const points = counts.map((count, index) => {\n const x = index * step\n const y = h - (count / max) * (h - 3) - 1.5\n return `${x},${y}`\n }).join(' ')\n return (\n <svg width={w} height={h} className={className} aria-hidden>\n <polyline\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.2\"\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n points={points}\n className=\"text-muted-foreground/80\"\n />\n </svg>\n )\n}\n\nexport default function IntegrationsMarketplacePage() {\n const [data, setData] = React.useState<ListResponse | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [searchInput, setSearchInput] = React.useState('')\n const [debouncedSearch, setDebouncedSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [sortField, setSortField] = React.useState<'title' | 'category' | 'enabledAt' | 'healthStatus'>('title')\n const [sortOrder, setSortOrder] = React.useState<'asc' | 'desc'>('asc')\n const [page, setPage] = React.useState(1)\n const [togglingIds, setTogglingIds] = React.useState<Set<string>>(new Set())\n const scopeVersion = useOrganizationScopeVersion()\n const t = useT()\n const { runMutation, retryLastMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'integrations.marketplace',\n })\n\n React.useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(searchInput.trim()), 300)\n return () => clearTimeout(timer)\n }, [searchInput])\n\n const selectedCategory = React.useMemo(() => getIntegrationMarketplaceCategory(filterValues), [filterValues])\n\n const listQuery = React.useMemo(() => {\n const fromFilters = getListQueryFromFilterValues(filterValues)\n const category = selectedCategory !== 'all' ? selectedCategory : fromFilters.category\n return buildListQueryString({\n q: debouncedSearch || undefined,\n ...(category ? { category } : {}),\n ...(fromFilters.bundleId ? { bundleId: fromFilters.bundleId } : {}),\n ...(fromFilters.isEnabled !== undefined ? { isEnabled: fromFilters.isEnabled } : {}),\n ...(fromFilters.healthStatus ? { healthStatus: fromFilters.healthStatus } : {}),\n sort: sortField,\n order: sortOrder,\n page,\n pageSize: 100,\n })\n }, [debouncedSearch, filterValues, page, selectedCategory, sortField, sortOrder])\n\n const bundleFilterOptions = React.useMemo(\n () => (data?.bundles ?? []).map((bundle) => ({ id: bundle.id, title: bundle.title })),\n [data?.bundles],\n )\n\n const categoryFilters = React.useMemo(\n () => buildIntegrationMarketplaceFilterDefs(t, bundleFilterOptions),\n [bundleFilterOptions, t],\n )\n\n const load = React.useCallback(async () => {\n setIsLoading(true)\n const fallback: ListResponse = { items: [], bundles: [], total: 0, page: 1, pageSize: 100, totalPages: 1 }\n const call = await apiCall<ListResponse>(`/api/integrations${listQuery}`, undefined, { fallback })\n if (!call.ok) {\n flash(t('integrations.marketplace.loadError'), 'error')\n setIsLoading(false)\n return\n }\n setData(call.result ?? fallback)\n setIsLoading(false)\n }, [listQuery, t])\n\n React.useEffect(() => {\n void load()\n }, [load, scopeVersion])\n\n React.useEffect(() => {\n setPage(1)\n }, [debouncedSearch, filterValues, selectedCategory, sortField, sortOrder])\n\n const handleToggle = React.useCallback(async (integrationId: string, enabled: boolean, updatedAt?: string | null) => {\n setTogglingIds((prev) => new Set(prev).add(integrationId))\n try {\n const call = await runMutation({\n mutationPayload: { integrationId, isEnabled: enabled },\n context: {\n formId: 'integrations.marketplace',\n operation: 'update',\n actionId: 'toggle-state',\n resourceKind: 'integrations.integration',\n resourceId: integrationId,\n integrationId,\n retryLastMutation,\n },\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(updatedAt),\n () => apiCall<{ updatedAt?: string | null }>(`/api/integrations/${encodeURIComponent(integrationId)}/state`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ isEnabled: enabled }),\n }, { fallback: null }),\n ),\n })\n\n if (!call.ok) {\n flash(t('integrations.detail.stateError'), 'error')\n } else {\n const nextUpdatedAt = call.result?.updatedAt ?? null\n setData((prev) => {\n if (!prev) return prev\n return {\n ...prev,\n items: prev.items.map((item) =>\n item.id === integrationId\n ? { ...item, isEnabled: enabled, stateUpdatedAt: nextUpdatedAt ?? item.stateUpdatedAt }\n : item,\n ),\n }\n })\n }\n } catch {\n flash(t('integrations.detail.stateError'), 'error')\n } finally {\n setTogglingIds((prev) => { const next = new Set(prev); next.delete(integrationId); return next })\n }\n }, [retryLastMutation, runMutation, t])\n\n const grouped = React.useMemo(() => {\n if (!data) return { bundles: [] as Array<BundleItem & { integrations: IntegrationItem[] }>, standalone: [] as IntegrationItem[] }\n\n const bundled = new Map<string, IntegrationItem[]>()\n const standalone: IntegrationItem[] = []\n for (const item of data.items) {\n if (item.bundleId) {\n const list = bundled.get(item.bundleId) ?? []\n list.push(item)\n bundled.set(item.bundleId, list)\n } else {\n standalone.push(item)\n }\n }\n\n const bundles = (data.bundles ?? [])\n .filter((b) => bundled.has(b.id))\n .map((b) => ({ ...b, integrations: bundled.get(b.id) ?? [] }))\n\n return { bundles, standalone }\n }, [data])\n\n const renderCategoryIcon = React.useCallback((category: string | undefined, className: string) => {\n if (!category) return null\n const Icon = CATEGORY_ICONS[category]\n if (!Icon) return null\n return <Icon className={className} />\n }, [])\n\n const renderHealthBadge = React.useCallback((status: IntegrationItem['healthStatus']) => {\n return (\n <span\n className={`inline-flex shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-semibold uppercase tracking-wide ${HEALTH_BADGE_CLASS[status] ?? HEALTH_BADGE_CLASS.unconfigured}`}\n >\n {t(`integrations.marketplace.health.${status}`, status)}\n </span>\n )\n }, [t])\n\n if (isLoading && !data) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex items-center justify-center py-16\">\n <Spinner />\n </div>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody className=\"space-y-6\">\n <section className=\"space-y-6 rounded-lg border bg-background p-6\">\n <header className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"space-y-0.5\">\n <h2 className=\"text-lg font-semibold\">{t('integrations.marketplace.title')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('integrations.marketplace.description')}\n </p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative w-full min-w-[200px] max-w-xs lg:w-64\">\n <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground pointer-events-none\" />\n <Input\n placeholder={t('integrations.marketplace.search')}\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n className=\"pl-8\"\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <span className=\"sr-only\">{t('integrations.marketplace.sort.label', 'Sort by')}</span>\n <select\n className=\"h-9 rounded-md border border-input bg-background px-2 text-sm\"\n value={sortField}\n onChange={(e) => setSortField(e.target.value as typeof sortField)}\n >\n <option value=\"title\">{t('integrations.marketplace.sort.title', 'Title')}</option>\n <option value=\"category\">{t('integrations.marketplace.sort.category', 'Category')}</option>\n <option value=\"enabledAt\">{t('integrations.marketplace.sort.enabledAt', 'Enabled date')}</option>\n <option value=\"healthStatus\">{t('integrations.marketplace.sort.health', 'Health')}</option>\n </select>\n </label>\n <select\n className=\"h-9 rounded-md border border-input bg-background px-2 text-sm\"\n value={sortOrder}\n onChange={(e) => setSortOrder(e.target.value as typeof sortOrder)}\n aria-label={t('integrations.marketplace.sort.order', 'Sort order')}\n >\n <option value=\"asc\">{t('integrations.marketplace.sort.asc', 'Ascending')}</option>\n <option value=\"desc\">{t('integrations.marketplace.sort.desc', 'Descending')}</option>\n </select>\n </div>\n </header>\n\n <div className=\"lg:hidden\">\n <FilterBar\n searchValue={searchInput}\n onSearchChange={setSearchInput}\n searchPlaceholder={t('integrations.marketplace.search')}\n searchAlign=\"left\"\n filters={categoryFilters}\n values={filterValues}\n onApply={(values) => setFilterValues(normalizeIntegrationMarketplaceFilterValues(values))}\n onClear={() => setFilterValues({})}\n />\n </div>\n\n <div className=\"hidden lg:flex flex-wrap gap-1.5\">\n {INTEGRATION_MARKETPLACE_CATEGORIES.map((category) => {\n const Icon = CATEGORY_ICONS[category]\n return (\n <Button\n key={category}\n type=\"button\"\n variant={selectedCategory === category ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setFilterValues(normalizeIntegrationMarketplaceFilterValues({ category }))}\n >\n {Icon ? <Icon className=\"mr-1.5 h-3.5 w-3.5\" /> : null}\n {t(`integrations.marketplace.categories.${category}`)}\n </Button>\n )\n })}\n </div>\n\n {isLoading ? (\n <div className=\"flex justify-center py-8\">\n <Spinner />\n </div>\n ) : null}\n\n {data && data.totalPages > 1 ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-sm text-muted-foreground\">\n <span>\n {data.total === 0\n ? t('integrations.marketplace.pagination.empty', 'No results')\n : t('integrations.marketplace.pagination.summary', {\n from: (data.page - 1) * data.pageSize + 1,\n to: Math.min(data.page * data.pageSize, data.total),\n total: data.total,\n })}\n </span>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={data.page <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n >\n {t('integrations.marketplace.pagination.prev', 'Previous')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={data.page >= data.totalPages}\n onClick={() => setPage((p) => p + 1)}\n >\n {t('integrations.marketplace.pagination.next', 'Next')}\n </Button>\n </div>\n </div>\n ) : null}\n\n {grouped.bundles.map((bundle) => (\n <Card key={bundle.id}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <div>\n <CardTitle>{bundle.title}</CardTitle>\n {bundle.description && (\n <p className=\"text-muted-foreground text-sm mt-1\">{bundle.description}</p>\n )}\n <p className=\"text-muted-foreground text-xs mt-1\">\n {t('integrations.marketplace.integrations', { count: bundle.integrations.length })}\n </p>\n </div>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={`/backend/integrations/bundle/${encodeURIComponent(bundle.id)}`}>\n <Cog className=\"mr-1.5 h-4 w-4\" />\n {t('integrations.marketplace.configure')}\n </Link>\n </Button>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {bundle.integrations.map((item) => (\n <div\n key={item.id}\n className=\"flex flex-col gap-2 rounded-lg border p-3\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {renderCategoryIcon(item.category, 'h-4 w-4 text-muted-foreground shrink-0')}\n <Link\n href={`/backend/integrations/${encodeURIComponent(item.id)}`}\n className=\"truncate text-sm font-medium hover:underline\"\n >\n {item.title}\n </Link>\n {renderHealthBadge(item.healthStatus)}\n </div>\n {(item.company || item.author || item.version) ? (\n <p className=\"text-xs text-muted-foreground\">\n {[item.company || item.author, item.version ? `v${item.version}` : null].filter(Boolean).join(' \u00B7 ')}\n </p>\n ) : null}\n </div>\n <Switch\n checked={item.isEnabled}\n disabled={togglingIds.has(item.id)}\n onCheckedChange={(checked) => void handleToggle(item.id, checked, item.stateUpdatedAt)}\n className=\"shrink-0\"\n />\n </div>\n <div className=\"flex items-end justify-between gap-2 border-t pt-2\">\n <div className=\"text-xs text-muted-foreground space-y-0.5\">\n <div>\n {t('integrations.marketplace.analytics.events', { count: item.analytics.totalCount })}\n </div>\n <div>\n {t('integrations.marketplace.analytics.errorRate', {\n rate: `${Math.round(item.analytics.errorRate * 1000) / 10}%`,\n })}\n </div>\n </div>\n <LogSparkline counts={item.analytics.dailyCounts} />\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n ))}\n\n {grouped.standalone.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {grouped.standalone.map((item) => (\n <Card key={item.id} className=\"flex flex-col\">\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n {renderCategoryIcon(item.category, 'h-4 w-4 text-muted-foreground shrink-0')}\n <CardTitle className=\"text-base\">{item.title}</CardTitle>\n {renderHealthBadge(item.healthStatus)}\n </div>\n <Switch\n checked={item.isEnabled}\n disabled={togglingIds.has(item.id)}\n onCheckedChange={(checked) => void handleToggle(item.id, checked, item.stateUpdatedAt)}\n className=\"shrink-0\"\n />\n </div>\n </CardHeader>\n <CardContent className=\"flex-1 space-y-2\">\n {item.description && (\n <p className=\"text-muted-foreground text-sm\">{item.description}</p>\n )}\n {(item.company || item.author || item.version) && (\n <p className=\"text-muted-foreground text-xs\">\n {[item.company || item.author, item.version ? `v${item.version}` : null].filter(Boolean).join(' \u00B7 ')}\n </p>\n )}\n <div className=\"flex items-end justify-between gap-2 border-t pt-3\">\n <div className=\"text-xs text-muted-foreground space-y-0.5\">\n <div>\n {t('integrations.marketplace.analytics.events', { count: item.analytics.totalCount })}\n </div>\n <div>\n {t('integrations.marketplace.analytics.errorRate', {\n rate: `${Math.round(item.analytics.errorRate * 1000) / 10}%`,\n })}\n </div>\n </div>\n <LogSparkline counts={item.analytics.dailyCounts} />\n </div>\n </CardContent>\n <div className=\"px-6 pb-4\">\n <Button asChild variant=\"outline\" size=\"sm\" className=\"w-full\">\n <Link href={`/backend/integrations/${encodeURIComponent(item.id)}`}>\n <Cog className=\"mr-1.5 h-4 w-4\" />\n {t('integrations.marketplace.configure')}\n </Link>\n </Button>\n </div>\n </Card>\n ))}\n </div>\n )}\n\n {grouped.bundles.length === 0 && grouped.standalone.length === 0 && !isLoading && (\n <div className=\"text-center py-12 text-muted-foreground\">\n {t('integrations.marketplace.noResults')}\n </div>\n )}\n </section>\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Card, CardHeader, CardTitle, CardContent } from '@open-mercato/ui/primitives/card'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { FilterBar, type FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Bell, Cog, CreditCard, HardDrive, LayoutGrid, MessageSquare, RefreshCw, Search, Truck, Webhook } from 'lucide-react'\nimport {\n buildIntegrationMarketplaceFilterDefs,\n getIntegrationMarketplaceCategory,\n getListQueryFromFilterValues,\n INTEGRATION_MARKETPLACE_CATEGORIES,\n normalizeIntegrationMarketplaceFilterValues,\n} from './filters'\n\ntype IntegrationAnalytics = {\n lastActivityAt: string | null\n totalCount: number\n errorCount: number\n errorRate: number\n dailyCounts: number[]\n}\n\ntype IntegrationItem = {\n id: string\n title: string\n description?: string\n category?: string\n tags?: string[]\n bundleId?: string\n author?: string\n company?: string\n version?: string\n isEnabled: boolean\n hasCredentials: boolean\n healthStatus: 'healthy' | 'degraded' | 'unhealthy' | 'unconfigured'\n analytics: IntegrationAnalytics\n stateUpdatedAt?: string | null\n}\n\ntype BundleItem = {\n id: string\n title: string\n description?: string\n icon?: string\n integrationCount: number\n enabledCount: number\n}\n\ntype ListResponse = {\n items: IntegrationItem[]\n bundles: BundleItem[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nconst CATEGORY_ICONS: Record<string, React.ElementType> = {\n all: LayoutGrid,\n payment: CreditCard,\n shipping: Truck,\n data_sync: RefreshCw,\n communication: MessageSquare,\n notification: Bell,\n storage: HardDrive,\n webhook: Webhook,\n}\n\nconst HEALTH_BADGE_CLASS: Record<string, string> = {\n healthy: 'bg-emerald-500/15 text-emerald-800 dark:text-emerald-300',\n degraded: 'bg-amber-500/15 text-amber-900 dark:text-amber-300',\n unhealthy: 'bg-destructive/15 text-destructive',\n unconfigured: 'bg-muted text-muted-foreground',\n}\n\nfunction buildListQueryString(input: {\n q?: string\n category?: string\n bundleId?: string\n isEnabled?: boolean\n healthStatus?: string\n sort?: string\n order?: string\n page?: number\n pageSize?: number\n}): string {\n const params = new URLSearchParams()\n if (input.q) params.set('q', input.q)\n if (input.category) params.set('category', input.category)\n if (input.bundleId) params.set('bundleId', input.bundleId)\n if (input.isEnabled !== undefined) params.set('isEnabled', String(input.isEnabled))\n if (input.healthStatus) params.set('healthStatus', input.healthStatus)\n if (input.sort) params.set('sort', input.sort)\n if (input.order) params.set('order', input.order)\n if (input.page != null && input.page > 1) params.set('page', String(input.page))\n if (input.pageSize != null && input.pageSize !== 100) params.set('pageSize', String(input.pageSize))\n const qs = params.toString()\n return qs ? `?${qs}` : ''\n}\n\nfunction LogSparkline({ counts, className }: { counts: number[]; className?: string }) {\n const max = Math.max(1, ...counts)\n const w = 72\n const h = 22\n const step = counts.length > 1 ? w / (counts.length - 1) : w\n const points = counts.map((count, index) => {\n const x = index * step\n const y = h - (count / max) * (h - 3) - 1.5\n return `${x},${y}`\n }).join(' ')\n return (\n <svg width={w} height={h} className={className} aria-hidden>\n <polyline\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.2\"\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n points={points}\n className=\"text-muted-foreground/80\"\n />\n </svg>\n )\n}\n\nexport default function IntegrationsMarketplacePage() {\n const [data, setData] = React.useState<ListResponse | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [searchInput, setSearchInput] = React.useState('')\n const [debouncedSearch, setDebouncedSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [sortField, setSortField] = React.useState<'title' | 'category' | 'enabledAt' | 'healthStatus'>('title')\n const [sortOrder, setSortOrder] = React.useState<'asc' | 'desc'>('asc')\n const [page, setPage] = React.useState(1)\n const [togglingIds, setTogglingIds] = React.useState<Set<string>>(new Set())\n const scopeVersion = useOrganizationScopeVersion()\n const t = useT()\n const { runMutation, retryLastMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'integrations.marketplace',\n })\n\n React.useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(searchInput.trim()), 300)\n return () => clearTimeout(timer)\n }, [searchInput])\n\n const selectedCategory = React.useMemo(() => getIntegrationMarketplaceCategory(filterValues), [filterValues])\n\n const listQuery = React.useMemo(() => {\n const fromFilters = getListQueryFromFilterValues(filterValues)\n const category = selectedCategory !== 'all' ? selectedCategory : fromFilters.category\n return buildListQueryString({\n q: debouncedSearch || undefined,\n ...(category ? { category } : {}),\n ...(fromFilters.bundleId ? { bundleId: fromFilters.bundleId } : {}),\n ...(fromFilters.isEnabled !== undefined ? { isEnabled: fromFilters.isEnabled } : {}),\n ...(fromFilters.healthStatus ? { healthStatus: fromFilters.healthStatus } : {}),\n sort: sortField,\n order: sortOrder,\n page,\n pageSize: 100,\n })\n }, [debouncedSearch, filterValues, page, selectedCategory, sortField, sortOrder])\n\n const bundleFilterOptions = React.useMemo(\n () => (data?.bundles ?? []).map((bundle) => ({ id: bundle.id, title: bundle.title })),\n [data?.bundles],\n )\n\n const categoryFilters = React.useMemo(\n () => buildIntegrationMarketplaceFilterDefs(t, bundleFilterOptions),\n [bundleFilterOptions, t],\n )\n\n const load = React.useCallback(async () => {\n setIsLoading(true)\n const fallback: ListResponse = { items: [], bundles: [], total: 0, page: 1, pageSize: 100, totalPages: 1 }\n try {\n const call = await apiCall<ListResponse>(`/api/integrations${listQuery}`, undefined, { fallback })\n if (!call.ok) {\n flash(t('integrations.marketplace.loadError'), 'error')\n setIsLoading(false)\n return\n }\n setData(call.result ?? fallback)\n setIsLoading(false)\n } catch {\n // apiFetch throws on 401/403 even when its own redirect is suppressed\n // (e.g. a guarded repeat 401) \u2014 without this catch the page would spin\n // forever instead of surfacing the load error.\n flash(t('integrations.marketplace.loadError'), 'error')\n setIsLoading(false)\n }\n }, [listQuery, t])\n\n React.useEffect(() => {\n void load()\n }, [load, scopeVersion])\n\n React.useEffect(() => {\n setPage(1)\n }, [debouncedSearch, filterValues, selectedCategory, sortField, sortOrder])\n\n const handleToggle = React.useCallback(async (integrationId: string, enabled: boolean, updatedAt?: string | null) => {\n setTogglingIds((prev) => new Set(prev).add(integrationId))\n try {\n const call = await runMutation({\n mutationPayload: { integrationId, isEnabled: enabled },\n context: {\n formId: 'integrations.marketplace',\n operation: 'update',\n actionId: 'toggle-state',\n resourceKind: 'integrations.integration',\n resourceId: integrationId,\n integrationId,\n retryLastMutation,\n },\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(updatedAt),\n () => apiCall<{ updatedAt?: string | null }>(`/api/integrations/${encodeURIComponent(integrationId)}/state`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ isEnabled: enabled }),\n }, { fallback: null }),\n ),\n })\n\n if (!call.ok) {\n flash(t('integrations.detail.stateError'), 'error')\n } else {\n const nextUpdatedAt = call.result?.updatedAt ?? null\n setData((prev) => {\n if (!prev) return prev\n return {\n ...prev,\n items: prev.items.map((item) =>\n item.id === integrationId\n ? { ...item, isEnabled: enabled, stateUpdatedAt: nextUpdatedAt ?? item.stateUpdatedAt }\n : item,\n ),\n }\n })\n }\n } catch {\n flash(t('integrations.detail.stateError'), 'error')\n } finally {\n setTogglingIds((prev) => { const next = new Set(prev); next.delete(integrationId); return next })\n }\n }, [retryLastMutation, runMutation, t])\n\n const grouped = React.useMemo(() => {\n if (!data) return { bundles: [] as Array<BundleItem & { integrations: IntegrationItem[] }>, standalone: [] as IntegrationItem[] }\n\n const bundled = new Map<string, IntegrationItem[]>()\n const standalone: IntegrationItem[] = []\n for (const item of data.items) {\n if (item.bundleId) {\n const list = bundled.get(item.bundleId) ?? []\n list.push(item)\n bundled.set(item.bundleId, list)\n } else {\n standalone.push(item)\n }\n }\n\n const bundles = (data.bundles ?? [])\n .filter((b) => bundled.has(b.id))\n .map((b) => ({ ...b, integrations: bundled.get(b.id) ?? [] }))\n\n return { bundles, standalone }\n }, [data])\n\n const renderCategoryIcon = React.useCallback((category: string | undefined, className: string) => {\n if (!category) return null\n const Icon = CATEGORY_ICONS[category]\n if (!Icon) return null\n return <Icon className={className} />\n }, [])\n\n const renderHealthBadge = React.useCallback((status: IntegrationItem['healthStatus']) => {\n return (\n <span\n className={`inline-flex shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-semibold uppercase tracking-wide ${HEALTH_BADGE_CLASS[status] ?? HEALTH_BADGE_CLASS.unconfigured}`}\n >\n {t(`integrations.marketplace.health.${status}`, status)}\n </span>\n )\n }, [t])\n\n if (isLoading && !data) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex items-center justify-center py-16\">\n <Spinner />\n </div>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody className=\"space-y-6\">\n <section className=\"space-y-6 rounded-lg border bg-background p-6\">\n <header className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"space-y-0.5\">\n <h2 className=\"text-lg font-semibold\">{t('integrations.marketplace.title')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('integrations.marketplace.description')}\n </p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative w-full min-w-[200px] max-w-xs lg:w-64\">\n <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground pointer-events-none\" />\n <Input\n placeholder={t('integrations.marketplace.search')}\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n className=\"pl-8\"\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <span className=\"sr-only\">{t('integrations.marketplace.sort.label', 'Sort by')}</span>\n <select\n className=\"h-9 rounded-md border border-input bg-background px-2 text-sm\"\n value={sortField}\n onChange={(e) => setSortField(e.target.value as typeof sortField)}\n >\n <option value=\"title\">{t('integrations.marketplace.sort.title', 'Title')}</option>\n <option value=\"category\">{t('integrations.marketplace.sort.category', 'Category')}</option>\n <option value=\"enabledAt\">{t('integrations.marketplace.sort.enabledAt', 'Enabled date')}</option>\n <option value=\"healthStatus\">{t('integrations.marketplace.sort.health', 'Health')}</option>\n </select>\n </label>\n <select\n className=\"h-9 rounded-md border border-input bg-background px-2 text-sm\"\n value={sortOrder}\n onChange={(e) => setSortOrder(e.target.value as typeof sortOrder)}\n aria-label={t('integrations.marketplace.sort.order', 'Sort order')}\n >\n <option value=\"asc\">{t('integrations.marketplace.sort.asc', 'Ascending')}</option>\n <option value=\"desc\">{t('integrations.marketplace.sort.desc', 'Descending')}</option>\n </select>\n </div>\n </header>\n\n <div className=\"lg:hidden\">\n <FilterBar\n searchValue={searchInput}\n onSearchChange={setSearchInput}\n searchPlaceholder={t('integrations.marketplace.search')}\n searchAlign=\"left\"\n filters={categoryFilters}\n values={filterValues}\n onApply={(values) => setFilterValues(normalizeIntegrationMarketplaceFilterValues(values))}\n onClear={() => setFilterValues({})}\n />\n </div>\n\n <div className=\"hidden lg:flex flex-wrap gap-1.5\">\n {INTEGRATION_MARKETPLACE_CATEGORIES.map((category) => {\n const Icon = CATEGORY_ICONS[category]\n return (\n <Button\n key={category}\n type=\"button\"\n variant={selectedCategory === category ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setFilterValues(normalizeIntegrationMarketplaceFilterValues({ category }))}\n >\n {Icon ? <Icon className=\"mr-1.5 h-3.5 w-3.5\" /> : null}\n {t(`integrations.marketplace.categories.${category}`)}\n </Button>\n )\n })}\n </div>\n\n {isLoading ? (\n <div className=\"flex justify-center py-8\">\n <Spinner />\n </div>\n ) : null}\n\n {data && data.totalPages > 1 ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-sm text-muted-foreground\">\n <span>\n {data.total === 0\n ? t('integrations.marketplace.pagination.empty', 'No results')\n : t('integrations.marketplace.pagination.summary', {\n from: (data.page - 1) * data.pageSize + 1,\n to: Math.min(data.page * data.pageSize, data.total),\n total: data.total,\n })}\n </span>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={data.page <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n >\n {t('integrations.marketplace.pagination.prev', 'Previous')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={data.page >= data.totalPages}\n onClick={() => setPage((p) => p + 1)}\n >\n {t('integrations.marketplace.pagination.next', 'Next')}\n </Button>\n </div>\n </div>\n ) : null}\n\n {grouped.bundles.map((bundle) => (\n <Card key={bundle.id}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <div>\n <CardTitle>{bundle.title}</CardTitle>\n {bundle.description && (\n <p className=\"text-muted-foreground text-sm mt-1\">{bundle.description}</p>\n )}\n <p className=\"text-muted-foreground text-xs mt-1\">\n {t('integrations.marketplace.integrations', { count: bundle.integrations.length })}\n </p>\n </div>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={`/backend/integrations/bundle/${encodeURIComponent(bundle.id)}`}>\n <Cog className=\"mr-1.5 h-4 w-4\" />\n {t('integrations.marketplace.configure')}\n </Link>\n </Button>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {bundle.integrations.map((item) => (\n <div\n key={item.id}\n className=\"flex flex-col gap-2 rounded-lg border p-3\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {renderCategoryIcon(item.category, 'h-4 w-4 text-muted-foreground shrink-0')}\n <Link\n href={`/backend/integrations/${encodeURIComponent(item.id)}`}\n className=\"truncate text-sm font-medium hover:underline\"\n >\n {item.title}\n </Link>\n {renderHealthBadge(item.healthStatus)}\n </div>\n {(item.company || item.author || item.version) ? (\n <p className=\"text-xs text-muted-foreground\">\n {[item.company || item.author, item.version ? `v${item.version}` : null].filter(Boolean).join(' \u00B7 ')}\n </p>\n ) : null}\n </div>\n <Switch\n checked={item.isEnabled}\n disabled={togglingIds.has(item.id)}\n onCheckedChange={(checked) => void handleToggle(item.id, checked, item.stateUpdatedAt)}\n className=\"shrink-0\"\n />\n </div>\n <div className=\"flex items-end justify-between gap-2 border-t pt-2\">\n <div className=\"text-xs text-muted-foreground space-y-0.5\">\n <div>\n {t('integrations.marketplace.analytics.events', { count: item.analytics.totalCount })}\n </div>\n <div>\n {t('integrations.marketplace.analytics.errorRate', {\n rate: `${Math.round(item.analytics.errorRate * 1000) / 10}%`,\n })}\n </div>\n </div>\n <LogSparkline counts={item.analytics.dailyCounts} />\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n ))}\n\n {grouped.standalone.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {grouped.standalone.map((item) => (\n <Card key={item.id} className=\"flex flex-col\">\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n {renderCategoryIcon(item.category, 'h-4 w-4 text-muted-foreground shrink-0')}\n <CardTitle className=\"text-base\">{item.title}</CardTitle>\n {renderHealthBadge(item.healthStatus)}\n </div>\n <Switch\n checked={item.isEnabled}\n disabled={togglingIds.has(item.id)}\n onCheckedChange={(checked) => void handleToggle(item.id, checked, item.stateUpdatedAt)}\n className=\"shrink-0\"\n />\n </div>\n </CardHeader>\n <CardContent className=\"flex-1 space-y-2\">\n {item.description && (\n <p className=\"text-muted-foreground text-sm\">{item.description}</p>\n )}\n {(item.company || item.author || item.version) && (\n <p className=\"text-muted-foreground text-xs\">\n {[item.company || item.author, item.version ? `v${item.version}` : null].filter(Boolean).join(' \u00B7 ')}\n </p>\n )}\n <div className=\"flex items-end justify-between gap-2 border-t pt-3\">\n <div className=\"text-xs text-muted-foreground space-y-0.5\">\n <div>\n {t('integrations.marketplace.analytics.events', { count: item.analytics.totalCount })}\n </div>\n <div>\n {t('integrations.marketplace.analytics.errorRate', {\n rate: `${Math.round(item.analytics.errorRate * 1000) / 10}%`,\n })}\n </div>\n </div>\n <LogSparkline counts={item.analytics.dailyCounts} />\n </div>\n </CardContent>\n <div className=\"px-6 pb-4\">\n <Button asChild variant=\"outline\" size=\"sm\" className=\"w-full\">\n <Link href={`/backend/integrations/${encodeURIComponent(item.id)}`}>\n <Cog className=\"mr-1.5 h-4 w-4\" />\n {t('integrations.marketplace.configure')}\n </Link>\n </Button>\n </div>\n </Card>\n ))}\n </div>\n )}\n\n {grouped.bundles.length === 0 && grouped.standalone.length === 0 && !isLoading && (\n <div className=\"text-center py-12 text-muted-foreground\">\n {t('integrations.marketplace.noResults')}\n </div>\n )}\n </section>\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/messages/search.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchIndexSource,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction buildMessagePresenter(translate: TranslateFn, record: Record<string, unknown>): SearchResultPresenter {\n const title = pickString(record.subject) ?? translate('messages.search.fallback.title', 'Message')\n const body = snippet(record.body)\n const externalName = pickString(record.external_name, record.externalName)\n const subtitle = [externalName, body].filter(Boolean).join(' \u00B7 ') || undefined\n return {\n title: String(title),\n subtitle,\n icon: 'mail',\n badge: translate('messages.search.badge.message', 'Message'),\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'messages:message',\n enabled:
|
|
5
|
-
"mappings": "AAOA,SAAS,2BAA2B;AAEpC,SAAS,WAAW,OAAiB,OAAe,OAAgB;AAClE,MAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAM,OAAO,MAAM,QAAQ,KAAK,IAC5B,MAAM,IAAI,CAAC,SAAU,SAAS,QAAQ,SAAS,SAAY,KAAK,OAAO,IAAI,CAAE,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,IACvG,OAAO,UAAU,WAAW,KAAK,UAAU,KAAK,IAAI,OAAO,KAAK;AACrE,MAAI,CAAC,KAAK,KAAK,EAAG;AAClB,QAAM,KAAK,GAAG,KAAK,KAAK,IAAI,EAAE;AAChC;AAEA,SAAS,cAAc,YAA2C;AAChE,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,SAAU;AACnC,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,QAAQ,SAAS,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAgB,MAAM,KAAyB;AAC9D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,MAAI,QAAQ,UAAU,IAAK,QAAO;AAClC,SAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,CAAC,CAAC;AACrC;AAEA,SAAS,sBAAsB,WAAwB,QAAwD;AAC7G,QAAM,QAAQ,WAAW,OAAO,OAAO,KAAK,UAAU,kCAAkC,SAAS;AACjG,QAAM,OAAO,QAAQ,OAAO,IAAI;AAChC,QAAM,eAAe,WAAW,OAAO,eAAe,OAAO,YAAY;AACzE,QAAM,WAAW,CAAC,cAAc,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK,KAAK;AACrE,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB;AAAA,IACA,MAAM;AAAA,IACN,OAAO,UAAU,iCAAiC,SAAS;AAAA,EAC7D;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa,OAAO,QAA+D;AACjF,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,SAAS,IAAI;AACnB,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,WAAW,OAAO,OAAO;AAC3C,mBAAW,OAAO,QAAQ,OAAO,IAAI;AACrC,mBAAW,OAAO,aAAa,OAAO,iBAAiB,OAAO,YAAY;AAC1E,YAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW,sBAAsB,GAAG,MAAM;AAAA,UAC1C,gBAAgB;AAAA,YACd,QAAQ;AAAA,cACN,SAAS,OAAO;AAAA,cAChB,MAAM,OAAO;AAAA,cACb,eAAe,OAAO,iBAAiB,OAAO;AAAA,cAC9C,qBAAqB,OAAO,uBAAuB,OAAO;AAAA,YAC5D;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,cAAc,OAAO,QAAQ;AAC3B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,eAAO,sBAAsB,GAAG,IAAI,MAAM;AAAA,MAC5C;AAAA,MACA,YAAY,OAAO,QAAQ;AACzB,cAAM,KAAK,WAAW,IAAI,OAAO,EAAE;AACnC,eAAO,KAAK,qBAAqB,mBAAmB,EAAE,CAAC,KAAK;AAAA,MAC9D;AAAA,MACA,aAAa;AAAA,QACX,YAAY,CAAC,WAAW,QAAQ,eAAe;AAAA,QAC/C,UAAU,CAAC,gBAAgB;AAAA,QAC3B,UAAU,CAAC,eAAe,eAAe;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;AACR,MAAM,SAAS;",
|
|
4
|
+
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchIndexSource,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction buildMessagePresenter(translate: TranslateFn, record: Record<string, unknown>): SearchResultPresenter {\n const title = pickString(record.subject) ?? translate('messages.search.fallback.title', 'Message')\n const body = snippet(record.body)\n const externalName = pickString(record.external_name, record.externalName)\n const subtitle = [externalName, body].filter(Boolean).join(' \u00B7 ') || undefined\n return {\n title: String(title),\n subtitle,\n icon: 'mail',\n badge: translate('messages.search.badge.message', 'Message'),\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'messages:message',\n aclFeatures: ['messages.view'],\n enabled: false,\n priority: 5,\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Subject', record.subject)\n appendLine(lines, 'Body', record.body)\n appendLine(lines, 'From name', record.external_name ?? record.externalName)\n if (!lines.length) return null\n return {\n text: lines,\n presenter: buildMessagePresenter(t, record),\n checksumSource: {\n record: {\n subject: record.subject,\n body: record.body,\n external_name: record.external_name ?? record.externalName,\n external_email_hash: record.external_email_hash ?? record.externalEmailHash,\n },\n },\n }\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildMessagePresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const id = pickString(ctx.record.id)\n return id ? `/backend/messages/${encodeURIComponent(id)}` : null\n },\n fieldPolicy: {\n searchable: ['subject', 'body', 'external_name'],\n hashOnly: ['external_email'],\n excluded: ['action_data', 'action_result'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/planner/search.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildRuleSetPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('planner.search.badge.availabilityRuleSet', 'Availability rule set')\n const description = snippet(record.description ?? customFields.description)\n const timezone = pickString(record.timezone, customFields.timezone)\n return {\n title: String(title),\n subtitle: formatSubtitle(description, timezone),\n icon: 'calendar-check',\n badge: t('planner.search.badge.availabilityRuleSet', 'Availability rule set'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'planner:planner_availability_rule_set',\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Timezone', record.timezone ?? ctx.customFields.timezone)\n return buildIndexSource(ctx, buildRuleSetPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildRuleSetPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/planner/availability-rulesets/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'timezone'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildRuleSetPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('planner.search.badge.availabilityRuleSet', 'Availability rule set')\n const description = snippet(record.description ?? customFields.description)\n const timezone = pickString(record.timezone, customFields.timezone)\n return {\n title: String(title),\n subtitle: formatSubtitle(description, timezone),\n icon: 'calendar-check',\n badge: t('planner.search.badge.availabilityRuleSet', 'Availability rule set'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'planner:planner_availability_rule_set',\n aclFeatures: ['planner.view'],\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Timezone', record.timezone ?? ctx.customFields.timezone)\n return buildIndexSource(ctx, buildRuleSetPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildRuleSetPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/planner/availability-rulesets/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'timezone'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -67,6 +67,7 @@ const searchConfig = {
|
|
|
67
67
|
entities: [
|
|
68
68
|
{
|
|
69
69
|
entityId: "resources:resources_resource",
|
|
70
|
+
aclFeatures: ["resources.view"],
|
|
70
71
|
enabled: true,
|
|
71
72
|
priority: 8,
|
|
72
73
|
buildSource: async (ctx) => {
|
|
@@ -92,6 +93,7 @@ const searchConfig = {
|
|
|
92
93
|
},
|
|
93
94
|
{
|
|
94
95
|
entityId: "resources:resources_resource_type",
|
|
96
|
+
aclFeatures: ["resources.view"],
|
|
95
97
|
enabled: true,
|
|
96
98
|
priority: 7,
|
|
97
99
|
buildSource: async (ctx) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/resources/search.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildResourcePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resource', 'Resource')\n const description = snippet(record.description ?? customFields.description)\n const capacity = record.capacity ?? record.capacity_value ?? record.capacityValue\n const capacityUnit = pickString(record.capacity_unit_name, record.capacityUnitName, record.capacity_unit_value, record.capacityUnitValue)\n const capacityLabel = capacity != null ? `${capacity}${capacityUnit ? ` ${capacityUnit}` : ''}` : null\n return {\n title: String(title),\n subtitle: formatSubtitle(description, capacityLabel),\n icon: 'box',\n badge: t('resources.search.badge.resource', 'Resource'),\n }\n}\n\nfunction buildResourceTypePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resourceType', 'Resource type')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'shapes',\n badge: t('resources.search.badge.resourceType', 'Resource type'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'resources:resources_resource',\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Capacity', record.capacity ?? record.capacity_value ?? record.capacityValue)\n appendLine(lines, 'Capacity unit', record.capacity_unit_name ?? record.capacityUnitName ?? record.capacity_unit_value)\n appendLine(lines, 'Resource type', record.resource_type_id ?? record.resourceTypeId)\n appendLine(lines, 'Tags', record.tags)\n return buildIndexSource(ctx, buildResourcePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourcePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resources/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'capacity', 'capacity_unit_name', 'capacity_unit_value', 'tags'],\n },\n },\n {\n entityId: 'resources:resources_resource_type',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Icon', record.appearance_icon ?? record.appearanceIcon)\n appendLine(lines, 'Color', record.appearance_color ?? record.appearanceColor)\n return buildIndexSource(ctx, buildResourceTypePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourceTypePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resource-types/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description', 'appearance_icon', 'appearance_color'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
-
"mappings": "AAOA,SAAS,2BAA2B;AAEpC,SAAS,cAAc,YAA2C;AAChE,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,SAAU;AACnC,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,QAAQ,SAAS,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAgB,MAAM,KAAyB;AAC9D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,MAAI,QAAQ,UAAU,IAAK,QAAO;AAClC,SAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,CAAC,CAAC;AACrC;AAEA,SAAS,WAAW,OAAiB,OAAe,OAAgB;AAClE,MAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAM,OAAO,MAAM,QAAQ,KAAK,IAC5B,MAAM,IAAI,CAAC,SAAU,SAAS,QAAQ,SAAS,SAAY,KAAK,OAAO,IAAI,CAAE,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,IACvG,OAAO,UAAU,WAAW,KAAK,UAAU,KAAK,IAAI,OAAO,KAAK;AACrE,MAAI,CAAC,KAAK,KAAK,EAAG;AAClB,QAAM,KAAK,GAAG,KAAK,KAAK,IAAI,EAAE;AAChC;AAEA,SAAS,uBAAuB,OAAiB,cAAuC;AACtF,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,QAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,eAAW,OAAO,IAAI,QAAQ,QAAQ,EAAE,GAAG,KAAK;AAAA,EAClD;AACF;AAEA,SAAS,kBAAkB,OAA2C;AACpE,QAAM,OAAO,MACV,IAAI,CAAC,SAAU,SAAS,QAAQ,SAAS,SAAY,KAAK,OAAO,IAAI,CAAE,EACvE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AACjB,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,SAAO,KAAK,KAAK,QAAK;AACxB;AAEA,SAAS,uBACP,GACA,QACA,cACuB;AACvB,QAAM,QACJ,WAAW,OAAO,MAAM,OAAO,cAAc,OAAO,aAAa,aAAa,MAAM,aAAa,YAAY,KAC5G,OAAO,MACR,EAAE,mCAAmC,UAAU;AACjD,QAAM,cAAc,QAAQ,OAAO,eAAe,aAAa,WAAW;AAC1E,QAAM,WAAW,OAAO,YAAY,OAAO,kBAAkB,OAAO;AACpE,QAAM,eAAe,WAAW,OAAO,oBAAoB,OAAO,kBAAkB,OAAO,qBAAqB,OAAO,iBAAiB;AACxI,QAAM,gBAAgB,YAAY,OAAO,GAAG,QAAQ,GAAG,eAAe,IAAI,YAAY,KAAK,EAAE,KAAK;AAClG,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB,UAAU,eAAe,aAAa,aAAa;AAAA,IACnD,MAAM;AAAA,IACN,OAAO,EAAE,mCAAmC,UAAU;AAAA,EACxD;AACF;AAEA,SAAS,2BACP,GACA,QACA,cACuB;AACvB,QAAM,QACJ,WAAW,OAAO,MAAM,OAAO,cAAc,OAAO,aAAa,aAAa,MAAM,aAAa,YAAY,KAC5G,OAAO,MACR,EAAE,uCAAuC,eAAe;AAC1D,QAAM,cAAc,QAAQ,OAAO,eAAe,aAAa,WAAW;AAC1E,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB,UAAU,eAAe,WAAW;AAAA,IACpC,MAAM;AAAA,IACN,OAAO,EAAE,uCAAuC,eAAe;AAAA,EACjE;AACF;AAEA,SAAS,iBACP,KACA,WACA,OAC0B;AAC1B,yBAAuB,OAAO,IAAI,YAAY;AAC9C,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,gBAAgB,EAAE,QAAQ,IAAI,QAAQ,cAAc,IAAI,aAAa;AAAA,EACvE;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa,OAAO,QAAQ;AAC1B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,SAAS,IAAI;AACnB,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,QAAQ,OAAO,QAAQ,OAAO,gBAAgB,IAAI,aAAa,IAAI;AACrF,mBAAW,OAAO,eAAe,OAAO,eAAe,IAAI,aAAa,WAAW;AACnF,mBAAW,OAAO,YAAY,OAAO,YAAY,OAAO,kBAAkB,OAAO,aAAa;AAC9F,mBAAW,OAAO,iBAAiB,OAAO,sBAAsB,OAAO,oBAAoB,OAAO,mBAAmB;AACrH,mBAAW,OAAO,iBAAiB,OAAO,oBAAoB,OAAO,cAAc;AACnF,mBAAW,OAAO,QAAQ,OAAO,IAAI;AACrC,eAAO,iBAAiB,KAAK,uBAAuB,GAAG,QAAQ,IAAI,YAAY,GAAG,KAAK;AAAA,MACzF;AAAA,MACA,cAAc,OAAO,QAAQ;AAC3B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,eAAO,uBAAuB,GAAG,IAAI,QAAQ,IAAI,YAAY;AAAA,MAC/D;AAAA,MACA,YAAY,OAAO,QAAQ,gCAAgC,mBAAmB,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;AAAA,MACpG,aAAa;AAAA,QACX,YAAY,CAAC,QAAQ,eAAe,YAAY,sBAAsB,uBAAuB,MAAM;AAAA,MACrG;AAAA,IACF;AAAA,IACA;AAAA,MACE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa,OAAO,QAAQ;AAC1B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,SAAS,IAAI;AACnB,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,QAAQ,OAAO,QAAQ,OAAO,gBAAgB,IAAI,aAAa,IAAI;AACrF,mBAAW,OAAO,eAAe,OAAO,eAAe,IAAI,aAAa,WAAW;AACnF,mBAAW,OAAO,QAAQ,OAAO,mBAAmB,OAAO,cAAc;AACzE,mBAAW,OAAO,SAAS,OAAO,oBAAoB,OAAO,eAAe;AAC5E,eAAO,iBAAiB,KAAK,2BAA2B,GAAG,QAAQ,IAAI,YAAY,GAAG,KAAK;AAAA,MAC7F;AAAA,MACA,cAAc,OAAO,QAAQ;AAC3B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,eAAO,2BAA2B,GAAG,IAAI,QAAQ,IAAI,YAAY;AAAA,MACnE;AAAA,MACA,YAAY,OAAO,QAAQ,qCAAqC,mBAAmB,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;AAAA,MACzG,aAAa;AAAA,QACX,YAAY,CAAC,QAAQ,eAAe,mBAAmB,kBAAkB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;AACR,MAAM,SAAS;",
|
|
4
|
+
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildResourcePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resource', 'Resource')\n const description = snippet(record.description ?? customFields.description)\n const capacity = record.capacity ?? record.capacity_value ?? record.capacityValue\n const capacityUnit = pickString(record.capacity_unit_name, record.capacityUnitName, record.capacity_unit_value, record.capacityUnitValue)\n const capacityLabel = capacity != null ? `${capacity}${capacityUnit ? ` ${capacityUnit}` : ''}` : null\n return {\n title: String(title),\n subtitle: formatSubtitle(description, capacityLabel),\n icon: 'box',\n badge: t('resources.search.badge.resource', 'Resource'),\n }\n}\n\nfunction buildResourceTypePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resourceType', 'Resource type')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'shapes',\n badge: t('resources.search.badge.resourceType', 'Resource type'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'resources:resources_resource',\n aclFeatures: ['resources.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Capacity', record.capacity ?? record.capacity_value ?? record.capacityValue)\n appendLine(lines, 'Capacity unit', record.capacity_unit_name ?? record.capacityUnitName ?? record.capacity_unit_value)\n appendLine(lines, 'Resource type', record.resource_type_id ?? record.resourceTypeId)\n appendLine(lines, 'Tags', record.tags)\n return buildIndexSource(ctx, buildResourcePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourcePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resources/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'capacity', 'capacity_unit_name', 'capacity_unit_value', 'tags'],\n },\n },\n {\n entityId: 'resources:resources_resource_type',\n aclFeatures: ['resources.view'],\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Icon', record.appearance_icon ?? record.appearanceIcon)\n appendLine(lines, 'Color', record.appearance_color ?? record.appearanceColor)\n return buildIndexSource(ctx, buildResourceTypePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourceTypePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resource-types/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description', 'appearance_icon', 'appearance_color'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
+
"mappings": "AAOA,SAAS,2BAA2B;AAEpC,SAAS,cAAc,YAA2C;AAChE,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,SAAU;AACnC,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,QAAQ,SAAS,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAgB,MAAM,KAAyB;AAC9D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,MAAI,QAAQ,UAAU,IAAK,QAAO;AAClC,SAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,CAAC,CAAC;AACrC;AAEA,SAAS,WAAW,OAAiB,OAAe,OAAgB;AAClE,MAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAM,OAAO,MAAM,QAAQ,KAAK,IAC5B,MAAM,IAAI,CAAC,SAAU,SAAS,QAAQ,SAAS,SAAY,KAAK,OAAO,IAAI,CAAE,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,IACvG,OAAO,UAAU,WAAW,KAAK,UAAU,KAAK,IAAI,OAAO,KAAK;AACrE,MAAI,CAAC,KAAK,KAAK,EAAG;AAClB,QAAM,KAAK,GAAG,KAAK,KAAK,IAAI,EAAE;AAChC;AAEA,SAAS,uBAAuB,OAAiB,cAAuC;AACtF,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,QAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,eAAW,OAAO,IAAI,QAAQ,QAAQ,EAAE,GAAG,KAAK;AAAA,EAClD;AACF;AAEA,SAAS,kBAAkB,OAA2C;AACpE,QAAM,OAAO,MACV,IAAI,CAAC,SAAU,SAAS,QAAQ,SAAS,SAAY,KAAK,OAAO,IAAI,CAAE,EACvE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AACjB,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,SAAO,KAAK,KAAK,QAAK;AACxB;AAEA,SAAS,uBACP,GACA,QACA,cACuB;AACvB,QAAM,QACJ,WAAW,OAAO,MAAM,OAAO,cAAc,OAAO,aAAa,aAAa,MAAM,aAAa,YAAY,KAC5G,OAAO,MACR,EAAE,mCAAmC,UAAU;AACjD,QAAM,cAAc,QAAQ,OAAO,eAAe,aAAa,WAAW;AAC1E,QAAM,WAAW,OAAO,YAAY,OAAO,kBAAkB,OAAO;AACpE,QAAM,eAAe,WAAW,OAAO,oBAAoB,OAAO,kBAAkB,OAAO,qBAAqB,OAAO,iBAAiB;AACxI,QAAM,gBAAgB,YAAY,OAAO,GAAG,QAAQ,GAAG,eAAe,IAAI,YAAY,KAAK,EAAE,KAAK;AAClG,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB,UAAU,eAAe,aAAa,aAAa;AAAA,IACnD,MAAM;AAAA,IACN,OAAO,EAAE,mCAAmC,UAAU;AAAA,EACxD;AACF;AAEA,SAAS,2BACP,GACA,QACA,cACuB;AACvB,QAAM,QACJ,WAAW,OAAO,MAAM,OAAO,cAAc,OAAO,aAAa,aAAa,MAAM,aAAa,YAAY,KAC5G,OAAO,MACR,EAAE,uCAAuC,eAAe;AAC1D,QAAM,cAAc,QAAQ,OAAO,eAAe,aAAa,WAAW;AAC1E,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB,UAAU,eAAe,WAAW;AAAA,IACpC,MAAM;AAAA,IACN,OAAO,EAAE,uCAAuC,eAAe;AAAA,EACjE;AACF;AAEA,SAAS,iBACP,KACA,WACA,OAC0B;AAC1B,yBAAuB,OAAO,IAAI,YAAY;AAC9C,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,gBAAgB,EAAE,QAAQ,IAAI,QAAQ,cAAc,IAAI,aAAa;AAAA,EACvE;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,aAAa,CAAC,gBAAgB;AAAA,MAC9B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa,OAAO,QAAQ;AAC1B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,SAAS,IAAI;AACnB,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,QAAQ,OAAO,QAAQ,OAAO,gBAAgB,IAAI,aAAa,IAAI;AACrF,mBAAW,OAAO,eAAe,OAAO,eAAe,IAAI,aAAa,WAAW;AACnF,mBAAW,OAAO,YAAY,OAAO,YAAY,OAAO,kBAAkB,OAAO,aAAa;AAC9F,mBAAW,OAAO,iBAAiB,OAAO,sBAAsB,OAAO,oBAAoB,OAAO,mBAAmB;AACrH,mBAAW,OAAO,iBAAiB,OAAO,oBAAoB,OAAO,cAAc;AACnF,mBAAW,OAAO,QAAQ,OAAO,IAAI;AACrC,eAAO,iBAAiB,KAAK,uBAAuB,GAAG,QAAQ,IAAI,YAAY,GAAG,KAAK;AAAA,MACzF;AAAA,MACA,cAAc,OAAO,QAAQ;AAC3B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,eAAO,uBAAuB,GAAG,IAAI,QAAQ,IAAI,YAAY;AAAA,MAC/D;AAAA,MACA,YAAY,OAAO,QAAQ,gCAAgC,mBAAmB,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;AAAA,MACpG,aAAa;AAAA,QACX,YAAY,CAAC,QAAQ,eAAe,YAAY,sBAAsB,uBAAuB,MAAM;AAAA,MACrG;AAAA,IACF;AAAA,IACA;AAAA,MACE,UAAU;AAAA,MACV,aAAa,CAAC,gBAAgB;AAAA,MAC9B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa,OAAO,QAAQ;AAC1B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,SAAS,IAAI;AACnB,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,QAAQ,OAAO,QAAQ,OAAO,gBAAgB,IAAI,aAAa,IAAI;AACrF,mBAAW,OAAO,eAAe,OAAO,eAAe,IAAI,aAAa,WAAW;AACnF,mBAAW,OAAO,QAAQ,OAAO,mBAAmB,OAAO,cAAc;AACzE,mBAAW,OAAO,SAAS,OAAO,oBAAoB,OAAO,eAAe;AAC5E,eAAO,iBAAiB,KAAK,2BAA2B,GAAG,QAAQ,IAAI,YAAY,GAAG,KAAK;AAAA,MAC7F;AAAA,MACA,cAAc,OAAO,QAAQ;AAC3B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,eAAO,2BAA2B,GAAG,IAAI,QAAQ,IAAI,YAAY;AAAA,MACnE;AAAA,MACA,YAAY,OAAO,QAAQ,qCAAqC,mBAAmB,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;AAAA,MACzG,aAAa;AAAA,QACX,YAAY,CAAC,QAAQ,eAAe,mBAAmB,kBAAkB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;AACR,MAAM,SAAS;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -330,6 +330,7 @@ const searchConfig = {
|
|
|
330
330
|
entities: [
|
|
331
331
|
{
|
|
332
332
|
entityId: "sales:sales_channel",
|
|
333
|
+
aclFeatures: ["sales.channels.manage"],
|
|
333
334
|
enabled: true,
|
|
334
335
|
priority: 7,
|
|
335
336
|
buildSource: async (ctx) => {
|
|
@@ -356,6 +357,7 @@ const searchConfig = {
|
|
|
356
357
|
},
|
|
357
358
|
{
|
|
358
359
|
entityId: "sales:sales_order",
|
|
360
|
+
aclFeatures: ["sales.orders.view"],
|
|
359
361
|
enabled: true,
|
|
360
362
|
priority: 10,
|
|
361
363
|
buildSource: async (ctx) => {
|
|
@@ -379,6 +381,7 @@ const searchConfig = {
|
|
|
379
381
|
},
|
|
380
382
|
{
|
|
381
383
|
entityId: "sales:sales_quote",
|
|
384
|
+
aclFeatures: ["sales.quotes.view"],
|
|
382
385
|
enabled: true,
|
|
383
386
|
priority: 10,
|
|
384
387
|
buildSource: async (ctx) => {
|
|
@@ -401,6 +404,7 @@ const searchConfig = {
|
|
|
401
404
|
},
|
|
402
405
|
{
|
|
403
406
|
entityId: "sales:sales_order_line",
|
|
407
|
+
aclFeatures: ["sales.orders.view"],
|
|
404
408
|
enabled: true,
|
|
405
409
|
priority: 7,
|
|
406
410
|
fieldPolicy: {
|
|
@@ -429,6 +433,7 @@ const searchConfig = {
|
|
|
429
433
|
},
|
|
430
434
|
{
|
|
431
435
|
entityId: "sales:sales_quote_line",
|
|
436
|
+
aclFeatures: ["sales.quotes.view"],
|
|
432
437
|
enabled: true,
|
|
433
438
|
priority: 7,
|
|
434
439
|
fieldPolicy: {
|
|
@@ -457,6 +462,7 @@ const searchConfig = {
|
|
|
457
462
|
},
|
|
458
463
|
{
|
|
459
464
|
entityId: "sales:sales_order_adjustment",
|
|
465
|
+
aclFeatures: ["sales.orders.view"],
|
|
460
466
|
enabled: true,
|
|
461
467
|
priority: 6,
|
|
462
468
|
buildSource: async (ctx) => {
|
|
@@ -477,6 +483,7 @@ const searchConfig = {
|
|
|
477
483
|
},
|
|
478
484
|
{
|
|
479
485
|
entityId: "sales:sales_quote_adjustment",
|
|
486
|
+
aclFeatures: ["sales.quotes.view"],
|
|
480
487
|
enabled: true,
|
|
481
488
|
priority: 6,
|
|
482
489
|
buildSource: async (ctx) => {
|
|
@@ -497,6 +504,7 @@ const searchConfig = {
|
|
|
497
504
|
},
|
|
498
505
|
{
|
|
499
506
|
entityId: "sales:sales_shipment",
|
|
507
|
+
aclFeatures: ["sales.orders.view"],
|
|
500
508
|
enabled: true,
|
|
501
509
|
priority: 6,
|
|
502
510
|
buildSource: async (ctx) => {
|
|
@@ -517,6 +525,7 @@ const searchConfig = {
|
|
|
517
525
|
},
|
|
518
526
|
{
|
|
519
527
|
entityId: "sales:sales_shipment_item",
|
|
528
|
+
aclFeatures: ["sales.orders.view"],
|
|
520
529
|
enabled: true,
|
|
521
530
|
priority: 5,
|
|
522
531
|
buildSource: async (ctx) => {
|
|
@@ -535,6 +544,7 @@ const searchConfig = {
|
|
|
535
544
|
},
|
|
536
545
|
{
|
|
537
546
|
entityId: "sales:sales_invoice",
|
|
547
|
+
aclFeatures: ["sales.invoices.manage"],
|
|
538
548
|
enabled: true,
|
|
539
549
|
priority: 6,
|
|
540
550
|
buildSource: async (ctx) => {
|
|
@@ -555,6 +565,7 @@ const searchConfig = {
|
|
|
555
565
|
},
|
|
556
566
|
{
|
|
557
567
|
entityId: "sales:sales_invoice_line",
|
|
568
|
+
aclFeatures: ["sales.invoices.manage"],
|
|
558
569
|
enabled: true,
|
|
559
570
|
priority: 5,
|
|
560
571
|
fieldPolicy: {
|
|
@@ -581,6 +592,7 @@ const searchConfig = {
|
|
|
581
592
|
},
|
|
582
593
|
{
|
|
583
594
|
entityId: "sales:sales_credit_memo",
|
|
595
|
+
aclFeatures: ["sales.credit_memos.manage"],
|
|
584
596
|
enabled: true,
|
|
585
597
|
priority: 6,
|
|
586
598
|
buildSource: async (ctx) => {
|
|
@@ -601,6 +613,7 @@ const searchConfig = {
|
|
|
601
613
|
},
|
|
602
614
|
{
|
|
603
615
|
entityId: "sales:sales_credit_memo_line",
|
|
616
|
+
aclFeatures: ["sales.credit_memos.manage"],
|
|
604
617
|
enabled: true,
|
|
605
618
|
priority: 5,
|
|
606
619
|
fieldPolicy: {
|
|
@@ -627,6 +640,7 @@ const searchConfig = {
|
|
|
627
640
|
},
|
|
628
641
|
{
|
|
629
642
|
entityId: "sales:sales_payment",
|
|
643
|
+
aclFeatures: ["sales.orders.view"],
|
|
630
644
|
enabled: true,
|
|
631
645
|
priority: 8,
|
|
632
646
|
buildSource: async (ctx) => {
|
|
@@ -647,6 +661,7 @@ const searchConfig = {
|
|
|
647
661
|
},
|
|
648
662
|
{
|
|
649
663
|
entityId: "sales:sales_payment_allocation",
|
|
664
|
+
aclFeatures: ["sales.orders.view"],
|
|
650
665
|
enabled: true,
|
|
651
666
|
priority: 5,
|
|
652
667
|
buildSource: async (ctx) => {
|
|
@@ -667,7 +682,8 @@ const searchConfig = {
|
|
|
667
682
|
},
|
|
668
683
|
{
|
|
669
684
|
entityId: "sales:sales_note",
|
|
670
|
-
|
|
685
|
+
aclFeatures: ["sales.orders.view"],
|
|
686
|
+
enabled: false,
|
|
671
687
|
priority: 7,
|
|
672
688
|
buildSource: async (ctx) => {
|
|
673
689
|
const { t: translate } = await resolveTranslations();
|
|
@@ -690,7 +706,8 @@ const searchConfig = {
|
|
|
690
706
|
},
|
|
691
707
|
{
|
|
692
708
|
entityId: "sales:sales_document_address",
|
|
693
|
-
|
|
709
|
+
aclFeatures: ["sales.orders.view"],
|
|
710
|
+
enabled: false,
|
|
694
711
|
priority: 7,
|
|
695
712
|
buildSource: async (ctx) => {
|
|
696
713
|
const { t: translate } = await resolveTranslations();
|
|
@@ -716,6 +733,7 @@ const searchConfig = {
|
|
|
716
733
|
},
|
|
717
734
|
{
|
|
718
735
|
entityId: "sales:sales_shipping_method",
|
|
736
|
+
aclFeatures: ["sales.settings.manage"],
|
|
719
737
|
enabled: true,
|
|
720
738
|
priority: 4,
|
|
721
739
|
buildSource: async (ctx) => {
|
|
@@ -736,6 +754,7 @@ const searchConfig = {
|
|
|
736
754
|
},
|
|
737
755
|
{
|
|
738
756
|
entityId: "sales:sales_delivery_window",
|
|
757
|
+
aclFeatures: ["sales.settings.manage"],
|
|
739
758
|
enabled: true,
|
|
740
759
|
priority: 4,
|
|
741
760
|
buildSource: async (ctx) => {
|
|
@@ -756,6 +775,7 @@ const searchConfig = {
|
|
|
756
775
|
},
|
|
757
776
|
{
|
|
758
777
|
entityId: "sales:sales_payment_method",
|
|
778
|
+
aclFeatures: ["sales.settings.manage"],
|
|
759
779
|
enabled: true,
|
|
760
780
|
priority: 4,
|
|
761
781
|
buildSource: async (ctx) => {
|
|
@@ -776,6 +796,7 @@ const searchConfig = {
|
|
|
776
796
|
},
|
|
777
797
|
{
|
|
778
798
|
entityId: "sales:sales_tax_rate",
|
|
799
|
+
aclFeatures: ["sales.settings.manage"],
|
|
779
800
|
enabled: true,
|
|
780
801
|
priority: 4,
|
|
781
802
|
buildSource: async (ctx) => {
|
|
@@ -796,6 +817,7 @@ const searchConfig = {
|
|
|
796
817
|
},
|
|
797
818
|
{
|
|
798
819
|
entityId: "sales:sales_document_tag",
|
|
820
|
+
aclFeatures: ["sales.orders.view"],
|
|
799
821
|
enabled: true,
|
|
800
822
|
priority: 3,
|
|
801
823
|
buildSource: async (ctx) => {
|