diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b7a74c9e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Dependencies +node_modules/ + +# Build output +dist/ +*.tsbuildinfo + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Testing +coverage/ + +# Temporary files +tmp/ +temp/ diff --git a/README.md b/README.md index d20fbd02e..6588438e0 100644 --- a/README.md +++ b/README.md @@ -1 +1,154 @@ -# spec \ No newline at end of file +# ObjectStack Specification + +The ObjectStack Protocol & Specification repository defines the core type definitions and interfaces for the ObjectStack ecosystem. This repository serves as the "Constitution" of the system, providing the contract between backend (ObjectQL) parsers and frontend (ObjectUI) renderers. + +## Purpose + +This repository contains: +- **TypeScript Interfaces**: Shared types for the entire ObjectStack ecosystem +- **No Logic**: Only type definitions, no runtime code or business logic +- **Universal Compatibility**: Works in Node.js, Browser, and Electron environments + +## Metamodel Interfaces + +The metamodel defines the structure for describing data models in ObjectStack: + +### Core Interfaces + +#### `FieldType` +Defines the available field data types: +- Text types: `text`, `textarea`, `email`, `url` +- Numeric types: `number`, `currency`, `percentage` +- Date/Time types: `date`, `datetime` +- Relation types: `lookup` +- Selection types: `select`, `multiselect` +- Special types: `boolean`, `json`, `file`, `image` + +#### `ObjectField` +Represents a field definition within an entity: +```typescript +interface ObjectField { + name: string; // Field identifier + label: string; // Display label + type: FieldType; // Data type + required?: boolean; // Validation + unique?: boolean; // Constraint + lookupEntity?: string; // For lookup fields + // ... and more options +} +``` + +#### `ObjectEntity` +Represents a complete entity (data model) definition: +```typescript +interface ObjectEntity { + name: string; // Entity identifier + label: string; // Singular display label + pluralLabel: string; // Plural display label + fields: ObjectField[]; // Field definitions + primaryKey?: string; // Primary key field + displayField?: string; // Display field for lookups + // ... and more options +} +``` + +#### `ObjectView` +Represents a view configuration for presenting entity data: +```typescript +interface ObjectView { + name: string; // View identifier + label: string; // Display label + entityName: string; // Target entity + type: ViewType; // Presentation type (list, form, detail, etc.) + fields?: string[]; // Fields to display + columns?: ViewColumn[]; // Column configuration + filters?: ViewFilter[]; // Default filters + sort?: ViewSort[]; // Default sort order + // ... and more options +} +``` + +## Usage + +### Installation + +```bash +npm install @objectstack/spec +``` + +### Importing Types + +```typescript +// Import all metamodel types +import { ObjectEntity, ObjectField, ObjectView, FieldType } from '@objectstack/spec'; + +// Or import specific types +import type { ObjectEntity } from '@objectstack/spec'; +``` + +### Example: Defining an Entity + +```typescript +import { ObjectEntity, ObjectField } from '@objectstack/spec'; + +const userEntity: ObjectEntity = { + name: 'User', + label: 'User', + pluralLabel: 'Users', + description: 'System user account', + fields: [ + { + name: 'id', + label: 'ID', + type: 'text', + required: true, + readonly: true + }, + { + name: 'email', + label: 'Email', + type: 'email', + required: true, + unique: true + }, + { + name: 'name', + label: 'Full Name', + type: 'text', + required: true + }, + { + name: 'role', + label: 'Role', + type: 'select', + required: true, + options: [ + { value: 'admin', label: 'Administrator' }, + { value: 'user', label: 'User' } + ] + } + ], + primaryKey: 'id', + displayField: 'name' +}; +``` + +## Building + +```bash +npm install +npm run build +``` + +This will compile TypeScript files to JavaScript and generate type declarations in the `dist/` directory. + +## Philosophy + +Following the ObjectStack Protocol: +- **Strict Types, No Logic**: This repository contains only type definitions +- **Documentation as Code**: Every interface property has TSDoc comments for IntelliSense +- **Universal Compatibility**: Pure TypeScript with no platform-specific dependencies + +## License + +MIT \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..2e7eece0a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,30 @@ +{ + "name": "@objectstack/spec", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@objectstack/spec", + "version": "0.1.0", + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..f6490d04b --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "@objectstack/spec", + "version": "0.1.0", + "description": "ObjectStack Protocol & Specification - Type definitions and schemas", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist", + "src" + ], + "scripts": { + "build": "tsc", + "clean": "rm -rf dist" + }, + "keywords": [ + "objectstack", + "specification", + "types", + "metamodel" + ], + "author": "ObjectStack", + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/src/examples.ts b/src/examples.ts new file mode 100644 index 000000000..4e8225fc9 --- /dev/null +++ b/src/examples.ts @@ -0,0 +1,257 @@ +/** + * Example Usage of ObjectStack Metamodel + * + * This file demonstrates how to use the metamodel interfaces + * to define entities and views. + */ + +import type { ObjectEntity, ObjectView } from './types/meta'; + +/** + * Example: User Entity Definition + */ +export const UserEntity: ObjectEntity = { + name: 'User', + label: 'User', + pluralLabel: 'Users', + description: 'System user account', + fields: [ + { + name: 'id', + label: 'ID', + type: 'text', + required: true, + readonly: true, + }, + { + name: 'email', + label: 'Email Address', + type: 'email', + required: true, + unique: true, + maxLength: 255, + }, + { + name: 'name', + label: 'Full Name', + type: 'text', + required: true, + maxLength: 100, + }, + { + name: 'role', + label: 'Role', + type: 'select', + required: true, + options: [ + { value: 'admin', label: 'Administrator' }, + { value: 'editor', label: 'Editor' }, + { value: 'viewer', label: 'Viewer' }, + ], + }, + { + name: 'status', + label: 'Status', + type: 'select', + required: true, + defaultValue: 'active', + options: [ + { value: 'active', label: 'Active' }, + { value: 'inactive', label: 'Inactive' }, + { value: 'suspended', label: 'Suspended' }, + ], + }, + { + name: 'createdAt', + label: 'Created At', + type: 'datetime', + readonly: true, + }, + ], + primaryKey: 'id', + displayField: 'name', + icon: 'user', + auditable: true, + searchable: true, + searchableFields: ['name', 'email'], +}; + +/** + * Example: All Users List View + */ +export const AllUsersView: ObjectView = { + name: 'all_users', + label: 'All Users', + entityName: 'User', + type: 'list', + description: 'View all users in the system', + columns: [ + { + field: 'name', + label: 'Name', + width: '25%', + sortable: true, + }, + { + field: 'email', + label: 'Email', + width: '30%', + sortable: true, + }, + { + field: 'role', + label: 'Role', + width: '15%', + sortable: true, + }, + { + field: 'status', + label: 'Status', + width: '15%', + sortable: true, + }, + { + field: 'createdAt', + label: 'Created', + width: '15%', + sortable: true, + format: 'date:MM/DD/YYYY', + }, + ], + sort: [ + { + field: 'name', + direction: 'asc', + }, + ], + pageSize: 25, + default: true, +}; + +/** + * Example: Active Users View (with filter) + */ +export const ActiveUsersView: ObjectView = { + name: 'active_users', + label: 'Active Users', + entityName: 'User', + type: 'list', + description: 'View only active users', + columns: [ + { + field: 'name', + width: '30%', + }, + { + field: 'email', + width: '40%', + }, + { + field: 'role', + width: '30%', + }, + ], + filters: [ + { + field: 'status', + operator: 'equals', + value: 'active', + }, + ], + sort: [ + { + field: 'name', + direction: 'asc', + }, + ], +}; + +/** + * Example: User Form View + */ +export const UserFormView: ObjectView = { + name: 'user_form', + label: 'User Form', + entityName: 'User', + type: 'form', + description: 'Form for creating and editing users', + fields: ['name', 'email', 'role', 'status'], + layout: { + type: 'sections', + sections: [ + { + id: 'basic', + title: 'Basic Information', + fields: ['name', 'email'], + }, + { + id: 'settings', + title: 'Settings', + fields: ['role', 'status'], + }, + ], + }, +}; + +/** + * Example: Product Entity with Lookup + */ +export const ProductEntity: ObjectEntity = { + name: 'Product', + label: 'Product', + pluralLabel: 'Products', + description: 'Product catalog', + fields: [ + { + name: 'id', + label: 'ID', + type: 'text', + required: true, + readonly: true, + }, + { + name: 'name', + label: 'Product Name', + type: 'text', + required: true, + maxLength: 200, + }, + { + name: 'description', + label: 'Description', + type: 'textarea', + maxLength: 1000, + }, + { + name: 'price', + label: 'Price', + type: 'currency', + required: true, + min: 0, + }, + { + name: 'category', + label: 'Category', + type: 'lookup', + required: true, + lookupEntity: 'Category', + lookupDisplayField: 'name', + }, + { + name: 'inStock', + label: 'In Stock', + type: 'boolean', + defaultValue: true, + }, + { + name: 'image', + label: 'Product Image', + type: 'image', + }, + ], + primaryKey: 'id', + displayField: 'name', + icon: 'package', + searchable: true, + searchableFields: ['name', 'description'], +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 000000000..42100fee2 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,10 @@ +/** + * ObjectStack Specification + * + * This module provides the core type definitions and interfaces for the ObjectStack ecosystem. + * It defines the contract between backend (ObjectQL) parsers and frontend (ObjectUI) renderers. + * + * @packageDocumentation + */ + +export * from './types'; diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 000000000..b9a4610a2 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,9 @@ +/** + * Type Definitions + * + * This module exports all type definitions used in the ObjectStack specification. + * + * @module types + */ + +export * from './meta'; diff --git a/src/types/meta/field-type.ts b/src/types/meta/field-type.ts new file mode 100644 index 000000000..a3ada74f9 --- /dev/null +++ b/src/types/meta/field-type.ts @@ -0,0 +1,91 @@ +/** + * Field Type Definitions + * + * Defines the available field types in the ObjectStack metamodel. + * These types determine how fields are stored, validated, and rendered. + * + * @module types/meta/field-type + */ + +/** + * Available field types in the ObjectStack metamodel. + * + * @remarks + * Each field type corresponds to specific storage, validation, and rendering behavior: + * + * - `text`: Short text strings (single line) + * - `textarea`: Long text content (multi-line) + * - `number`: Numeric values (integer or decimal) + * - `boolean`: True/false values (checkbox) + * - `date`: Date values (without time) + * - `datetime`: Date and time values + * - `email`: Email address with validation + * - `url`: URL with validation + * - `lookup`: Reference to another entity (foreign key) + * - `select`: Single selection from predefined options + * - `multiselect`: Multiple selections from predefined options + * - `json`: Arbitrary JSON data structure + * - `file`: File attachment reference + * - `image`: Image file reference with preview + * - `currency`: Monetary values with precision + * - `percentage`: Percentage values (0-100) + * + * @example + * ```typescript + * const nameField: FieldType = 'text'; + * const priceField: FieldType = 'currency'; + * const ownerField: FieldType = 'lookup'; + * ``` + */ +export type FieldType = + | 'text' + | 'textarea' + | 'number' + | 'boolean' + | 'date' + | 'datetime' + | 'email' + | 'url' + | 'lookup' + | 'select' + | 'multiselect' + | 'json' + | 'file' + | 'image' + | 'currency' + | 'percentage'; + +/** + * Type guard to check if a string is a valid FieldType + * + * @param value - The value to check + * @returns True if the value is a valid FieldType + * + * @example + * ```typescript + * if (isFieldType('text')) { + * // value is a valid FieldType + * } + * ``` + */ +export function isFieldType(value: unknown): value is FieldType { + const validTypes: FieldType[] = [ + 'text', + 'textarea', + 'number', + 'boolean', + 'date', + 'datetime', + 'email', + 'url', + 'lookup', + 'select', + 'multiselect', + 'json', + 'file', + 'image', + 'currency', + 'percentage', + ]; + return typeof value === 'string' && validTypes.includes(value as FieldType); +} diff --git a/src/types/meta/index.ts b/src/types/meta/index.ts new file mode 100644 index 000000000..6fee88473 --- /dev/null +++ b/src/types/meta/index.ts @@ -0,0 +1,13 @@ +/** + * Metamodel Type Definitions + * + * This module defines the core metamodel interfaces that form the contract + * between the backend (ObjectQL) parser and the frontend (ObjectUI) renderer. + * + * @module types/meta + */ + +export * from './field-type'; +export * from './object-field'; +export * from './object-entity'; +export * from './object-view'; diff --git a/src/types/meta/object-entity.ts b/src/types/meta/object-entity.ts new file mode 100644 index 000000000..bf7dfce1e --- /dev/null +++ b/src/types/meta/object-entity.ts @@ -0,0 +1,265 @@ +/** + * Object Entity Interface + * + * Defines the structure of an entity in the ObjectStack metamodel. + * Entities represent data models/tables with their fields and relationships. + * + * @module types/meta/object-entity + */ + +import { ObjectField } from './object-field'; + +/** + * Represents an entity definition in the ObjectStack metamodel + * + * @remarks + * ObjectEntity is the core data model definition. It describes a logical + * entity (like User, Account, Product) with its fields, constraints, + * and metadata. This interface is used by: + * + * - ObjectQL parser: To validate and process schema definitions + * - ObjectUI renderer: To generate forms, tables, and views + * - Database drivers: To create tables and migrations + * - API generators: To expose REST/GraphQL endpoints + * + * @example + * ```typescript + * const userEntity: ObjectEntity = { + * name: 'User', + * label: 'User', + * pluralLabel: 'Users', + * description: 'System user account', + * fields: [ + * { + * name: 'id', + * label: 'ID', + * type: 'text', + * required: true, + * readonly: true + * }, + * { + * name: 'email', + * label: 'Email', + * type: 'email', + * required: true, + * unique: true + * }, + * { + * name: 'name', + * label: 'Full Name', + * type: 'text', + * required: true + * } + * ], + * primaryKey: 'id', + * displayField: 'name' + * }; + * ``` + */ +export interface ObjectEntity { + /** + * Technical name of the entity + * + * @remarks + * Used in code, APIs, and database table names. + * Should be in PascalCase for entities. + * Must be unique across the system. + * + * @example 'User', 'Account', 'SalesOrder' + */ + name: string; + + /** + * Human-readable singular label for the entity + * + * @remarks + * Used in UI headers, forms, and documentation. + * + * @example 'User', 'Sales Order', 'Product Category' + */ + label: string; + + /** + * Human-readable plural label for the entity + * + * @remarks + * Used in UI when displaying lists or collections. + * + * @example 'Users', 'Sales Orders', 'Product Categories' + */ + pluralLabel: string; + + /** + * Detailed description of the entity's purpose + * + * @remarks + * Used for documentation and context-sensitive help + */ + description?: string; + + /** + * Array of field definitions that make up this entity + * + * @remarks + * Each field represents a column/attribute in the entity. + * Field names must be unique within the entity. + * + * @see ObjectField + */ + fields: ObjectField[]; + + /** + * Name of the field that serves as the primary key + * + * @remarks + * The primary key uniquely identifies each record. + * Must be one of the field names in the fields array. + * + * @defaultValue 'id' + * + * @example 'id', 'uuid', 'userId' + */ + primaryKey?: string; + + /** + * Name of the field to use as the display/title field + * + * @remarks + * Used when showing a record reference in lookups, breadcrumbs, etc. + * Should be a field that uniquely and meaningfully identifies a record. + * + * @defaultValue 'name' + * + * @example 'name', 'title', 'email', 'code' + */ + displayField?: string; + + /** + * Icon identifier for the entity + * + * @remarks + * Used in navigation menus, headers, and lists. + * Can be an icon library reference (e.g., 'user', 'building', 'package') + * or a URL to a custom icon. + * + * @example 'user', 'briefcase', 'https://example.com/icon.svg' + */ + icon?: string; + + /** + * Color theme for the entity + * + * @remarks + * Used for visual distinction in UI elements. + * Can be a CSS color name, hex code, or theme variable. + * + * @example 'blue', '#3B82F6', 'primary' + */ + color?: string; + + /** + * Whether this entity should be audited + * + * @remarks + * When enabled, tracks create/update/delete operations with user and timestamp. + * Typically adds fields like: createdBy, createdAt, updatedBy, updatedAt + * + * @defaultValue false + */ + auditable?: boolean; + + /** + * Whether this entity supports soft deletion + * + * @remarks + * When enabled, records are marked as deleted rather than physically removed. + * Typically adds a 'deletedAt' timestamp field. + * + * @defaultValue false + */ + softDelete?: boolean; + + /** + * Whether this entity can be searched via full-text search + * + * @remarks + * When enabled, the entity is indexed for full-text search operations + * + * @defaultValue false + */ + searchable?: boolean; + + /** + * Names of fields to include in full-text search + * + * @remarks + * Only relevant when searchable is true. + * If not specified, all text fields are included. + * + * @example ['name', 'description', 'email'] + */ + searchableFields?: string[]; + + /** + * Permission scope identifier + * + * @remarks + * Defines the permission namespace for this entity. + * Used to generate permission strings like: '{scope}.read', '{scope}.write' + * + * @example 'user', 'sales.order', 'product.category' + */ + permissionScope?: string; + + /** + * Custom validation rules + * + * @remarks + * Array of validation rule identifiers that apply to the entire entity. + * Can reference built-in validators or custom validation functions. + * + * @example ['uniqueTogether:email,domain', 'requiredIf:field1,field2'] + */ + validationRules?: string[]; + + /** + * Database table name override + * + * @remarks + * By default, table name is derived from entity name. + * Use this to specify a custom table name. + * + * @example 'tbl_users', 'legacy_accounts' + */ + tableName?: string; + + /** + * Entity version for schema migration tracking + * + * @remarks + * Incremented when breaking changes are made to the entity structure. + * Used for migration management and compatibility checking. + * + * @defaultValue 1 + */ + version?: number; + + /** + * Tags for categorization and filtering + * + * @remarks + * Used to organize entities into logical groups. + * + * @example ['core', 'sales', 'internal'] + */ + tags?: string[]; + + /** + * Custom metadata for extensions and plugins + * + * @remarks + * Allows third-party code to attach arbitrary metadata to entities + * without modifying the core interface + */ + metadata?: Record; +} diff --git a/src/types/meta/object-field.ts b/src/types/meta/object-field.ts new file mode 100644 index 000000000..f20b50bf4 --- /dev/null +++ b/src/types/meta/object-field.ts @@ -0,0 +1,218 @@ +/** + * Object Field Interface + * + * Defines the structure of a field within an ObjectEntity. + * Fields represent individual data attributes and their metadata. + * + * @module types/meta/object-field + */ + +import { FieldType } from './field-type'; + +/** + * Represents a field definition within an ObjectEntity + * + * @remarks + * ObjectField defines the complete metadata for a single field/attribute + * in an entity. This includes its type, validation rules, UI hints, and + * relationships to other entities (in the case of lookup fields). + * + * @example + * ```typescript + * const nameField: ObjectField = { + * name: 'name', + * label: 'Full Name', + * type: 'text', + * required: true, + * maxLength: 100 + * }; + * + * const ownerField: ObjectField = { + * name: 'owner', + * label: 'Owner', + * type: 'lookup', + * required: true, + * lookupEntity: 'User', + * lookupDisplayField: 'name' + * }; + * ``` + */ +export interface ObjectField { + /** + * Technical name of the field (used in code and database) + * + * @remarks + * Should be in camelCase or snake_case format. + * Must be unique within the entity. + * + * @example 'firstName', 'email', 'created_at' + */ + name: string; + + /** + * Human-readable label for the field + * + * @remarks + * Used in UI forms, tables, and documentation. + * + * @example 'First Name', 'Email Address', 'Created At' + */ + label: string; + + /** + * Data type of the field + * + * @see FieldType + */ + type: FieldType; + + /** + * Detailed description of the field's purpose and usage + * + * @remarks + * Used for tooltips, help text, and documentation. + */ + description?: string; + + /** + * Whether the field is required (cannot be null/empty) + * + * @defaultValue false + */ + required?: boolean; + + /** + * Whether the field value must be unique across all records + * + * @defaultValue false + */ + unique?: boolean; + + /** + * Default value when creating new records + * + * @remarks + * Can be a static value or a function reference (e.g., 'NOW()' for timestamps) + */ + defaultValue?: unknown; + + /** + * Maximum length for text fields + * + * @remarks + * Only applicable to 'text', 'textarea', 'email', 'url' field types + */ + maxLength?: number; + + /** + * Minimum length for text fields + * + * @remarks + * Only applicable to 'text', 'textarea', 'email', 'url' field types + */ + minLength?: number; + + /** + * Minimum value for numeric fields + * + * @remarks + * Only applicable to 'number', 'currency', 'percentage' field types + */ + min?: number; + + /** + * Maximum value for numeric fields + * + * @remarks + * Only applicable to 'number', 'currency', 'percentage' field types + */ + max?: number; + + /** + * Regular expression pattern for validation + * + * @remarks + * Applied to text-based field types for custom validation rules + * + * @example '^[A-Z]{2}-\\d{4}$' for pattern like 'AB-1234' + */ + pattern?: string; + + /** + * Target entity name for lookup fields + * + * @remarks + * Required when type is 'lookup'. Specifies which entity this field references. + * + * @example 'User', 'Account', 'Product' + */ + lookupEntity?: string; + + /** + * Field name in the lookup entity to display + * + * @remarks + * Used to show human-readable text instead of IDs. + * Common values: 'name', 'title', 'label' + * + * @defaultValue 'name' + */ + lookupDisplayField?: string; + + /** + * Available options for select/multiselect fields + * + * @remarks + * Only applicable to 'select' and 'multiselect' field types + * + * @example + * ```typescript + * options: [ + * { value: 'draft', label: 'Draft' }, + * { value: 'published', label: 'Published' } + * ] + * ``` + */ + options?: Array<{ + /** Internal value stored in database */ + value: string | number; + /** Human-readable label shown in UI */ + label: string; + }>; + + /** + * Whether the field is indexed for faster queries + * + * @defaultValue false + */ + indexed?: boolean; + + /** + * Whether the field is read-only + * + * @remarks + * Read-only fields can only be set by the system, not by users + * + * @defaultValue false + */ + readonly?: boolean; + + /** + * Whether the field is hidden from UI by default + * + * @remarks + * Hidden fields are still stored and queryable but not shown in standard forms/views + * + * @defaultValue false + */ + hidden?: boolean; + + /** + * Custom metadata for extensions and plugins + * + * @remarks + * Allows third-party code to attach arbitrary metadata to fields + * without modifying the core interface + */ + metadata?: Record; +} diff --git a/src/types/meta/object-view.ts b/src/types/meta/object-view.ts new file mode 100644 index 000000000..34cd3be80 --- /dev/null +++ b/src/types/meta/object-view.ts @@ -0,0 +1,475 @@ +/** + * Object View Interface + * + * Defines the structure of a view in the ObjectStack metamodel. + * Views represent different UI presentations of entity data (list, form, detail, etc.). + * + * @module types/meta/object-view + */ + +/** + * Available view types in the ObjectStack metamodel + * + * @remarks + * Each view type corresponds to a different UI presentation pattern: + * + * - `list`: Tabular list view (grid/table) + * - `detail`: Single record detail view (read-only) + * - `form`: Single record form view (editable) + * - `card`: Card-based list view + * - `kanban`: Kanban board view + * - `calendar`: Calendar view (for date-based records) + * - `chart`: Chart/graph visualization + * - `map`: Geographic map view + * - `timeline`: Timeline view for chronological data + * - `custom`: Custom view implementation + */ +export type ViewType = + | 'list' + | 'detail' + | 'form' + | 'card' + | 'kanban' + | 'calendar' + | 'chart' + | 'map' + | 'timeline' + | 'custom'; + +/** + * Layout configuration for a view + * + * @remarks + * Defines how fields are organized visually in the view + */ +export interface ViewLayout { + /** + * Layout type/strategy + * + * @remarks + * - `single-column`: One field per row + * - `two-column`: Two fields per row + * - `grid`: Flexible grid layout + * - `tabs`: Fields organized in tabs + * - `sections`: Fields grouped in named sections + * + * @defaultValue 'single-column' + */ + type?: 'single-column' | 'two-column' | 'grid' | 'tabs' | 'sections'; + + /** + * Sections for organizing fields + * + * @remarks + * Only applicable when layout type is 'sections' or 'tabs' + */ + sections?: Array<{ + /** Section identifier */ + id: string; + /** Section title */ + title: string; + /** Field names to include in this section */ + fields: string[]; + /** Whether section is collapsed by default */ + collapsed?: boolean; + }>; +} + +/** + * Filter configuration for a view + * + * @remarks + * Defines how records are filtered in the view + */ +export interface ViewFilter { + /** + * Field name to filter on + * + * @example 'status', 'createdAt', 'owner' + */ + field: string; + + /** + * Filter operator + * + * @remarks + * Available operators depend on the field type: + * - Text: equals, contains, startsWith, endsWith + * - Number: equals, gt, gte, lt, lte, between + * - Boolean: equals + * - Date: equals, before, after, between + * - Lookup: equals, in + */ + operator: 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'before' | 'after' | 'in' | 'notIn'; + + /** + * Filter value(s) + * + * @remarks + * Type depends on operator and field type. + * For 'between' operator, should be an array of two values. + */ + value: unknown; +} + +/** + * Sort configuration for a view + * + * @remarks + * Defines how records are sorted in the view + */ +export interface ViewSort { + /** + * Field name to sort by + * + * @example 'name', 'createdAt', 'priority' + */ + field: string; + + /** + * Sort direction + * + * @defaultValue 'asc' + */ + direction: 'asc' | 'desc'; +} + +/** + * Column configuration for list views + * + * @remarks + * Defines how a field is displayed as a column in a list/table view + */ +export interface ViewColumn { + /** + * Field name to display + * + * @remarks + * Must be a valid field name from the entity + */ + field: string; + + /** + * Column header label + * + * @remarks + * If not provided, uses the field's label + */ + label?: string; + + /** + * Column width + * + * @remarks + * Can be in pixels (e.g., 100) or percentage (e.g., '20%') + */ + width?: number | string; + + /** + * Whether the column is sortable + * + * @defaultValue true + */ + sortable?: boolean; + + /** + * Whether the column is visible by default + * + * @defaultValue true + */ + visible?: boolean; + + /** + * Text alignment in the column + * + * @defaultValue 'left' + */ + align?: 'left' | 'center' | 'right'; + + /** + * Custom formatting function name + * + * @remarks + * Reference to a formatting function (e.g., 'currency', 'date', 'percentage') + * + * @example 'currency', 'date:MM/DD/YYYY', 'number:2' (2 decimal places) + */ + format?: string; +} + +/** + * Represents a view definition for an ObjectEntity + * + * @remarks + * ObjectView defines how an entity's data is presented in the UI. + * Multiple views can exist for the same entity, each tailored for + * different use cases (e.g., "All Users", "Active Users", "Admin Users"). + * + * Views are used by ObjectUI to: + * - Render lists with specific columns and filters + * - Display forms with specific field layouts + * - Show detailed records with custom presentations + * + * @example + * ```typescript + * const allUsersView: ObjectView = { + * name: 'all_users', + * label: 'All Users', + * entityName: 'User', + * type: 'list', + * columns: [ + * { field: 'name', width: '30%' }, + * { field: 'email', width: '30%' }, + * { field: 'status', width: '20%' }, + * { field: 'createdAt', width: '20%', format: 'date:MM/DD/YYYY' } + * ], + * sort: [ + * { field: 'name', direction: 'asc' } + * ] + * }; + * + * const userFormView: ObjectView = { + * name: 'user_form', + * label: 'User Form', + * entityName: 'User', + * type: 'form', + * fields: ['name', 'email', 'role', 'status'], + * layout: { + * type: 'sections', + * sections: [ + * { + * id: 'basic', + * title: 'Basic Information', + * fields: ['name', 'email'] + * }, + * { + * id: 'settings', + * title: 'Settings', + * fields: ['role', 'status'] + * } + * ] + * } + * }; + * ``` + */ +export interface ObjectView { + /** + * Technical name of the view + * + * @remarks + * Used in code and URLs. + * Should be in snake_case format. + * Must be unique within the entity's views. + * + * @example 'all_users', 'active_orders', 'recent_products' + */ + name: string; + + /** + * Human-readable label for the view + * + * @remarks + * Used in UI menus, tabs, and headers. + * + * @example 'All Users', 'Active Orders', 'Recent Products' + */ + label: string; + + /** + * Name of the entity this view is for + * + * @remarks + * Must be a valid entity name in the system. + * + * @example 'User', 'SalesOrder', 'Product' + */ + entityName: string; + + /** + * Type of view presentation + * + * @see ViewType + */ + type: ViewType; + + /** + * Detailed description of the view's purpose + * + * @remarks + * Used for tooltips and documentation + */ + description?: string; + + /** + * Field names to display in the view + * + * @remarks + * For form/detail views: determines which fields to show and in what order. + * For list views: used if columns are not specified. + * Must be valid field names from the entity. + */ + fields?: string[]; + + /** + * Column configurations for list views + * + * @remarks + * Only applicable to 'list', 'card', 'kanban' view types. + * Defines how each field is rendered as a column. + * + * @see ViewColumn + */ + columns?: ViewColumn[]; + + /** + * Layout configuration for the view + * + * @remarks + * Only applicable to 'form' and 'detail' view types. + * + * @see ViewLayout + */ + layout?: ViewLayout; + + /** + * Default filters to apply to the view + * + * @remarks + * Filters are applied when the view is loaded. + * Users can typically modify or remove these filters. + * + * @see ViewFilter + */ + filters?: ViewFilter[]; + + /** + * Default sort order for the view + * + * @remarks + * Can specify multiple sort levels (first by field1, then by field2, etc.) + * + * @see ViewSort + */ + sort?: ViewSort[]; + + /** + * Number of records to display per page + * + * @remarks + * Only applicable to list-based views. + * + * @defaultValue 25 + */ + pageSize?: number; + + /** + * Icon identifier for the view + * + * @remarks + * Used in view switchers, menus, and tabs. + * + * @example 'list', 'grid', 'calendar' + */ + icon?: string; + + /** + * Whether this is the default view for the entity + * + * @remarks + * The default view is shown when navigating to the entity + * without specifying a view. + * + * @defaultValue false + */ + default?: boolean; + + /** + * Whether the view is visible in navigation menus + * + * @remarks + * Hidden views can still be accessed directly via URL + * + * @defaultValue true + */ + visible?: boolean; + + /** + * Permission required to access this view + * + * @remarks + * Users without this permission cannot see or access the view. + * + * @example 'user.read', 'sales.order.view.active' + */ + permission?: string; + + /** + * Query string for advanced filtering + * + * @remarks + * Alternative to the filters array for complex queries. + * Uses the ObjectQL query syntax. + * + * @example 'status = "active" AND createdAt > NOW() - 30d' + */ + query?: string; + + /** + * Field name for grouping records (kanban view) + * + * @remarks + * Only applicable to 'kanban' view type. + * The field should have predefined options (select/lookup). + * + * @example 'status', 'priority', 'assignedTo' + */ + groupBy?: string; + + /** + * Date field name for calendar/timeline views + * + * @remarks + * Only applicable to 'calendar' and 'timeline' view types. + * Must be a date or datetime field. + * + * @example 'dueDate', 'scheduledAt', 'eventDate' + */ + dateField?: string; + + /** + * Chart configuration for chart views + * + * @remarks + * Only applicable to 'chart' view type. + */ + chartConfig?: { + /** Chart type (bar, line, pie, etc.) */ + type: 'bar' | 'line' | 'pie' | 'donut' | 'area' | 'scatter'; + /** Field for x-axis */ + xAxis?: string; + /** Field for y-axis */ + yAxis?: string; + /** Aggregation function (count, sum, avg, etc.) */ + aggregation?: 'count' | 'sum' | 'avg' | 'min' | 'max'; + }; + + /** + * Custom component reference for custom views + * + * @remarks + * Only applicable to 'custom' view type. + * References a registered custom component. + * + * @example 'MyCustomDashboard', 'AnalyticsView' + */ + customComponent?: string; + + /** + * Custom metadata for extensions and plugins + * + * @remarks + * Allows third-party code to attach arbitrary metadata to views + * without modifying the core interface + */ + metadata?: Record; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..61a295967 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "lib": ["ES2020"], + "moduleResolution": "node", + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}