Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/ResourceEditor/edit-tab-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export function EditTabContent({
issueLineNumbers={issueLineNumbers}
getStructureDefinitions={getStructureDefinitions}
expandValueSet={expandValueSet}
resourceTypeHint={resourceType}
trailingActions={
!isProfileOpen && (
<HSComp.Toggle
Expand Down
3 changes: 3 additions & 0 deletions src/components/ResourceEditor/editor-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type EditorTabProps = {
issueLineNumbers?: { line: number; message?: string }[];
getStructureDefinitions?: GetStructureDefinitions;
expandValueSet?: ExpandValueSet;
resourceTypeHint?: string;
};

export const EditorTab = ({
Expand All @@ -36,6 +37,7 @@ export const EditorTab = ({
issueLineNumbers,
getStructureDefinitions,
expandValueSet,
resourceTypeHint,
}: EditorTabProps) => {
const vimMode = useVimMode();
return (
Expand Down Expand Up @@ -67,6 +69,7 @@ export const EditorTab = ({
getStructureDefinitions={getStructureDefinitions}
expandValueSet={expandValueSet}
vimMode={vimMode}
resourceTypeHint={resourceTypeHint}
/>
</div>
</div>
Expand Down
80 changes: 72 additions & 8 deletions src/components/rest/collections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ export async function SaveRequest(
saveToRootCollection?: boolean,
setLeftMenuOpen?: (open: boolean) => void,
) {
const currentSnippet = collectionEntries.find((entry) => entry.id === tab.id);
const targetId = tab.historyId ?? tab.id;
const currentSnippet = collectionEntries.find(
(entry) => entry.id === targetId,
);
let collection: string | undefined;
let snippetId: string;

Expand All @@ -74,10 +77,17 @@ export async function SaveRequest(
snippetId = generateId();
setTabs([
...tabs.map((t) => ({ ...t, selected: false })),
{ ...tab, id: snippetId, selected: true },
{ ...tab, id: snippetId, historyId: snippetId, selected: true },
]);
} else {
snippetId = tab.id;
snippetId = targetId;
// Bind the editor tab to the underlying snippet so subsequent edits
// update the same sidebar entry instead of spawning a new one.
if (tab.historyId !== snippetId) {
setTabs(
tabs.map((t) => (t.id === tab.id ? { ...t, historyId: snippetId } : t)),
);
}
}

const result = await client.update({
Expand Down Expand Up @@ -399,7 +409,19 @@ function CollectionMoreButton({
</ReactComponents.DropdownMenuTrigger>
<ReactComponents.DropdownMenuContent>
<ReactComponents.DropdownMenuItem
onClick={() => tree.getItemInstance(itemId).startRenaming()}
onClick={(e) => {
e.stopPropagation();
// Defer so the dropdown close completes before input is focused;
// otherwise the immediate blur aborts the rename. Also keep the
// folder expanded — closing it on rename hides children mid-edit.
setTimeout(() => {
const instance = tree.getItemInstance(itemId);
if (instance.isFolder() && !instance.isExpanded()) {
instance.expand();
}
instance.startRenaming();
}, 0);
}}
>
Rename
</ReactComponents.DropdownMenuItem>
Expand Down Expand Up @@ -480,10 +502,13 @@ function SnippetMoreButton({
</ReactComponents.DropdownMenuTrigger>
<ReactComponents.DropdownMenuContent>
<ReactComponents.DropdownMenuItem
onClick={() => {
if (itemData.meta?.id !== undefined) {
tree.getItemInstance(itemData.meta.id).startRenaming();
}
onClick={(e) => {
e.stopPropagation();
const id = itemData.meta?.id;
if (id === undefined) return;
// Defer so the dropdown close completes before input is focused;
// otherwise the immediate blur aborts the rename.
setTimeout(() => tree.getItemInstance(id).startRenaming(), 0);
}}
>
Rename
Expand Down Expand Up @@ -639,6 +664,14 @@ function customItemView(
className="h-5 border-none p-0"
autoFocus
{...item.getRenameInputProps()}
onBlur={(e) => {
const tree = item.getTree();
if (e.target.value.trim()) {
tree.completeRenaming();
} else {
tree.abortRenaming();
}
}}
/>
) : itemData?.meta?.title ? (
<div>{itemData.meta.title}</div>
Expand Down Expand Up @@ -881,6 +914,27 @@ export const CollectionsView = ({
/>
) : (
<div className="px-1 py-2">
{selectedTab && (
<button
type="button"
className="flex items-center gap-2 w-full pl-2.5 pr-2 py-1 typo-body text-text-secondary hover:text-text-primary cursor-pointer"
onClick={() =>
SaveRequest(
client,
selectedTab,
queryClient,
collectionEntries.data ?? [],
setSelectedCollectionItemId,
true,
setTabs,
tabs,
)
}
>
<Lucide.Plus className="size-4 shrink-0" />
<span>Create</span>
</button>
)}
<ReactComponents.TreeView
key={
queryClient.getQueryState(["rest-console-collections"])
Expand All @@ -891,6 +945,16 @@ export const CollectionsView = ({
expandedItems={expandedItems}
onExpandedItemsChange={setExpandedItems}
onRename={(item, newTitle) => {
if (item.isFolder()) {
const oldId = item.getId();
// Carry collapsed state over to the new folder id so the
// rename does not visually expand a previously-closed folder.
if (collapsedItems.includes(oldId)) {
setCollapsedItems(
collapsedItems.map((id) => (id === oldId ? newTitle : id)),
);
}
}
handleRenameSnippet(client, item, newTitle, queryClient);
}}
onItemLabelClick={(item) => {
Expand Down
21 changes: 21 additions & 0 deletions src/routes/rest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
Play,
SquareTerminalIcon,
Timer,
X,
} from "lucide-react";
import type React from "react";
import {
Expand Down Expand Up @@ -749,6 +750,7 @@ type ResponsePaneProps = {
sendVersion: number;
onExplainSubTabChange: (subTab: "query" | "statement" | "plan") => void;
onFollowContentLocation?: (path: string) => void;
onClearResponse?: () => void;
};

function ResponseInfo({ response }: { response: ResponseData }) {
Expand Down Expand Up @@ -1178,6 +1180,7 @@ function ResponsePane({
sendVersion,
onExplainSubTabChange,
onFollowContentLocation,
onClearResponse,
}: ResponsePaneProps) {
// Use response mode from the response itself (set at request time)
const responseMode = response?.mode || "json";
Expand Down Expand Up @@ -1214,6 +1217,21 @@ function ResponsePane({
onToggle={(state) => onFullScreenToggle(state)}
state={fullScreenState}
/>
{response && onClearResponse && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="small"
aria-label="Clear response"
onClick={onClearResponse}
>
<X className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Clear response</TooltipContent>
</Tooltip>
)}
</div>
</div>
<div className="flex-1 min-h-0 overflow-hidden">
Expand Down Expand Up @@ -2341,6 +2359,9 @@ function RouteComponent() {
aidboxClient={client}
sendVersion={sendVersion}
onExplainSubTabChange={handleExplainSubTabChange}
onClearResponse={() =>
responseStorage.delete(selectedTab.id)
}
onFollowContentLocation={(contentPath) => {
const updatedTab = {
...selectedTab,
Expand Down