import React from 'react'; import { IconType } from 'react-icons'; import { DragDropConfig } from '../../components/UiComponents/DragDropOverlay/DragDropOverlay'; // Generic privilege checker function type export type PrivilegeChecker = () => boolean | Promise; // Form field configuration for create/edit buttons export interface ButtonFormField { key: string; label: string | LanguageText; type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly' | 'multiselect' | 'number'; required?: boolean; placeholder?: string | LanguageText; minRows?: number; maxRows?: number; validator?: (value: any) => string | null; defaultValue?: any; options?: string[] | Array<{ value: string | number; label: string }>; // For enum/multiselect fields optionsReference?: string; // Reference to a data source for dynamic options (e.g., 'TrusteeOrganisation', 'User') } // Dropdown configuration for header dropdown buttons export interface DropdownConfig { type: 'dropdown'; items: Array<{ id: string | number; label: string | LanguageText; value: T; metadata?: Record; }>; selectedItemId?: string | number | null; onSelect: (item: { id: string | number; label: string | LanguageText; value: T; metadata?: Record } | null, hookData?: any) => void | Promise; placeholder?: string | LanguageText; emptyMessage?: string | LanguageText; headerText?: string | LanguageText; // Optional: name of property in hookData that provides items, selectedItemId, and onSelect dataSource?: { itemsProperty?: string; // Property name in hookData that contains items array selectedIdProperty?: string; // Property name in hookData that contains selectedItemId onSelectMethod?: string; // Method name in hookData for onSelect callback loadingProperty?: string; // Property name in hookData that contains loading state }; } // Button configuration for header actions export interface PageButton { id: string; label: string | LanguageText; variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'warning'; size?: 'sm' | 'md' | 'lg'; icon?: IconType; onClick?: (hookData?: any) => void | Promise; disabled?: boolean | ((hookData?: any) => boolean | { disabled: boolean; message?: string }); // Form configuration for create buttons formConfig?: { fields: ButtonFormField[]; popupTitle?: string | LanguageText; popupSize?: 'small' | 'medium' | 'large'; createOperationName?: string; // Name of the create operation in hookData (e.g., 'handlePromptCreate') successMessage?: string | LanguageText; errorMessage?: string | LanguageText; multiStep?: boolean; // Enable multi-step form mode }; // Dropdown configuration for dropdown selection buttons dropdownConfig?: DropdownConfig; } // Input form configuration export interface InputFormConfig { hookFactory?: () => () => GenericDataHook; // Optional, can use page-level hook from tableConfig if exists placeholder?: string | LanguageText; buttonLabel?: string | LanguageText; stopButtonLabel?: string | LanguageText; // Label for stop button when workflow is running buttonIcon?: IconType; stopButtonIcon?: IconType; // Icon for stop button when workflow is running buttonVariant?: 'primary' | 'secondary' | 'danger' | 'success' | 'warning'; stopButtonVariant?: 'primary' | 'secondary' | 'danger' | 'success' | 'warning'; // Variant for stop button buttonSize?: 'sm' | 'md' | 'lg'; textFieldSize?: 'sm' | 'md' | 'lg'; showFileUpload?: boolean; // Whether to show file upload button (default: true if hook provides file upload) } // Settings field configuration export interface SettingsFieldConfig { id: string; type: 'text' | 'select' | 'toggle'; label: string | LanguageText; description?: string | LanguageText; required?: boolean; disabled?: boolean | ((data: any) => boolean); inputType?: 'text' | 'email' | 'tel'; placeholder?: string | LanguageText; options?: Array<{id: string | number; label: string | LanguageText; value: any}>; dataKey: string; // Dot-notation path (e.g., "mandate_general.company_name") onSave?: (value: any, data: any) => Promise | void; } // Settings section configuration export interface SettingsSectionConfig { id: string; title: string | LanguageText; description?: string | LanguageText; icon?: IconType; // Optional icon for section header // Fields will be loaded from backend based on sectionId sectionId: string; // Identifier sent to backend to fetch fields // Save handler per section (uses Button component) onSave?: (sectionId: string, data: any) => Promise; saveButtonLabel?: string | LanguageText; saveButtonVariant?: 'primary' | 'secondary' | 'danger' | 'success' | 'warning'; saveButtonSize?: 'sm' | 'md' | 'lg'; // Optional: Static field overrides from config (takes precedence over backend) staticFields?: SettingsFieldConfig[]; // Optional: Conditional rendering - if provided, section only renders if condition returns true renderCondition?: (formData: any) => boolean; // Optional: Alternative content to render when renderCondition returns false renderAlternative?: (formData: any, t: (key: string) => string, resolveLanguageText: (text: string | LanguageText, t: (key: string) => string) => string) => React.ReactNode; } // Settings configuration export interface SettingsConfig { sections: SettingsSectionConfig[]; hookFactory?: () => () => GenericDataHook; // For data fetching and field loading } // Content section for paragraphs export interface PageContent { id: string; type: 'paragraph' | 'heading' | 'list' | 'code' | 'divider' | 'custom' | 'table' | 'inputForm' | 'messages' | 'settings' | 'log' | 'tabs' | 'columns' | 'chatHistory'; content?: string | LanguageText; // Optional for dividers level?: number; // For headings (1-6) items?: (string | LanguageText)[]; // For lists language?: string; // For code blocks customComponent?: React.ComponentType; // Table-specific properties tableConfig?: TableContentConfig; // Input form-specific properties inputFormConfig?: InputFormConfig; // Messages-specific properties messagesConfig?: { variant?: 'chat' | 'log'; // Message display variant: 'chat' for bubble UI, 'log' for list/table UI dataSource?: 'messages' | 'logs' | 'both'; // Data source to render: 'messages' (default), 'logs', or 'both' (logs use log variant when merged) showDocuments?: boolean; showMetadata?: boolean; showProgress?: boolean; emptyMessage?: string | LanguageText; }; // Settings-specific properties settingsConfig?: SettingsConfig; // Log-specific properties logConfig?: { emptyMessage?: string | LanguageText; }; // Chat history-specific properties chatHistoryConfig?: { emptyMessage?: string | LanguageText; }; // Tabs-specific properties tabsConfig?: { tabs: Array<{ id: string; label: string | LanguageText; content: PageContent[]; // Nested content sections for each tab }>; defaultTabId?: string; }; // Columns-specific properties columnsConfig?: { columns: Array<{ id: string; width?: string; // CSS width (e.g., "3fr", "1fr", "75%", "25%") content: PageContent[]; // Nested content sections for each column }>; gap?: string; // CSS gap value }; } // Generic hook interface for data fetching export interface GenericDataHook { data: any[]; loading: boolean; isRefetching?: boolean; // True when refetching data (keeps existing data visible) error: string | null; refetch?: (params?: { page?: number; pageSize?: number; sort?: Array<{field: string; direction: 'asc' | 'desc'}>; filters?: any; search?: string }) => Promise; pagination?: { currentPage: number; pageSize: number; totalItems: number; totalPages: number; sort?: Array<{ field: string; direction: 'asc' | 'desc' }>; filters?: any; } | null; removeFileOptimistically?: (fileId: string) => void; // For optimistic updates columns?: any[]; // Optional columns configuration // File operations handleUpload?: (file: File) => Promise<{ success: boolean; data: any }>; // For file upload functionality handleFileUpload?: (file: File) => Promise<{ success: boolean; data: any }>; // Alias for handleUpload handleDownload?: (fileId: string, fileName: string) => Promise; // For file download functionality handleDelete?: (fileId: string, onOptimisticDelete?: () => void) => Promise; // For file delete functionality handleFileDelete?: ((fileId: string, onOptimisticDelete?: () => void) => Promise) | ((file: any) => Promise); // Can accept fileId or WorkflowFile handlePreview?: (fileId: string, fileName: string, mimeType?: string) => Promise; // For file preview functionality // File management properties workflowFiles?: any[]; // Files connected to workflow pendingFiles?: any[]; // Files pending attachment allUserFiles?: any[]; // All user files handleFileRemove?: ((fileId: string) => Promise | void) | ((file: any) => Promise | void); // Can accept fileId or WorkflowFile handleFileAttach?: (fileId: string) => Promise; // Attach file to workflow (always returns Promise) handleFileUploadAndAttach?: (file: File) => Promise<{ success: boolean; data: any }>; // Upload and attach file uploadingFile?: boolean; // Loading state for file upload deletingFiles?: Set; // Set of file IDs being deleted previewingFiles?: Set; // Set of file IDs being previewed removingFiles?: Set; // Set of file IDs being removed isFileAttachmentPopupOpen?: boolean; // Whether file attachment popup is open setIsFileAttachmentPopupOpen?: (open: boolean) => void; // Set file attachment popup state // FormGenerator specific handlers onDelete?: (row: any) => Promise; // For single item deletion onDeleteMultiple?: (rows: any[]) => Promise; // For multiple item deletion // Input form operations inputValue?: string; onInputChange?: (value: string) => void; handleSubmit?: () => Promise; // No parameters, uses internal inputValue isSubmitting?: boolean; // Prompt selector properties promptPermission?: { view?: boolean; read?: string; }; promptItems?: Array<{ id: string | number; label: string; value: any }>; selectedPromptId?: string | number | null; onPromptSelect?: (item: { id: string | number; label: string; value: any } | null) => void | Promise; promptsLoading?: boolean; // Workflow mode selector properties workflowModeItems?: Array<{ id: string | number; label: string; value: any }>; selectedWorkflowMode?: string | number | null; onWorkflowModeSelect?: (item: { id: string | number; label: string; value: any } | null) => void | Promise; // Workflow lifecycle state workflowId?: string; workflowStatus?: string; workflowData?: { currentRound?: number; [key: string]: any; }; isRunning?: boolean; currentRound?: number; // Current workflow round latestStats?: any; // Latest workflow statistics // Messages from workflow messages?: any[]; // Logs from workflow logs?: any[]; // Dashboard log tree dashboardTree?: any; // Dashboard log tree structure onToggleOperationExpanded?: (operationId: string) => void; getChildOperations?: (parentId: string | null) => string[]; // Settings-specific properties settingsData?: any; // Unified data object for settings fields settingsFields?: Record; // Field definitions per sectionId settingsLoading?: Record; // Loading state per section settingsErrors?: Record; // Error state per section saveSection?: (sectionId: string, data: any) => Promise; // Save handler for a section // Dropdown data source loading property [key: string]: any; // Allow additional properties for dynamic data sources } // Standard action button configuration (built-in actions: edit, delete, view, copy, connect, play) export interface ActionButtonConfig { type: 'view' | 'edit' | 'delete' | 'copy' | 'connect' | 'play'; onAction?: (row: any) => Promise | void; // Optional for delete buttons since they handle their own logic title?: string | LanguageText; disabled?: (row: any, hookData?: any) => boolean | { disabled: boolean; message?: string }; loading?: (row: any, hookData?: any) => boolean; // Field mappings for flexible data access idField?: string; // Field name for the unique identifier (default: 'id') nameField?: string; // Field name for display name (default: 'name' or 'file_name') typeField?: string; // Field name for type/mime type (default: 'type' or 'mime_type') contentField?: string; // Field name for content (default: 'content') statusField?: string; // Field name for status (used by connect action) // Operation and loading state names operationName?: string; // Name of the operation function in hookData loadingStateName?: string; // Name of the loading state in hookData fetchItemFunctionName?: string; // Name of the function in hookData to fetch a single item by ID (for edit button) // Navigation and mode (for play action) navigateTo?: string; // Path to navigate to after action mode?: string; // Mode to set (e.g., 'prompt', 'workflow') } // Custom action button configuration (for entity-specific actions like download, connect, play, sendPasswordLink) export interface CustomActionConfig { id: string; // Unique identifier for the action icon: React.ReactNode; // Icon component to display onClick: (row: any, hookData?: any) => Promise | void; // Handler function visible?: (row: any, hookData?: any) => boolean; // Show/hide based on row data (default: true) disabled?: (row: any, hookData?: any) => boolean | { disabled: boolean; message?: string }; // Disable based on row data loading?: (row: any, hookData?: any) => boolean; // Loading state based on row data title?: string | LanguageText | ((row: any) => string); // Tooltip text className?: string; // Optional custom CSS class // Field mappings (optional, for convenience) idField?: string; // Field name for the unique identifier (default: 'id') } // Table content configuration export interface TableContentConfig { hookFactory: () => () => GenericDataHook; // Hook factory that returns a hook function columns?: any[]; // Column configuration (optional - can be generated dynamically from attributes via hookData.columns) actionButtons?: ActionButtonConfig[]; // Standard action buttons configuration (edit, delete, view, copy) customActions?: CustomActionConfig[]; // Custom action buttons (download, connect, play, sendPasswordLink, etc.) searchable?: boolean; filterable?: boolean; sortable?: boolean; resizable?: boolean; pagination?: boolean; pageSize?: number; className?: string; emptyMessage?: string; // Custom message to display when table is empty } // Language-aware text interface export interface LanguageText { de: string; en: string; fr: string; } // Utility function to resolve language text export const resolveLanguageText = (text: string | LanguageText | undefined, t?: (key: string, fallback?: string) => string): string => { if (!text) return ''; if (typeof text === 'string') { // Always use the translation function for strings (language keys) if (t) { return t(text); } return text; } // For LanguageText objects, we should convert them to language keys // For now, fallback to the first available language return text.de || text.en || text.fr || ''; }; // Generic page data interface export interface GenericPageData { // Core identification id: string; path: string; name: string; description?: string | LanguageText; // Navigation parentPath?: string; // For subpages/subsubpages order?: number; showInSidebar?: boolean; // Visual icon?: IconType; title: string | LanguageText; subtitle?: string | LanguageText; // Header configuration headerButtons?: PageButton[]; // Content sections content?: PageContent[]; // Page behavior persistent?: boolean; preserveState?: boolean; preload?: boolean; moduleEnabled?: boolean; hide?: boolean; // If true, page is completely hidden and not rendered // Subpage support hasSubpages?: boolean; // Lifecycle hooks onActivate?: () => void | Promise; onDeactivate?: () => void | Promise; onLoad?: () => void | Promise; onUnload?: () => void | Promise; // Custom component override (optional) customComponent?: React.ComponentType; // Privilege checker - if provided, page will only render if checker returns true privilegeChecker?: PrivilegeChecker; // Drag and drop configuration dragDropConfig?: DragDropConfig; } // Page data file structure export interface PageDataFile { page: GenericPageData; subpages?: PageDataFile[]; } // Sidebar item interface for compatibility export interface SidebarItem { id: string; name: string; link: string | undefined; // Allow undefined for parent groups that aren't clickable pages icon?: IconType | React.ComponentType>; // Allow both IconType and SVG components moduleEnabled: boolean; order: number; submenu?: SidebarSubmenuItemData[]; } // Sidebar submenu item data interface export interface SidebarSubmenuItemData { id: string; name: string; link: string; icon?: IconType; } // Page instance for PageManager export interface PageInstance { path: string; component: React.ReactElement; isActive: boolean; shouldPreserve: boolean; pageData: GenericPageData; } // Page manager props export interface PageManagerProps { loadingComponent: React.ComponentType; errorComponent: React.ComponentType; }