improve path editing

This commit is contained in:
Malte Teichert
2024-06-10 00:54:08 +02:00
parent b09f2dff5b
commit d7e054dd48
4 changed files with 250 additions and 27 deletions

View File

@@ -3,12 +3,39 @@
import { SlideToggle } from '@skeletonlabs/skeleton';
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;
</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>
<p class="-ml-2 font-bold">{name}</p>
{#if schema}
@@ -18,19 +45,45 @@
{:else}
<label>
<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>
<p>Description</p>
<textarea class="textarea" name="description" bind:value={example.description} />
<textarea
class="textarea"
name="description"
placeholder="A description of the example. Supports Markdown."
bind:value={example.description}
/>
</label>
<SlideToggle name="external" bind:checked={external} size="sm">External Value</SlideToggle>
{#if !external}
<label>
<p>Value</p>
<input type="text" class="input" name="value" bind:value={example.value} />
<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" bind:value={example.externalValue} />
<input
type="text"
class="input"
name="externalValue"
placeholder="URL to external value."
bind:value={example.externalValue}
/>
</label>
{/if}
{/if}
</div>

View File

@@ -7,6 +7,7 @@
// if the parameter is a reference, we need to link to the reference
let isReference = '$ref' in parameter;
let multipleExamples = false;
parameter = isReference
? (parameter as OpenAPIV3.ReferenceObject)
@@ -15,15 +16,84 @@
// 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
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>
<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}
<p class="text-xs text-error">This parameter is a reference and cannot be edited here.</p>
{:else}
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
{#if isPathParameter}
<p class="h3 font-bold">{parameter.name}</p>
<p class="h3 font-bold">"{parameter.name}" in: {parameter.in}</p>
{:else}
<label>
<p>Name</p>
@@ -55,5 +125,83 @@
/>
</label>
</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}
</div>

View File

@@ -2,10 +2,11 @@
import type { OpenAPIV3_1 } from 'openapi-types';
import ServerInput from '../ServerInput.svelte';
import ParameterInput from '../ParameterInput.svelte';
import { version } from '$app/environment';
export let path: OpenAPIV3_1.PathItemObject;
let newParameter = 'query';
export const editedPath: OpenAPIV3_1.PathItemObject = {
summary: path.summary ?? '',
description: path.description ?? '',
@@ -42,6 +43,10 @@
editedPath.parameters.splice(index, 1);
editedPath.parameters = editedPath.parameters;
};
const addParameter = () => {
}
</script>
<div class="flex flex-col gap-1">
@@ -94,13 +99,15 @@
<p class="font-bold h5">Parameters</p>
{#if editedPath.parameters}
{#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 '$ref' in parameter}
<p class="text-sm">This parameter is a reference</p>
{: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"
@@ -111,6 +118,16 @@
Remove Parameter
</button>
</div>
{/each}
{/if}
</div>
{/each}
{/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>

View File

@@ -34,7 +34,12 @@
explode: false, // Defaults to true when style is form, otherwise false.
schema: {},
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: {},
});
});