mirror of
https://github.com/LukeHagar/OpenAPI.gg.git
synced 2025-12-06 04:20:29 +00:00
improve path editing
This commit is contained in:
@@ -3,12 +3,39 @@
|
|||||||
import { SlideToggle } from '@skeletonlabs/skeleton';
|
import { SlideToggle } from '@skeletonlabs/skeleton';
|
||||||
|
|
||||||
export let example: OpenAPIV3.ExampleObject;
|
export let example: OpenAPIV3.ExampleObject;
|
||||||
export let name: string;
|
export let name: string = '';
|
||||||
|
|
||||||
|
let exampleValue = example.value;
|
||||||
|
let external = false;
|
||||||
|
|
||||||
|
// initialize the component
|
||||||
|
(() => {
|
||||||
|
if (
|
||||||
|
'value'! in example &&
|
||||||
|
'externalValue' in example &&
|
||||||
|
example.externalValue !== ('' || undefined)
|
||||||
|
) {
|
||||||
|
external = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
external = false;
|
||||||
|
})();
|
||||||
|
|
||||||
|
$: {
|
||||||
|
// make sure the exampleValue is a JSON-compatible string
|
||||||
|
try {
|
||||||
|
JSON.parse(exampleValue);
|
||||||
|
} catch (e) {
|
||||||
|
exampleValue = JSON.stringify(exampleValue);
|
||||||
|
}
|
||||||
|
// apply the changes to the example object
|
||||||
|
example.value = exampleValue;
|
||||||
|
}
|
||||||
|
|
||||||
let schema = false;
|
let schema = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="ml-6 ring-1 p-4 rounded-container-token ring-surface-500">
|
<div class="ml-6 ring-1 p-4 rounded-container-token ring-surface-500 space-y-4">
|
||||||
<SlideToggle name="schema" bind:checked={schema}>Schema</SlideToggle>
|
<SlideToggle name="schema" bind:checked={schema}>Schema</SlideToggle>
|
||||||
<p class="-ml-2 font-bold">{name}</p>
|
<p class="-ml-2 font-bold">{name}</p>
|
||||||
{#if schema}
|
{#if schema}
|
||||||
@@ -18,19 +45,45 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<label>
|
<label>
|
||||||
<p>Summary</p>
|
<p>Summary</p>
|
||||||
<input type="text" class="input" name="summary" bind:value={example.summary} />
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
name="summary"
|
||||||
|
placeholder="A short summary"
|
||||||
|
bind:value={example.summary}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<p>Description</p>
|
<p>Description</p>
|
||||||
<textarea class="textarea" name="description" bind:value={example.description} />
|
<textarea
|
||||||
</label>
|
class="textarea"
|
||||||
<label>
|
name="description"
|
||||||
<p>Value</p>
|
placeholder="A description of the example. Supports Markdown."
|
||||||
<input type="text" class="input" name="value" bind:value={example.value} />
|
bind:value={example.description}
|
||||||
</label>
|
/>
|
||||||
<label>
|
|
||||||
<p>External Value</p>
|
|
||||||
<input type="text" class="input" name="externalValue" bind:value={example.externalValue} />
|
|
||||||
</label>
|
</label>
|
||||||
|
<SlideToggle name="external" bind:checked={external} size="sm">External Value</SlideToggle>
|
||||||
|
{#if !external}
|
||||||
|
<label>
|
||||||
|
<p>Value</p>
|
||||||
|
<textarea
|
||||||
|
class="textarea"
|
||||||
|
name="value"
|
||||||
|
placeholder="The example value."
|
||||||
|
bind:value={exampleValue}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{:else}
|
||||||
|
<label>
|
||||||
|
<p>External Value</p>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
name="externalValue"
|
||||||
|
placeholder="URL to external value."
|
||||||
|
bind:value={example.externalValue}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
// if the parameter is a reference, we need to link to the reference
|
// if the parameter is a reference, we need to link to the reference
|
||||||
let isReference = '$ref' in parameter;
|
let isReference = '$ref' in parameter;
|
||||||
|
let multipleExamples = false;
|
||||||
|
|
||||||
parameter = isReference
|
parameter = isReference
|
||||||
? (parameter as OpenAPIV3.ReferenceObject)
|
? (parameter as OpenAPIV3.ReferenceObject)
|
||||||
@@ -15,15 +16,84 @@
|
|||||||
// if the parameter is a path parameter, we need to limit the editing options
|
// if the parameter is a path parameter, we need to limit the editing options
|
||||||
// @ts-expect-error parameter.in has to exist if the parameter is not a reference
|
// @ts-expect-error parameter.in has to exist if the parameter is not a reference
|
||||||
let isPathParameter = !isReference && parameter.in === 'path';
|
let isPathParameter = !isReference && parameter.in === 'path';
|
||||||
|
(() => {
|
||||||
|
if (isReference) return;
|
||||||
|
// set default requirements
|
||||||
|
if (isPathParameter) {
|
||||||
|
parameter.required = true;
|
||||||
|
parameter.style = 'simple';
|
||||||
|
}
|
||||||
|
if (parameter.in === 'query') {
|
||||||
|
parameter.style = 'form';
|
||||||
|
}
|
||||||
|
if (parameter.in === 'header') {
|
||||||
|
parameter.style = 'simple';
|
||||||
|
}
|
||||||
|
if (parameter.in === 'cookie') {
|
||||||
|
parameter.style = 'form';
|
||||||
|
}
|
||||||
|
// if parameter.examples contains values, we need to set multipleExamples to true
|
||||||
|
if (Object.keys(parameter.examples ?? {}).length > 0) {
|
||||||
|
multipleExamples = true;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
$: () => {
|
||||||
|
if (isReference) return;
|
||||||
|
if (parameter.style == 'form') {
|
||||||
|
parameter.explode = true;
|
||||||
|
} else {
|
||||||
|
parameter.explode = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: maybe needs validation for query-deepObject
|
||||||
|
const styleOptions = [
|
||||||
|
{
|
||||||
|
style: 'matrix',
|
||||||
|
description: 'Matrix',
|
||||||
|
validFor: ['path']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 'label',
|
||||||
|
description: 'Label',
|
||||||
|
validFor: ['path']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 'form',
|
||||||
|
description: 'Form',
|
||||||
|
validFor: ['query', 'cookie']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 'simple',
|
||||||
|
description: 'Simple',
|
||||||
|
validFor: ['header', 'path']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 'spaceDelimited',
|
||||||
|
description: 'Space Delimited',
|
||||||
|
validFor: ['query']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 'pipeDelimited',
|
||||||
|
description: 'Pipe Delimited',
|
||||||
|
validFor: ['query']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: 'deepObject',
|
||||||
|
description: 'Deep Object',
|
||||||
|
validFor: ['query']
|
||||||
|
}
|
||||||
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card py-6 px-4 flex flex-col gap-4 text-sm">
|
<div class="py-6 px-4 flex flex-col gap-6 text-sm">
|
||||||
{#if isReference}
|
{#if isReference}
|
||||||
<p class="text-xs text-error">This parameter is a reference and cannot be edited here.</p>
|
<p class="text-xs text-error">This parameter is a reference and cannot be edited here.</p>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||||
{#if isPathParameter}
|
{#if isPathParameter}
|
||||||
<p class="h3 font-bold">{parameter.name}</p>
|
<p class="h3 font-bold">"{parameter.name}" in: {parameter.in}</p>
|
||||||
{:else}
|
{:else}
|
||||||
<label>
|
<label>
|
||||||
<p>Name</p>
|
<p>Name</p>
|
||||||
@@ -55,5 +125,83 @@
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex gap-3 divide-x">
|
||||||
|
<div>
|
||||||
|
<SlideToggle
|
||||||
|
name="required"
|
||||||
|
active="bg-primary-500"
|
||||||
|
size="sm"
|
||||||
|
disabled={isPathParameter}
|
||||||
|
bind:checked={parameter.required}>Required</SlideToggle
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="pl-2">
|
||||||
|
<SlideToggle
|
||||||
|
name="required"
|
||||||
|
active="bg-primary-500"
|
||||||
|
size="sm"
|
||||||
|
bind:checked={parameter.deprecated}>Deprecated</SlideToggle
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="pl-2">
|
||||||
|
<SlideToggle
|
||||||
|
name="required"
|
||||||
|
active="bg-primary-500"
|
||||||
|
size="sm"
|
||||||
|
bind:checked={parameter.allowEmptyValue}
|
||||||
|
>
|
||||||
|
Allow empty value (Use of this property is NOT RECOMMENDED, as it is likely to be removed
|
||||||
|
in a later revision.)
|
||||||
|
</SlideToggle>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-6 items-center">
|
||||||
|
<label>
|
||||||
|
<p>Style</p>
|
||||||
|
<select name="style" class="select" bind:value={parameter.style}>
|
||||||
|
{#each styleOptions as styleOption}
|
||||||
|
{#if styleOption.validFor.includes(parameter.in)}
|
||||||
|
<option value={styleOption.style}>{styleOption.description}</option>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<SlideToggle
|
||||||
|
name="explode"
|
||||||
|
active="bg-primary-500"
|
||||||
|
size="sm"
|
||||||
|
bind:checked={parameter.explode}
|
||||||
|
>
|
||||||
|
Explode
|
||||||
|
</SlideToggle>
|
||||||
|
{#if parameter.in === 'query'}
|
||||||
|
<SlideToggle
|
||||||
|
name="allowReserved"
|
||||||
|
active="bg-primary-500"
|
||||||
|
size="sm"
|
||||||
|
bind:checked={parameter.allowReserved}
|
||||||
|
>
|
||||||
|
Allow Reserved
|
||||||
|
</SlideToggle>
|
||||||
|
{/if}
|
||||||
|
<pre>TODO: Schema selector</pre>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<label for="name"> Single Example </label>
|
||||||
|
<SlideToggle
|
||||||
|
name="multipleExamples"
|
||||||
|
active="bg-primary-500"
|
||||||
|
size="sm"
|
||||||
|
bind:checked={multipleExamples}
|
||||||
|
/>
|
||||||
|
<label for="name"> Multiple Examples </label>
|
||||||
|
</div>
|
||||||
|
{#if multipleExamples}
|
||||||
|
multiple examples editor
|
||||||
|
{:else}
|
||||||
|
<ExampleInput bind:example={parameter.example} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
import type { OpenAPIV3_1 } from 'openapi-types';
|
import type { OpenAPIV3_1 } from 'openapi-types';
|
||||||
import ServerInput from '../ServerInput.svelte';
|
import ServerInput from '../ServerInput.svelte';
|
||||||
import ParameterInput from '../ParameterInput.svelte';
|
import ParameterInput from '../ParameterInput.svelte';
|
||||||
import { version } from '$app/environment';
|
|
||||||
|
|
||||||
export let path: OpenAPIV3_1.PathItemObject;
|
export let path: OpenAPIV3_1.PathItemObject;
|
||||||
|
|
||||||
|
let newParameter = 'query';
|
||||||
|
|
||||||
export const editedPath: OpenAPIV3_1.PathItemObject = {
|
export const editedPath: OpenAPIV3_1.PathItemObject = {
|
||||||
summary: path.summary ?? '',
|
summary: path.summary ?? '',
|
||||||
description: path.description ?? '',
|
description: path.description ?? '',
|
||||||
@@ -42,6 +43,10 @@
|
|||||||
editedPath.parameters.splice(index, 1);
|
editedPath.parameters.splice(index, 1);
|
||||||
editedPath.parameters = editedPath.parameters;
|
editedPath.parameters = editedPath.parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addParameter = () => {
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
@@ -94,23 +99,35 @@
|
|||||||
<p class="font-bold h5">Parameters</p>
|
<p class="font-bold h5">Parameters</p>
|
||||||
{#if editedPath.parameters}
|
{#if editedPath.parameters}
|
||||||
{#each editedPath.parameters as parameter, i}
|
{#each editedPath.parameters as parameter, i}
|
||||||
<div class="ring-1 ring-surface-600-300-token rounded-container-token p-2 space-y-2">
|
<div class="card ring-1 ring-surface-600-300-token rounded-container-token p-2 space-y-2">
|
||||||
<!-- If the parameter is a reference: show the reference link -->
|
<!-- If the parameter is a reference: show the reference link -->
|
||||||
{#if '$ref' in parameter}
|
{#if '$ref' in parameter}
|
||||||
<p class="text-sm">This parameter is a reference</p>
|
<p class="text-sm">This parameter is a reference</p>
|
||||||
{:else}
|
{:else}
|
||||||
<ParameterInput parameter={parameter} />
|
<ParameterInput bind:parameter />
|
||||||
|
{/if}
|
||||||
|
{#if parameter.in !== 'path'}
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm variant-filled-error"
|
||||||
|
on:click={() => {
|
||||||
|
removeParameter(i);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove Parameter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-sm variant-filled-error"
|
|
||||||
on:click={() => {
|
|
||||||
removeParameter(i);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Remove Parameter
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
<span class="mx-auto flex gap-2">
|
||||||
|
<select name="parameter-location" class="select" bind:value={newParameter}>
|
||||||
|
<option value="query">Query</option>
|
||||||
|
<option value="header">Header</option>
|
||||||
|
<option value="cookie">Cookie</option>
|
||||||
|
</select>
|
||||||
|
<button type="button" class="btn btn-sm variant-filled-primary"> Add {newParameter} parameter </button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -34,7 +34,12 @@
|
|||||||
explode: false, // Defaults to true when style is form, otherwise false.
|
explode: false, // Defaults to true when style is form, otherwise false.
|
||||||
schema: {},
|
schema: {},
|
||||||
content: {},
|
content: {},
|
||||||
example: {}, // any -> Example and Examples are mutually exclusive
|
example: {
|
||||||
|
summary: '',
|
||||||
|
description: '',
|
||||||
|
value: undefined, // any -> Example and Examples are mutually exclusive
|
||||||
|
externalValue: undefined
|
||||||
|
}, // any -> Example and Examples are mutually exclusive
|
||||||
examples: {},
|
examples: {},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user