Refactor the React OpenAPI admin framework to support fully customizable field rendering and UI composition. (#11)

# Summary

Refactor the React OpenAPI admin framework to support fully customizable field rendering and UI composition.

## Changes

### Admin UI Customization

* Added support for custom:

  * Dashboard component
  * Layout component
  * Login page component
* Introduced `AdminAppProps` and extended `Admin` configuration API.
* Renamed internal dashboard implementation to `DefaultDashboard`.

### Field Component Architecture

* Extracted field rendering into dedicated field components:

  * TextField
  * NumberField
  * BooleanField
  * DateField
  * EnumField
  * RelationField
  * ObjectField
  * FallbackField
  * DateRangeField
  * NumberRangeField
* Added `defaultFieldComponents` registry.
* Refactored `FormField` to resolve components dynamically from a component map instead of hardcoded field type handling.

### Resource Customization

* Added `FieldComponents` support across:

  * Admin
  * ResourceView
  * GenericForm
  * useResource
* Introduced wrapped `FormField` and `GenericForm` components generated from configured field overrides.

### Table Customization

* Added `EnhancedTableComponents`.
* Added support for custom cell renderers per field type.
* Enabled custom rendering for both desktop and mobile table layouts.

### Filter Improvements

* Exported `FilterAutocomplete`.
* Added support for custom date-range and number-range filter components.
* Added filter component extension points.
* Updated filter option label resolution to support `displayFormat`.

### Display Formatting

* Replaced `displayField` usage with `displayFormat`.
* Added template-based display rendering support through `resolveTemplate`.
* Improved relation display configuration handling.

### TypeScript Improvements

* Added TypeScript as a project dependency.
* Removed multiple `@ts-ignore` usages.
* Added strongly typed Axios wrapper methods with generic response support.
* Improved typing across hooks and component interfaces.

### OpenAPI Configuration Validation

* Added validation for enum fields without enum values.
* Added validation for relation resources missing `referenceOptions.enumOption`.
* Improved relation metadata propagation during schema parsing.

### Library Exports

* Exported:

  * Field component types
  * Override types
  * EnhancedTable
  * GenericForm
  * ResourceView
  * Field components and defaults
* Expanded public API surface for consumers extending the framework.

## Benefits

* Enables complete UI customization without modifying framework internals.
* Simplifies creation of custom field types and renderers.
* Improves type safety and developer experience.
* Provides consistent extension points for forms, tables, filters, and admin layouts.
* Makes the framework more suitable for reusable library distribution.

Reviewed-on: #11
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
This commit is contained in:
2026-06-07 12:35:52 +00:00
committed by aetos
parent e6ce62a166
commit 7bd946ec7a
35 changed files with 1028 additions and 618 deletions

View File

@@ -21,13 +21,13 @@ export interface EnumOption {
}
export interface ResourceField {
displayFormat: string;
type: FieldType;
label: string;
required?: boolean;
options?: string[];
readOnly?: boolean;
schema?: Record<string, ResourceField>;
displayField?: string | string[];
formatter?: (value: any) => string;
relation?: string;
filterType?: "autocomplete" | "multiselect" | "number-range" | "date-range";

View File

@@ -1,14 +1,19 @@
import { ResourceField, FieldType } from './config';
export interface EnumOption {
key: string;
value: string;
}
export interface FieldOverride {
displayField?: string | string[];
displayFormat?: string;
display?: boolean;
formatter?: (value: any) => string;
filterType?: "autocomplete" | "multiselect" | "number-range" | "date-range";
enumLabels?: Record<string, string>;
// New optional properties to support custom config extensions
path?: string;
refers?: string;
}
export interface ResourceOverride {
@@ -20,4 +25,62 @@ export interface ResourceOverride {
fields?: string[];
};
enumOption?: EnumOption;
// New optional property for referencetype resources
referenceOptions?: {
enumOption?: EnumOption;
autoComplete?: boolean;
prefetch?: boolean;
};
}
export interface FieldComponentProps {
name: string;
field: ResourceField;
value: any;
onChange: (val: any) => void;
disabled?: boolean;
error?: string;
baseUrl?: string;
relationDataMap?: Record<string, any[]>;
uploadFile?: (file: File) => Promise<string | null>;
uploading?: boolean;
}
export type FieldComponent = React.ComponentType<FieldComponentProps>;
export type FieldComponents = Partial<Record<FieldType, FieldComponent>> & {
relation?: FieldComponent;
image?: FieldComponent;
default?: FieldComponent;
dateRange?: FieldComponent;
numberRange?: FieldComponent;
FormField?: React.ComponentType<any>;
GenericForm?: React.ComponentType<any>;
};
export interface CellRendererProps {
value: any;
row: any;
field: ResourceField;
fieldKey: string;
config: import('./config').ResourceConfig;
onNavigate?: (resourceName: string, id: string) => void;
isMobile?: boolean;
}
export type CellRenderer = React.ComponentType<CellRendererProps>;
export interface EnhancedTableComponents {
cellRenderers?: Partial<Record<FieldType, CellRenderer>>;
}
export interface FilterBarComponents {
filterInputs?: Record<string, React.ComponentType<{
field: ResourceField;
value: any;
onChange: (val: any) => void;
options: string[];
}>>;
}
export type { FieldType };