Skip to content
Open
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
170b16e
API visual first pass
royendo Feb 3, 2026
b50943c
nit
royendo Feb 3, 2026
737d298
args
royendo Feb 3, 2026
05a5b87
simpler, prettier
royendo Feb 3, 2026
8614d13
web code qual
royendo Feb 3, 2026
74ad9bb
code qual
royendo Feb 3, 2026
cd82c30
Update VisualAPIEditor.svelte
royendo Feb 3, 2026
7cc6139
Update VisualAPIEditor.svelte
royendo Feb 3, 2026
a96efa5
fixed heights and JSON view
royendo Feb 3, 2026
08b2ef7
prettier
royendo Feb 3, 2026
2d1f1f5
code qual
royendo Feb 3, 2026
0a45bdc
Update APIWorkspace.svelte
royendo Feb 3, 2026
7d6e002
Merge branch 'main' into feat/visual-editor-api
royendo Feb 20, 2026
425ecfb
Update errors.ts
royendo Feb 20, 2026
83779f2
themeing css
royendo Feb 20, 2026
05d2383
remove viz editor, consolidate tests into text editor
royendo Mar 5, 2026
563a773
Merge branch 'main' into feat/visual-editor-api
royendo Mar 5, 2026
813ad67
rename
royendo Mar 5, 2026
c34565b
reset review on nav
royendo Mar 5, 2026
8272f9b
reset
royendo Mar 5, 2026
1dbc8f3
template overwrites
royendo Mar 5, 2026
b04e4b9
local PR reviews
royendo Mar 5, 2026
c63a253
Remove unused `mapParseErrorsToLines` import in `+page.svelte`
royendo Mar 11, 2026
a6f6529
Merge branch 'main' into feat/visual-editor-api
royendo Mar 11, 2026
c1ff4d6
importing runtime changes
royendo Mar 11, 2026
2c5ec94
Merge remote-tracking branch 'origin/main' into feat/visual-editor-api
royendo Mar 30, 2026
4b68698
migration svelte/vite
royendo Mar 30, 2026
08af507
prettier
royendo Mar 30, 2026
e670982
prettier
royendo Mar 30, 2026
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
Prev Previous commit
Next Next commit
prettier
  • Loading branch information
royendo committed Mar 30, 2026
commit 08af507758bbb4c4d17810184f154a89489b4f1e
150 changes: 80 additions & 70 deletions web-common/src/features/apis/editor/APITestPanel.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<script lang="ts">
import Button from "@rilldata/web-common/components/button/Button.svelte";
import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu";
import Input from "@rilldata/web-common/components/forms/Input.svelte";
import Trash from "@rilldata/web-common/components/icons/Trash.svelte";
import Resizer from "@rilldata/web-common/layout/Resizer.svelte";
import { copyToClipboard } from "@rilldata/web-common/lib/actions/copy-to-clipboard";
import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte";
import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte";
import { PlusIcon, PlayIcon, ChevronDownIcon, CopyIcon } from "lucide-svelte";
import {
PlusIcon,
PlayIcon,
ChevronDownIcon,
ChevronRightIcon,
CopyIcon,
} from "lucide-svelte";
import { tick } from "svelte";
import APIResponsePreview from "./APIResponsePreview.svelte";
import type { Arg } from "./types";
Expand All @@ -22,7 +27,8 @@
let apiResponse: unknown[] | null = null;
let responseError: string | null = null;
let isLoading = false;
let previewHeight = 300;
let previewHeight = 500;
let argsOpen = false;

// Clear response and args when switching to a different API
$: apiName, resetState();
Expand Down Expand Up @@ -139,81 +145,34 @@
>
<Resizer max={500} direction="NS" side="top" bind:dimension={previewHeight} />

<div class="flex items-center gap-x-3 px-3 py-2 border-b">
<div class="flex items-center gap-x-2 flex-1 min-w-0">
<span class="text-xs font-medium text-fg-secondary shrink-0">URL Preview: </span>
<span class="text-[11px] font-mono text-fg-muted truncate">{fullUrl}</span>
</div>

