frontend_nyla/src/core/PageManager/pageInterface.ts
2025-10-12 16:16:21 +02:00

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;
}