diff --git a/ROADMAP.md b/ROADMAP.md index 1aa872a7f3..7feed00363 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -81,7 +81,7 @@ Full adoption of Cloud namespace, contracts/integration/security/studio modules, ### CRM Example Metadata Enrichment ✅ -Enriched all 8 CRM object definitions (`account`, `contact`, `opportunity`, `product`, `order`, `user`, `project_task`, `event`) to exercise the full `@objectstack/spec` feature set. Added `description` to all objects; field enrichments (`required`, `searchable`, `unique`, `defaultValue`, `helpText`, `placeholder`, `readonly`); diverse field types (`richtext`, `phone`, `avatar`, `color`, `multi-select`); 30+ new fields (tags, linkedin, expected_revenue, shipping_address, etc.); 2+ list views per object with sort/filter; select options with colors across all objects; updated seed data leveraging new fields. +Enriched all 8 CRM object definitions (`account`, `contact`, `opportunity`, `product`, `order`, `user`, `project_task`, `event`) to exercise the full `@objectstack/spec` feature set. Added `description` to all objects; field enrichments (`required`, `searchable`, `unique`, `defaultValue`, `readonly`); diverse field types (`richtext`, `phone`, `avatar`, `color`, `multi-select`); 30+ new fields (tags, linkedin, expected_revenue, shipping_address, etc.); 2+ list views per object with sort/filter; select options with colors across all objects; updated seed data leveraging new fields. Added 21 object-level actions across all 8 objects (Send Email, Change Status, Assign Owner, Mark as Won/Lost, Generate Invoice, Reset Password, etc.) with `params`, `confirmText`, `variant`, `locations`, and `refreshAfter`. Added sections-based `form_layout` for all 8 objects organizing fields into logical groups (e.g., Basic Info, Financials, Address, Timeline) with `columns`, `collapsible`, and field grouping. ### Architecture diff --git a/examples/crm/objectstack.config.ts b/examples/crm/objectstack.config.ts index 944dae24d3..43f01d2d54 100644 --- a/examples/crm/objectstack.config.ts +++ b/examples/crm/objectstack.config.ts @@ -8,6 +8,22 @@ import { OrderObject } from './src/objects/order.object'; import { UserObject } from './src/objects/user.object'; import { ProjectObject } from './src/objects/project.object'; import { EventObject } from './src/objects/event.object'; +import { AccountView } from './src/views/account.view'; +import { ContactView } from './src/views/contact.view'; +import { OpportunityView } from './src/views/opportunity.view'; +import { ProductView } from './src/views/product.view'; +import { OrderView } from './src/views/order.view'; +import { UserView } from './src/views/user.view'; +import { EventView } from './src/views/event.view'; +import { ProjectView } from './src/views/project.view'; +import { AccountActions } from './src/actions/account.actions'; +import { ContactActions } from './src/actions/contact.actions'; +import { OpportunityActions } from './src/actions/opportunity.actions'; +import { ProductActions } from './src/actions/product.actions'; +import { OrderActions } from './src/actions/order.actions'; +import { UserActions } from './src/actions/user.actions'; +import { ProjectActions } from './src/actions/project.actions'; +import { EventActions } from './src/actions/event.actions'; export default defineStack({ objects: [ @@ -21,218 +37,26 @@ export default defineStack({ EventObject ], views: [ - // --- Account Views --- - { - listViews: { - all_accounts: { - name: 'all_accounts', - label: 'All Accounts', - type: 'grid', - data: { provider: 'object', object: 'account' }, - columns: ['name', 'industry', 'type', 'annual_revenue', 'rating', 'owner'], - sort: [{ field: 'name', order: 'asc' }], - }, - active_accounts: { - name: 'active_accounts', - label: 'Active Customers', - type: 'grid', - data: { provider: 'object', object: 'account' }, - columns: ['name', 'industry', 'annual_revenue', 'phone', 'owner'], - filter: ['type', '=', 'Customer'], - sort: [{ field: 'annual_revenue', order: 'desc' }], - }, - }, - }, - // --- Contact Views --- - { - listViews: { - all_contacts: { - name: 'all_contacts', - label: 'All Contacts', - type: 'grid', - data: { provider: 'object', object: 'contact' }, - columns: ['name', 'email', 'phone', 'title', 'account', 'status', 'priority'], - sort: [{ field: 'name', order: 'asc' }], - }, - active_contacts: { - name: 'active_contacts', - label: 'Active Contacts', - type: 'grid', - data: { provider: 'object', object: 'contact' }, - columns: ['name', 'email', 'title', 'account', 'status'], - filter: ['is_active', '=', true], - }, - }, - }, - // --- Opportunity Views --- - { - listViews: { - all: { - name: 'all', - label: 'All Opportunities', - type: 'grid', - data: { provider: 'object', object: 'opportunity' }, - columns: ['name', 'amount', 'stage', 'close_date', 'probability', 'forecast_category'], - sort: [{ field: 'close_date', order: 'asc' }], - }, - pipeline: { - name: 'pipeline', - label: 'Pipeline', - type: 'kanban', - data: { provider: 'object', object: 'opportunity' }, - columns: ['name', 'amount', 'close_date', 'probability'], - kanban: { - groupByField: 'stage', - columns: ['name', 'amount', 'close_date'], - }, - }, - closing_this_month: { - name: 'closing_this_month', - label: 'Closing This Month', - type: 'grid', - data: { provider: 'object', object: 'opportunity' }, - columns: ['name', 'amount', 'stage', 'close_date', 'probability'], - sort: [{ field: 'close_date', order: 'asc' }], - }, - }, - }, - // --- Product Views --- - { - listViews: { - all_products: { - name: 'all_products', - label: 'All Products', - type: 'grid', - data: { provider: 'object', object: 'product' }, - columns: ['name', 'sku', 'category', 'price', 'stock', 'is_active'], - sort: [{ field: 'name', order: 'asc' }], - }, - active_products: { - name: 'active_products', - label: 'Active Products', - type: 'grid', - data: { provider: 'object', object: 'product' }, - columns: ['name', 'sku', 'category', 'price', 'stock', 'tags'], - filter: ['is_active', '=', true], - }, - }, - }, - // --- Order Views --- - { - listViews: { - all_orders: { - name: 'all_orders', - label: 'All Orders', - type: 'grid', - data: { provider: 'object', object: 'order' }, - columns: ['name', 'customer', 'amount', 'status', 'order_date', 'payment_method'], - sort: [{ field: 'order_date', order: 'desc' }], - }, - pending_orders: { - name: 'pending_orders', - label: 'Pending Orders', - type: 'grid', - data: { provider: 'object', object: 'order' }, - columns: ['name', 'customer', 'amount', 'order_date'], - filter: ['status', '=', 'pending'], - }, - }, - }, - // --- User Views --- - { - listViews: { - all_users: { - name: 'all_users', - label: 'All Users', - type: 'grid', - data: { provider: 'object', object: 'user' }, - columns: ['name', 'email', 'role', 'department', 'active'], - sort: [{ field: 'name', order: 'asc' }], - }, - active_users: { - name: 'active_users', - label: 'Active Users', - type: 'grid', - data: { provider: 'object', object: 'user' }, - columns: ['name', 'email', 'role', 'title'], - filter: ['active', '=', true], - }, - }, - }, - // --- Event Views --- - { - listViews: { - all_events: { - name: 'all_events', - label: 'All Events', - type: 'grid', - data: { provider: 'object', object: 'event' }, - columns: ['subject', 'start', 'end', 'location', 'type', 'status'], - sort: [{ field: 'start', order: 'asc' }], - }, - calendar: { - name: 'calendar', - label: 'Calendar', - type: 'calendar', - data: { provider: 'object', object: 'event' }, - columns: ['subject', 'start', 'end', 'type'], - calendar: { - startDateField: 'start', - endDateField: 'end', - titleField: 'subject', - }, - }, - upcoming_meetings: { - name: 'upcoming_meetings', - label: 'Upcoming Meetings', - type: 'grid', - data: { provider: 'object', object: 'event' }, - columns: ['subject', 'start', 'location', 'organizer'], - filter: ['type', '=', 'meeting'], - sort: [{ field: 'start', order: 'asc' }], - }, - }, - }, - // --- Project Task Views --- - { - listViews: { - all_tasks: { - name: 'all_tasks', - label: 'All Tasks', - type: 'grid', - data: { provider: 'object', object: 'project_task' }, - columns: ['name', 'status', 'priority', 'start_date', 'end_date', 'progress', 'assignee'], - sort: [{ field: 'start_date', order: 'asc' }], - }, - board: { - name: 'board', - label: 'Board', - type: 'kanban', - data: { provider: 'object', object: 'project_task' }, - columns: ['name', 'priority', 'start_date', 'end_date'], - kanban: { - groupByField: 'status', - columns: ['name', 'priority', 'start_date', 'end_date'], - }, - }, - gantt: { - name: 'gantt', - label: 'Gantt', - type: 'gantt', - data: { provider: 'object', object: 'project_task' }, - columns: ['name', 'start_date', 'end_date', 'progress', 'status'], - }, - timeline: { - name: 'timeline', - label: 'Timeline', - type: 'timeline', - data: { provider: 'object', object: 'project_task' }, - columns: ['name', 'start_date', 'status'], - }, - }, - }, + AccountView, + ContactView, + OpportunityView, + ProductView, + OrderView, + UserView, + EventView, + ProjectView, ], reports: [], + actions: [ + ...AccountActions, + ...ContactActions, + ...OpportunityActions, + ...ProductActions, + ...OrderActions, + ...UserActions, + ...ProjectActions, + ...EventActions, + ], pages: [ { name: 'crm_help', diff --git a/examples/crm/src/actions/account.actions.ts b/examples/crm/src/actions/account.actions.ts new file mode 100644 index 0000000000..07051920c1 --- /dev/null +++ b/examples/crm/src/actions/account.actions.ts @@ -0,0 +1,37 @@ +export const AccountActions = [ + { + name: 'account_send_email', + label: 'Send Email', + icon: 'mail', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { name: 'to', label: 'To Email', type: 'email' as const, required: true }, + { name: 'subject', label: 'Subject', type: 'text' as const, required: true }, + { name: 'body', label: 'Message', type: 'textarea' as const }, + ], + successMessage: 'Email sent successfully', + }, + { + name: 'account_assign_owner', + label: 'Assign Owner', + icon: 'user-plus', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { name: 'owner_id', label: 'New Owner', type: 'lookup' as const, required: true }, + ], + refreshAfter: true, + successMessage: 'Owner assigned successfully', + }, + { + name: 'account_merge', + label: 'Merge Accounts', + icon: 'git-merge', + type: 'api' as const, + locations: ['record_more' as const], + confirmText: 'Are you sure you want to merge these accounts? This action cannot be undone.', + variant: 'danger' as const, + refreshAfter: true, + }, +]; diff --git a/examples/crm/src/actions/contact.actions.ts b/examples/crm/src/actions/contact.actions.ts new file mode 100644 index 0000000000..1a0a44926f --- /dev/null +++ b/examples/crm/src/actions/contact.actions.ts @@ -0,0 +1,37 @@ +export const ContactActions = [ + { + name: 'contact_send_email', + label: 'Send Email', + icon: 'mail', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { name: 'subject', label: 'Subject', type: 'text' as const, required: true }, + { name: 'body', label: 'Message', type: 'textarea' as const }, + ], + successMessage: 'Email sent successfully', + }, + { + name: 'contact_convert_to_customer', + label: 'Convert to Customer', + icon: 'user-check', + type: 'api' as const, + locations: ['record_header' as const], + confirmText: 'Convert this contact to a customer?', + refreshAfter: true, + successMessage: 'Contact converted to customer', + }, + { + name: 'contact_log_call', + label: 'Log a Call', + icon: 'phone', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { name: 'call_subject', label: 'Subject', type: 'text' as const, required: true }, + { name: 'call_notes', label: 'Notes', type: 'textarea' as const }, + { name: 'call_duration', label: 'Duration (min)', type: 'number' as const }, + ], + successMessage: 'Call logged successfully', + }, +]; diff --git a/examples/crm/src/actions/event.actions.ts b/examples/crm/src/actions/event.actions.ts new file mode 100644 index 0000000000..d2632d89d5 --- /dev/null +++ b/examples/crm/src/actions/event.actions.ts @@ -0,0 +1,38 @@ +export const EventActions = [ + { + name: 'event_send_invitation', + label: 'Send Invitation', + icon: 'send', + type: 'api' as const, + locations: ['record_header' as const], + params: [ + { name: 'message', label: 'Optional Message', type: 'textarea' as const }, + ], + successMessage: 'Invitation sent to all participants', + }, + { + name: 'event_mark_completed', + label: 'Mark as Completed', + icon: 'check-circle', + type: 'api' as const, + locations: ['record_header' as const], + confirmText: 'Mark this event as completed?', + refreshAfter: true, + successMessage: 'Event marked as completed', + }, + { + name: 'event_cancel', + label: 'Cancel Event', + icon: 'x-circle', + type: 'api' as const, + locations: ['record_more' as const], + variant: 'danger' as const, + params: [ + { name: 'cancel_reason', label: 'Cancellation Reason', type: 'text' as const }, + { name: 'notify_participants', label: 'Notify Participants', type: 'boolean' as const }, + ], + confirmText: 'Are you sure you want to cancel this event?', + refreshAfter: true, + successMessage: 'Event cancelled', + }, +]; diff --git a/examples/crm/src/actions/opportunity.actions.ts b/examples/crm/src/actions/opportunity.actions.ts new file mode 100644 index 0000000000..3d04da3bde --- /dev/null +++ b/examples/crm/src/actions/opportunity.actions.ts @@ -0,0 +1,48 @@ +export const OpportunityActions = [ + { + name: 'opportunity_change_stage', + label: 'Change Stage', + icon: 'arrow-right-circle', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { + name: 'new_stage', label: 'New Stage', type: 'select' as const, required: true, + options: [ + { label: 'Prospecting', value: 'prospecting' }, + { label: 'Qualification', value: 'qualification' }, + { label: 'Proposal', value: 'proposal' }, + { label: 'Negotiation', value: 'negotiation' }, + { label: 'Closed Won', value: 'closed_won' }, + { label: 'Closed Lost', value: 'closed_lost' }, + ], + }, + ], + refreshAfter: true, + successMessage: 'Stage updated successfully', + }, + { + name: 'opportunity_mark_won', + label: 'Mark as Won', + icon: 'trophy', + type: 'api' as const, + locations: ['record_header' as const], + variant: 'primary' as const, + confirmText: 'Mark this opportunity as Closed Won?', + refreshAfter: true, + successMessage: 'Opportunity marked as won!', + }, + { + name: 'opportunity_mark_lost', + label: 'Mark as Lost', + icon: 'x-circle', + type: 'api' as const, + locations: ['record_more' as const], + variant: 'danger' as const, + params: [ + { name: 'loss_reason', label: 'Reason for Loss', type: 'text' as const, required: true }, + ], + confirmText: 'Mark this opportunity as Closed Lost?', + refreshAfter: true, + }, +]; diff --git a/examples/crm/src/actions/order.actions.ts b/examples/crm/src/actions/order.actions.ts new file mode 100644 index 0000000000..432304632c --- /dev/null +++ b/examples/crm/src/actions/order.actions.ts @@ -0,0 +1,46 @@ +export const OrderActions = [ + { + name: 'order_change_status', + label: 'Change Status', + icon: 'refresh-cw', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { + name: 'new_status', label: 'New Status', type: 'select' as const, required: true, + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Pending', value: 'pending' }, + { label: 'Paid', value: 'paid' }, + { label: 'Shipped', value: 'shipped' }, + { label: 'Delivered', value: 'delivered' }, + { label: 'Cancelled', value: 'cancelled' }, + ], + }, + ], + refreshAfter: true, + successMessage: 'Order status updated', + }, + { + name: 'order_generate_invoice', + label: 'Generate Invoice', + icon: 'file-text', + type: 'api' as const, + locations: ['record_header' as const], + confirmText: 'Generate an invoice for this order?', + successMessage: 'Invoice generated successfully', + }, + { + name: 'order_mark_shipped', + label: 'Mark as Shipped', + icon: 'truck', + type: 'api' as const, + locations: ['record_header' as const], + params: [ + { name: 'tracking_number', label: 'Tracking Number', type: 'text' as const, required: true }, + { name: 'carrier', label: 'Carrier', type: 'text' as const }, + ], + refreshAfter: true, + successMessage: 'Order marked as shipped', + }, +]; diff --git a/examples/crm/src/actions/product.actions.ts b/examples/crm/src/actions/product.actions.ts new file mode 100644 index 0000000000..c5eae1e556 --- /dev/null +++ b/examples/crm/src/actions/product.actions.ts @@ -0,0 +1,23 @@ +export const ProductActions = [ + { + name: 'product_toggle_active', + label: 'Toggle Active', + icon: 'toggle-left', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + refreshAfter: true, + successMessage: 'Product status updated', + }, + { + name: 'product_update_price', + label: 'Update Price', + icon: 'dollar-sign', + type: 'api' as const, + locations: ['record_header' as const], + params: [ + { name: 'new_price', label: 'New Price', type: 'currency' as const, required: true }, + ], + refreshAfter: true, + successMessage: 'Price updated successfully', + }, +]; diff --git a/examples/crm/src/actions/project.actions.ts b/examples/crm/src/actions/project.actions.ts new file mode 100644 index 0000000000..2cf8621b18 --- /dev/null +++ b/examples/crm/src/actions/project.actions.ts @@ -0,0 +1,34 @@ +export const ProjectActions = [ + { + name: 'task_change_status', + label: 'Change Status', + icon: 'circle-check', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { + name: 'new_status', label: 'New Status', type: 'select' as const, required: true, + options: [ + { label: 'Planned', value: 'planned' }, + { label: 'In Progress', value: 'in_progress' }, + { label: 'Completed', value: 'completed' }, + { label: 'On Hold', value: 'on_hold' }, + ], + }, + ], + refreshAfter: true, + successMessage: 'Task status updated', + }, + { + name: 'task_assign', + label: 'Assign User', + icon: 'user-plus', + type: 'api' as const, + locations: ['record_header' as const, 'list_item' as const], + params: [ + { name: 'assignee_id', label: 'Assignee', type: 'lookup' as const, required: true }, + ], + refreshAfter: true, + successMessage: 'Task assigned successfully', + }, +]; diff --git a/examples/crm/src/actions/user.actions.ts b/examples/crm/src/actions/user.actions.ts new file mode 100644 index 0000000000..fac610f92a --- /dev/null +++ b/examples/crm/src/actions/user.actions.ts @@ -0,0 +1,22 @@ +export const UserActions = [ + { + name: 'user_reset_password', + label: 'Reset Password', + icon: 'key', + type: 'api' as const, + locations: ['record_header' as const, 'record_more' as const], + confirmText: 'Send a password reset link to this user?', + successMessage: 'Password reset email sent', + }, + { + name: 'user_deactivate', + label: 'Deactivate User', + icon: 'user-x', + type: 'api' as const, + locations: ['record_more' as const], + variant: 'danger' as const, + confirmText: 'Are you sure you want to deactivate this user?', + refreshAfter: true, + successMessage: 'User deactivated', + }, +]; diff --git a/examples/crm/src/index.ts b/examples/crm/src/index.ts index 8aba64c8b2..0bf19a7d69 100644 --- a/examples/crm/src/index.ts +++ b/examples/crm/src/index.ts @@ -6,4 +6,20 @@ export * from './objects/order.object'; export * from './objects/user.object'; export * from './objects/project.object'; export * from './objects/event.object'; +export * from './views/account.view'; +export * from './views/contact.view'; +export * from './views/opportunity.view'; +export * from './views/product.view'; +export * from './views/order.view'; +export * from './views/user.view'; +export * from './views/event.view'; +export * from './views/project.view'; +export * from './actions/account.actions'; +export * from './actions/contact.actions'; +export * from './actions/opportunity.actions'; +export * from './actions/product.actions'; +export * from './actions/order.actions'; +export * from './actions/user.actions'; +export * from './actions/project.actions'; +export * from './actions/event.actions'; export { default as config } from '../objectstack.config'; diff --git a/examples/crm/src/views/account.view.ts b/examples/crm/src/views/account.view.ts new file mode 100644 index 0000000000..a4098c50a5 --- /dev/null +++ b/examples/crm/src/views/account.view.ts @@ -0,0 +1,47 @@ +export const AccountView = { + listViews: { + all_accounts: { + name: 'all_accounts', + label: 'All Accounts', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'account' }, + columns: ['name', 'industry', 'type', 'annual_revenue', 'rating', 'owner'], + sort: [{ field: 'name', order: 'asc' as const }], + }, + active_accounts: { + name: 'active_accounts', + label: 'Active Customers', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'account' }, + columns: ['name', 'industry', 'annual_revenue', 'phone', 'owner'], + filter: ['type', '=', 'Customer'], + sort: [{ field: 'annual_revenue', order: 'desc' as const }], + }, + }, + form: { + data: { provider: 'object' as const, object: 'account' }, + sections: [ + { + label: 'Basic Information', + columns: '2' as const, + fields: ['name', 'industry', 'type', 'rating', 'website', 'phone', 'employees', 'owner'], + }, + { + label: 'Financial', + columns: '2' as const, + fields: ['annual_revenue', 'tags'], + }, + { + label: 'Address', + columns: '2' as const, + fields: ['billing_address', 'shipping_address', 'latitude', 'longitude'], + }, + { + label: 'Additional Details', + columns: '1' as const, + collapsible: true, + fields: ['linkedin_url', 'founded_date', 'description', 'created_at'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/contact.view.ts b/examples/crm/src/views/contact.view.ts new file mode 100644 index 0000000000..ca21e52fd9 --- /dev/null +++ b/examples/crm/src/views/contact.view.ts @@ -0,0 +1,46 @@ +export const ContactView = { + listViews: { + all_contacts: { + name: 'all_contacts', + label: 'All Contacts', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'contact' }, + columns: ['name', 'email', 'phone', 'title', 'account', 'status', 'priority'], + sort: [{ field: 'name', order: 'asc' as const }], + }, + active_contacts: { + name: 'active_contacts', + label: 'Active Contacts', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'contact' }, + columns: ['name', 'email', 'title', 'account', 'status'], + filter: ['is_active', '=', true], + }, + }, + form: { + data: { provider: 'object' as const, object: 'contact' }, + sections: [ + { + label: 'Personal Information', + columns: '2' as const, + fields: ['avatar', 'name', 'email', 'phone', 'title', 'department', 'company'], + }, + { + label: 'Account & Status', + columns: '2' as const, + fields: ['account', 'status', 'priority', 'lead_source', 'is_active', 'do_not_call'], + }, + { + label: 'Address & Social', + columns: '2' as const, + fields: ['address', 'linkedin', 'birthdate', 'latitude', 'longitude'], + }, + { + label: 'Notes', + columns: '1' as const, + collapsible: true, + fields: ['notes'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/event.view.ts b/examples/crm/src/views/event.view.ts new file mode 100644 index 0000000000..89821100c4 --- /dev/null +++ b/examples/crm/src/views/event.view.ts @@ -0,0 +1,59 @@ +export const EventView = { + listViews: { + all_events: { + name: 'all_events', + label: 'All Events', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'event' }, + columns: ['subject', 'start', 'end', 'location', 'type', 'status'], + sort: [{ field: 'start', order: 'asc' as const }], + }, + calendar: { + name: 'calendar', + label: 'Calendar', + type: 'calendar' as const, + data: { provider: 'object' as const, object: 'event' }, + columns: ['subject', 'start', 'end', 'type'], + calendar: { + startDateField: 'start', + endDateField: 'end', + titleField: 'subject', + }, + }, + upcoming_meetings: { + name: 'upcoming_meetings', + label: 'Upcoming Meetings', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'event' }, + columns: ['subject', 'start', 'location', 'organizer'], + filter: ['type', '=', 'meeting'], + sort: [{ field: 'start', order: 'asc' as const }], + }, + }, + form: { + data: { provider: 'object' as const, object: 'event' }, + sections: [ + { + label: 'Event Details', + columns: '2' as const, + fields: ['subject', 'type', 'status', 'location', 'is_all_day', 'is_private'], + }, + { + label: 'Schedule', + columns: '2' as const, + fields: ['start', 'end', 'reminder'], + }, + { + label: 'Participants', + columns: '2' as const, + fields: ['organizer', 'participants'], + }, + { + label: 'Description', + columns: '1' as const, + collapsible: true, + fields: ['description'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/opportunity.view.ts b/examples/crm/src/views/opportunity.view.ts new file mode 100644 index 0000000000..48f2baee4c --- /dev/null +++ b/examples/crm/src/views/opportunity.view.ts @@ -0,0 +1,57 @@ +export const OpportunityView = { + listViews: { + all: { + name: 'all', + label: 'All Opportunities', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'opportunity' }, + columns: ['name', 'amount', 'stage', 'close_date', 'probability', 'forecast_category'], + sort: [{ field: 'close_date', order: 'asc' as const }], + }, + pipeline: { + name: 'pipeline', + label: 'Pipeline', + type: 'kanban' as const, + data: { provider: 'object' as const, object: 'opportunity' }, + columns: ['name', 'amount', 'close_date', 'probability'], + kanban: { + groupByField: 'stage', + columns: ['name', 'amount', 'close_date'], + }, + }, + closing_this_month: { + name: 'closing_this_month', + label: 'Closing This Month', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'opportunity' }, + columns: ['name', 'amount', 'stage', 'close_date', 'probability'], + sort: [{ field: 'close_date', order: 'asc' as const }], + }, + }, + form: { + data: { provider: 'object' as const, object: 'opportunity' }, + sections: [ + { + label: 'Deal Information', + columns: '2' as const, + fields: ['name', 'account', 'contacts', 'type', 'lead_source', 'campaign_source'], + }, + { + label: 'Financials & Stage', + columns: '2' as const, + fields: ['amount', 'expected_revenue', 'probability', 'stage', 'forecast_category'], + }, + { + label: 'Timeline', + columns: '2' as const, + fields: ['close_date', 'next_step'], + }, + { + label: 'Description', + columns: '1' as const, + collapsible: true, + fields: ['description'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/order.view.ts b/examples/crm/src/views/order.view.ts new file mode 100644 index 0000000000..35561a17c8 --- /dev/null +++ b/examples/crm/src/views/order.view.ts @@ -0,0 +1,46 @@ +export const OrderView = { + listViews: { + all_orders: { + name: 'all_orders', + label: 'All Orders', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'order' }, + columns: ['name', 'customer', 'amount', 'status', 'order_date', 'payment_method'], + sort: [{ field: 'order_date', order: 'desc' as const }], + }, + pending_orders: { + name: 'pending_orders', + label: 'Pending Orders', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'order' }, + columns: ['name', 'customer', 'amount', 'order_date'], + filter: ['status', '=', 'pending'], + }, + }, + form: { + data: { provider: 'object' as const, object: 'order' }, + sections: [ + { + label: 'Order Information', + columns: '2' as const, + fields: ['name', 'customer', 'account', 'order_date', 'status', 'payment_method'], + }, + { + label: 'Financials', + columns: '2' as const, + fields: ['amount', 'discount'], + }, + { + label: 'Shipping', + columns: '2' as const, + fields: ['shipping_address', 'tracking_number'], + }, + { + label: 'Notes', + columns: '1' as const, + collapsible: true, + fields: ['notes'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/product.view.ts b/examples/crm/src/views/product.view.ts new file mode 100644 index 0000000000..60d649d237 --- /dev/null +++ b/examples/crm/src/views/product.view.ts @@ -0,0 +1,41 @@ +export const ProductView = { + listViews: { + all_products: { + name: 'all_products', + label: 'All Products', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'product' }, + columns: ['name', 'sku', 'category', 'price', 'stock', 'is_active'], + sort: [{ field: 'name', order: 'asc' as const }], + }, + active_products: { + name: 'active_products', + label: 'Active Products', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'product' }, + columns: ['name', 'sku', 'category', 'price', 'stock', 'tags'], + filter: ['is_active', '=', true], + }, + }, + form: { + data: { provider: 'object' as const, object: 'product' }, + sections: [ + { + label: 'Product Details', + columns: '2' as const, + fields: ['name', 'sku', 'category', 'manufacturer', 'is_active', 'tags'], + }, + { + label: 'Pricing & Inventory', + columns: '2' as const, + fields: ['price', 'stock', 'weight'], + }, + { + label: 'Media & Description', + columns: '1' as const, + collapsible: true, + fields: ['image', 'description'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/project.view.ts b/examples/crm/src/views/project.view.ts new file mode 100644 index 0000000000..2de660b690 --- /dev/null +++ b/examples/crm/src/views/project.view.ts @@ -0,0 +1,58 @@ +export const ProjectView = { + listViews: { + all_tasks: { + name: 'all_tasks', + label: 'All Tasks', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'project_task' }, + columns: ['name', 'status', 'priority', 'start_date', 'end_date', 'progress', 'assignee'], + sort: [{ field: 'start_date', order: 'asc' as const }], + }, + board: { + name: 'board', + label: 'Board', + type: 'kanban' as const, + data: { provider: 'object' as const, object: 'project_task' }, + columns: ['name', 'priority', 'start_date', 'end_date'], + kanban: { + groupByField: 'status', + columns: ['name', 'priority', 'start_date', 'end_date'], + }, + }, + gantt: { + name: 'gantt', + label: 'Gantt', + type: 'gantt' as const, + data: { provider: 'object' as const, object: 'project_task' }, + columns: ['name', 'start_date', 'end_date', 'progress', 'status'], + }, + timeline: { + name: 'timeline', + label: 'Timeline', + type: 'timeline' as const, + data: { provider: 'object' as const, object: 'project_task' }, + columns: ['name', 'start_date', 'status'], + }, + }, + form: { + data: { provider: 'object' as const, object: 'project_task' }, + sections: [ + { + label: 'Task Information', + columns: '2' as const, + fields: ['name', 'status', 'priority', 'color', 'manager', 'assignee'], + }, + { + label: 'Timeline & Progress', + columns: '2' as const, + fields: ['start_date', 'end_date', 'progress', 'estimated_hours', 'actual_hours'], + }, + { + label: 'Details', + columns: '1' as const, + collapsible: true, + fields: ['dependencies', 'description'], + }, + ], + }, +}; diff --git a/examples/crm/src/views/user.view.ts b/examples/crm/src/views/user.view.ts new file mode 100644 index 0000000000..18a4598245 --- /dev/null +++ b/examples/crm/src/views/user.view.ts @@ -0,0 +1,41 @@ +export const UserView = { + listViews: { + all_users: { + name: 'all_users', + label: 'All Users', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'user' }, + columns: ['name', 'email', 'role', 'department', 'active'], + sort: [{ field: 'name', order: 'asc' as const }], + }, + active_users: { + name: 'active_users', + label: 'Active Users', + type: 'grid' as const, + data: { provider: 'object' as const, object: 'user' }, + columns: ['name', 'email', 'role', 'title'], + filter: ['active', '=', true], + }, + }, + form: { + data: { provider: 'object' as const, object: 'user' }, + sections: [ + { + label: 'Profile', + columns: '2' as const, + fields: ['avatar', 'name', 'email', 'username', 'phone'], + }, + { + label: 'Role & Department', + columns: '2' as const, + fields: ['role', 'title', 'department', 'active'], + }, + { + label: 'Bio', + columns: '1' as const, + collapsible: true, + fields: ['bio'], + }, + ], + }, +};