|
@@ -1,5 +1,4 @@
|
|
|
<script lang="ts">
|
|
<script lang="ts">
|
|
|
- let { requestPane = $bindable(), responsePane = $bindable() } = $props();
|
|
|
|
|
import { Clipboard } from "@lucide/svelte";
|
|
import { Clipboard } from "@lucide/svelte";
|
|
|
import * as Select from "$lib/components/ui/select";
|
|
import * as Select from "$lib/components/ui/select";
|
|
|
import {
|
|
import {
|
|
@@ -15,6 +14,7 @@
|
|
|
updateBodyContent,
|
|
updateBodyContent,
|
|
|
updateEntryName,
|
|
updateEntryName,
|
|
|
updateHeader,
|
|
updateHeader,
|
|
|
|
|
+ updateHeaderEnabled,
|
|
|
updateQueryParamEnabled,
|
|
updateQueryParamEnabled,
|
|
|
updateRequestMethod,
|
|
updateRequestMethod,
|
|
|
updateUrl,
|
|
updateUrl,
|
|
@@ -37,6 +37,10 @@
|
|
|
import Response from "./Response.svelte";
|
|
import Response from "./Response.svelte";
|
|
|
import Checkbox from "./ui/checkbox/checkbox.svelte";
|
|
import Checkbox from "./ui/checkbox/checkbox.svelte";
|
|
|
import { tick } from "svelte";
|
|
import { tick } from "svelte";
|
|
|
|
|
+ import KeyValInput from "./KeyValInput.svelte";
|
|
|
|
|
+ import WorkspaceEntrySection from "./WorkspaceEntrySection.svelte";
|
|
|
|
|
+
|
|
|
|
|
+ let { requestPane = $bindable(), responsePane = $bindable() } = $props();
|
|
|
|
|
|
|
|
let isSending = $derived.by(isRequestSending);
|
|
let isSending = $derived.by(isRequestSending);
|
|
|
|
|
|
|
@@ -123,39 +127,40 @@
|
|
|
}, 200);
|
|
}, 200);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function handleAddQueryParam() {
|
|
|
|
|
- if (addQueryTimeout != undefined) {
|
|
|
|
|
- clearTimeout(addQueryTimeout);
|
|
|
|
|
|
|
+ async function handleAddHeader(key: string, val: string) {
|
|
|
|
|
+ const headerId = await insertHeader(key, val);
|
|
|
|
|
+
|
|
|
|
|
+ await tick(); // wait for DOM update
|
|
|
|
|
+
|
|
|
|
|
+ if (key) {
|
|
|
|
|
+ document.getElementById(`${headerId}_header_key`)?.focus();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ document.getElementById(`${headerId}_header_val`)?.focus();
|
|
|
}
|
|
}
|
|
|
- addQueryTimeout = setTimeout(async () => {
|
|
|
|
|
- const key = addQueryParamKeyInput ? addQueryParamKeyInput : "";
|
|
|
|
|
- const val = addQueryParamValInput ? addQueryParamValInput : "";
|
|
|
|
|
-
|
|
|
|
|
- if (_state.entry.query.length === 0) {
|
|
|
|
|
- _state.entry.url += `?${key}=${val}`;
|
|
|
|
|
- } else {
|
|
|
|
|
- _state.entry.url += `&${key}=${val}`;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- await updateUrl({
|
|
|
|
|
- type: "URL",
|
|
|
|
|
- url: _state.entry.url,
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ async function handleAddQueryParam(key: string, val: string) {
|
|
|
|
|
+ if (_state.entry.query.length === 0) {
|
|
|
|
|
+ _state.entry.url += `?${key}=${val}`;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _state.entry.url += `&${key}=${val}`;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- await tick(); // wait for DOM update
|
|
|
|
|
|
|
+ await updateUrl({
|
|
|
|
|
+ type: "URL",
|
|
|
|
|
+ url: _state.entry.url,
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- addQueryParamValInput = "";
|
|
|
|
|
- addQueryParamKeyInput = "";
|
|
|
|
|
|
|
+ await tick(); // wait for DOM update
|
|
|
|
|
|
|
|
- // Added param will always be last
|
|
|
|
|
- const param = _state.entry.query[_state.entry.query.length - 1];
|
|
|
|
|
|
|
+ // Added param will always be last
|
|
|
|
|
+ const param = _state.entry.query[_state.entry.query.length - 1];
|
|
|
|
|
|
|
|
- if (key) {
|
|
|
|
|
- document.getElementById(`${param.id}_query_key`)?.focus();
|
|
|
|
|
- } else {
|
|
|
|
|
- document.getElementById(`${param.id}_query_val`)?.focus();
|
|
|
|
|
- }
|
|
|
|
|
- }, 200);
|
|
|
|
|
|
|
+ if (key) {
|
|
|
|
|
+ document.getElementById(`${param.id}_query_key`)?.focus();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ document.getElementById(`${param.id}_query_val`)?.focus();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
@@ -337,64 +342,61 @@
|
|
|
<Tabs.Root value="params" class="h-full flex flex-col">
|
|
<Tabs.Root value="params" class="h-full flex flex-col">
|
|
|
<Tabs.List class="shrink-0">
|
|
<Tabs.List class="shrink-0">
|
|
|
<Tabs.Trigger value="params">Parameters</Tabs.Trigger>
|
|
<Tabs.Trigger value="params">Parameters</Tabs.Trigger>
|
|
|
- <Tabs.Trigger value="headers">Headers</Tabs.Trigger>
|
|
|
|
|
<Tabs.Trigger value="auth">Auth</Tabs.Trigger>
|
|
<Tabs.Trigger value="auth">Auth</Tabs.Trigger>
|
|
|
</Tabs.List>
|
|
</Tabs.List>
|
|
|
|
|
|
|
|
<div class="flex-1 overflow-auto p-2">
|
|
<div class="flex-1 overflow-auto p-2">
|
|
|
<!-- ================= PARAMETERS ================= -->
|
|
<!-- ================= PARAMETERS ================= -->
|
|
|
|
|
|
|
|
- <!-- ================= HEADERS ================= -->
|
|
|
|
|
-
|
|
|
|
|
- <div>
|
|
|
|
|
- <h3
|
|
|
|
|
- class="mb-2 pb-1 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
|
|
- >
|
|
|
|
|
- Headers
|
|
|
|
|
- </h3>
|
|
|
|
|
- <div
|
|
|
|
|
- class="grid grid-cols-[2%_1fr_1fr_2%] items-center justify-center gap-2 text-sm"
|
|
|
|
|
- >
|
|
|
|
|
- {#each _state.entry.headers as header (header.id)}
|
|
|
|
|
- <Input
|
|
|
|
|
- class="col-start-2"
|
|
|
|
|
- bind:value={header.name}
|
|
|
|
|
- placeholder="Name"
|
|
|
|
|
- oninput={() =>
|
|
|
|
|
- updateHeader(header.id, header.name, header.value)}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <Tabs.Content value="params" class="space-y-4">
|
|
|
|
|
+ <!-- ================= HEADERS ================= -->
|
|
|
|
|
|
|
|
- <Input
|
|
|
|
|
- class="col-start-3"
|
|
|
|
|
- bind:value={header.value}
|
|
|
|
|
- placeholder="Value"
|
|
|
|
|
- oninput={() =>
|
|
|
|
|
- updateHeader(header.id, header.name, header.value)}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <WorkspaceEntrySection title="Headers" initialOpen={false}>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="grid grid-cols-[2%_1fr_1fr_2%] items-center justify-center gap-2 text-sm"
|
|
|
|
|
+ >
|
|
|
|
|
+ {#each _state.entry.headers as header (header.id)}
|
|
|
|
|
+ <Checkbox
|
|
|
|
|
+ checked={header.enabled}
|
|
|
|
|
+ onCheckedChange={() =>
|
|
|
|
|
+ updateHeaderEnabled(header.id, !header.enabled)}
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
- <Trash
|
|
|
|
|
- class="col-start-4 h-4 w-4 cursor-pointer text-muted-foreground hover:text-destructive"
|
|
|
|
|
- onclick={() => deleteHeader(header.id)}
|
|
|
|
|
- />
|
|
|
|
|
- {/each}
|
|
|
|
|
|
|
+ <Input
|
|
|
|
|
+ id={`${header.id}_header_key`}
|
|
|
|
|
+ class="col-start-2"
|
|
|
|
|
+ bind:value={header.name}
|
|
|
|
|
+ placeholder="Name"
|
|
|
|
|
+ oninput={() =>
|
|
|
|
|
+ updateHeader(header.id, header.name, header.value)}
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
- <PlusIcon
|
|
|
|
|
- class="border p-1 rounded-2xl mx-auto col-span-3 cursor-pointer"
|
|
|
|
|
- onclick={() => insertHeader()}
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <Input
|
|
|
|
|
+ id={`${header.id}_header_val`}
|
|
|
|
|
+ class="col-start-3"
|
|
|
|
|
+ bind:value={header.value}
|
|
|
|
|
+ placeholder="Value"
|
|
|
|
|
+ oninput={() =>
|
|
|
|
|
+ updateHeader(header.id, header.name, header.value)}
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <Trash
|
|
|
|
|
+ class="col-start-4 h-4 w-4 cursor-pointer text-muted-foreground hover:text-destructive"
|
|
|
|
|
+ onclick={() => deleteHeader(header.id)}
|
|
|
|
|
+ />
|
|
|
|
|
+ {/each}
|
|
|
|
|
+
|
|
|
|
|
+ <KeyValInput
|
|
|
|
|
+ class="col-start-2 col-span-2"
|
|
|
|
|
+ onInput={handleAddHeader}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </WorkspaceEntrySection>
|
|
|
|
|
|
|
|
- <Tabs.Content value="params" class="space-y-4">
|
|
|
|
|
<!-- ================= PATH ================= -->
|
|
<!-- ================= PATH ================= -->
|
|
|
|
|
|
|
|
{#if _state.entry?.path?.length > 0}
|
|
{#if _state.entry?.path?.length > 0}
|
|
|
- <div>
|
|
|
|
|
- <h3
|
|
|
|
|
- class="mb-2 pb-1 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
|
|
- >
|
|
|
|
|
- Path
|
|
|
|
|
- </h3>
|
|
|
|
|
|
|
+ <WorkspaceEntrySection title="Path">
|
|
|
<div class="grid grid-cols-2 gap-2 text-sm">
|
|
<div class="grid grid-cols-2 gap-2 text-sm">
|
|
|
{#each _state.entry.path as param}
|
|
{#each _state.entry.path as param}
|
|
|
<Input
|
|
<Input
|
|
@@ -419,78 +421,67 @@
|
|
|
/>
|
|
/>
|
|
|
{/each}
|
|
{/each}
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
|
+ </WorkspaceEntrySection>
|
|
|
{/if}
|
|
{/if}
|
|
|
|
|
|
|
|
<!-- ================= QUERY ================= -->
|
|
<!-- ================= QUERY ================= -->
|
|
|
|
|
|
|
|
- <div>
|
|
|
|
|
- <h3
|
|
|
|
|
- class="mb-2 pb-1 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
|
|
- >
|
|
|
|
|
- Query
|
|
|
|
|
- </h3>
|
|
|
|
|
- <div
|
|
|
|
|
- class="grid grid-cols-[2%_1fr_1fr_2%] items-center justify-center gap-2 text-sm"
|
|
|
|
|
- >
|
|
|
|
|
- {#each _state.entry.query as param (param.id)}
|
|
|
|
|
- <div class="flex justify-center">
|
|
|
|
|
- <Checkbox
|
|
|
|
|
- checked={param.position != null}
|
|
|
|
|
- onCheckedChange={() => updateQueryParamEnabled(param)}
|
|
|
|
|
|
|
+ {#if _state.entry?.query?.length > 0}
|
|
|
|
|
+ <WorkspaceEntrySection title="Query">
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="grid grid-cols-[2%_1fr_1fr_2%] items-center justify-center gap-2 text-sm"
|
|
|
|
|
+ >
|
|
|
|
|
+ {#each _state.entry.query as param (param.id)}
|
|
|
|
|
+ <div class="flex justify-center">
|
|
|
|
|
+ <Checkbox
|
|
|
|
|
+ checked={param.position != null}
|
|
|
|
|
+ onCheckedChange={() => updateQueryParamEnabled(param)}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <Input
|
|
|
|
|
+ id={`${param.id}_query_key`}
|
|
|
|
|
+ class={param.position == null
|
|
|
|
|
+ ? `text-muted-foreground opacity-75`
|
|
|
|
|
+ : ""}
|
|
|
|
|
+ bind:value={param.key}
|
|
|
|
|
+ placeholder="key"
|
|
|
|
|
+ oninput={() =>
|
|
|
|
|
+ handleUrlUpdate({
|
|
|
|
|
+ type: "Query",
|
|
|
|
|
+ url: _state.entry.url,
|
|
|
|
|
+ param,
|
|
|
|
|
+ })}
|
|
|
/>
|
|
/>
|
|
|
- </div>
|
|
|
|
|
- <Input
|
|
|
|
|
- id={`${param.id}_query_key`}
|
|
|
|
|
- class={param.position == null
|
|
|
|
|
- ? `text-muted-foreground opacity-75`
|
|
|
|
|
- : ""}
|
|
|
|
|
- bind:value={param.key}
|
|
|
|
|
- placeholder="key"
|
|
|
|
|
- oninput={() =>
|
|
|
|
|
- handleUrlUpdate({
|
|
|
|
|
- type: "Query",
|
|
|
|
|
- url: _state.entry.url,
|
|
|
|
|
- param,
|
|
|
|
|
- })}
|
|
|
|
|
- />
|
|
|
|
|
- <Input
|
|
|
|
|
- id={`${param.id}_query_val`}
|
|
|
|
|
- class={param.position == null
|
|
|
|
|
- ? `text-muted-foreground opacity-75`
|
|
|
|
|
- : ""}
|
|
|
|
|
- bind:value={param.value}
|
|
|
|
|
- placeholder="value"
|
|
|
|
|
- oninput={() =>
|
|
|
|
|
- handleUrlUpdate({
|
|
|
|
|
- type: "Query",
|
|
|
|
|
- url: _state.entry.url,
|
|
|
|
|
- param,
|
|
|
|
|
- })}
|
|
|
|
|
- />
|
|
|
|
|
- <div class="flex justify-center">
|
|
|
|
|
- <Trash
|
|
|
|
|
- class="h-4 w-4 cursor-pointer text-muted-foreground hover:text-destructive"
|
|
|
|
|
- onclick={() => deleteQueryParam(param)}
|
|
|
|
|
|
|
+ <Input
|
|
|
|
|
+ id={`${param.id}_query_val`}
|
|
|
|
|
+ class={param.position == null
|
|
|
|
|
+ ? `text-muted-foreground opacity-75`
|
|
|
|
|
+ : ""}
|
|
|
|
|
+ bind:value={param.value}
|
|
|
|
|
+ placeholder="value"
|
|
|
|
|
+ oninput={() =>
|
|
|
|
|
+ handleUrlUpdate({
|
|
|
|
|
+ type: "Query",
|
|
|
|
|
+ url: _state.entry.url,
|
|
|
|
|
+ param,
|
|
|
|
|
+ })}
|
|
|
/>
|
|
/>
|
|
|
- </div>
|
|
|
|
|
- {/each}
|
|
|
|
|
- <!-- ================= ADD QUERY PARAM ================= -->
|
|
|
|
|
|
|
+ <div class="flex justify-center">
|
|
|
|
|
+ <Trash
|
|
|
|
|
+ class="h-4 w-4 cursor-pointer text-muted-foreground hover:text-destructive"
|
|
|
|
|
+ onclick={() => deleteQueryParam(param)}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ {/each}
|
|
|
|
|
+ <!-- ================= ADD QUERY PARAM ================= -->
|
|
|
|
|
|
|
|
- <Input
|
|
|
|
|
- class="col-start-2"
|
|
|
|
|
- bind:value={addQueryParamKeyInput}
|
|
|
|
|
- placeholder="Key"
|
|
|
|
|
- oninput={() => handleAddQueryParam()}
|
|
|
|
|
- />
|
|
|
|
|
- <Input
|
|
|
|
|
- class="col-start-3"
|
|
|
|
|
- bind:value={addQueryParamValInput}
|
|
|
|
|
- placeholder="Value"
|
|
|
|
|
- oninput={() => handleAddQueryParam()}
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <KeyValInput
|
|
|
|
|
+ class="col-start-2 col-span-2"
|
|
|
|
|
+ onInput={handleAddQueryParam}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </WorkspaceEntrySection>
|
|
|
|
|
+ {/if}
|
|
|
|
|
|
|
|
<!-- ================= BODY ================= -->
|
|
<!-- ================= BODY ================= -->
|
|
|
|
|
|