|
|
@@ -1,4 +1,5 @@
|
|
|
<script lang="ts">
|
|
|
+ import * as Select from "$lib/components/ui/select";
|
|
|
import {
|
|
|
state as _state,
|
|
|
deleteBody,
|
|
|
@@ -6,6 +7,7 @@
|
|
|
insertHeader,
|
|
|
selectEntry,
|
|
|
sendRequest,
|
|
|
+ setEntryAuth,
|
|
|
updateBodyContent,
|
|
|
updateEntryName,
|
|
|
updateHeader,
|
|
|
@@ -23,6 +25,9 @@
|
|
|
import { Loader, PlusIcon, TrashIcon } from "@lucide/svelte";
|
|
|
import CodeMirror from "./CodeMirror.svelte";
|
|
|
import * as Resizable from "$lib/components/ui/resizable/index";
|
|
|
+ import Auth from "./Auth.svelte";
|
|
|
+ import AuthParams from "./AuthParams.svelte";
|
|
|
+ import Checkbox from "./ui/checkbox/checkbox.svelte";
|
|
|
|
|
|
let requestPane: Resizable.Pane;
|
|
|
let responsePane: Resizable.Pane;
|
|
|
@@ -121,6 +126,14 @@
|
|
|
|
|
|
return url;
|
|
|
}
|
|
|
+
|
|
|
+ function resolveAuthName() {
|
|
|
+ if (_state.entry.auth !== null) {
|
|
|
+ return _state.auth.find((a) => a.id === _state.entry.auth).name;
|
|
|
+ } else {
|
|
|
+ return "None";
|
|
|
+ }
|
|
|
+ }
|
|
|
</script>
|
|
|
|
|
|
<svelte:head>
|
|
|
@@ -213,32 +226,27 @@
|
|
|
|
|
|
<Resizable.PaneGroup direction="vertical" class="flex-1 w-full rounded-lg">
|
|
|
<Resizable.Pane defaultSize={100} bind:this={requestPane}>
|
|
|
- <Accordion.Root
|
|
|
- type="multiple"
|
|
|
- value={["auth", "params", "headers", "body"]}
|
|
|
- class="h-full overflow-scroll"
|
|
|
- >
|
|
|
- <!-- URL PARAMS -->
|
|
|
-
|
|
|
- {#if _state.entry.path.length > 0 || _state.entry.workingUrl?.query_params?.length > 0}
|
|
|
- <Accordion.Item value="params">
|
|
|
- <Accordion.Trigger class="transition-none!"
|
|
|
- >Parameters</Accordion.Trigger
|
|
|
- >
|
|
|
-
|
|
|
- <!-- PATH PARAMS -->
|
|
|
-
|
|
|
- <Accordion.Content
|
|
|
- class="flex-col justify-center items-center space-y-4 "
|
|
|
- >
|
|
|
- <div class="flex flex-wrap">
|
|
|
- <h3 class="w-full mb-2 text-sm font-medium">Path</h3>
|
|
|
- <div class="w-1/2 grid grid-cols-2 gap-2 text-sm">
|
|
|
+ <Tabs.Root value="params" class="h-full flex flex-col">
|
|
|
+ <Tabs.List class="shrink-0">
|
|
|
+ <Tabs.Trigger value="params">Parameters</Tabs.Trigger>
|
|
|
+ <Tabs.Trigger value="headers">Headers</Tabs.Trigger>
|
|
|
+ <Tabs.Trigger value="body">Body</Tabs.Trigger>
|
|
|
+ <Tabs.Trigger value="auth">Auth</Tabs.Trigger>
|
|
|
+ </Tabs.List>
|
|
|
+
|
|
|
+ <div class="flex-1 overflow-auto p-2">
|
|
|
+ <!-- ================= PARAMETERS ================= -->
|
|
|
+
|
|
|
+ <Tabs.Content value="params" class="space-y-4">
|
|
|
+ {#if _state.entry.path.length > 0}
|
|
|
+ <div>
|
|
|
+ <h3 class="mb-2 text-sm font-medium">Path</h3>
|
|
|
+ <div class="grid grid-cols-2 gap-2 text-sm">
|
|
|
{#each _state.entry.path as param}
|
|
|
<Input
|
|
|
bind:value={param.name}
|
|
|
placeholder="key"
|
|
|
- oninput={(_) => handleUrlUpdate()}
|
|
|
+ oninput={() => handleUrlUpdate()}
|
|
|
/>
|
|
|
<Input
|
|
|
bind:value={param.value}
|
|
|
@@ -248,13 +256,13 @@
|
|
|
{/each}
|
|
|
</div>
|
|
|
</div>
|
|
|
+ {/if}
|
|
|
|
|
|
- <!-- QUERY PARAMS -->
|
|
|
-
|
|
|
- {#if _state.entry.workingUrl?.query_params.length > 0}
|
|
|
- <h3 class="w-full mb-2 text-sm font-medium">Query</h3>
|
|
|
- <div class="grid items-center grid-cols-2 gap-2 text-sm">
|
|
|
- {#each _state.entry.workingUrl!!.query_params as param}
|
|
|
+ {#if _state.entry.workingUrl?.query_params.length > 0}
|
|
|
+ <div>
|
|
|
+ <h3 class="mb-2 text-sm font-medium">Query</h3>
|
|
|
+ <div class="grid grid-cols-2 gap-2 text-sm">
|
|
|
+ {#each _state.entry.workingUrl.query_params as param}
|
|
|
<Input
|
|
|
bind:value={param[0]}
|
|
|
placeholder="key"
|
|
|
@@ -267,21 +275,17 @@
|
|
|
/>
|
|
|
{/each}
|
|
|
</div>
|
|
|
- {/if}
|
|
|
- </Accordion.Content>
|
|
|
- </Accordion.Item>
|
|
|
- {/if}
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
+ </Tabs.Content>
|
|
|
|
|
|
- <!-- HEADERS -->
|
|
|
+ <!-- ================= HEADERS ================= -->
|
|
|
|
|
|
- <Accordion.Item value="headers">
|
|
|
- <Accordion.Trigger>Headers</Accordion.Trigger>
|
|
|
- <Accordion.Content>
|
|
|
+ <Tabs.Content value="headers">
|
|
|
<div class="grid grid-cols-3 gap-2 text-sm">
|
|
|
{#each _state.entry.headers as header}
|
|
|
<div class="contents">
|
|
|
<Input
|
|
|
- class="w-full"
|
|
|
bind:value={header.name}
|
|
|
placeholder="Name"
|
|
|
oninput={() =>
|
|
|
@@ -304,22 +308,20 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
{/each}
|
|
|
+
|
|
|
<PlusIcon
|
|
|
class="col-span-3 mt-2 cursor-pointer text-muted-foreground hover:text-primary"
|
|
|
onclick={() => insertHeader()}
|
|
|
/>
|
|
|
</div>
|
|
|
- </Accordion.Content>
|
|
|
- </Accordion.Item>
|
|
|
+ </Tabs.Content>
|
|
|
|
|
|
- <!-- BODY -->
|
|
|
+ <!-- ================= BODY ================= -->
|
|
|
|
|
|
- <Accordion.Item value="body">
|
|
|
- <Accordion.Trigger>Body</Accordion.Trigger>
|
|
|
- <Accordion.Content class="space-y-4">
|
|
|
+ <Tabs.Content value="body" class="space-y-4">
|
|
|
<Tabs.Root value={_state.entry.body === null ? "none" : "json"}>
|
|
|
<Tabs.List>
|
|
|
- <Tabs.Trigger value="none" onclick={() => deleteBody()}
|
|
|
+ <Tabs.Trigger value="none" onclick={deleteBody}
|
|
|
>None</Tabs.Trigger
|
|
|
>
|
|
|
<Tabs.Trigger value="json">JSON</Tabs.Trigger>
|
|
|
@@ -327,17 +329,13 @@
|
|
|
<Tabs.Trigger value="text">Text</Tabs.Trigger>
|
|
|
</Tabs.List>
|
|
|
|
|
|
- <Tabs.Content value="none"></Tabs.Content>
|
|
|
-
|
|
|
<Tabs.Content value="json">
|
|
|
<CodeMirror
|
|
|
input={_state.entry.body?.body}
|
|
|
onStateChange={(update) => {
|
|
|
- // console.log(update);
|
|
|
if (
|
|
|
update.docChanged &&
|
|
|
- _state.entry!!.body?.body !==
|
|
|
- update.state.doc.toString()
|
|
|
+ _state.entry.body?.body !== update.state.doc.toString()
|
|
|
) {
|
|
|
updateBodyContent(update.state.doc.toString(), "Json");
|
|
|
}
|
|
|
@@ -358,9 +356,54 @@
|
|
|
></textarea>
|
|
|
</Tabs.Content>
|
|
|
</Tabs.Root>
|
|
|
- </Accordion.Content>
|
|
|
- </Accordion.Item>
|
|
|
- </Accordion.Root>
|
|
|
+ </Tabs.Content>
|
|
|
+
|
|
|
+ <Tabs.Content value="auth" class="space-y-4">
|
|
|
+ <div class="flex items-center">
|
|
|
+ <p class="mr-2">Inherit</p>
|
|
|
+ <Checkbox
|
|
|
+ checked={_state.entry.auth_inherit}
|
|
|
+ onCheckedChange={(v) => setEntryAuth(_state.entry.auth, v)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="transition-opacity"
|
|
|
+ class:opacity-50={_state.entry.auth_inherit}
|
|
|
+ class:pointer-events-none={_state.entry.auth_inherit}
|
|
|
+ >
|
|
|
+ <Select.Root type="single" value={resolveAuthName()}>
|
|
|
+ <Select.Trigger class="w-64">
|
|
|
+ {resolveAuthName()}
|
|
|
+ </Select.Trigger>
|
|
|
+
|
|
|
+ <Select.Content>
|
|
|
+ <Select.Item
|
|
|
+ onclick={() => setEntryAuth(null, null)}
|
|
|
+ value={"None"}
|
|
|
+ >
|
|
|
+ None
|
|
|
+ </Select.Item>
|
|
|
+ {#each _state.auth as auth}
|
|
|
+ <Select.Item
|
|
|
+ onclick={() => setEntryAuth(auth.id, null)}
|
|
|
+ value={auth.name}
|
|
|
+ >
|
|
|
+ {auth.name}
|
|
|
+ </Select.Item>
|
|
|
+ {/each}
|
|
|
+ </Select.Content>
|
|
|
+ </Select.Root>
|
|
|
+
|
|
|
+ {#if _state.entry.auth}
|
|
|
+ <AuthParams
|
|
|
+ auth={_state.auth.find((a) => a.id === _state.entry.auth)!!}
|
|
|
+ readonly={true}
|
|
|
+ />
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
+ </Tabs.Content>
|
|
|
+ </div>
|
|
|
+ </Tabs.Root>
|
|
|
</Resizable.Pane>
|
|
|
|
|
|
<Resizable.Handle
|