How to Create Custom Collections in the Instatic Data Workspace
The Instatic data workspace enables custom collection creation through a React dialog component that submits table schemas to a persistence layer, instantiating new data tables via the createCmsDataTable API.
The Instatic admin panel provides a Data Workspace for managing dynamic content structures. This article explains how developers and content managers can create custom collections—essentially new database tables with defined schemas—through the coordinated interaction of UI components and persistence hooks. According to the CoreBunch/Instatic source code, this process centers on the NewTableDialog component and the useDataWorkspace hook.
Architectural Flow for Creating Custom Collections
The data workspace follows a strict unidirectional flow to ensure type safety and atomicity when creating custom collections.
Step 1: Initiating Creation via DataSidebar
The entry point begins in src/admin/pages/data/DataPage.tsx, where the workspace initializes the useDataWorkspace hook to load existing tables. The left-hand DataSidebar component renders a "Create collection" button that toggles the dialog state.
// In src/admin/pages/data/DataPage.tsx
const [newTableDialogOpen, setNewTableDialogOpen] = useState(false);
// Button rendered via DataSidebar
<Button onClick={() => setNewTableDialogOpen(true)}>Create collection</Button>
Step 2: Schema Composition in NewTableDialog
When triggered, src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsx renders a modal that collects the collection name and field definitions. It utilizes the shared FieldSchemaComposer component to build the initial schema array before submission.
// In src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsx
export function NewTableDialog({ open, onClose, tables, onCreate }) {
const [name, setName] = useState('');
const [fields, setFields] = useState<FieldDefinition[]>([]);
const handleSubmit = async () => {
await onCreate({
name,
slug: slugify(name),
fields, // Array generated by FieldSchemaComposer
});
onClose();
};
return (
<Dialog open={open} onClose={onClose}>
<DialogTitle>Create collection</DialogTitle>
<FieldSchemaComposer fields={fields} onChange={setFields} />
<Button onClick={handleSubmit}>Create</Button>
</Dialog>
);
}
Step 3: Persistence via createCmsDataTable
Upon confirmation, the dialog invokes workspace.createTable(), which calls createCmsDataTable() from the @core/persistence layer. This function inserts a new row into the data_tables database table and returns the created metadata.
Step 4: Reactive State Updates
The useDataWorkspace hook updates its local tables state with the new entry, clears existing rows, and sets the newly created table as selected, ensuring the UI reflects the new collection immediately.
// In src/admin/pages/data/hooks/useDataWorkspace.ts
const createTable = async (input: CreateDataTableInput): Promise<DataTable> => {
setTablesError(null);
const table = await createCmsDataTable(input); // Persistence layer call
setTables((current) => [...current, { ...table, rowCount: 0 }]);
setSelectedTableId(table.id);
setRows([]);
setSelectedRowId(null);
return table;
};
Implementation Code Examples
Consuming the Workspace Hook
Components access the creation logic through the useDataWorkspace hook, which isolates table management from presentation layers.
const workspace = useDataWorkspace({ shouldLoadRows: true });
const handleCreate = async (input) => {
await workspace.createTable(input); // Creates the custom collection
};
Handling Field Defaults
The workspace imports utility functions from src/admin/pages/data/utils/fieldDefaults.ts to generate default values for new fields, ensuring consistency across collections.
Key Source Files and Functions
src/admin/pages/data/DataPage.tsx: Orchestrates the workspace UI and dialog state management.src/admin/pages/data/hooks/useDataWorkspace.ts: Core hook exposingcreateTableand managing table/row state.src/admin/pages/data/components/DataSidebar/DataSidebar.tsx: Sidebar component containing the creation trigger button.src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsx: Modal dialog for collection name and schema input.src/admin/pages/data/components/FieldSchemaComposer/FieldSchemaComposer.tsx: Shared UI component for building field definitions.@core/persistence(createCmsDataTable): Server-side persistence function that writes to thedata_tablesdatabase.src/core/data/duplicateRow.ts: Utilities for row duplication logic within collections.src/admin/pages/data/utils/fieldDefaults.ts: Helper functions for generating default field values.
Summary
- The Data Workspace creates custom collections by combining React UI components with a typed persistence layer.
- NewTableDialog handles user input and schema composition before submitting to the
useDataWorkspacehook. - The createCmsDataTable function in the persistence layer handles the actual database insertion, ensuring atomic table creation.
- State management automatically updates the UI, selects the new collection, and clears stale row data to prevent inconsistencies.
- File paths like
src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsxandsrc/admin/pages/data/hooks/useDataWorkspace.tsdefine the critical integration points.
Frequently Asked Questions
What is a custom collection in Instatic?
A custom collection in Instatic represents a dynamically created data table defined in the data_tables schema. It consists of a unique slug, display name, and an array of field definitions that determine the structure of content entries stored within that collection.
How does the FieldSchemaComposer contribute to collection creation?
The FieldSchemaComposer component renders the UI for defining initial fields (such as text, number, or boolean types) before the collection is created. It generates the fields array passed to createTable, ensuring the new collection has a valid schema immediately upon instantiation.
Is the collection creation process atomic?
Yes. The creation process is atomic because createCmsDataTable handles both the database insertion and metadata return in a single operation. The useDataWorkspace hook only updates local React state after receiving confirmation from the persistence layer, preventing partial or failed creation states from appearing in the UI.
Can I customize the collection after initial creation?
Absolutely. After creation, the collection appears in the DataSidebar and can be selected for editing. The workspace supports schema modifications through the FieldSchemaComposer and allows adding, editing, or deleting rows via the data inspector panel, all synchronized through the same useDataWorkspace hook.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →