Skip to content

Conversation

@abdotop
Copy link
Member

@abdotop abdotop commented Jan 16, 2026

feat(Dep..Page.tsx): Add functionality to view individual table row details in a resizable drawer.

@abdotop abdotop self-assigned this Jan 16, 2026
Copilot AI review requested due to automatic review settings January 16, 2026 03:04
@abdotop abdotop linked an issue Jan 16, 2026 that may be closed by this pull request
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds functionality to view individual table row details in a resizable drawer. When users click on a table row, it opens a side drawer displaying all the row's fields with their values in a formatted view.

Changes:

  • Added row click functionality to open a drawer with detailed row information
  • Implemented a new RowDetails component to display individual row data
  • Refactored the Drawer component to support child content and be resizable
  • Added a new API signal for fetching individual row details

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const schema = api['GET/api/deployment/schema'].signal()
// API signal for table data
export const tableData = api['POST/api/deployment/table/data'].signal()
export const rowDetailsData = api['POST/api/deployment/table/data'].signal()
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two separate signals (tableData and rowDetailsData) are created from the same API endpoint. This means they will have independent state and cache. If the same row exists in both datasets, they could become out of sync. Consider reusing the tableData signal or implementing a shared cache mechanism to avoid inconsistencies.

Suggested change
export const rowDetailsData = api['POST/api/deployment/table/data'].signal()
export const rowDetailsData = tableData

Copilot uses AI. Check for mistakes.
Comment on lines +333 to +336
const tableName = url.params.table || schema.data?.tables?.[0]?.table
const tableDef = schema.data?.tables?.find((t) => t.table === tableName)
const pk = tableDef?.columns?.[0]?.name
const rowId = pk ? String(row[pk]) : undefined
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for determining the primary key and table name is duplicated in both the DataRow component (lines 333-336) and the effect that fetches row details (lines 1082-1084). Consider extracting this logic into a shared helper function to improve maintainability and ensure consistency.

Copilot uses AI. Check for mistakes.
return (
<A
params={{ drawer: 'view-row', 'row-id': rowId }}
class='contents'
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The clickable row lacks keyboard accessibility. Users navigating with keyboard cannot activate the row since the anchor tag is styled with 'contents' which makes it invisible to keyboard navigation. Add tabIndex={0} to the anchor or consider using a button element with proper keyboard event handlers to ensure the feature is accessible to keyboard users.

Suggested change
class='contents'
class='contents'
tabIndex={0}

Copilot uses AI. Check for mistakes.
Comment on lines +336 to +337
const rowId = pk ? String(row[pk]) : undefined

Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the primary key is not found or is undefined, clicking the row will navigate with a 'row-id' parameter set to 'undefined'. This will trigger the effect at line 1077 but won't fetch valid data. Consider disabling the link or not rendering it when rowId is undefined to prevent invalid navigation.

Suggested change
const rowId = pk ? String(row[pk]) : undefined
const rowId = pk && row[pk] != null ? String(row[pk]) : undefined
if (!rowId) {
return (
<tr class='hover:bg-base-200/50'>
<RowNumberCell index={index} />
{columns.map((key, i) => (
<td key={i} class='align-top min-w-[8rem] max-w-[20rem]'>
<TableCell value={row[key]} />
</td>
))}
</tr>
)
}

Copilot uses AI. Check for mistakes.
limit: 1,
offset: 0,
})
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The effect doesn't clean up or reset rowDetailsData when the row-id parameter is removed. This means stale data from a previously viewed row may still be displayed if the drawer is reopened. Consider clearing rowDetailsData when rowId becomes null or undefined.

Suggested change
}
}
} else {
// Clear row details when there is no selected row to avoid stale data
rowDetailsData.data = undefined
if ('error' in rowDetailsData) {
rowDetailsData.error = undefined as typeof rowDetailsData.error
}

Copilot uses AI. Check for mistakes.
) => {
const tableName = url.params.table || schema.data?.tables?.[0]?.table
const tableDef = schema.data?.tables?.find((t) => t.table === tableName)
const pk = tableDef?.columns?.[0]?.name
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption that the first column is the primary key may not always be correct. Many databases have primary keys defined by constraints rather than column order. Consider using schema metadata to identify the actual primary key column, or add a fallback mechanism to handle tables where the first column is not the primary key.

Suggested change
const pk = tableDef?.columns?.[0]?.name
const pkColumn =
// Prefer an explicit primary key flag if present in the column metadata.
(tableDef?.columns as any[])?.find(
(c) =>
('isPrimaryKey' in c && c.isPrimaryKey) ||
('primaryKey' in c && c.primaryKey) ||
('pk' in c && c.pk),
) ?? tableDef?.columns?.[0]
const pk = (pkColumn as any)?.name as string | undefined

Copilot uses AI. Check for mistakes.
</div>
)}
<div
class='bg-base-200 text-base-content h-full flex flex-col resize-x overflow-auto pointer-events-auto'
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resizable drawer implementation using CSS resize-x property may not provide a good user experience across all browsers. The resize handle is often subtle and difficult to discover. Consider implementing a custom resize handle with a visible drag indicator or using a dedicated resize library for better cross-browser compatibility and user experience.

Copilot uses AI. Check for mistakes.
Comment on lines +1082 to +1083
const tableName = url.params.table || schema.data?.tables?.[0]?.table
const tableDef = schema.data?.tables?.find((t) => t.table === tableName)
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The effect fetches row details whenever dep and rowId are present, but it doesn't validate whether the schema data is loaded. If schema.data is not yet available, tableName and pk will be undefined, causing the fetch to be skipped silently. Consider adding a check for schema.data availability or showing a loading state while the schema is being fetched.

Suggested change
const tableName = url.params.table || schema.data?.tables?.[0]?.table
const tableDef = schema.data?.tables?.find((t) => t.table === tableName)
// Ensure schema data is loaded before attempting to derive table/primary key
if (!schema.data || !schema.data.tables || schema.data.tables.length === 0) {
return
}
const tableName = url.params.table || schema.data.tables[0]?.table
const tableDef = schema.data.tables.find((t) => t.table === tableName)

Copilot uses AI. Check for mistakes.
Comment on lines 1178 to 1180
}
}}
/>
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When closing the drawer via the checkbox onChange handler, only the 'drawer' parameter is cleared, but not the 'row-id' parameter. This leaves the row-id in the URL even after the drawer is closed, which could cause confusion or unexpected behavior if the user reopens the drawer. Ensure 'row-id' is also cleared when closing the drawer.

Copilot uses AI. Check for mistakes.
Comment on lines +1059 to +1075
const schemaPanel = <SchemaPanel />
const TabViews = {
tables: (
<div class='flex flex-1 h-full'>
{schemaPanel}
<DataTable />
</div>
),
queries: (
<div class='flex flex-1 h-full'>
{schemaPanel}
<QueryEditor />
</div>
),
logs: <LogsViewer />,
// Add other tab views here as needed
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TabViews constant and its associated schemaPanel variable have been moved from after the Drawer component to before it. While this doesn't affect functionality due to hoisting, it breaks the logical flow of the code where components are typically defined before they're used. Consider keeping related component definitions together for better code organization.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Visualize single row data in drawer view

2 participants