218 lines
7.2 KiB
TypeScript
218 lines
7.2 KiB
TypeScript
import React from 'react';
|
|
import { IconType } from 'react-icons';
|
|
import { DragDropConfig } from '../../components/ui/DragDropOverlay/DragDropOverlay';
|
|
|
|
// Generic privilege checker function type
|
|
export type PrivilegeChecker = () => boolean | Promise<boolean>;
|
|
|
|
// Form field configuration for create/edit buttons
|
|
export interface ButtonFormField {
|
|
key: string;
|
|
label: string | LanguageText;
|
|
type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly';
|
|
required?: boolean;
|
|
placeholder?: string | LanguageText;
|
|
minRows?: number;
|
|
maxRows?: number;
|
|
validator?: (value: any) => string | null;
|
|
defaultValue?: any;
|
|
}
|
|
|
|
// 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<void>;
|
|
disabled?: boolean;
|
|
privilegeChecker?: PrivilegeChecker;
|
|
// 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;
|
|
};
|
|
}
|
|
|
|
// Content section for paragraphs
|
|
export interface PageContent {
|
|
id: string;
|
|
type: 'paragraph' | 'heading' | 'list' | 'code' | 'divider' | 'custom' | 'table';
|
|
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<any>;
|
|
privilegeChecker?: PrivilegeChecker;
|
|
// Table-specific properties
|
|
tableConfig?: TableContentConfig;
|
|
}
|
|
|
|
// 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?: () => Promise<void>;
|
|
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
|
|
handleDownload?: (fileId: string, fileName: string) => Promise<boolean>; // For file download functionality
|
|
handleDelete?: (fileId: string, onOptimisticDelete?: () => void) => Promise<boolean>; // For file delete functionality
|
|
handlePreview?: (fileId: string, fileName: string, mimeType?: string) => Promise<any>; // For file preview functionality
|
|
// FormGenerator specific handlers
|
|
onDelete?: (row: any) => Promise<void>; // For single item deletion
|
|
onDeleteMultiple?: (rows: any[]) => Promise<void>; // For multiple item deletion
|
|
// Message overlay component
|
|
MessageOverlayComponent?: () => React.ReactElement;
|
|
}
|
|
|
|
// Action button configuration
|
|
export interface ActionButtonConfig {
|
|
type: 'view' | 'edit' | 'download' | 'delete' | 'copy';
|
|
onAction?: (row: any) => Promise<void> | void; // Optional for delete buttons since they handle their own logic
|
|
title?: string | LanguageText;
|
|
disabled?: (row: any) => boolean | { disabled: boolean; message?: string };
|
|
loading?: (row: 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')
|
|
// Operation and loading state names
|
|
operationName?: string; // Name of the operation function in hookData
|
|
loadingStateName?: string; // Name of the loading state in hookData
|
|
}
|
|
|
|
// Table content configuration
|
|
export interface TableContentConfig {
|
|
hookFactory: () => () => GenericDataHook; // Hook factory that returns a hook function
|
|
columns: any[]; // Column configuration
|
|
actionButtons?: ActionButtonConfig[]; // Action buttons configuration
|
|
searchable?: boolean;
|
|
filterable?: boolean;
|
|
sortable?: boolean;
|
|
resizable?: boolean;
|
|
pagination?: boolean;
|
|
pageSize?: number;
|
|
className?: string;
|
|
}
|
|
|
|
// 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[];
|
|
|
|
// Privilege system
|
|
privilegeChecker?: PrivilegeChecker;
|
|
|
|
// Page behavior
|
|
persistent?: boolean;
|
|
preserveState?: boolean;
|
|
preload?: boolean;
|
|
moduleEnabled?: boolean;
|
|
|
|
// Subpage support
|
|
hasSubpages?: boolean;
|
|
subpagePrivilegeChecker?: PrivilegeChecker;
|
|
|
|
// Lifecycle hooks
|
|
onActivate?: () => void | Promise<void>;
|
|
onDeactivate?: () => void | Promise<void>;
|
|
onLoad?: () => void | Promise<void>;
|
|
onUnload?: () => void | Promise<void>;
|
|
|
|
// Custom component override (optional)
|
|
customComponent?: React.ComponentType<any>;
|
|
|
|
// 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;
|
|
icon?: IconType;
|
|
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;
|
|
}
|