<div class="flex items-center gap-x-2 px-3 py-2 border-b">
<span class="text-xs font-medium text-fg-primary uppercase tracking-wide"
>URL Preview: </span>
<span class="text-[11px] font-mono text-fg-muted truncate flex-1 min-w-0"
>{fullUrl}</span
>
<div class="flex items-center gap-x-2 shrink-0">
<Tooltip distance={8}>
<Button type="text" compact small onClick={handleCopyUrl}>
<CopyIcon size="10px" />
</Button>
<TooltipContent slot="tooltip-content">Copy URL</TooltipContent>
</Tooltip>

<DropdownMenu.Root closeOnItemClick={false}>
<DropdownMenu.Trigger>
{#snippet child({ props })}
<Button {...props} type="text" compact small>
Args
{#if args.length > 0}
<span
class="inline-flex items-center justify-center w-4 h-4 text-[10px] font-medium bg-surface-active text-fg-accent rounded-full"
>
{args.length}
</span>
{/if}
<ChevronDownIcon size="10px" />
</Button>
{/snippet}
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end" class="w-96 p-3">
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="args-container flex flex-col gap-y-2"
onkeydown={handleArgsKeydown}
<Button type="text" small compact onClick={() => (argsOpen = !argsOpen)}>
{#if argsOpen}
<ChevronDownIcon size="12px" />
{:else}
<ChevronRightIcon size="12px" />
{/if}
Args
{#if args.length > 0}
<span
class="inline-flex items-center justify-center w-4 h-4 text-[10px] font-medium bg-primary-100 text-primary-600 rounded-full"
>
{#if args.length === 0}
<p class="text-xs text-fg-muted px-1 py-2">
No arguments. Click "Add" below.
</p>
{:else}
{#each args as arg (arg.id)}
<div class="flex items-center gap-x-1">
<Input
bind:value={arg.key}
placeholder="key"
size="sm"
width="100px"
/>
<Input
bind:value={arg.value}
placeholder="value"
size="sm"
full
/>
<Button
type="ghost"
square
small
compact
onClick={() => removeArg(arg.id)}
>
<Trash size="12px" />
</Button>
</div>
{/each}
{/if}
<Button type="text" compact small onClick={addArg}>
<PlusIcon size="12px" />
Add
</Button>
</div>
</DropdownMenu.Content>
</DropdownMenu.Root>

{args.length}
</span>
{/if}
</Button>
<Button
type="primary"
small
Expand All @@ -232,6 +191,57 @@
</div>
</div>

{#if argsOpen}
<div class="border-b px-3 py-2">
<div class="flex items-center justify-between mb-2">
<span
class="text-[10px] font-semibold text-fg-primary uppercase tracking-wide"
>Query Parameters</span
>
<Button type="text" compact small onClick={addArg}>
<PlusIcon size="12px" />
Add
</Button>
</div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="args-container flex flex-col gap-y-2"
onkeydown={handleArgsKeydown}
>
{#if args.length === 0}
<p class="text-xs text-fg-muted py-1">
No query parameters. Click "Add" to create one.
</p>
{:else}
<div class="grid grid-cols-[1fr_1fr_28px] gap-x-2 gap-y-2">
<span
class="text-[10px] font-medium text-fg-muted uppercase tracking-wide"
>Key</span
>
<span
class="text-[10px] font-medium text-fg-muted uppercase tracking-wide"
>Value</span
>
<span></span>
{#each args as arg (arg.id)}
<Input bind:value={arg.key} placeholder="key" size="sm" />
<Input bind:value={arg.value} placeholder="value" size="sm" />
<Button
type="ghost"
square
small
compact
onClick={() => removeArg(arg.id)}
>
<Trash size="12px" />
</Button>
{/each}
</div>
{/if}
</div>
</div>
{/if}

<div class="flex-1 overflow-auto">
<APIResponsePreview
response={apiResponse}
Expand Down
Loading