Examples
Simple List Example
A minimal example of a list page with basic CRUD operations.
Complete Example
1. DataSource Definition
// src/lib/server/ds/defs/EntityDS.ts
import type { DataSource } from '@wayvo-ai/core/common';
import { DefaultAttribute, DefaultDataSource, DefaultFullAccess } from '@wayvo-ai/core/ds';
export interface Entity {
id: string;
name: string;
description?: string;
createdAt: string;
}
export const EntityDataSource: DataSource<Entity> = {
...DefaultDataSource,
id: 'Entity',
tableName: 'entities',
attributes: [
{
...DefaultAttribute,
code: 'id',
name: 'ID',
type: 'Text',
column: 'id',
maxLength: 40,
primary: true,
defaultValue: 'ULID',
},
{
...DefaultAttribute,
code: 'name',
name: 'Name',
type: 'Text',
column: 'name',
maxLength: 120,
optional: false,
},
{
...DefaultAttribute,
code: 'description',
name: 'Description',
type: 'Text',
column: 'description',
maxLength: 500,
},
{
...DefaultAttribute,
code: 'createdAt',
name: 'Created At',
type: 'Date',
column: 'created_at',
optional: false,
},
],
access: [
{
...DefaultFullAccess,
roleCode: 'all_users',
},
],
};
2. Type Definition
// src/lib/common/ds/types/Entity.ts
export interface Entity {
id: string;
name: string;
description?: string;
createdAt: string;
}
3. Store Hook
// src/app/(secure)/entities/hooks/use-store.ts
import { useStore } from '@wayvo-ai/core/client';
import type { Entity } from '@/lib/common/ds/types/Entity';
export function useEntityStore() {
return useStore<Entity>({
datasourceId: 'Entity',
page: 'entity-page',
alias: 'entity-list',
limit: 20,
includeCount: true,
autoQuery: true,
sort: { createdAt: -1 },
});
}
4. Table Columns
// src/app/(secure)/entities/hooks/use-table-columns.tsx
import type { Store } from '@wayvo-ai/core/common';
import type { Entity } from '@/lib/common/ds/types/Entity';
import type { AccessorKeyColumnDef } from '@tanstack/react-table';
import { HeaderCell, TableCell } from '@wayvo-ai/core/ui';
import { useMemo } from 'react';
export default function useTableColumns(store: Store<Entity>): AccessorKeyColumnDef<Entity>[] {
return useMemo(
() => [
{
accessorKey: 'name',
header: (props) => <HeaderCell {...props} type="Text" store={store} accessorKey="name" title="Name" />,
cell: (props) => <TableCell type="Text" attributeCode="name" {...props} />,
},
{
accessorKey: 'description',
header: (props) => (
<HeaderCell {...props} type="Text" store={store} accessorKey="description" title="Description" />
),
cell: (props) => <TableCell type="Text" attributeCode="description" {...props} />,
},
],
[store],
);
}
5. Smart Search Columns
// src/app/(secure)/entities/hooks/smart-search-columns.ts
import type { Column } from '@wayvo-ai/core/ui/smart-search';
import type { Entity } from '@/lib/common/ds/types/Entity';
export default function useSmartSearchColumns(): Column<Entity>[] {
return [
{
key: 'name',
label: 'Name',
type: 'Text',
defaultOperator: 'is',
},
{
key: 'description',
label: 'Description',
type: 'Text',
defaultOperator: 'contains',
},
];
}
6. Edit Form
// src/app/(secure)/entities/components/edit-form.tsx
'use client';
import { TextInput } from '@wayvo-ai/core/ui';
import { useCurrentRowSync } from '@wayvo-ai/core/ui';
import type { Store } from '@wayvo-ai/core/common';
import type { Entity } from '@/lib/common/ds/types/Entity';
export function EditForm({ store }: { store: Store<Entity> }) {
const row = useCurrentRowSync(store);
if (!row) return null;
return (
<div className="grid gap-4 p-4">
<TextInput
label="Name"
value={row.name || ''}
onChange={(value) => store.setValue('name', value)}
required
/>
<TextInput
label="Description"
value={row.description || ''}
onChange={(value) => store.setValue('description', value)}
/>
</div>
);
}
7. Page Content
// src/app/(secure)/entities/page-content.tsx
'use client';
import { PageLayoutTemplate } from '@wayvo-ai/core/ui';
import { FileText } from 'lucide-react';
import { useEntityStore } from './hooks/use-store';
import useTableColumns from './hooks/use-table-columns';
import useSmartSearchColumns from './hooks/smart-search-columns';
import { EditForm } from './components/edit-form';
export default function EntityPageContent() {
const store = useEntityStore();
const tableColumns = useTableColumns(store);
const smartSearchColumns = useSmartSearchColumns();
return (
<PageLayoutTemplate
title="Entities"
subTitle="Manage your entities"
icon={<FileText className="h-12 w-12 text-muted-foreground" />}
store={store}
smartSearchColumns={smartSearchColumns}
tableColumns={tableColumns}
pageId="entity-page"
itemId="entity"
editForm={<EditForm store={store} />}
getDefaultRow={() => ({})}
addNewButtonText="Add Entity"
/>
);
}
8. Page Entry Point
// src/app/(secure)/entities/page.tsx
'use client';
import { PageShell } from '@wayvo-ai/core/ui';
import dynamic from 'next/dynamic';
const PageContent = dynamic(() => import('./page-content'), { ssr: false });
export default function EntityPage() {
return (
<PageShell title="Entities" noPadding>
<PageContent />
</PageShell>
);
}
What This Provides
- ✅ List view with pagination
- ✅ Search and filtering
- ✅ Add/Edit dialog
- ✅ Automatic data synchronization
- ✅ Type-safe throughout
Next Steps
- CRUD Form Example - More complex form example
- Filtered Table Example - Advanced filtering