@genispace/geniapp 0.1.0
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/LICENSE +21 -0
- package/README.md +153 -0
- package/dist/CrossAppRecordPicker-BXchXcK5.js +624 -0
- package/dist/CrossAppRecordPicker-BXchXcK5.js.map +1 -0
- package/dist/Page-wHZrMN17.js +24 -0
- package/dist/Page-wHZrMN17.js.map +1 -0
- package/dist/ai/adopt/AiSuggestionPanel.d.ts +30 -0
- package/dist/ai/adopt/BusinessGuidancePanel.d.ts +31 -0
- package/dist/ai/adopt/DetailPageAiLayout.d.ts +7 -0
- package/dist/ai/adopt/adoptPresets.d.ts +11 -0
- package/dist/ai/adopt/guidanceContent.d.ts +27 -0
- package/dist/ai/adopt/parseAiSummary.d.ts +7 -0
- package/dist/ai/components/AgentJobProgress.d.ts +124 -0
- package/dist/ai/components/AsyncCombobox.d.ts +44 -0
- package/dist/ai/components/BulkActionBar.d.ts +44 -0
- package/dist/ai/components/EntityRef.d.ts +39 -0
- package/dist/ai/components/JobProgress.d.ts +64 -0
- package/dist/ai/components/ServerDataTable.d.ts +89 -0
- package/dist/ai/components/Timeline.d.ts +35 -0
- package/dist/ai/components/useInfiniteRows.d.ts +25 -0
- package/dist/ai/errors/userFacingError.d.ts +14 -0
- package/dist/ai/errors/userFacingError.js +48 -0
- package/dist/ai/errors/userFacingError.js.map +1 -0
- package/dist/ai/index.d.ts +34 -0
- package/dist/ai/integrations/partner/createPartnerRecordPickerHook.d.ts +15 -0
- package/dist/ai/integrations/partner/partnerRecordPicker.d.ts +20 -0
- package/dist/ai/layout/ModalWithAiLayout.d.ts +11 -0
- package/dist/ai/layout/aiUi.d.ts +16 -0
- package/dist/ai/layout/layoutConstants.d.ts +19 -0
- package/dist/ai/layout/modalSizeForAi.d.ts +5 -0
- package/dist/ai/locales/sharedAiCopy.d.ts +6 -0
- package/dist/ai/managed-data/DatasourceReadonlyTable.d.ts +11 -0
- package/dist/ai/managed-data/createTableClient.d.ts +7 -0
- package/dist/ai/managed-data/emitManagedEvent.d.ts +18 -0
- package/dist/ai/managed-data/executeManagedDatasource.d.ts +21 -0
- package/dist/ai/managed-data/queryManagedDatasource.d.ts +28 -0
- package/dist/ai/providers/AppUiProviders.d.ts +6 -0
- package/dist/ai/types/app-ai.types.d.ts +29 -0
- package/dist/ai/types/index.d.ts +1 -0
- package/dist/ai.d.ts +1 -0
- package/dist/ai.js +1817 -0
- package/dist/ai.js.map +1 -0
- package/dist/case-workspace/domain.d.ts +41 -0
- package/dist/case-workspace/domain.js +24 -0
- package/dist/case-workspace/domain.js.map +1 -0
- package/dist/case-workspace/index.d.ts +91 -0
- package/dist/case-workspace.d.ts +1 -0
- package/dist/case-workspace.js +392 -0
- package/dist/case-workspace.js.map +1 -0
- package/dist/cn-B6yFEsav.js +9 -0
- package/dist/cn-B6yFEsav.js.map +1 -0
- package/dist/components/ui/calendar.css +7 -0
- package/dist/cookieSettings-D_v3KS02.js +97 -0
- package/dist/cookieSettings-D_v3KS02.js.map +1 -0
- package/dist/dashboard/index.d.ts +16 -0
- package/dist/dashboard/src/ChartFrame.d.ts +18 -0
- package/dist/dashboard/src/ChartTooltip.d.ts +38 -0
- package/dist/dashboard/src/FilterBar.d.ts +23 -0
- package/dist/dashboard/src/KpiStatCard.d.ts +29 -0
- package/dist/dashboard/src/StatGrid.d.ts +15 -0
- package/dist/dashboard/src/TimeRangePicker.d.ts +14 -0
- package/dist/dashboard/src/chart.d.ts +10 -0
- package/dist/dashboard/src/format.d.ts +16 -0
- package/dist/dashboard/src/links.d.ts +2 -0
- package/dist/dashboard/src/useDashboardRange.d.ts +27 -0
- package/dist/dashboard.d.ts +1 -0
- package/dist/dashboard.js +361 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/fonts.css +15 -0
- package/dist/hooks/access/AppAccessGate.d.ts +20 -0
- package/dist/hooks/access/AppAccessNotice.d.ts +8 -0
- package/dist/hooks/access/useAppAccess.d.ts +26 -0
- package/dist/hooks/config/businessLocale.d.ts +12 -0
- package/dist/hooks/config/currencies.d.ts +9 -0
- package/dist/hooks/index.d.ts +17 -0
- package/dist/hooks/picker/CrossAppRecordPicker.d.ts +37 -0
- package/dist/hooks/picker/managedAppPicker.d.ts +21 -0
- package/dist/hooks/picker/partnerPayload.d.ts +6 -0
- package/dist/hooks/routing/draftEntityId.d.ts +5 -0
- package/dist/hooks/routing/useRefetchOnRouteMatch.d.ts +6 -0
- package/dist/hooks/shell/resolveApiRoot.d.ts +13 -0
- package/dist/hooks/shell/shell.d.ts +4 -0
- package/dist/hooks/shell/useGenispacePlatformClient.d.ts +7 -0
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.js +42 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/kit.d.ts +50 -0
- package/dist/kit.js +2067 -0
- package/dist/kit.js.map +1 -0
- package/dist/page.d.ts +1 -0
- package/dist/page.js +5 -0
- package/dist/page.js.map +1 -0
- package/dist/shell-DIHnXIUb.js +6 -0
- package/dist/shell-DIHnXIUb.js.map +1 -0
- package/dist/shell.d.ts +30 -0
- package/dist/shell.js +104 -0
- package/dist/shell.js.map +1 -0
- package/dist/storage/assetPreview.d.ts +12 -0
- package/dist/storage/components/AssetThumbnail.d.ts +15 -0
- package/dist/storage/components/CopyStorageLinkButton.d.ts +13 -0
- package/dist/storage/components/StorageImage.d.ts +9 -0
- package/dist/storage/components/StoragePreviewContent.d.ts +22 -0
- package/dist/storage/components/StorageVideo.d.ts +9 -0
- package/dist/storage/copyTextToClipboard.d.ts +5 -0
- package/dist/storage/hooks/useAuthenticatedStorageBlobs.d.ts +3 -0
- package/dist/storage/hooks/useImageThumbnailBlobs.d.ts +4 -0
- package/dist/storage/hooks/useShareableStorageLink.d.ts +7 -0
- package/dist/storage/index.d.ts +12 -0
- package/dist/storage/openUrlInNewTab.d.ts +6 -0
- package/dist/storage/platformStorage.d.ts +43 -0
- package/dist/storage.d.ts +1 -0
- package/dist/storage.js +605 -0
- package/dist/storage.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/styles/base.css +616 -0
- package/dist/styles/reduced-motion.css +14 -0
- package/dist/styles/tailwind-preset.js +269 -0
- package/dist/task-workspace/domain.d.ts +35 -0
- package/dist/task-workspace/domain.js +45 -0
- package/dist/task-workspace/domain.js.map +1 -0
- package/dist/task-workspace/experience.d.ts +50 -0
- package/dist/task-workspace/index.d.ts +172 -0
- package/dist/task-workspace.d.ts +1 -0
- package/dist/task-workspace.js +626 -0
- package/dist/task-workspace.js.map +1 -0
- package/dist/ui/components/features/app/AppCheckboxInput.d.ts +9 -0
- package/dist/ui/components/features/app/AppConfirmDialog.d.ts +12 -0
- package/dist/ui/components/features/app/AppDashboardSkeleton.d.ts +9 -0
- package/dist/ui/components/features/app/AppDatePicker.d.ts +69 -0
- package/dist/ui/components/features/app/AppModal.d.ts +27 -0
- package/dist/ui/components/features/app/AppPageStates.d.ts +17 -0
- package/dist/ui/components/features/app/AppSelectInput.d.ts +10 -0
- package/dist/ui/components/features/app/AppTemporalInput.d.ts +19 -0
- package/dist/ui/components/features/app/Page.d.ts +14 -0
- package/dist/ui/components/features/app/QueryErrorAlert.d.ts +7 -0
- package/dist/ui/components/features/app/Sidebar.d.ts +47 -0
- package/dist/ui/components/features/app/index.d.ts +17 -0
- package/dist/ui/components/features/user/UserAvatar.d.ts +17 -0
- package/dist/ui/components/features/user/UserDisplay.d.ts +10 -0
- package/dist/ui/components/features/user/UserSelect.d.ts +14 -0
- package/dist/ui/components/features/user/useUserDirectory.d.ts +13 -0
- package/dist/ui/components/features/user/userDirectoryTypes.d.ts +18 -0
- package/dist/ui/components/patterns/form-section.d.ts +11 -0
- package/dist/ui/components/primitives/feedback/index.d.ts +2 -0
- package/dist/ui/components/primitives/feedback/toaster.d.ts +1 -0
- package/dist/ui/components/primitives/feedback/use-toast.d.ts +46 -0
- package/dist/ui/components/primitives/page-skeleton/ChartAreaSkeleton.d.ts +13 -0
- package/dist/ui/components/primitives/page-skeleton/ChartEmptyState.d.ts +14 -0
- package/dist/ui/components/primitives/page-skeleton/ComponentSkeletonShell.d.ts +16 -0
- package/dist/ui/components/primitives/page-skeleton/ConfigEditorSkeleton.d.ts +5 -0
- package/dist/ui/components/primitives/page-skeleton/DetailTabsSkeleton.d.ts +6 -0
- package/dist/ui/components/primitives/page-skeleton/EmptyStateBadge.d.ts +13 -0
- package/dist/ui/components/primitives/page-skeleton/FormCardSkeleton.d.ts +7 -0
- package/dist/ui/components/primitives/page-skeleton/FormFieldSkeleton.d.ts +6 -0
- package/dist/ui/components/primitives/page-skeleton/FormPageSkeleton.d.ts +6 -0
- package/dist/ui/components/primitives/page-skeleton/GridCardsSkeleton.d.ts +6 -0
- package/dist/ui/components/primitives/page-skeleton/ListSkeleton.d.ts +26 -0
- package/dist/ui/components/primitives/page-skeleton/PageHeaderSkeleton.d.ts +6 -0
- package/dist/ui/components/primitives/page-skeleton/SplitPaneSkeleton.d.ts +4 -0
- package/dist/ui/components/primitives/page-skeleton/StatsRowSkeleton.d.ts +5 -0
- package/dist/ui/components/primitives/page-skeleton/TableEmptyState.d.ts +27 -0
- package/dist/ui/components/primitives/page-skeleton/TablePageSkeleton.d.ts +8 -0
- package/dist/ui/components/primitives/page-skeleton/TabsBarSkeleton.d.ts +6 -0
- package/dist/ui/components/primitives/page-skeleton/index.d.ts +24 -0
- package/dist/ui/components/primitives/page-skeleton/skeletonMetrics.d.ts +9 -0
- package/dist/ui/components/primitives/page-skeleton/useVisibleCenter.d.ts +34 -0
- package/dist/ui/components/ui/accordion.d.ts +7 -0
- package/dist/ui/components/ui/ai-draft-banner.d.ts +21 -0
- package/dist/ui/components/ui/alert-dialog.d.ts +48 -0
- package/dist/ui/components/ui/alert.d.ts +8 -0
- package/dist/ui/components/ui/avatar.d.ts +6 -0
- package/dist/ui/components/ui/badge.d.ts +9 -0
- package/dist/ui/components/ui/breadcrumb.d.ts +19 -0
- package/dist/ui/components/ui/button.d.ts +11 -0
- package/dist/ui/components/ui/calendar.d.ts +8 -0
- package/dist/ui/components/ui/card.d.ts +8 -0
- package/dist/ui/components/ui/chart.d.ts +16 -0
- package/dist/ui/components/ui/checkbox.d.ts +4 -0
- package/dist/ui/components/ui/collapsible.d.ts +5 -0
- package/dist/ui/components/ui/column-config.d.ts +42 -0
- package/dist/ui/components/ui/date-picker.d.ts +9 -0
- package/dist/ui/components/ui/date-range-filter.d.ts +32 -0
- package/dist/ui/components/ui/date-range-picker.d.ts +11 -0
- package/dist/ui/components/ui/dialog-input.d.ts +17 -0
- package/dist/ui/components/ui/dialog-safe-select.d.ts +13 -0
- package/dist/ui/components/ui/dialog.d.ts +25 -0
- package/dist/ui/components/ui/dropdown-menu.d.ts +27 -0
- package/dist/ui/components/ui/feature-guide.d.ts +43 -0
- package/dist/ui/components/ui/form.d.ts +25 -0
- package/dist/ui/components/ui/help-tip.d.ts +29 -0
- package/dist/ui/components/ui/hint-notice.d.ts +22 -0
- package/dist/ui/components/ui/index.d.ts +6 -0
- package/dist/ui/components/ui/input.d.ts +3 -0
- package/dist/ui/components/ui/label.d.ts +5 -0
- package/dist/ui/components/ui/modal-container.d.ts +56 -0
- package/dist/ui/components/ui/modal-templates.d.ts +46 -0
- package/dist/ui/components/ui/multi-select.d.ts +20 -0
- package/dist/ui/components/ui/pagination.d.ts +28 -0
- package/dist/ui/components/ui/popover.d.ts +7 -0
- package/dist/ui/components/ui/progress.d.ts +7 -0
- package/dist/ui/components/ui/radio-button-group.d.ts +18 -0
- package/dist/ui/components/ui/radio-group.d.ts +5 -0
- package/dist/ui/components/ui/scroll-area.d.ts +5 -0
- package/dist/ui/components/ui/select.d.ts +16 -0
- package/dist/ui/components/ui/separator.d.ts +7 -0
- package/dist/ui/components/ui/sheet.d.ts +25 -0
- package/dist/ui/components/ui/sidebar-rail.d.ts +9 -0
- package/dist/ui/components/ui/skeleton.d.ts +2 -0
- package/dist/ui/components/ui/slider.d.ts +13 -0
- package/dist/ui/components/ui/switch.d.ts +4 -0
- package/dist/ui/components/ui/table.d.ts +10 -0
- package/dist/ui/components/ui/tabs.d.ts +10 -0
- package/dist/ui/components/ui/textarea.d.ts +3 -0
- package/dist/ui/components/ui/toast.d.ts +21 -0
- package/dist/ui/components/ui/toggle-group.d.ts +12 -0
- package/dist/ui/components/ui/toggle.d.ts +12 -0
- package/dist/ui/components/ui/tooltip.d.ts +7 -0
- package/dist/ui/components/ui/typography.d.ts +15 -0
- package/dist/ui/components/ui/underline-tabs.d.ts +13 -0
- package/dist/ui/components/ui/view-mode-toggle.d.ts +9 -0
- package/dist/ui/hooks/useIsMobile.d.ts +16 -0
- package/dist/ui/styles/design-tokens.d.ts +189 -0
- package/dist/ui/styles/z-index-layers.d.ts +46 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.js +35 -0
- package/dist/ui.js.map +1 -0
- package/dist/useUserDirectory-CqkyCQoR.js +2377 -0
- package/dist/useUserDirectory-CqkyCQoR.js.map +1 -0
- package/dist/utils/cookieSettings.d.ts +12 -0
- package/dist/utils/data/countryCodes.d.ts +26 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/utils/appPath.d.ts +5 -0
- package/dist/utils/utils/chunkLoadRecovery.d.ts +7 -0
- package/dist/utils/utils/cn.d.ts +3 -0
- package/dist/utils/utils/crossApp.d.ts +71 -0
- package/dist/utils/utils/debounce.d.ts +1 -0
- package/dist/utils/utils/formatUserLabel.d.ts +8 -0
- package/dist/utils/utils/formatting.d.ts +18 -0
- package/dist/utils/utils/logoutNotification.d.ts +28 -0
- package/dist/utils/utils/operatorLocale.d.ts +32 -0
- package/dist/utils/utils/routeLocalePrefetch.d.ts +5 -0
- package/dist/utils/utils/shellIframeUrl.d.ts +20 -0
- package/dist/utils/utils/spaceSettings.d.ts +20 -0
- package/dist/utils/utils/sso.d.ts +42 -0
- package/dist/utils/utils/throttle.d.ts +1 -0
- package/dist/utils/utils/timezones.d.ts +14 -0
- package/dist/utils/utils/toDateInputValue.d.ts +5 -0
- package/dist/utils/utils/watermark.d.ts +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1334 -0
- package/dist/utils.js.map +1 -0
- package/dist/vite.d.ts +22 -0
- package/dist/vite.js +74 -0
- package/dist/vite.js.map +1 -0
- package/package.json +191 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrossAppRecordPicker-BXchXcK5.js","sources":["../src/hooks/routing/useRefetchOnRouteMatch.ts","../src/hooks/routing/draftEntityId.ts","../src/hooks/config/currencies.ts","../src/hooks/config/businessLocale.ts","../src/hooks/shell/useGenispacePlatformClient.ts","../src/hooks/access/useAppAccess.ts","../src/hooks/access/AppAccessNotice.tsx","../src/hooks/access/AppAccessGate.tsx","../src/hooks/picker/partnerPayload.ts","../src/hooks/shell/resolveApiRoot.ts","../src/hooks/picker/managedAppPicker.ts","../src/hooks/picker/CrossAppRecordPicker.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { useLocation } from 'react-router-dom';\n\nfunction normalizePath(p: string): string {\n const t = p.replace(/\\/$/, '');\n return t || '/';\n}\n\n/** True when pathname is exactly the list route (not `/list/new` or `/list/:id`). */\nexport function isListRoutePath(pathname: string, listPath: string): boolean {\n return normalizePath(pathname) === normalizePath(listPath);\n}\n\n/**\n * Refetch list data when the user is on the list route (including returning from a FormPage).\n */\nexport function useRefetchOnRouteMatch(\n listPath: string,\n load: () => void | Promise<void>\n): void {\n const { pathname } = useLocation();\n const loadRef = useRef(load);\n loadRef.current = load;\n const onList = isListRoutePath(pathname, listPath);\n\n useEffect(() => {\n if (!onList) return;\n void loadRef.current();\n }, [onList, pathname, listPath]);\n}\n","export const ROUTE_NEW_PLACEHOLDER = 'new';\n\nexport function isRouteNewPlaceholder(id?: string | null): boolean {\n return !id?.trim() || id === ROUTE_NEW_PLACEHOLDER;\n}\n\nexport function isRouteEditMode(id?: string | null): boolean {\n return !isRouteNewPlaceholder(id);\n}\n\n/** For transaction saves: generate a client-side UUID when route id is invalid. */\nexport function resolveDraftEntityId(id?: string | null): string {\n const trimmed = id?.trim();\n if (!trimmed || trimmed === ROUTE_NEW_PLACEHOLDER) return crypto.randomUUID();\n return trimmed;\n}\n","export const ROUTE_NEW_PLACEHOLDER = 'new';\n\nexport const COMMON_CURRENCY_OPTIONS = [\n 'USD',\n 'CNY',\n 'EUR',\n 'GBP',\n 'JPY',\n 'HKD',\n 'AUD',\n 'CAD',\n 'SGD',\n 'CHF',\n] as const;\n\nexport type CurrencyCode = (typeof COMMON_CURRENCY_OPTIONS)[number];\n\nconst displayNamesCache = new Map<string, Intl.DisplayNames>();\n\nfunction getDisplayNames(locale: string): Intl.DisplayNames {\n let dn = displayNamesCache.get(locale);\n if (!dn) {\n dn = new Intl.DisplayNames([locale], { type: 'currency' });\n displayNamesCache.set(locale, dn);\n }\n return dn;\n}\n\nexport function currencyLabel(code: string, locale = 'en'): string {\n const upper = code.trim().toUpperCase();\n try {\n return getDisplayNames(locale).of(upper) ?? upper;\n } catch {\n return upper;\n }\n}\n\nexport function parseEnabledCurrenciesJson(raw: unknown): string[] {\n if (Array.isArray(raw)) {\n return raw.filter((x): x is string => typeof x === 'string').map((x) => x.trim().toUpperCase());\n }\n if (typeof raw === 'string' && raw.trim()) {\n try {\n return parseEnabledCurrenciesJson(JSON.parse(raw));\n } catch {\n return [];\n }\n }\n return [];\n}\n\nexport function normalizeEnabledCurrencies(\n codes: string[] | null | undefined,\n options: { minOne?: string } = {}\n): string[] {\n const minOne = (options.minOne ?? 'USD').toUpperCase();\n const seen = new Set<string>();\n const out: string[] = [];\n for (const code of codes ?? []) {\n const upper = code.trim().toUpperCase();\n if (!upper || seen.has(upper)) continue;\n seen.add(upper);\n out.push(upper);\n }\n if (out.length === 0) return [minOne];\n if (!seen.has(minOne)) out.unshift(minOne);\n return out;\n}\n\nexport const DEFAULT_ENABLED_CURRENCIES = ['USD'] as const;\n","export type BusinessLocale = 'en-US' | 'zh-CN';\n\nfunction selectedApplicationLanguage(): string | null {\n if (typeof window === 'undefined') return null;\n try {\n return window.localStorage.getItem('i18nextLng') || window.localStorage.getItem('language');\n } catch {\n return null;\n }\n}\n\n/**\n * Convert the language explicitly selected in GeniSpace into the locale used\n * for business dates, numbers and currencies. Browser locale is deliberately\n * ignored so a Chinese page cannot silently render US dates (or vice versa).\n */\nexport function resolveBusinessLocale(language?: string | null): BusinessLocale {\n const selectedLanguage = language || selectedApplicationLanguage();\n return selectedLanguage?.trim().toLowerCase().replaceAll('_', '-').startsWith('zh')\n ? 'zh-CN'\n : 'en-US';\n}\n\nexport function formatBusinessTime(\n value: unknown,\n language?: string | null,\n options: Intl.DateTimeFormatOptions = { timeStyle: 'short' },\n): string {\n return formatBusinessDate(value, language, options);\n}\n\nexport function formatBusinessDate(\n value: unknown,\n language?: string | null,\n options: Intl.DateTimeFormatOptions = { dateStyle: 'medium' },\n): string {\n if (value == null || value === '') return '—';\n const date = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(date.getTime())) return String(value);\n return new Intl.DateTimeFormat(resolveBusinessLocale(language), options).format(date);\n}\n\nexport function formatBusinessDateTime(\n value: unknown,\n language?: string | null,\n options: Intl.DateTimeFormatOptions = { dateStyle: 'medium', timeStyle: 'short' },\n): string {\n return formatBusinessDate(value, language, options);\n}\n\nexport function formatBusinessNumber(\n value: unknown,\n language?: string | null,\n options?: Intl.NumberFormatOptions,\n): string {\n const numericValue = Number(value ?? 0);\n return new Intl.NumberFormat(resolveBusinessLocale(language), options).format(\n Number.isFinite(numericValue) ? numericValue : 0,\n );\n}\n\nexport function formatBusinessCurrency(\n value: unknown,\n currency: unknown,\n language?: string | null,\n): string {\n const numericValue = Number(value ?? 0);\n return new Intl.NumberFormat(resolveBusinessLocale(language), {\n style: 'currency',\n currency: String(currency || 'USD'),\n maximumFractionDigits: 2,\n }).format(Number.isFinite(numericValue) ? numericValue : 0);\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport GeniSpace from 'genispace';\nimport { GENISPACE_SHELL_INIT_APPLIED_EVENT } from './shell';\n\nfunction readAccessToken(): string {\n try {\n return localStorage.getItem('token') ?? '';\n } catch {\n return '';\n }\n}\n\n/**\n * Platform GeniSpace client for `/teams/members`, `/users/profiles/batch`, etc.\n * Rebuilds when Shell posts GENISPACE_SHELL_INIT (API base + token).\n */\nexport function useGenispacePlatformClient(getApiRoot: () => string): GeniSpace {\n const [shellRevision, setShellRevision] = useState(0);\n\n useEffect(() => {\n const onShellInit = () => setShellRevision((n) => n + 1);\n window.addEventListener(GENISPACE_SHELL_INIT_APPLIED_EVENT, onShellInit);\n return () => window.removeEventListener(GENISPACE_SHELL_INIT_APPLIED_EVENT, onShellInit);\n }, []);\n\n return useMemo(() => {\n const token = readAccessToken();\n const baseURL = getApiRoot().replace(/\\/$/, '');\n const client = new GeniSpace({\n baseURL,\n apiKey: token,\n accessToken: token || undefined,\n });\n return client;\n }, [shellRevision, getApiRoot]);\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { GENISPACE_SHELL_INIT_APPLIED_EVENT, GENISPACE_SHELL_SESSION_API_KEY } from '../shell/shell';\n\nexport type AppAccess = {\n isUser: boolean;\n permissionCodes: string[];\n loading: boolean;\n /** Set when the access API call fails (network / server error). Distinct from zero permissions. */\n accessError: string | null;\n reloadAccess: () => void;\n};\n\nexport type UseAppAccessOptions = {\n /** Application instance id from Shell GENISPACE_SHELL_INIT (sessionStorage). */\n sessionStorageKey: string;\n /** Resolve platform API root including `/api` suffix. */\n getApiRoot: () => string;\n};\n\nexport function setAppApplicationId(sessionStorageKey: string, applicationId: string | null) {\n try {\n if (applicationId) sessionStorage.setItem(sessionStorageKey, applicationId);\n else sessionStorage.removeItem(sessionStorageKey);\n } catch {\n /* ignore */\n }\n}\n\nexport function getAppApplicationId(sessionStorageKey: string): string | null {\n try {\n return sessionStorage.getItem(sessionStorageKey);\n } catch {\n return null;\n }\n}\n\nexport function hasAppPermission(codes: string[], required: string): boolean {\n if (codes.length === 0 && !isAppRbacRelaxed()) return false;\n return codes.includes(required);\n}\n\n/** Allow-all RBAC only in dev or when explicitly relaxed (standalone local dev). */\nexport function isAppRbacRelaxed(): boolean {\n try {\n return import.meta.env.DEV === true || import.meta.env.VITE_RBAC_RELAXED === 'true';\n } catch {\n return false;\n }\n}\n\nexport function canAccessNavItem(\n loading: boolean,\n permissionCodes: string[],\n permission: string,\n accessError?: string | null,\n): boolean {\n if (loading) return false;\n if (accessError != null) return false;\n if (permissionCodes.length === 0) return isAppRbacRelaxed();\n return permissionCodes.includes(permission);\n}\n\n/** Page-level action gate — fail-closed when access fetch fails. */\nexport function canPerformAppAction(\n loading: boolean,\n permissionCodes: string[],\n required: string,\n accessError?: string | null,\n): boolean {\n if (loading) return false;\n if (accessError != null) return false;\n return hasAppPermission(permissionCodes, required);\n}\n\n/** Default API root from Shell injection or window origin. */\nexport function resolvePlatformApiRootFromShell(): string {\n try {\n if (typeof sessionStorage !== 'undefined') {\n const injected = sessionStorage.getItem(GENISPACE_SHELL_SESSION_API_KEY);\n if (injected && injected.trim() !== '') {\n const u = new URL(injected, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');\n return `${u.origin}/api`;\n }\n }\n } catch {\n /* ignore */\n }\n if (typeof window !== 'undefined') {\n return `${window.location.origin}/api`;\n }\n return '';\n}\n\nexport function createAppAccessHook(\n sessionStorageKey: string,\n getApiRoot: () => string\n): () => AppAccess {\n return () => useAppAccess({ sessionStorageKey, getApiRoot });\n}\n\nasync function fetchAppAccess(\n sessionStorageKey: string,\n getApiRoot: () => string\n): Promise<Pick<AppAccess, 'isUser' | 'permissionCodes' | 'accessError'>> {\n const applicationId = getAppApplicationId(sessionStorageKey);\n if (!applicationId) {\n return { isUser: true, permissionCodes: [], accessError: null };\n }\n const root = getApiRoot().replace(/\\/$/, '');\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n try {\n const token = localStorage.getItem('token');\n if (token) headers.Authorization = `Bearer ${token}`;\n } catch {\n /* ignore */\n }\n const res = await fetch(`${root}/applications/${encodeURIComponent(applicationId)}/users/me/access`, {\n headers,\n credentials: 'include',\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 404) {\n try {\n const body = text ? JSON.parse(text) : null;\n if (body?.code === 'NOT_FOUND') {\n // Stale instance id after reinstall — drop cache so Shell GENISPACE_SHELL_INIT can refresh it.\n setAppApplicationId(sessionStorageKey, null);\n }\n } catch {\n /* ignore */\n }\n }\n if (res.status === 401 || res.status === 403) {\n return {\n isUser: false,\n permissionCodes: [],\n accessError: text || res.statusText || `Access denied (${res.status})`,\n };\n }\n return {\n isUser: true,\n permissionCodes: [],\n accessError: text || res.statusText || `Access check failed (${res.status})`,\n };\n }\n const body = await res.json();\n const data = body?.data ?? body;\n return {\n isUser: Boolean(data?.isUser),\n permissionCodes: Array.isArray(data?.permissionCodes) ? data.permissionCodes : [],\n accessError: null,\n };\n}\n\nexport function useAppAccess({ sessionStorageKey, getApiRoot }: UseAppAccessOptions): AppAccess {\n const [state, setState] = useState<AppAccess>({\n isUser: true,\n permissionCodes: [],\n loading: true,\n accessError: null,\n reloadAccess: () => {},\n });\n\n const reloadAccess = useCallback(() => {\n setState((prev) => ({ ...prev, loading: true, accessError: null }));\n void fetchAppAccess(sessionStorageKey, getApiRoot)\n .then((result) => {\n setState((prev) => ({\n ...prev,\n ...result,\n loading: false,\n }));\n })\n .catch((e) => {\n setState((prev) => ({\n ...prev,\n isUser: true,\n permissionCodes: [],\n loading: false,\n accessError: e instanceof Error ? e.message : String(e),\n }));\n });\n }, [sessionStorageKey, getApiRoot]);\n\n useEffect(() => {\n reloadAccess();\n }, [reloadAccess]);\n\n useEffect(() => {\n const onApplied = () => reloadAccess();\n window.addEventListener(GENISPACE_SHELL_INIT_APPLIED_EVENT, onApplied);\n return () => window.removeEventListener(GENISPACE_SHELL_INIT_APPLIED_EVENT, onApplied);\n }, [reloadAccess]);\n\n useEffect(() => {\n setState((prev) => ({ ...prev, reloadAccess }));\n }, [reloadAccess]);\n\n return state;\n}\n","import type { AppAccess } from './useAppAccess';\n\ntype Props = {\n access: Pick<AppAccess, 'loading' | 'accessError' | 'reloadAccess'>;\n};\n\n/** Shown when RBAC access fetch fails so users see an error instead of a blank sidebar. */\nexport function AppAccessNotice({ access }: Props) {\n if (access.loading || !access.accessError) return null;\n return (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 dark:border-amber-900/50 dark:bg-amber-950/40 dark:text-amber-100\"\n >\n <p className=\"font-medium\">Unable to load permissions</p>\n <p className=\"mt-1 text-amber-800 dark:text-amber-200\">{access.accessError}</p>\n <button\n type=\"button\"\n onClick={access.reloadAccess}\n className=\"mt-2 rounded-lg border border-amber-300 bg-white px-3 py-1.5 text-xs font-medium text-amber-900 transition hover:bg-amber-100 dark:border-amber-800 dark:bg-neutral-900 dark:text-amber-100 dark:hover:bg-amber-900/30\"\n >\n Retry\n </button>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport type { AppAccess } from './useAppAccess';\nimport { AppAccessNotice } from './AppAccessNotice';\n\ntype Props = {\n access: Pick<AppAccess, 'loading' | 'accessError' | 'permissionCodes' | 'reloadAccess'>;\n children: ReactNode;\n /** Keep the final page geometry visible while permissions are loading. */\n showLoadingSkeleton?: boolean;\n};\n\nexport type AppContentSkeletonVariant = 'table' | 'dashboard' | 'detail';\n\n/**\n * Shared route fallback. It uses the same responsive page padding as AppPage so\n * switching from a skeleton to real content does not cause a horizontal jump.\n */\nexport function AppContentSkeleton({ variant = 'table' }: { variant?: AppContentSkeletonVariant }) {\n return (\n <div\n className=\"w-full min-w-0 max-w-full animate-pulse px-4 py-4 sm:px-6 sm:py-6 lg:px-8\"\n role=\"status\"\n aria-busy=\"true\"\n >\n <div className=\"mb-6 flex min-h-[52px] items-center justify-between gap-4 sm:min-h-[60px]\">\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"h-7 w-48 max-w-full rounded-md bg-muted\" />\n <div className=\"h-4 w-80 max-w-[70%] rounded bg-muted\" />\n </div>\n <div className=\"h-10 w-28 shrink-0 rounded-md bg-muted\" />\n </div>\n {variant === 'dashboard' ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n {Array.from({ length: 4 }).map((_, index) => <div key={index} className=\"h-28 rounded-xl border border-border bg-card\" />)}\n </div>\n <div className=\"mt-6 grid gap-6 xl:grid-cols-2\">\n <div className=\"h-72 rounded-xl border border-border bg-card\" />\n <div className=\"h-72 rounded-xl border border-border bg-card\" />\n </div>\n </>\n ) : variant === 'detail' ? (\n <div className=\"grid gap-6 xl:grid-cols-[minmax(0,1fr)_22rem]\">\n <div className=\"h-[30rem] rounded-xl border border-border bg-card\" />\n <div className=\"h-72 rounded-xl border border-border bg-card\" />\n </div>\n ) : (\n <>\n <div className=\"mb-4 flex gap-3\"><div className=\"h-10 flex-1 rounded-md bg-muted\" /><div className=\"h-10 w-36 rounded-md bg-muted\" /></div>\n <div className=\"overflow-hidden rounded-xl border border-border bg-card\">\n {Array.from({ length: 7 }).map((_, row) => (\n <div key={row} className=\"grid grid-cols-[minmax(12rem,2fr)_repeat(3,minmax(7rem,1fr))] gap-4 border-b border-border px-4 py-4 last:border-b-0\">\n {Array.from({ length: 4 }).map((__, column) => <div key={column} className={`h-4 rounded bg-muted ${column === 0 ? 'w-3/4' : 'w-2/3'}`} />)}\n </div>\n ))}\n </div>\n </>\n )}\n </div>\n );\n}\n\n/** Blocks page content when RBAC access fetch fails; keeps loading geometry stable. */\nexport function AppAccessGate({ access, children, showLoadingSkeleton = true }: Props) {\n if (access.accessError) {\n return <AppAccessNotice access={access} />;\n }\n if (showLoadingSkeleton && access.loading && access.permissionCodes.length === 0) {\n return <AppContentSkeleton />;\n }\n return <>{children}</>;\n}\n","export type PartnerFields = {\n partner_id?: string | null;\n partner_name?: string | null;\n};\n\nfunction normalizePartnerId(partnerId: string | null | undefined): string | null {\n if (partnerId == null || partnerId === '') return null;\n return partnerId;\n}\n\n/** Weak-dependency save: persist FK only when partner picker is available. */\nexport function applyPartnerPayload<T extends PartnerFields>(\n payload: T,\n pickerAvailable: boolean,\n pickerLoading = false,\n pickerLoadError: string | null = null,\n): T {\n if (pickerLoading || pickerLoadError != null) return { ...payload };\n\n const next = { ...payload };\n\n if (pickerAvailable) {\n next.partner_id = normalizePartnerId(next.partner_id);\n if (next.partner_id == null) {\n next.partner_id = null;\n next.partner_name = null;\n }\n return next;\n }\n\n // Picker unavailable: preserve server FK — do not write partner_id.\n delete next.partner_id;\n if (next.partner_name === '') next.partner_name = null;\n return next;\n}\n","import { GENISPACE_SHELL_SESSION_API_KEY } from './shell';\n\nexport type CreateResolveApiRootOptions = {\n /** e.g. import.meta.env.VITE_HR_API_BASE */\n dedicatedEnv?: string | undefined;\n platformEnv?: string | undefined;\n};\n\n/** Platform API root (`…/api`) for GeniApp iframe + standalone dev. */\nexport function createResolveApiRoot(options: CreateResolveApiRootOptions = {}): () => string {\n return () => {\n const dedicated = options.dedicatedEnv;\n if (typeof dedicated === 'string' && dedicated.trim() !== '') {\n return dedicated.replace(/\\/$/, '');\n }\n const platform = options.platformEnv;\n if (typeof platform === 'string' && platform.trim() !== '') {\n return platform.replace(/\\/$/, '');\n }\n try {\n if (typeof sessionStorage !== 'undefined') {\n const injected = sessionStorage.getItem(GENISPACE_SHELL_SESSION_API_KEY);\n if (injected && injected.trim() !== '') {\n const u = new URL(injected, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');\n return `${u.origin}/api`;\n }\n }\n } catch {\n /* ignore */\n }\n if (typeof window !== 'undefined') {\n return `${window.location.origin}/api`;\n }\n return '';\n };\n}\n\n/** Cross–dataScope table CRUD (read/patch). Documented integration exception only. */\nexport function createScopeTableClient(buildApiRoot: () => string) {\n function readToken(): string | null {\n try {\n return localStorage.getItem('token');\n } catch {\n return null;\n }\n }\n\n function authHeaders(): Record<string, string> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const token = readToken();\n if (token) headers.Authorization = `Bearer ${token}`;\n return headers;\n }\n\n function tableUrl(scope: string, table: string, id?: string): string {\n const root = buildApiRoot();\n const base = `${root}/data/${encodeURIComponent(scope)}/tables/${encodeURIComponent(table)}`;\n return id ? `${base}/${encodeURIComponent(id)}` : base;\n }\n\n async function scopeGet<T>(scope: string, table: string, id: string): Promise<T> {\n const res = await fetch(tableUrl(scope, table, id), { headers: authHeaders() });\n const text = await res.text();\n if (!res.ok) throw new Error(text || res.statusText);\n const body = text ? JSON.parse(text) : {};\n return ((body as { data?: T }).data ?? body) as T;\n }\n\n async function scopeList<T>(\n scope: string,\n table: string,\n filter?: Record<string, string | boolean | number | null>\n ): Promise<T[]> {\n const params = new URLSearchParams();\n if (filter) params.set('filter', JSON.stringify(filter));\n const res = await fetch(`${tableUrl(scope, table)}?${params}`, { headers: authHeaders() });\n const text = await res.text();\n if (!res.ok) throw new Error(text || res.statusText);\n const body = text ? JSON.parse(text) : {};\n const data = (body as { data?: { items?: T[] } | T[] }).data;\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n }\n\n async function scopePatch(\n scope: string,\n table: string,\n id: string,\n payload: Record<string, unknown>\n ): Promise<void> {\n const res = await fetch(tableUrl(scope, table, id), {\n method: 'PATCH',\n headers: authHeaders(),\n body: JSON.stringify(payload),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(text || res.statusText);\n }\n }\n\n return { scopeGet, scopeList, scopePatch };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { GENISPACE_SHELL_INIT_APPLIED_EVENT } from '../shell/shell';\n\nexport type ManagedPickerOption = {\n id: string;\n label: string;\n [key: string]: unknown;\n};\n\nexport type ManagedPickerConfig = {\n providerGeniappId: string;\n datasourceIdentifier: string;\n buildApiRoot: () => string;\n readToken: () => string | null;\n probePicker: (apiRoot: string, token: string | null) => Promise<boolean>;\n loadOptions: (apiRoot: string, token: string | null, ensureIds?: string[]) => Promise<ManagedPickerOption[]>;\n};\n\nexport function createUseManagedAppPicker(config: ManagedPickerConfig) {\n return function useManagedGeniappPicker(enabled: boolean, ensureIds: string[] = []) {\n const ensureKey = ensureIds.filter(Boolean).sort().join('\\0');\n const [pickerAvailable, setPickerAvailable] = useState(false);\n const [options, setOptions] = useState<ManagedPickerOption[]>([]);\n const [loading, setLoading] = useState(false);\n const [loadError, setLoadError] = useState<string | null>(null);\n\n const reloadGeneration = useRef(0);\n\n const reload = useCallback(async () => {\n const generation = ++reloadGeneration.current;\n if (!enabled) {\n if (generation !== reloadGeneration.current) return;\n setPickerAvailable(false);\n setOptions([]);\n setLoadError(null);\n setLoading(false);\n return;\n }\n const apiRoot = config.buildApiRoot();\n const token = config.readToken();\n setLoading(true);\n setLoadError(null);\n try {\n const available = await config.probePicker(apiRoot, token);\n if (generation !== reloadGeneration.current) return;\n if (!available) {\n setPickerAvailable(false);\n setOptions([]);\n return;\n }\n try {\n const opts = await config.loadOptions(apiRoot, token, ensureIds.filter(Boolean));\n if (generation !== reloadGeneration.current) return;\n setPickerAvailable(true);\n setOptions(opts);\n } catch (e) {\n if (generation !== reloadGeneration.current) return;\n setLoadError(e instanceof Error ? e.message : String(e));\n setPickerAvailable(false);\n setOptions([]);\n }\n } catch (e) {\n if (generation !== reloadGeneration.current) return;\n setLoadError(e instanceof Error ? e.message : String(e));\n setPickerAvailable(false);\n setOptions([]);\n } finally {\n if (generation === reloadGeneration.current) {\n setLoading(false);\n }\n }\n }, [enabled, ensureKey]);\n\n useEffect(() => {\n void reload();\n }, [reload]);\n\n useEffect(() => {\n const onApplied = () => {\n void reload();\n };\n window.addEventListener(GENISPACE_SHELL_INIT_APPLIED_EVENT, onApplied);\n return () => window.removeEventListener(GENISPACE_SHELL_INIT_APPLIED_EVENT, onApplied);\n }, [reload]);\n\n return { pickerAvailable, options, loading, loadError, reload, providerGeniappId: config.providerGeniappId };\n };\n}\n","import { useEffect, useId, useRef, useState } from \"react\";\n\nexport type CrossAppRecordOption = {\n id: string;\n primary: string;\n secondary?: string;\n status?: string;\n snapshot?: Record<string, CrossAppSnapshotValue>;\n};\n\nexport type CrossAppSnapshotValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | CrossAppSnapshotValue[]\n | { [key: string]: CrossAppSnapshotValue };\n\nexport type CrossAppRecordPage = {\n records: CrossAppRecordOption[];\n total: number;\n};\n\nexport type CrossAppRecordPickerProps = {\n label: string;\n description?: string;\n placeholder?: string;\n emptyText: string;\n unavailableText: string;\n forbiddenText: string;\n selected?: CrossAppRecordOption | null;\n pageSize?: number;\n disabled?: boolean;\n providerState?: \"ready\" | \"unavailable\" | \"forbidden\";\n loadPage: (input: {\n search: string;\n limit: number;\n offset: number;\n }) => Promise<CrossAppRecordPage>;\n onSelect: (record: CrossAppRecordOption | null) => void;\n};\n\n/**\n * Shared cross-GeniApp record picker. The provider remains responsible for\n * row/field authorization; consumers only receive display-safe snapshots.\n */\nexport function CrossAppRecordPicker({\n label,\n description,\n placeholder = \"\",\n emptyText,\n unavailableText,\n forbiddenText,\n selected = null,\n pageSize = 10,\n disabled = false,\n providerState = \"ready\",\n loadPage,\n onSelect,\n}: CrossAppRecordPickerProps) {\n const id = useId();\n const request = useRef(0);\n const loadPageRef = useRef(loadPage);\n loadPageRef.current = loadPage;\n const [search, setSearch] = useState(\"\");\n const [appliedSearch, setAppliedSearch] = useState(\"\");\n const [page, setPage] = useState(1);\n const [records, setRecords] = useState<CrossAppRecordOption[]>([]);\n const [total, setTotal] = useState(0);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n\n useEffect(() => {\n const current = ++request.current;\n if (providerState !== \"ready\") {\n setRecords([]);\n setTotal(0);\n setLoading(false);\n setError(\"\");\n return;\n }\n setLoading(true);\n setError(\"\");\n void loadPageRef\n .current({\n search: appliedSearch,\n limit: pageSize,\n offset: (page - 1) * pageSize,\n })\n .then((result) => {\n if (request.current !== current) return;\n setRecords(result.records);\n setTotal(Math.max(0, result.total));\n })\n .catch((reason: unknown) => {\n if (request.current !== current) return;\n setRecords([]);\n setTotal(0);\n setError(reason instanceof Error ? reason.message : String(reason));\n })\n .finally(() => {\n if (request.current === current) setLoading(false);\n });\n return () => {\n request.current += 1;\n };\n }, [appliedSearch, page, pageSize, providerState]);\n\n const pageCount = Math.max(1, Math.ceil(total / pageSize));\n const stateMessage =\n providerState === \"unavailable\"\n ? unavailableText\n : providerState === \"forbidden\"\n ? forbiddenText\n : error;\n\n return (\n <section\n className=\"rounded-xl border border-border p-4\"\n aria-labelledby={`${id}-label`}\n >\n <div>\n <label\n id={`${id}-label`}\n htmlFor={`${id}-search`}\n className=\"block text-sm font-medium\"\n >\n {label}\n </label>\n {description && (\n <p className=\"mt-1 text-xs leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n {selected && (\n <div className=\"mt-3 flex items-start justify-between gap-3 rounded-lg border border-primary/30 bg-primary/5 p-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium\">{selected.primary}</p>\n {selected.secondary && (\n <p className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {selected.secondary}\n </p>\n )}\n </div>\n <button\n type=\"button\"\n className=\"min-h-[44px] rounded-lg border border-border bg-background px-3 text-xs\"\n disabled={disabled}\n onClick={() => onSelect(null)}\n >\n ×\n </button>\n </div>\n )}\n <form\n className=\"mt-3 flex gap-2\"\n onSubmit={(event) => {\n event.preventDefault();\n setPage(1);\n setAppliedSearch(search.trim());\n }}\n >\n <input\n id={`${id}-search`}\n className=\"h-[44px] min-w-0 flex-1 rounded-lg border border-input bg-background px-3 text-sm outline-none focus:border-primary focus:ring-2 focus:ring-primary/15\"\n value={search}\n disabled={disabled || providerState !== \"ready\"}\n onChange={(event) => setSearch(event.target.value)}\n placeholder={placeholder}\n />\n <button\n type=\"submit\"\n className=\"min-h-[44px] rounded-lg border border-border bg-background px-4 text-sm font-medium disabled:opacity-50\"\n disabled={disabled || providerState !== \"ready\" || loading}\n >\n ⌕\n </button>\n </form>\n {stateMessage && (\n <p\n role=\"alert\"\n className=\"mt-3 rounded-lg bg-muted px-3 py-2 text-xs text-muted-foreground\"\n >\n {stateMessage}\n </p>\n )}\n {providerState === \"ready\" && !stateMessage && (\n <div className=\"mt-3 space-y-2\" aria-busy={loading}>\n {loading && (\n <p className=\"py-4 text-center text-xs text-muted-foreground\">…</p>\n )}\n {!loading &&\n records.map((record) => (\n <button\n key={record.id}\n type=\"button\"\n disabled={disabled}\n onClick={() => onSelect(record)}\n className=\"flex min-h-[48px] w-full items-center justify-between gap-3 rounded-lg border border-border px-3 py-2 text-left hover:bg-accent disabled:opacity-50\"\n >\n <span className=\"min-w-0\">\n <span className=\"block truncate text-sm font-medium\">\n {record.primary}\n </span>\n {record.secondary && (\n <span className=\"mt-0.5 block truncate text-xs text-muted-foreground\">\n {record.secondary}\n </span>\n )}\n </span>\n {record.status && (\n <span className=\"shrink-0 rounded-full bg-muted px-2 py-1 text-[11px] text-muted-foreground\">\n {record.status}\n </span>\n )}\n </button>\n ))}\n {!loading && !records.length && (\n <p className=\"py-4 text-center text-xs text-muted-foreground\">\n {emptyText}\n </p>\n )}\n </div>\n )}\n {providerState === \"ready\" &&\n !loading &&\n !stateMessage &&\n total > pageSize && (\n <div className=\"mt-3 flex items-center justify-between gap-3 text-xs text-muted-foreground\">\n <span>\n {page}/{pageCount} · {total}\n </span>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n className=\"min-h-[44px] rounded-lg border border-border px-3 disabled:opacity-40\"\n disabled={page <= 1}\n onClick={() => setPage((value) => Math.max(1, value - 1))}\n >\n ‹\n </button>\n <button\n type=\"button\"\n className=\"min-h-[44px] rounded-lg border border-border px-3 disabled:opacity-40\"\n disabled={page >= pageCount}\n onClick={() =>\n setPage((value) => Math.min(pageCount, value + 1))\n }\n >\n ›\n </button>\n </div>\n </div>\n )}\n </section>\n );\n}\n"],"names":["normalizePath","p","isListRoutePath","pathname","listPath","useRefetchOnRouteMatch","load","useLocation","loadRef","useRef","onList","useEffect","ROUTE_NEW_PLACEHOLDER","isRouteNewPlaceholder","id","isRouteEditMode","resolveDraftEntityId","trimmed","COMMON_CURRENCY_OPTIONS","displayNamesCache","getDisplayNames","locale","dn","currencyLabel","code","upper","parseEnabledCurrenciesJson","raw","x","normalizeEnabledCurrencies","codes","options","minOne","seen","out","DEFAULT_ENABLED_CURRENCIES","selectedApplicationLanguage","resolveBusinessLocale","language","formatBusinessTime","value","formatBusinessDate","date","formatBusinessDateTime","formatBusinessNumber","numericValue","formatBusinessCurrency","currency","readAccessToken","useGenispacePlatformClient","getApiRoot","shellRevision","setShellRevision","useState","onShellInit","n","GENISPACE_SHELL_INIT_APPLIED_EVENT","useMemo","token","baseURL","GeniSpace","setAppApplicationId","sessionStorageKey","applicationId","getAppApplicationId","hasAppPermission","required","isAppRbacRelaxed","canAccessNavItem","loading","permissionCodes","permission","accessError","canPerformAppAction","resolvePlatformApiRootFromShell","injected","GENISPACE_SHELL_SESSION_API_KEY","createAppAccessHook","useAppAccess","fetchAppAccess","root","headers","res","text","body","data","state","setState","reloadAccess","useCallback","prev","result","e","onApplied","AppAccessNotice","access","jsxs","jsx","AppContentSkeleton","variant","Fragment","_","index","row","__","column","AppAccessGate","children","showLoadingSkeleton","normalizePartnerId","partnerId","applyPartnerPayload","payload","pickerAvailable","pickerLoading","pickerLoadError","next","createResolveApiRoot","dedicated","platform","createScopeTableClient","buildApiRoot","readToken","authHeaders","tableUrl","scope","table","base","scopeGet","scopeList","filter","params","scopePatch","createUseManagedAppPicker","config","enabled","ensureIds","ensureKey","setPickerAvailable","setOptions","setLoading","loadError","setLoadError","reloadGeneration","reload","generation","apiRoot","available","opts","CrossAppRecordPicker","label","description","placeholder","emptyText","unavailableText","forbiddenText","selected","pageSize","disabled","providerState","loadPage","onSelect","useId","request","loadPageRef","search","setSearch","appliedSearch","setAppliedSearch","page","setPage","records","setRecords","total","setTotal","error","setError","current","reason","pageCount","stateMessage","event","record"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsxs as s, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
function x({ title: n, icon: l, description: m, leading: i, actions: a, children: c }) {
|
|
3
|
+
const t = /* @__PURE__ */ s("div", { className: "min-w-0", children: [
|
|
4
|
+
/* @__PURE__ */ s("h1", { className: "flex min-w-0 items-center gap-2 text-xl font-bold sm:text-2xl", children: [
|
|
5
|
+
l && /* @__PURE__ */ e(l, { className: "h-5 w-5 shrink-0 sm:h-6 sm:w-6" }),
|
|
6
|
+
/* @__PURE__ */ e("span", { className: "truncate", children: n })
|
|
7
|
+
] }),
|
|
8
|
+
m && /* @__PURE__ */ e("p", { className: "mt-1 hidden text-sm text-muted-foreground sm:block", children: m })
|
|
9
|
+
] });
|
|
10
|
+
return /* @__PURE__ */ s("div", { className: "relative w-full min-w-0 max-w-full px-4 py-4 sm:px-6 sm:py-6 lg:px-8", children: [
|
|
11
|
+
/* @__PURE__ */ s("div", { className: "mb-6 flex min-h-[52px] w-full min-w-0 flex-col items-stretch justify-between gap-3 sm:min-h-[60px] sm:flex-row sm:items-center sm:gap-4", children: [
|
|
12
|
+
i ? /* @__PURE__ */ s("div", { className: "flex min-w-0 flex-1 items-center gap-3 sm:gap-4", children: [
|
|
13
|
+
i,
|
|
14
|
+
t
|
|
15
|
+
] }) : /* @__PURE__ */ e("div", { className: "min-w-0 flex-1", children: t }),
|
|
16
|
+
a ? /* @__PURE__ */ e("div", { className: "flex w-full min-w-0 flex-wrap items-center justify-start gap-2 sm:w-auto sm:shrink-0 sm:justify-end sm:gap-3", children: a }) : null
|
|
17
|
+
] }),
|
|
18
|
+
/* @__PURE__ */ e("div", { className: "relative min-w-0 max-w-full", children: c })
|
|
19
|
+
] });
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
x as A
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=Page-wHZrMN17.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Page-wHZrMN17.js","sources":["../src/ui/components/features/app/Page.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { LucideIcon } from 'lucide-react';\n\nexport interface AppPageProps {\n title: string;\n icon?: LucideIcon;\n description?: string;\n /** Renders to the left of the title block (e.g. a back button). */\n leading?: ReactNode;\n /** Action buttons rendered top-right. */\n actions?: ReactNode;\n children: ReactNode;\n}\n\nexport function AppPage({ title, icon: Icon, description, leading, actions, children }: AppPageProps) {\n // The title/description block. On mobile the description is hidden — under a\n // narrow header it wraps to several lines and reads awkwardly; the title alone\n // is enough there. Title always truncates so actions keep their right slot.\n const titleBlock = (\n <div className=\"min-w-0\">\n <h1 className=\"flex min-w-0 items-center gap-2 text-xl font-bold sm:text-2xl\">\n {Icon && <Icon className=\"h-5 w-5 shrink-0 sm:h-6 sm:w-6\" />}\n <span className=\"truncate\">{title}</span>\n </h1>\n {description && (\n <p className=\"mt-1 hidden text-sm text-muted-foreground sm:block\">{description}</p>\n )}\n </div>\n );\n\n return (\n <div className=\"relative w-full min-w-0 max-w-full px-4 py-4 sm:px-6 sm:py-6 lg:px-8\">\n {/* Stack the actions below the title on narrow screens. Keeping every action\n in one row can shrink a long, translated title to zero width. */}\n <div className=\"mb-6 flex min-h-[52px] w-full min-w-0 flex-col items-stretch justify-between gap-3 sm:min-h-[60px] sm:flex-row sm:items-center sm:gap-4\">\n {leading ? (\n <div className=\"flex min-w-0 flex-1 items-center gap-3 sm:gap-4\">\n {leading}\n {titleBlock}\n </div>\n ) : (\n <div className=\"min-w-0 flex-1\">{titleBlock}</div>\n )}\n {actions ? (\n <div className=\"flex w-full min-w-0 flex-wrap items-center justify-start gap-2 sm:w-auto sm:shrink-0 sm:justify-end sm:gap-3\">\n {actions}\n </div>\n ) : null}\n </div>\n <div className=\"relative min-w-0 max-w-full\">\n {children}\n </div>\n </div>\n );\n}\n"],"names":["AppPage","title","Icon","description","leading","actions","children","titleBlock","jsxs","jsx"],"mappings":";AAcO,SAASA,EAAQ,EAAE,OAAAC,GAAO,MAAMC,GAAM,aAAAC,GAAa,SAAAC,GAAS,SAAAC,GAAS,UAAAC,KAA0B;AAIpG,QAAMC,IACJ,gBAAAC,EAAC,OAAA,EAAI,WAAU,WACb,UAAA;AAAA,IAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,iEACX,UAAA;AAAA,MAAAN,KAAQ,gBAAAO,EAACP,GAAA,EAAK,WAAU,iCAAA,CAAiC;AAAA,MAC1D,gBAAAO,EAAC,QAAA,EAAK,WAAU,YAAY,UAAAR,EAAA,CAAM;AAAA,IAAA,GACpC;AAAA,IACCE,KACC,gBAAAM,EAAC,KAAA,EAAE,WAAU,sDAAsD,UAAAN,EAAA,CAAY;AAAA,EAAA,GAEnF;AAGF,SACE,gBAAAK,EAAC,OAAA,EAAI,WAAU,wEAGb,UAAA;AAAA,IAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,2IACZ,UAAA;AAAA,MAAAJ,IACC,gBAAAI,EAAC,OAAA,EAAI,WAAU,mDACZ,UAAA;AAAA,QAAAJ;AAAA,QACAG;AAAA,MAAA,GACH,IAEA,gBAAAE,EAAC,OAAA,EAAI,WAAU,kBAAkB,UAAAF,GAAW;AAAA,MAE7CF,IACC,gBAAAI,EAAC,OAAA,EAAI,WAAU,gHACZ,aACH,IACE;AAAA,IAAA,GACN;AAAA,IACA,gBAAAA,EAAC,OAAA,EAAI,WAAU,+BACZ,UAAAH,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AdoptFieldConfig, AppTableClient } from '../types';
|
|
2
|
+
|
|
3
|
+
export interface AiSuggestionPanelProps {
|
|
4
|
+
recordId: string | undefined;
|
|
5
|
+
resultsTable: string;
|
|
6
|
+
businessTable: string;
|
|
7
|
+
client: AppTableClient;
|
|
8
|
+
fields: AdoptFieldConfig[];
|
|
9
|
+
sourceRecordKey?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
onAdopted?: (patch: Record<string, unknown>) => void;
|
|
13
|
+
lang?: 'zh' | 'en';
|
|
14
|
+
owners: readonly string[];
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
emptyTitle?: string;
|
|
18
|
+
emptyDescription?: string;
|
|
19
|
+
applyLabel?: string;
|
|
20
|
+
applyAllLabel?: string;
|
|
21
|
+
successMessage?: string;
|
|
22
|
+
allowEditing?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function AiSuggestionPanel({ recordId, resultsTable, businessTable, client, fields, sourceRecordKey, disabled, className, onAdopted, lang, owners, title, description, emptyTitle, emptyDescription, applyLabel, applyAllLabel, successMessage, allowEditing, }: AiSuggestionPanelProps): import("react").JSX.Element | null;
|
|
25
|
+
/** Common field mappers for product description agent output */
|
|
26
|
+
export declare const productDescriptionAdoptFields: (labels: {
|
|
27
|
+
description: string;
|
|
28
|
+
descriptionSale: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
}) => AdoptFieldConfig[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AppTableClient, WorkflowResultRow } from '../types';
|
|
3
|
+
|
|
4
|
+
interface BusinessGuidancePanelBaseProps {
|
|
5
|
+
client: AppTableClient;
|
|
6
|
+
resultsTable: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
emptyTitle: string;
|
|
10
|
+
emptyDescription: string;
|
|
11
|
+
unreadableText?: string;
|
|
12
|
+
owners: readonly string[];
|
|
13
|
+
limit?: number;
|
|
14
|
+
className?: string;
|
|
15
|
+
footer?: ReactNode;
|
|
16
|
+
renderAction?: (row: WorkflowResultRow) => ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export type BusinessGuidancePanelProps = BusinessGuidancePanelBaseProps & ({
|
|
19
|
+
scope: 'aggregate';
|
|
20
|
+
sourceRecordKey?: never;
|
|
21
|
+
} | {
|
|
22
|
+
scope?: 'record';
|
|
23
|
+
sourceRecordKey: string;
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* A business-page feed for useful recommendations. It deliberately hides run
|
|
27
|
+
* identifiers, model payloads and raw JSON; those remain available to platform
|
|
28
|
+
* diagnostics without becoming part of the user's daily navigation.
|
|
29
|
+
*/
|
|
30
|
+
export declare function BusinessGuidancePanel({ client, resultsTable, title, description, emptyTitle, emptyDescription, unreadableText, sourceRecordKey, owners, limit, className, footer, renderAction, }: BusinessGuidancePanelProps): import("react").JSX.Element;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AdoptFieldConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
export declare function genericSummaryField(label: string, targetField: string): AdoptFieldConfig;
|
|
4
|
+
export declare function narrationAdoptField(label: string): AdoptFieldConfig;
|
|
5
|
+
export declare function recommendationAdoptField(label: string, targetField?: string): AdoptFieldConfig;
|
|
6
|
+
export declare function synopsisAdoptField(label: string, targetField?: string): AdoptFieldConfig;
|
|
7
|
+
export declare function noteAdoptField(label: string, targetField?: string): AdoptFieldConfig;
|
|
8
|
+
export declare function internalNotesAdoptField(label: string): AdoptFieldConfig;
|
|
9
|
+
export declare function jobTitleAdoptField(label: string): AdoptFieldConfig;
|
|
10
|
+
export declare function descriptionAdoptField(label: string, targetField?: string): AdoptFieldConfig;
|
|
11
|
+
export declare function appendTextAdoptField(label: string, summaryPath: string, targetField: string, currentValue: string | null | undefined): AdoptFieldConfig;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { WorkflowResultRow } from '../types';
|
|
2
|
+
|
|
3
|
+
export type GuidanceLanguage = 'en' | 'zh';
|
|
4
|
+
export interface GuidanceContent {
|
|
5
|
+
summary: string;
|
|
6
|
+
details: string[];
|
|
7
|
+
sources: string[];
|
|
8
|
+
confidence: number | null;
|
|
9
|
+
}
|
|
10
|
+
export interface ContextualWorkflowSelection {
|
|
11
|
+
sourceRecordKey?: string;
|
|
12
|
+
owners: readonly string[];
|
|
13
|
+
limit: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extract only business-readable copy from a workflow result. Unknown objects
|
|
17
|
+
* intentionally return null: raw JSON belongs in platform diagnostics, not in
|
|
18
|
+
* a business application.
|
|
19
|
+
*/
|
|
20
|
+
export declare function guidanceContentFromSummary(rawSummary: string | null | undefined, language: GuidanceLanguage): GuidanceContent | null;
|
|
21
|
+
export declare function guidanceStatus(status: WorkflowResultRow['status']): 'ready' | 'applied' | 'dismissed' | 'attention';
|
|
22
|
+
/**
|
|
23
|
+
* Enforce the business context again after a datasource response. Some legacy
|
|
24
|
+
* adapters ignore filters, so a server response is never trusted to isolate a
|
|
25
|
+
* record or an Agent/workflow owner on its own.
|
|
26
|
+
*/
|
|
27
|
+
export declare function selectContextualWorkflowResults(rows: readonly WorkflowResultRow[], { sourceRecordKey, owners, limit }: ContextualWorkflowSelection): WorkflowResultRow[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Parse workflow_results.summary (JSON string or plain text). */
|
|
2
|
+
export declare function parseAiSummary(summary: string | null | undefined): Record<string, unknown> | null;
|
|
3
|
+
export declare function getByPath(obj: unknown, path: string): unknown;
|
|
4
|
+
/** Prefer the active language; English is the platform default. */
|
|
5
|
+
export declare function localizedText(value: unknown, lang?: 'zh' | 'en'): string;
|
|
6
|
+
/** Convert structured values into readable lines without exposing raw JSON. */
|
|
7
|
+
export declare function formatDisplayValue(value: unknown, lang?: 'zh' | 'en'): string;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async agent-invoke progress UX v1.
|
|
3
|
+
*
|
|
4
|
+
* `useAgentJobRunner` drives a background AGENT_INVOKE job (SDK
|
|
5
|
+
* `agents.invokeAsync`) through an explicit state machine and exposes a live
|
|
6
|
+
* elapsed ticker + server phase; `AgentJobProgressInline` renders it as a
|
|
7
|
+
* rounded card in the same visual family as AiDraftBanner. Both are
|
|
8
|
+
* i18n-agnostic — every user-facing string comes in via label props with
|
|
9
|
+
* sensible English defaults; apps pass t() values.
|
|
10
|
+
*/
|
|
11
|
+
export type AgentRunState = 'idle' | 'starting' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
12
|
+
/** Structural subset of the SDK AgentJob DTO the runner needs. */
|
|
13
|
+
export interface AgentJobLike {
|
|
14
|
+
id: string;
|
|
15
|
+
status?: string;
|
|
16
|
+
phase?: string | null;
|
|
17
|
+
cancelRequested?: boolean;
|
|
18
|
+
createdAt?: string;
|
|
19
|
+
error?: string | null;
|
|
20
|
+
}
|
|
21
|
+
/** Context handed to the task function passed to {@link UseAgentJobRunnerResult.start}. */
|
|
22
|
+
export interface AgentTaskContext {
|
|
23
|
+
/** Thread as BOTH `onCreated` and `onProgress` of `agents.invokeAsync`. */
|
|
24
|
+
onJob: (job: AgentJobLike) => void;
|
|
25
|
+
/** Report an app-level retry (e.g. schema-invalid re-invoke): call with 2, 3, ... */
|
|
26
|
+
onAttempt: (n: number) => void;
|
|
27
|
+
/** Thread as `invokeAsync({ signal })`; aborted automatically on unmount. */
|
|
28
|
+
signal: AbortSignal;
|
|
29
|
+
}
|
|
30
|
+
export interface AgentJobStartOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Cooperative server-side cancel, e.g. `(id) => client.agentJobs.cancel(id)`.
|
|
33
|
+
* Called by {@link UseAgentJobRunnerResult.cancel} once a job id is known;
|
|
34
|
+
* without it (or before a job exists) cancel falls back to aborting the
|
|
35
|
+
* polling signal locally.
|
|
36
|
+
*/
|
|
37
|
+
cancel?: (jobId: string) => Promise<unknown> | unknown;
|
|
38
|
+
}
|
|
39
|
+
export interface UseAgentJobRunnerResult {
|
|
40
|
+
state: AgentRunState;
|
|
41
|
+
/** Latest server phase ('resolve' | 'invoke' | 'finalize' | ...), null before the first snapshot. */
|
|
42
|
+
phase: string | null;
|
|
43
|
+
/** Wall-clock since job.createdAt (when parseable) or the local start; ticks every second. */
|
|
44
|
+
elapsedMs: number;
|
|
45
|
+
/** Latest observed job snapshot (null until the 202 create lands). */
|
|
46
|
+
job: AgentJobLike | null;
|
|
47
|
+
/** Raw error message of a failed run (apps usually map their typed errors instead). */
|
|
48
|
+
error: string | null;
|
|
49
|
+
/** Current attempt number (1-based); >1 after noteAttempt/onAttempt. */
|
|
50
|
+
attempt: number;
|
|
51
|
+
/** True once cancel() was called or the server echoed job.cancelRequested. */
|
|
52
|
+
cancelRequested: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Run `task`. Resolves with the task result on success, resolves `null` when
|
|
55
|
+
* the run was cancelled/superseded, and REJECTS with the task's error on
|
|
56
|
+
* failure (after moving the state machine to 'failed') so callers keep their
|
|
57
|
+
* typed-error handling. No-op (resolves null) while a run is in flight.
|
|
58
|
+
*/
|
|
59
|
+
start: <T>(task: (ctx: AgentTaskContext) => Promise<T>, opts?: AgentJobStartOptions) => Promise<T | null>;
|
|
60
|
+
/** Request cooperative cancellation of the in-flight run. */
|
|
61
|
+
cancel: () => void;
|
|
62
|
+
/** Back to 'idle', invalidating any in-flight run (its late updates are dropped). */
|
|
63
|
+
reset: () => void;
|
|
64
|
+
/** Feed a job snapshot into the runner (what the task ctx.onJob does). */
|
|
65
|
+
observe: (job: AgentJobLike) => void;
|
|
66
|
+
/** Mark an app-level retry attempt (what the task ctx.onAttempt does). */
|
|
67
|
+
noteAttempt: (n: number) => void;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* State machine + 1s elapsed ticker for one background agent invoke at a time.
|
|
71
|
+
* Stale updates from a superseded run are dropped via a monotonic run-id guard
|
|
72
|
+
* (mirrors JobProgress.tsx); the AbortController wired into the task signal is
|
|
73
|
+
* aborted on unmount so polling never outlives the component — the job itself
|
|
74
|
+
* keeps running server-side unless cancel() reached the platform.
|
|
75
|
+
*/
|
|
76
|
+
export declare function useAgentJobRunner(): UseAgentJobRunnerResult;
|
|
77
|
+
export interface AgentJobProgressLabels {
|
|
78
|
+
/** Primary action line, e.g. "AI is generating the draft". */
|
|
79
|
+
title?: string;
|
|
80
|
+
/** "Elapsed Xs" fragment appended to the title. */
|
|
81
|
+
elapsed?: (seconds: number) => string;
|
|
82
|
+
/** Expected-duration fragment after the elapsed one, e.g. " (usually ~30s)". */
|
|
83
|
+
expectedNote?: string;
|
|
84
|
+
/** Swapped in for expectedNote once elapsed exceeds 1.5x expectedSeconds. */
|
|
85
|
+
slow?: string;
|
|
86
|
+
/** Step-list labels (server phases queued -> resolve -> invoke -> finalize). */
|
|
87
|
+
queued?: string;
|
|
88
|
+
resolve?: string;
|
|
89
|
+
invoke?: string;
|
|
90
|
+
finalize?: string;
|
|
91
|
+
/** Notice line shown when attempt > 1 (app-level schema retry). */
|
|
92
|
+
retryNotice?: string;
|
|
93
|
+
cancel?: string;
|
|
94
|
+
cancelling?: string;
|
|
95
|
+
/** Fallback failed line when no `error` prop is passed. */
|
|
96
|
+
failed?: string;
|
|
97
|
+
retry?: string;
|
|
98
|
+
cancelled?: string;
|
|
99
|
+
}
|
|
100
|
+
export interface AgentJobProgressInlineProps {
|
|
101
|
+
state: AgentRunState;
|
|
102
|
+
phase?: string | null;
|
|
103
|
+
elapsedMs: number;
|
|
104
|
+
/** Typical duration; drives the slow-hint swap (elapsed > 1.5x expected). */
|
|
105
|
+
expectedSeconds?: number;
|
|
106
|
+
/** 1-based attempt count; >1 renders the retry notice line. */
|
|
107
|
+
attempt?: number;
|
|
108
|
+
/** True once cancellation was requested (button flips to a disabled "cancelling"). */
|
|
109
|
+
cancelRequested?: boolean;
|
|
110
|
+
/** Localized error text supplied by the app for the failed state. */
|
|
111
|
+
error?: string | null;
|
|
112
|
+
onCancel?: () => void;
|
|
113
|
+
onRetry?: () => void;
|
|
114
|
+
labels?: AgentJobProgressLabels;
|
|
115
|
+
className?: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Inline progress card for a background agent invoke — spinner + elapsed
|
|
119
|
+
* primary line, queued→resolve→invoke→finalize step list, indeterminate pulse
|
|
120
|
+
* bar and a cooperative cancel button while running; destructive line + retry
|
|
121
|
+
* when failed; muted line + retry when cancelled; nothing when idle/succeeded.
|
|
122
|
+
* Same visual family as AiDraftBanner (status-info tokens while running).
|
|
123
|
+
*/
|
|
124
|
+
export declare function AgentJobProgressInline({ state, phase, elapsedMs, expectedSeconds, attempt, cancelRequested, error, onCancel, onRetry, labels, className, }: AgentJobProgressInlineProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface AsyncOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
/** Optional secondary text (e.g. store of an associate). */
|
|
5
|
+
hint?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AsyncComboboxLabels {
|
|
8
|
+
/** Shown on the trigger when nothing is selected. */
|
|
9
|
+
placeholder: string;
|
|
10
|
+
searchPlaceholder: string;
|
|
11
|
+
empty: string;
|
|
12
|
+
loadMore: string;
|
|
13
|
+
clear: string;
|
|
14
|
+
}
|
|
15
|
+
export interface AsyncComboboxProps {
|
|
16
|
+
value: string | null;
|
|
17
|
+
onChange: (value: string | null) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Server-side search. Return up to `limit` options for the page; the combobox
|
|
20
|
+
* requests `pageSize + 1` to detect "has more" without a COUNT.
|
|
21
|
+
*/
|
|
22
|
+
loadOptions: (args: {
|
|
23
|
+
search: string;
|
|
24
|
+
limit: number;
|
|
25
|
+
offset: number;
|
|
26
|
+
}) => Promise<AsyncOption[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the label for the current `value` when it isn't in the loaded page
|
|
29
|
+
* (e.g. a preselected id). Optional — falls back to showing the raw value.
|
|
30
|
+
*/
|
|
31
|
+
resolveSelected?: (value: string) => Promise<AsyncOption | null>;
|
|
32
|
+
labels: AsyncComboboxLabels;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
allowClear?: boolean;
|
|
35
|
+
pageSize?: number;
|
|
36
|
+
triggerClassName?: string;
|
|
37
|
+
contentClassName?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Searchable, paginated single-select bound to a server datasource. Replaces
|
|
41
|
+
* "load-all + client filter" dropdowns; safe for very large option sets because
|
|
42
|
+
* it only ever fetches one debounced page at a time. i18n-agnostic (labels in).
|
|
43
|
+
*/
|
|
44
|
+
export declare function AsyncCombobox({ value, onChange, loadOptions, resolveSelected, labels, disabled, allowClear, pageSize, triggerClassName, contentClassName, }: AsyncComboboxProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ButtonProps } from '../../kit';
|
|
3
|
+
|
|
4
|
+
/** One action button rendered in a {@link BulkActionBar}. */
|
|
5
|
+
export interface BulkAction {
|
|
6
|
+
/** Stable id (used for React keys). */
|
|
7
|
+
key: string;
|
|
8
|
+
/** Button content (already localized by the caller). */
|
|
9
|
+
label: ReactNode;
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
/** Button visual variant; forwarded to the kit `Button`. */
|
|
12
|
+
variant?: ButtonProps['variant'];
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface BulkActionBarLabels {
|
|
16
|
+
/** Localized "N selected" label; receives the current selected count. */
|
|
17
|
+
selected: (n: number) => string;
|
|
18
|
+
/** Localized "select all M matching" affordance; receives the total match count. */
|
|
19
|
+
selectAllMatching?: (m: number) => string;
|
|
20
|
+
/** Localized "clear selection" label. */
|
|
21
|
+
clear: string;
|
|
22
|
+
}
|
|
23
|
+
export interface BulkActionBarProps {
|
|
24
|
+
/** Number of currently selected rows. */
|
|
25
|
+
selectedCount: number;
|
|
26
|
+
/** Total rows matching the active filter (across all pages), if known. */
|
|
27
|
+
totalMatching?: number;
|
|
28
|
+
/** Whether every matching row (not just the visible page) is already selected. */
|
|
29
|
+
allMatchingSelected?: boolean;
|
|
30
|
+
/** Promote the current page selection to "all M matching". */
|
|
31
|
+
onSelectAllMatching?: () => void;
|
|
32
|
+
/** Clear the entire selection. */
|
|
33
|
+
onClear: () => void;
|
|
34
|
+
actions: BulkAction[];
|
|
35
|
+
labels: BulkActionBarLabels;
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Sticky toolbar surfaced when rows are selected. Shows the selected count, an
|
|
40
|
+
* optional "select all M matching" affordance (for selecting beyond the visible
|
|
41
|
+
* page), the caller's bulk actions, and a clear control. Renders nothing when the
|
|
42
|
+
* selection is empty. i18n-agnostic — all text comes from `labels`/`actions`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function BulkActionBar({ selectedCount, totalMatching, allMatchingSelected, onSelectAllMatching, onClear, actions, labels, className, }: BulkActionBarProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves opaque entity ids (e.g. `cust_123`) to human-readable names in batch,
|
|
5
|
+
* with an internal cache so a given id is fetched at most once. Pair it with
|
|
6
|
+
* {@link EntityRef} to render references as "name" instead of raw ids.
|
|
7
|
+
*
|
|
8
|
+
* The `resolver` receives the de-duplicated set of ids that aren't cached yet and
|
|
9
|
+
* returns a `{ id: name }` map; ids missing from the map are remembered as
|
|
10
|
+
* "resolved to nothing" so they aren't retried on every render.
|
|
11
|
+
*/
|
|
12
|
+
export interface UseEntityNamesResult {
|
|
13
|
+
/** Cached display name for `id`, or `undefined` until resolved (or if unknown). */
|
|
14
|
+
resolve: (id: string) => string | undefined;
|
|
15
|
+
/** Queue ids for resolution; already-cached/in-flight ids are skipped. */
|
|
16
|
+
ensure: (ids: ReadonlyArray<string>) => void;
|
|
17
|
+
/** True while at least one batch is in flight. */
|
|
18
|
+
loading: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function useEntityNames(resolver: (ids: string[]) => Promise<Record<string, string>>): UseEntityNamesResult;
|
|
21
|
+
export interface EntityRefProps {
|
|
22
|
+
/** The raw entity id being referenced. */
|
|
23
|
+
value: string;
|
|
24
|
+
/** Resolved display name; when undefined the ref renders a muted `value`. */
|
|
25
|
+
name?: string;
|
|
26
|
+
/** Render as a link to this href (takes precedence over `onClick`). */
|
|
27
|
+
href?: string;
|
|
28
|
+
/** Render as a button invoking this handler when there is no `href`. */
|
|
29
|
+
onClick?: () => void;
|
|
30
|
+
/** Shown when `name` is undefined, before falling back to `value`. */
|
|
31
|
+
fallback?: ReactNode;
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Renders an entity reference as its display name (with an optional link/button),
|
|
36
|
+
* falling back to a muted raw id while the name is unresolved. i18n-agnostic:
|
|
37
|
+
* the caller supplies `name`/`fallback`; only layout symbols are hardcoded.
|
|
38
|
+
*/
|
|
39
|
+
export declare function EntityRef({ value, name, href, onClick, fallback, className }: EntityRefProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type JobStatus = 'idle' | 'running' | 'done' | 'error';
|
|
2
|
+
/** Progress snapshot reported by a running job. */
|
|
3
|
+
export interface JobProgressState {
|
|
4
|
+
done: number;
|
|
5
|
+
total: number;
|
|
6
|
+
message?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Terminal outcome of a job's `run` function. */
|
|
9
|
+
export interface JobResult {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
/** Number of items that failed (for partial-success jobs). */
|
|
12
|
+
failed?: number;
|
|
13
|
+
/** Human-readable error (already localized by the caller, if any). */
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
/** A job runner: invoked with a `report` callback to push progress updates. */
|
|
17
|
+
export type JobRunner = (report: (progress: JobProgressState) => void) => Promise<JobResult>;
|
|
18
|
+
export interface UseAsyncJobResult {
|
|
19
|
+
status: JobStatus;
|
|
20
|
+
progress: JobProgressState;
|
|
21
|
+
result: JobResult | null;
|
|
22
|
+
/** Begin (or restart) the job. No-op while already running. */
|
|
23
|
+
start: () => void;
|
|
24
|
+
/** Return to the idle state, clearing progress and result. */
|
|
25
|
+
reset: () => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Drives a long-running, optionally batched async job: calls `run`, threading a
|
|
29
|
+
* `report` callback that updates the live progress, and captures the terminal
|
|
30
|
+
* result or a thrown error. Stale reports/results from a superseded run (e.g.
|
|
31
|
+
* after a retry) are ignored via a monotonic run-id guard.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useAsyncJob({ run }: {
|
|
34
|
+
run: JobRunner;
|
|
35
|
+
}): UseAsyncJobResult;
|
|
36
|
+
export interface JobProgressLabels {
|
|
37
|
+
/** Optional text shown in the idle state (before the job starts). */
|
|
38
|
+
idle?: string;
|
|
39
|
+
/** Localized "X of Y" running label; receives done and total counts. */
|
|
40
|
+
running: (done: number, total: number) => string;
|
|
41
|
+
/** Text shown when the job completes successfully. */
|
|
42
|
+
done: string;
|
|
43
|
+
/** Text shown when the job fails. */
|
|
44
|
+
error: string;
|
|
45
|
+
/** Retry button label. */
|
|
46
|
+
retry: string;
|
|
47
|
+
}
|
|
48
|
+
export interface JobProgressProps {
|
|
49
|
+
/** The return value of {@link useAsyncJob}. */
|
|
50
|
+
job: UseAsyncJobResult;
|
|
51
|
+
labels: JobProgressLabels;
|
|
52
|
+
/**
|
|
53
|
+
* Invoked when the retry button is pressed. Defaults to `job.start`, so a plain
|
|
54
|
+
* retry re-runs the same job; pass a custom handler to retry only failures.
|
|
55
|
+
*/
|
|
56
|
+
onRetry?: () => void;
|
|
57
|
+
className?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Displays the state of a {@link useAsyncJob}: a progress bar while running, a
|
|
61
|
+
* status line, and a retry button on error. i18n-agnostic — every string is
|
|
62
|
+
* supplied via `labels`; only the bar and layout are hardcoded.
|
|
63
|
+
*/
|
|
64
|
+
export declare function JobProgress({ job, labels, onRetry, className }: JobProgressProps): import("react").JSX.Element;
|