fix: record default view selection T713#2304
Conversation
11ee377 to
aa6008b
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes an issue with default view selection when navigating to table pages with record IDs (T713). The main changes focus on improving URL query string handling and filtering out form views when a record ID is present in the query parameters.
Key changes:
- Enhanced query string handling to avoid appending empty query strings to redirect URLs
- Modified default view selection logic to exclude form views when a record ID is present
- Refactored tree rendering in BaseNodeTree to separate view and edit modes
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
apps/nextjs-app/src/pages/base/[baseId]/[[...slug]].tsx |
Fixed query string handling to avoid appending ? when query string is empty |
apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseNodeTree.tsx |
Split tree rendering into separate functions for view and edit modes, added border styling fix |
apps/nextjs-app/src/features/app/base-node/TablePage.tsx |
Enhanced default view selection to filter out form views when record ID is present, improved query string handling |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseNodeTree.tsx:840
- There is significant code duplication between renderViewTree and renderEditTree functions. Both functions share nearly identical tree rendering logic (ScrollArea, Tree, TreeItem structure, ItemIcon, ItemStatus, name handling). Consider extracting the common tree item rendering logic into a shared component or helper function, parameterized by the edit mode differences (e.g., editing input, additional action buttons).
const renderViewTree = () => {
return (
<ScrollArea
viewportRef={viewportRef}
className="flex w-full !border-none px-2 [&>[data-radix-scroll-area-viewport]>div]:!block [&>[data-radix-scroll-area-viewport]>div]:!min-w-0"
scrollBar="none"
>
<Tree indent={INDENTATION_WIDTH} tree={tree} className="py-1">
<AssistiveTreeDescription tree={tree} />
{tree.getItems().map((item) => {
const nodeId = item.getId();
const node = item.getItemData();
if (!node || Object.keys(node).length === 0) return null;
const { resourceType, resourceId } = node;
const name = getNodeName(node);
const isPinned = pinMap?.[resourceId];
return (
<TreeItem asChild key={nodeId} item={item}>
<div className="h-8 w-full cursor-pointer">
<TreeItemLabel className={cn('size-full min-w-0 py-0')}>
<div className="flex min-w-0 flex-1 items-center gap-2">
<ItemIcon item={item} />
<div className="flex min-w-0 grow items-center gap-1" title={name}>
<span className="truncate text-left">{name}</span>
<ItemStatus item={item} />
{
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
<div
onClick={(e) => {
e.stopPropagation();
}}
className={cn('flex shrink-0 cursor-pointer items-center', {
'w-0 group-hover:w-auto': !isPinned,
})}
>
<BaseNodeStarButton
resourceType={resourceType}
resourceId={resourceId}
/>
</div>
}
</div>
</div>
</TreeItemLabel>
</div>
</TreeItem>
);
})}
<TreeDragLine />
</Tree>
<ScrollBar className="z-30" />
</ScrollArea>
);
};
const renderEditTree = () => {
return (
<ScrollArea
viewportRef={viewportRef}
className={cn(
'flex w-full px-2 [&>[data-radix-scroll-area-viewport]>div]:!block [&>[data-radix-scroll-area-viewport]>div]:!min-w-0',
{
'!border-none': canCreateResource,
}
)}
scrollBar="none"
>
<Tree indent={INDENTATION_WIDTH} tree={tree} className="py-1">
<AssistiveTreeDescription tree={tree} />
{tree.getItems().map((item) => {
const nodeId = item.getId();
const node = item.getItemData();
if (!node || Object.keys(node).length === 0) return null;
const { resourceType, resourceId } = node;
const name = getNodeName(node);
const isHighlighted = isEditMode && highlightedTableId === resourceId;
const isPinned = pinMap?.[resourceId];
return (
<TreeItem asChild key={nodeId} item={item}>
<div className="h-8 w-full cursor-pointer">
<TreeItemLabel
className={cn('size-full min-w-0 py-0', {
'bg-orange-300/40 hover:bg-orange-300/40': isHighlighted,
})}
>
<div className="flex min-w-0 flex-1 items-center gap-2">
{editingNodeId === nodeId ? (
<Input
ref={inputRef}
type="text"
placeholder="name"
defaultValue={item.getItemName()}
style={{
boxShadow: 'none',
}}
className="round-none size-full cursor-text bg-background outline-none"
onKeyDown={(e) => {
if (e.key === 'Enter') {
const newVal = e.currentTarget.value;
if (newVal && newVal !== item.getItemName()) {
curdHooks.updateNode(nodeId, { name: newVal });
}
setEditingNodeId(null);
} else if (e.key === 'Escape') {
setEditingNodeId(null);
}
}}
onClick={(e) => {
e.stopPropagation();
}}
onMouseDown={(e) => {
e.stopPropagation();
}}
/>
) : (
<>
<ItemIcon item={item} />
<div className="flex min-w-0 grow items-center gap-1" title={name}>
<span
className="truncate text-left"
onDoubleClick={() => {
setEditingNodeId(nodeId);
}}
>
{name}
</span>
<ItemStatus item={item} />
</div>
{
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
<div
onClick={(e) => {
e.stopPropagation();
}}
className={cn('flex shrink-0 cursor-pointer items-center gap-2', {
'w-0 group-hover:w-auto': !isPinned,
})}
>
<div className="opacity-0 group-hover:opacity-100 group-data-[folder=false]:hidden">
{canCreateResource && (
<BaseNodeAddResourceButton
curdHooks={curdHooks}
parentId={nodeId === ROOT_ID ? undefined : nodeId}
canCreateFolder={
canCreateFolder && checkCanCreateFolder(item, maxFolderDepth)
}
canCreateTable={canCreateTable}
canCreateDashboard={canCreateDashboard}
canCreateWorkflow={canCreateWorkflow}
canCreateApp={canCreateApp}
>
<Button variant={'ghost'} size={'xs'} className="size-4 p-0">
<AddBoldIcon className="size-full" />
</Button>
</BaseNodeAddResourceButton>
)}
</div>
{
<BaseNodeStarButton
resourceType={resourceType}
resourceId={resourceId}
/>
}
<div className="opacity-0 group-hover:opacity-100 ">
<BaseNodeMore
resourceType={resourceType}
resourceId={resourceId}
className="size-4 shrink-0 sm:opacity-0 sm:group-hover:opacity-100"
onRename={() => setEditingNodeId(nodeId)}
onDelete={async (permanent: boolean, confirm: boolean = true) => {
const titleMap = {
[BaseNodeResourceType.Folder]: t('common:noun.folder'),
[BaseNodeResourceType.Table]: t('common:noun.table'),
[BaseNodeResourceType.Dashboard]: t('common:noun.dashboard'),
[BaseNodeResourceType.Workflow]: t('common:noun.automation'),
[BaseNodeResourceType.App]: t('common:noun.app'),
};
const result = !confirm
? true
: await comfirmModal({
title: `${t('common:actions.delete')} ${(titleMap[resourceType] ?? '').toLowerCase()}`,
description: t('common:actions.deleteTip', {
name,
}),
confirmText: t('common:actions.delete'),
cancelText: t('common:actions.cancel'),
confirmButtonVariant: 'destructive',
});
if (result) {
await curdHooks.deleteNode(nodeId, permanent);
}
}}
onDuplicate={async (ro?: IDuplicateBaseNodeRo) => {
await curdHooks.duplicateNode(nodeId, {
name,
...(ro ?? {}),
});
}}
/>
</div>
</div>
}
</>
)}
</div>
</TreeItemLabel>
</div>
</TreeItem>
);
})}
<TreeDragLine />
</Tree>
<ScrollBar className="z-30" />
</ScrollArea>
);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🧹 Preview Environment Cleanup
|
* fix: improve query handling in TablePage component T713 * refactor: enhance BaseNodeTree component with improved rendering logic and styling adjustments * refactor: improve view selection logic in TablePage component
Related Issues: T713