feat(frontend): fill schema and test args from payload

This commit is contained in:
Ruben Fiszel
2022-11-05 02:29:32 +01:00
parent 4a2dff5cf2
commit cc65bf5f48
15 changed files with 192 additions and 46 deletions
+11
View File
@@ -10,6 +10,7 @@
"dependencies": {
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@redocly/json-to-json-schema": "^0.0.1",
"async-mutex": "^0.4.0",
"fuse.js": "^6.4.6",
"highlight.js": "^11.5.1",
@@ -403,6 +404,11 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@redocly/json-to-json-schema": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@redocly/json-to-json-schema/-/json-to-json-schema-0.0.1.tgz",
"integrity": "sha512-dSMyuNPN2k+tFeNZ0+QJ7S1zDJ0UeNL+lpnPFR9K5avj2V4uG4m6FdjrApQ9Zi35AIocaDp/KGfBD9gR5MLUbQ=="
},
"node_modules/@rollup/pluginutils": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
@@ -6847,6 +6853,11 @@
"dev": true,
"peer": true
},
"@redocly/json-to-json-schema": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@redocly/json-to-json-schema/-/json-to-json-schema-0.0.1.tgz",
"integrity": "sha512-dSMyuNPN2k+tFeNZ0+QJ7S1zDJ0UeNL+lpnPFR9K5avj2V4uG4m6FdjrApQ9Zi35AIocaDp/KGfBD9gR5MLUbQ=="
},
"@rollup/pluginutils": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
+1
View File
@@ -56,6 +56,7 @@
"dependencies": {
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@redocly/json-to-json-schema": "^0.0.1",
"async-mutex": "^0.4.0",
"fuse.js": "^6.4.6",
"highlight.js": "^11.5.1",
@@ -12,7 +12,9 @@
import FlowStatusViewer from '../components/FlowStatusViewer.svelte'
import FlowProgressBar from './flows/FlowProgressBar.svelte'
import { flowStateStore } from './flows/flowState'
import CapturePayload from './flows/content/CapturePayload.svelte'
let capturePayload: CapturePayload
export let previewMode: 'upTo' | 'whole'
export let open: boolean
@@ -89,19 +91,33 @@
}
</script>
<CapturePayload bind:this={capturePayload} />
<svelte:window on:keydown={onKeyDown} />
<div class="flex divide-y flex-col space-y-2 h-screen bg-white p-6 w-full">
<div class="flex justify-between">
<div class="flex flex-row justify-center items-center ">
<div class="flex justify-between w-full ">
<div class="flex flex-row justify-center items-center w-full mr-4">
<div class="flex justify-center p-2 w-8 h-8 bg-blue-200 rounded-lg mr-2 ">
<Icon data={faPlay} scale={1} class="text-blue-500" />
</div>
<h3 class="text-lg leading-6 font-bold text-gray-900">
Test preview - {previewMode === 'upTo'
? `up to step ${$selectedId.split('-').join(',')}`
: ' whole flow'}
<h3
class="text-lg leading-6 font-bold text-gray-900 inline-flex flex-row justify-between w-full"
>
<div>
Test preview - {previewMode === 'upTo'
? `up to step ${$selectedId.split('-').join(',')}`
: ' whole flow'}
</div>
<Button
btnClasses="ml-2"
size="sm"
variant="border"
on:click={() => {
capturePayload.openDrawer()
}}>Fill test args from payload</Button
>
</h3>
</div>
<Button
@@ -190,7 +190,7 @@
<td>
<SchemaEditorProperty {property} />
</td>
<td>{property.description}</td>
<td>{property.description ?? ''}</td>
<td>{property.default ? JSON.stringify(property.default) : ''}</td>
<td
>{#if schema.required.includes(name)}
@@ -8,6 +8,7 @@
import Tab from './common/tabs/Tab.svelte'
import TabContent from './common/tabs/TabContent.svelte'
import Tabs from './common/tabs/Tabs.svelte'
import { Badge } from './common'
export let schema: Schema | undefined = emptySchema()
</script>
@@ -32,11 +33,13 @@
<tbody slot="body">
{#each Object.entries(schema.properties) as [name, property] (name)}
<tr>
<td>{name}</td>
<td class="font-semibold pl-1">{name}</td>
<td
>{#if !property.type} any {:else} {property.type} {/if}</td
><Badge color="blue"
>{#if !property.type} any {:else} {property.type} {/if}</Badge
></td
>
<td>{property.description}</td>
<td>{property.description ?? ''}</td>
<td
>{property.default == '<function call>'
? '<function call>'
@@ -17,6 +17,7 @@
import { Button, Kbd } from './common'
import SplitPanesWrapper from './splitPanes/SplitPanesWrapper.svelte'
import Tooltip from './Tooltip.svelte'
import WindmillIcon from './icons/WindmillIcon.svelte'
// Exported
export let schema: Schema = emptySchema()
@@ -177,16 +178,13 @@
<Pane size={67}>
<div class="px-2 py-1 w-full">
{#if testIsLoading}
<Button
on:click={testJobLoader?.cancelJob}
btnClasses="w-full"
color="red"
size="xs"
startIcon={{
icon: faRotateRight,
classes: 'animate-spin'
}}
>
<Button on:click={testJobLoader?.cancelJob} btnClasses="w-full" color="red" size="xs">
<WindmillIcon
white={true}
class="animate-[spin_5s_linear_infinite] mr-2 text-white"
height="20px"
width="20px"
/>
Cancel
</Button>
{:else}
@@ -61,7 +61,8 @@
'focus:ring-4 font-semibold',
'rounded-md',
'justify-center items-center text-center whitespace-nowrap inline-flex',
btnClasses
btnClasses,
disabled ? 'bg-gray-200' : ''
),
disabled,
href,
@@ -61,7 +61,7 @@
<svelte:window on:keydown={onKeyDown} />
<aside class="drawer" class:open class:close={!open} {style}>
<aside class="drawer" class:open class:close={!open && timeout} {style}>
<div class="overlay" on:click={handleClickAway} />
<div class="panel {placement}" class:size>
{#if open || !timeout}
@@ -0,0 +1,96 @@
<script lang="ts">
import { page } from '$app/stores'
import { Button } from '$lib/components/common'
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
import DrawerContent from '$lib/components/common/drawer/DrawerContent.svelte'
import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte'
import ObjectViewer from '$lib/components/propertyPicker/ObjectViewer.svelte'
import { CaptureService } from '$lib/gen'
import { workspaceStore } from '$lib/stores'
import { flowStore } from '../flowStore'
import { convert } from '@redocly/json-to-json-schema'
import SchemaViewer from '$lib/components/SchemaViewer.svelte'
import { getContext } from 'svelte'
import type { FlowEditorContext } from '../types'
const { previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
let drawer: Drawer
let interval: NodeJS.Timeout | undefined = undefined
let captureInput: any | undefined = undefined
let jsonSchema: any = undefined
export function openDrawer() {
drawer.openDrawer()
}
async function startCapturePoint() {
await CaptureService.createCapture({
workspace: $workspaceStore!,
path: $flowStore.path
})
}
async function getCaptureInput() {
const capture = await CaptureService.getCapture({
workspace: $workspaceStore!,
path: $flowStore.path
})
captureInput = capture
jsonSchema = { required: [], ...convert(capture) }
}
</script>
<Drawer
bind:this={drawer}
on:open={() => {
startCapturePoint()
interval = setInterval(() => {
getCaptureInput()
}, 1000)
}}
on:close={() => interval && clearInterval(interval)}
>
<DrawerContent title="Capture from a request to seed inputs" on:close={drawer.closeDrawer}>
Send a payload at: <div
><a
class="text-2xl"
href="{$page.url.protocol}//{$page.url
.hostname}/api/w/{$workspaceStore}/capture/{$flowStore.path}"
>{$page.url.protocol}//{$page.url
.hostname}/api/w/{$workspaceStore}/capture/{$flowStore.path}</a
></div
>
<div class="items-center flex flex-row gap-x-2 text-xs text-gray-600">
Listening for new payload
<WindmillIcon
class="animate-[pulse_5s_linear_infinite] animate-[spin_5s_linear_infinite]"
/></div
>
<div class="box p-2 my-2">
<ObjectViewer topBrackets={true} json={captureInput} />
</div>
<div class="flex flex-row gap-2">
<Button
size="sm"
on:click={() => {
$previewArgs = captureInput
$flowStore.schema = jsonSchema
}}>Copy as flow inputs and test args</Button
>
<Button
size="sm"
variant="border"
on:click={() => {
$previewArgs = captureInput
}}>Copy only as test args</Button
>
</div>
<h3 class="mt-2">JSONSchema</h3>
<div class="box p-2">
<SchemaViewer schema={jsonSchema} />
</div>
</DrawerContent>
</Drawer>
@@ -1,15 +0,0 @@
<script lang="ts">
import Button from '$lib/components/common/button/Button.svelte'
import { copyFirstStepSchema, flowStore } from '../flowStore'
import { isEmptyFlowModule } from '../utils'
</script>
<Button
color="light"
size="xs"
disabled={$flowStore.value.modules.length === 0 || isEmptyFlowModule($flowStore.value.modules[0])}
on:click={copyFirstStepSchema}
variant="border"
>
Copy from first step schema
</Button>
@@ -1,15 +1,42 @@
<script lang="ts">
import { flowStore } from '$lib/components/flows/flowStore'
import { Button } from '$lib/components/common'
import SchemaEditor from '$lib/components/SchemaEditor.svelte'
import SchemaForm from '$lib/components/SchemaForm.svelte'
import FlowCard from '../common/FlowCard.svelte'
import { copyFirstStepSchema, flowStore } from '../flowStore'
import { isEmptyFlowModule } from '../utils'
import CapturePayload from './CapturePayload.svelte'
import CopyFirstStepSchema from './CopyFirstStepSchema.svelte'
let capturePayload: CapturePayload
</script>
<CapturePayload bind:this={capturePayload} />
<FlowCard title="Flow Inputs">
<div slot="header">
<CopyFirstStepSchema />
<div class="flex flex-row space-x-4">
<Button
color="light"
size="sm"
on:click={() => {
capturePayload.openDrawer()
}}
variant="border"
>
Capture from a request to seed inputs
</Button>
<Button
color="light"
size="sm"
disabled={$flowStore.value.modules.length === 0 ||
isEmptyFlowModule($flowStore.value.modules[0])}
on:click={copyFirstStepSchema}
variant="border"
>
Copy from first step schema {#if $flowStore.value.modules.length === 0 || isEmptyFlowModule($flowStore.value.modules[0])}
(no steps to copy from!){/if}
</Button>
</div>
</div>
<div>
<div class="p-6">
@@ -1,10 +1,12 @@
<script lang="ts">
export let height = '24px'
export let width = '24px'
export let white = false
</script>
<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
class={$$props.class}
version="1.1"
id="Calque_1"
xmlns="http://www.w3.org/2000/svg"
@@ -74,16 +76,19 @@
points="134.78,14.22 114.31,48.21 101.33,69.75 158.22,69.75 177.97,36.95 191.67,14.22 "
/>
<polygon
class="st3"
class:st3={!white}
class:st0={white}
points="227.55,69.75 186.61,69.75 101.33,69.75 129.78,119.02 158.16,119.02 228.61,119.02 256,119.02 "
/>
<polygon
class="st3"
class:st3={!white}
class:st0={white}
points="136.93,132.47 116.46,167.93 73.82,241.78 130.71,241.78 144.9,217.2 180.13,156.18 193.82,132.46
"
/>
<polygon
class="st3"
class:st3={!white}
class:st0={white}
points="121.7,131.95 101.23,96.49 58.59,22.63 30.15,71.91 44.34,96.49 79.57,157.5 93.26,181.22 "
/>
<polygon
+2 -1
View File
@@ -14,6 +14,7 @@
import { beforeNavigate } from '$app/navigation'
import UserSettings from '$lib/components/UserSettings.svelte'
import SuperadminSettings from '$lib/components/SuperadminSettings.svelte'
import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte'
OpenAPI.WITH_CREDENTIALS = true
@@ -180,7 +181,7 @@
{:else}
<CenteredModal title="Loading user">
<div class="mx-auto w-0">
<Icon class="animate-spin" data={faSpinner} scale={2.0} />
<WindmillIcon class="animate-[spin_5s_linear_infinite]" height="80px" width="80px" />
</div>
</CenteredModal>
{/if}
@@ -9,6 +9,7 @@
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
import CenteredPage from '$lib/components/CenteredPage.svelte'
import PageHeader from '$lib/components/PageHeader.svelte'
import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte'
let error = $page.url.searchParams.get('error')
let code = $page.url.searchParams.get('code') ?? undefined
@@ -33,6 +34,6 @@
<CenteredPage>
<PageHeader title="Connection to slack in progress" />
<div class="mx-auto w-0">
<Icon class="animate-spin" data={faSpinner} scale={2.0} />
<WindmillIcon class="animate-[spin_5s_linear_infinite]" height="80px" width="80px" />
</div>
</CenteredPage>
@@ -10,6 +10,7 @@
import { userStore, workspaceStore } from '$lib/stores'
import { getUserExt } from '$lib/user'
import { logoutWithRedirect } from '$lib/logout'
import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte'
let error = $page.url.searchParams.get('error')
let clientName = $page.params.client_name
@@ -51,6 +52,6 @@
<CenteredModal title="Login from {clientName} in progress">
<div class="mx-auto w-0">
<Icon class="animate-spin" data={faSpinner} scale={2.0} />
<WindmillIcon class="animate-[spin_5s_linear_infinite]" height="80px" width="80px" />
</div>
</CenteredModal>