= ({
)}
+ {/* Record count status bar (Airtable-style) */}
+ {!loading && data.length > 0 && (
+
+ {data.length} {data.length === 1 ? 'record' : 'records'}
+
+ )}
+
{/* Navigation Overlay (drawer/modal/popover) */}
{navigation.isOverlay && (
{
renderWithProvider();
expect(screen.queryByTestId('share-button')).not.toBeInTheDocument();
});
+
+ it('should show record count bar when data is loaded', async () => {
+ const mockItems = [
+ { _id: '1', name: 'Alice', email: 'alice@test.com' },
+ { _id: '2', name: 'Bob', email: 'bob@test.com' },
+ { _id: '3', name: 'Charlie', email: 'charlie@test.com' },
+ ];
+ mockDataSource.find.mockResolvedValue(mockItems);
+
+ const schema: ListViewSchema = {
+ type: 'list-view',
+ objectName: 'contacts',
+ viewType: 'grid',
+ fields: ['name', 'email'],
+ };
+
+ renderWithProvider();
+
+ await vi.waitFor(() => {
+ expect(screen.getByTestId('record-count-bar')).toBeInTheDocument();
+ });
+ expect(screen.getByText('3 records')).toBeInTheDocument();
+ });
+
+ it('should not show record count bar when no data', async () => {
+ mockDataSource.find.mockResolvedValue([]);
+
+ const schema: ListViewSchema = {
+ type: 'list-view',
+ objectName: 'contacts',
+ viewType: 'grid',
+ fields: ['name', 'email'],
+ };
+
+ renderWithProvider();
+
+ await vi.waitFor(() => {
+ expect(screen.getByTestId('empty-state')).toBeInTheDocument();
+ });
+ expect(screen.queryByTestId('record-count-bar')).not.toBeInTheDocument();
+ });
});
diff --git a/packages/types/src/data-display.ts b/packages/types/src/data-display.ts
index 63fdd74193..1e5c331509 100644
--- a/packages/types/src/data-display.ts
+++ b/packages/types/src/data-display.ts
@@ -424,6 +424,15 @@ export interface DataTableSchema extends BaseSchema {
* @default false
*/
showRowNumbers?: boolean;
+ /**
+ * Show "+ Add record" row at the bottom of the table (Airtable-style)
+ * @default false
+ */
+ showAddRow?: boolean;
+ /**
+ * Callback when the "+ Add record" row is clicked
+ */
+ onAddRecord?: () => void;
/**
* Column resize handler
* Called when a column is resized
diff --git a/packages/types/src/zod/objectql.zod.ts b/packages/types/src/zod/objectql.zod.ts
index a2bd63c669..835b1cae2d 100644
--- a/packages/types/src/zod/objectql.zod.ts
+++ b/packages/types/src/zod/objectql.zod.ts
@@ -73,6 +73,10 @@ export const ListColumnSchema = z.object({
type: z.string().optional().describe('Renderer type override'),
link: z.boolean().optional().describe('Functions as the primary navigation link (triggers View navigation)'),
action: z.string().optional().describe('Registered Action ID to execute when clicked'),
+ prefix: z.object({
+ field: z.string().describe('Field name to render as prefix'),
+ type: z.enum(['badge', 'text']).optional().describe('Renderer type for the prefix'),
+ }).optional().describe('Prefix configuration for compound cell rendering (Airtable-style)'),
});
/**