|
|
@@ -36,6 +36,7 @@
|
|
|
import AuthParams from "./AuthParams.svelte";
|
|
|
import Response from "./Response.svelte";
|
|
|
import Checkbox from "./ui/checkbox/checkbox.svelte";
|
|
|
+ import { tick } from "svelte";
|
|
|
|
|
|
let isSending = $derived.by(isRequestSending);
|
|
|
|
|
|
@@ -63,8 +64,15 @@
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+ // Used for inputs in the URL bar
|
|
|
let updateUrlTimeout: number | undefined = $state();
|
|
|
|
|
|
+ // Used for inputs in the query params
|
|
|
+ let addQueryTimeout: number | undefined = $state();
|
|
|
+
|
|
|
+ let addQueryParamKeyInput: string | undefined = $state();
|
|
|
+ let addQueryParamValInput: string | undefined = $state();
|
|
|
+
|
|
|
async function handleRequest() {
|
|
|
if (isRequestSending()) {
|
|
|
try {
|
|
|
@@ -87,7 +95,7 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async function handleUrlUpdate(update: UrlUpdate) {
|
|
|
+ function handleUrlUpdate(update: UrlUpdate) {
|
|
|
if (updateUrlTimeout != undefined) {
|
|
|
clearTimeout(updateUrlTimeout);
|
|
|
}
|
|
|
@@ -114,6 +122,41 @@
|
|
|
}
|
|
|
}, 200);
|
|
|
}
|
|
|
+
|
|
|
+ function handleAddQueryParam() {
|
|
|
+ if (addQueryTimeout != undefined) {
|
|
|
+ clearTimeout(addQueryTimeout);
|
|
|
+ }
|
|
|
+ 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,
|
|
|
+ });
|
|
|
+
|
|
|
+ await tick(); // wait for DOM update
|
|
|
+
|
|
|
+ addQueryParamValInput = "";
|
|
|
+ addQueryParamKeyInput = "";
|
|
|
+
|
|
|
+ // 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);
|
|
|
+ }
|
|
|
</script>
|
|
|
|
|
|
{#snippet authParams(
|
|
|
@@ -301,13 +344,54 @@
|
|
|
<div class="flex-1 overflow-auto p-2">
|
|
|
<!-- ================= PARAMETERS ================= -->
|
|
|
|
|
|
- <!-- ================= PATH ================= -->
|
|
|
+ <!-- ================= 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)}
|
|
|
+ />
|
|
|
+
|
|
|
+ <Input
|
|
|
+ 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}
|
|
|
+
|
|
|
+ <PlusIcon
|
|
|
+ class="border p-1 rounded-2xl mx-auto col-span-3 cursor-pointer"
|
|
|
+ onclick={() => insertHeader()}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
<Tabs.Content value="params" class="space-y-4">
|
|
|
+ <!-- ================= PATH ================= -->
|
|
|
+
|
|
|
{#if _state.entry?.path?.length > 0}
|
|
|
<div>
|
|
|
<h3
|
|
|
- class="mb-2 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
+ class="mb-2 pb-1 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
>
|
|
|
Path
|
|
|
</h3>
|
|
|
@@ -340,65 +424,79 @@
|
|
|
|
|
|
<!-- ================= QUERY ================= -->
|
|
|
|
|
|
- {#if _state.entry?.query?.length > 0}
|
|
|
- <div>
|
|
|
- <h3
|
|
|
- class="mb-2 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}
|
|
|
- <div class="flex justify-center">
|
|
|
- <Checkbox
|
|
|
- checked={param.position != null}
|
|
|
- onCheckedChange={() => updateQueryParamEnabled(param)}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <Input
|
|
|
- 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>
|
|
|
+ <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)}
|
|
|
/>
|
|
|
- <Input
|
|
|
- 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>
|
|
|
+ <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)}
|
|
|
/>
|
|
|
- <div class="flex justify-center">
|
|
|
- <Trash
|
|
|
- class="h-4 w-4 cursor-pointer text-muted-foreground hover:text-destructive"
|
|
|
- onclick={() => deleteQueryParam(param)}
|
|
|
- />
|
|
|
- </div>
|
|
|
- {/each}
|
|
|
- </div>
|
|
|
+ </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>
|
|
|
- {/if}
|
|
|
+ </div>
|
|
|
|
|
|
<!-- ================= BODY ================= -->
|
|
|
|
|
|
- <div class="space-y-4">
|
|
|
+ <div>
|
|
|
<h3
|
|
|
- class="mb-2 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
+ class="mb-2 pb-1 pointer-events-none text-xs font-medium border-b border-secondary text-muted-foreground"
|
|
|
>
|
|
|
Body
|
|
|
</h3>
|
|
|
@@ -447,42 +545,6 @@
|
|
|
</div>
|
|
|
</Tabs.Content>
|
|
|
|
|
|
- <!-- ================= HEADERS ================= -->
|
|
|
-
|
|
|
- <Tabs.Content value="headers">
|
|
|
- <div
|
|
|
- class="w-10/12 mx-auto grid grid-cols-[auto_1fr] gap-2 items-center"
|
|
|
- >
|
|
|
- {#each _state.entry.headers as header}
|
|
|
- <div class="contents">
|
|
|
- <Input
|
|
|
- bind:value={header.name}
|
|
|
- placeholder="Name"
|
|
|
- oninput={() =>
|
|
|
- updateHeader(header.id, header.name, header.value)}
|
|
|
- />
|
|
|
-
|
|
|
- <Input
|
|
|
- bind:value={header.value}
|
|
|
- placeholder="Value"
|
|
|
- oninput={() =>
|
|
|
- updateHeader(header.id, header.name, header.value)}
|
|
|
- />
|
|
|
-
|
|
|
- <Trash
|
|
|
- class="h-4 w-4 cursor-pointer text-muted-foreground hover:text-destructive"
|
|
|
- onclick={() => deleteHeader(header.id)}
|
|
|
- />
|
|
|
- </div>
|
|
|
- {/each}
|
|
|
-
|
|
|
- <PlusIcon
|
|
|
- class="border p-1 rounded-2xl mx-auto col-span-3 cursor-pointer"
|
|
|
- onclick={() => insertHeader()}
|
|
|
- />
|
|
|
- </div>
|
|
|
- </Tabs.Content>
|
|
|
-
|
|
|
<!-- ================= AUTH ================= -->
|
|
|
|
|
|
<Tabs.Content value="auth" class="space-y-4">
|