frontend(fix): rework all text inputs

This commit is contained in:
Ruben Fiszel
2022-11-03 13:47:40 +01:00
parent a97613401c
commit 47b4873a59
17 changed files with 140 additions and 141 deletions
+27
View File
@@ -16,6 +16,7 @@
"monaco-editor": "^0.34.1",
"monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "4.0.1",
"svelte-autosize": "^1.0.1",
"vscode-ws-jsonrpc": "^2.0.0"
},
"devDependencies": {
@@ -1005,6 +1006,11 @@
"postcss": "^8.1.0"
}
},
"node_modules/autosize": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/autosize/-/autosize-5.0.1.tgz",
"integrity": "sha512-UIWUlE4TOVPNNj2jjrU39wI4hEYbneUypEqcyRmRFIx5CC2gNdg3rQr+Zh7/3h6egbBvm33TDQjNQKtj9Tk1HA=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -5622,6 +5628,14 @@
"node": ">= 8"
}
},
"node_modules/svelte-autosize": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/svelte-autosize/-/svelte-autosize-1.0.1.tgz",
"integrity": "sha512-HBk7Xrt5bS0rpp5zSUZvuXNKc0UhAxvJGLNy1eTHMDK/KkHb0UsgWpbyn60jW3tE2ZfuXfLttnHvvb1H4zZZ0Q==",
"dependencies": {
"autosize": "*"
}
},
"node_modules/svelte-awesome": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/svelte-awesome/-/svelte-awesome-3.0.0.tgz",
@@ -7235,6 +7249,11 @@
"postcss-value-parser": "^4.2.0"
}
},
"autosize": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/autosize/-/autosize-5.0.1.tgz",
"integrity": "sha512-UIWUlE4TOVPNNj2jjrU39wI4hEYbneUypEqcyRmRFIx5CC2gNdg3rQr+Zh7/3h6egbBvm33TDQjNQKtj9Tk1HA=="
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -10503,6 +10522,14 @@
"integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==",
"dev": true
},
"svelte-autosize": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/svelte-autosize/-/svelte-autosize-1.0.1.tgz",
"integrity": "sha512-HBk7Xrt5bS0rpp5zSUZvuXNKc0UhAxvJGLNy1eTHMDK/KkHb0UsgWpbyn60jW3tE2ZfuXfLttnHvvb1H4zZZ0Q==",
"requires": {
"autosize": "*"
}
},
"svelte-awesome": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/svelte-awesome/-/svelte-awesome-3.0.0.tgz",
+1
View File
@@ -62,6 +62,7 @@
"monaco-editor": "^0.34.1",
"monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "4.0.1",
"svelte-autosize": "^1.0.1",
"vscode-ws-jsonrpc": "^2.0.0"
}
}
+34 -59
View File
@@ -13,6 +13,7 @@
import SchemaForm from './SchemaForm.svelte'
import type { SchemaProperty } from '$lib/common'
import SimpleEditor from './SimpleEditor.svelte'
import autosize from 'svelte-autosize'
export let label: string = ''
export let value: any
@@ -45,7 +46,7 @@
let error: string = ''
let el: HTMLElement | undefined = undefined
let el: HTMLTextAreaElement | undefined = undefined
export let editor: SimpleEditor | undefined = undefined
@@ -89,6 +90,7 @@
export function focus() {
el?.focus()
el && el.dispatchEvent(new Event('input'))
}
function validateInput(pattern: string | undefined, v: any): void {
@@ -266,24 +268,21 @@
/>
</div>
{:else}
<div class="container">
<pre aria-hidden="true" style="min-height: 2.2em; max-height: {maxHeight}"
>{rawValue + '\n'}</pre
>
<textarea
on:focus
{disabled}
style="max-height: {maxHeight}"
on:input={() => {
dispatch('input', { rawValue: value, isRaw: false })
}}
class="col-span-10 {valid
? ''
: 'border border-red-700 border-opacity-30 focus:border-red-700 focus:border-opacity-30 bg-red-100'}"
placeholder={defaultValue ? JSON.stringify(defaultValue, null, 4) : ''}
bind:value={rawValue}
/>
</div>
<textarea
bind:this={el}
on:focus
{disabled}
use:autosize
style="max-height: {maxHeight}"
on:input={() => {
dispatch('input', { rawValue: value, isRaw: false })
}}
class="col-span-10 {valid
? ''
: 'border border-red-700 border-opacity-30 focus:border-red-700 focus:border-opacity-30 bg-red-100'}"
placeholder={defaultValue ? JSON.stringify(defaultValue, null, 4) : ''}
bind:value={rawValue}
/>
{/if}
{:else if inputCat == 'enum'}
<select {disabled} class="px-6" bind:value>
@@ -322,25 +321,22 @@
: undefined}
/>
{:else if inputCat == 'string'}
<div class="container">
<pre aria-hidden="true" style="min-height: 2.2em; max-height: {maxHeight}"
>{value + '\n'}</pre
>
<textarea
on:focus={() => dispatch('focus')}
on:blur={() => dispatch('blur')}
type="text"
{disabled}
class="col-span-10 resize {valid
? ''
: 'border border-red-700 border-opacity-30 focus:border-red-700 focus:border-opacity-30 bg-red-100'}"
placeholder={defaultValue ?? ''}
bind:value
on:input={() => {
dispatch('input', { rawValue: value, isRaw: false })
}}
/>
</div>
<textarea
bind:this={el}
on:focus={() => dispatch('focus')}
on:blur={() => dispatch('blur')}
use:autosize
type="text"
{disabled}
class="col-span-10 {valid
? ''
: 'border border-red-700 border-opacity-30 focus:border-red-700 focus:border-opacity-30 bg-red-100'}"
placeholder={defaultValue ?? ''}
bind:value
on:input={() => {
dispatch('input', { rawValue: value, isRaw: false })
}}
/>
{/if}
{#if !required && inputCat != 'resource-object'}
<!-- <Tooltip placement="bottom" content="Reset to default value">
@@ -362,24 +358,3 @@
</div>
</div>
</div>
<style>
.container {
position: relative;
}
pre,
textarea {
font-family: inherit;
padding: 0.5em;
box-sizing: border-box;
line-height: 1.2;
overflow: hidden;
}
textarea {
position: absolute;
width: 100%;
height: 100%;
top: 0;
}
</style>
@@ -1,37 +0,0 @@
<script lang="ts">
export let value: string
export let placeholder = ''
export let minRows = 1
export let maxRows = 20
$: minHeight = `${1 + minRows * 1.2}em`
$: maxHeight = maxRows ? `${1 + maxRows * 1.2}em` : `auto`
</script>
<div class="container">
<pre aria-hidden="true" style="min-height: {minHeight}; max-height: {maxHeight}">
{value + '\n'}
</pre>
<textarea type="text" class="col-span-10 resize" bind:value {placeholder} />
</div>
<style>
.container {
position: relative;
}
pre,
textarea {
font-family: inherit;
padding: 0.5em;
box-sizing: border-box;
line-height: 1.2;
overflow: hidden;
}
textarea {
position: absolute;
width: 100%;
height: 100%;
top: 0;
}
</style>
+31 -5
View File
@@ -11,7 +11,7 @@
setQueryWithoutLoad
} from '$lib/utils'
import { faGlobe, faPen } from '@fortawesome/free-solid-svg-icons'
import { setContext } from 'svelte'
import { onMount, setContext } from 'svelte'
import { writable } from 'svelte/store'
import CenteredPage from './CenteredPage.svelte'
import { Button } from './common'
@@ -28,6 +28,8 @@
import { cleanInputs } from './flows/utils'
export let initialPath: string = ''
export let selectedId: string | undefined
let pathError = ''
async function createSchedule(path: string) {
@@ -118,11 +120,30 @@
goto(`/flows/get/${$flowStore.path}`)
}
flowStore.subscribe((flow: Flow) => {
if (flow) {
setQueryWithoutLoad($page.url, 'state', encodeState(flow))
let timeout: NodeJS.Timeout | undefined = undefined
$: {
if ($flowStore && $flowStateStore) {
setUrl()
}
})
}
function setUrl() {
timeout && clearTimeout(timeout)
timeout = setTimeout(
() =>
setQueryWithoutLoad(
$page.url,
'state',
encodeState({
flow: $flowStore,
selectedId: $selectedIdStore,
flowStateStore: $flowStateStore
})
),
500
)
}
const selectedIdStore = writable<string>('settings')
const scheduleStore = writable<Schedule>({ args: {}, cron: '', enabled: false })
@@ -153,6 +174,11 @@
})
}
onMount(() => {
console.log(selectedId)
selectedId && select(selectedId)
})
$: initialPath && $workspaceStore && loadSchedule()
loadHubScripts()
@@ -91,7 +91,6 @@
return true
})
}
argInput?.recomputeSize()
}
const { focusProp } = getContext<PropPickerWrapperContext>('PropPickerWrapper')
</script>
+1 -1
View File
@@ -7,6 +7,6 @@
<span class="text-red-700 font-normal {$$props.class}">*</span>
{:else if detail || detail != ''}
<span class="text-sm text-gray-500 ml-2 font-normal {$$props.class}"
>({detail != '' ? `, ${detail}` : ''})</span
>({detail != '' ? `${detail}` : ''})</span
>
{/if}
@@ -5,7 +5,6 @@
import type { Schema } from '$lib/common'
import Path from './Path.svelte'
import ArgInput from './ArgInput.svelte'
import AutosizedTextarea from './AutosizedTextarea.svelte'
import ItemPicker from './ItemPicker.svelte'
import VariableEditor from './VariableEditor.svelte'
import Required from './Required.svelte'
@@ -14,6 +13,7 @@
import { workspaceStore } from '$lib/stores'
import ResourceTypePicker from './ResourceTypePicker.svelte'
import DrawerContent from './common/drawer/DrawerContent.svelte'
import autosize from 'svelte-autosize'
let path = ''
let initialPath = ''
@@ -140,10 +140,11 @@
<span class=" mt-3 font-semibold text-gray-700 "
>Description <Required required={false} />
</span>
<AutosizedTextarea
<textarea
type="text"
use:autosize
bind:value={description}
placeholder={DESCRIPTION_PLACEHOLDER}
minRows={3}
/>
<div>
<div class="mb-2 font-semibold text-gray-700">
@@ -171,6 +171,6 @@
.few-lines-editor {
/* stylelint-disable-next-line unit-allowed-list */
height: 80px;
height: 150px;
}
</style>
@@ -1,7 +1,6 @@
<script lang="ts">
import { sendUserToast } from '$lib/utils'
import { VariableService } from '$lib/gen'
import AutosizedTextarea from './AutosizedTextarea.svelte'
import Path from './Path.svelte'
import { createEventDispatcher } from 'svelte'
import { workspaceStore } from '$lib/stores'
@@ -11,6 +10,7 @@
import Drawer from './common/drawer/Drawer.svelte'
import DrawerContent from './common/drawer/DrawerContent.svelte'
import Alert from './common/alert/Alert.svelte'
import autosize from 'svelte-autosize'
const dispatch = createEventDispatcher()
@@ -156,7 +156,7 @@
<span class="font-semibold text-gray-700">Variable value</span>
<span class="text-sm text-gray-500">({variable.value.length}/3000 characters)</span>
</div>
<AutosizedTextarea bind:value={variable.value} minRows={5} />
<textarea type="text" use:autosize bind:value={variable.value} />
</div>
<!-- {/if} -->
@@ -165,7 +165,12 @@
Description
<Required required={false} />
</div>
<AutosizedTextarea bind:value={variable.description} placeholder={''} minRows={3} />
<input
type="text"
use:autosize
bind:value={variable.description}
placeholder="Description (can use Markdown)"
/>
</div>
</div>
<div slot="submission">
@@ -19,8 +19,8 @@ export type FlowState = Record<string, FlowModuleState>
*/
export const flowStateStore = writable<FlowState>({})
export async function initFlowState(flow: Flow) {
const modulesState: FlowState = {}
export async function initFlowState(flow: Flow, flowState: FlowState | undefined) {
const modulesState: FlowState = flowState ?? {}
await mapFlowModules(flow.value.modules, modulesState)
@@ -1,6 +1,6 @@
import type { Flow, FlowModule, ForloopFlow, InputTransform } from '$lib/gen'
import { get, writable, derived } from 'svelte/store'
import { flowStateStore, initFlowState } from './flowState'
import { flowStateStore, initFlowState, type FlowState } from './flowState'
import { numberToChars } from './utils'
export type FlowMode = 'push' | 'pull'
@@ -51,7 +51,7 @@ export function dfs(modules: FlowModule[], previewOrder: boolean = false): strin
export const flowIds = derived(flowStore, flow => dfs(flow.value.modules))
export async function initFlow(flow: Flow) {
export async function initFlow(flow: Flow, flowState: FlowState | undefined) {
let counter = 40
for (const mod of flow.value.modules) {
@@ -68,7 +68,8 @@ export async function initFlow(flow: Flow) {
}
}
await initFlowState(flow)
await initFlowState(flow, flowState)
flowStore.set(flow)
function migrateFlowModule(mod: FlowModule) {
@@ -20,7 +20,7 @@
function importJson() {
Object.assign($flowStore, JSON.parse(pendingJson))
initFlow($flowStore)
initFlow($flowStore, undefined)
sendUserToast('OpenFlow imported from JSON')
jsonSetterDrawer.toggleDrawer()
}
@@ -45,7 +45,7 @@
</script>
<Splitpanes>
<Pane minSize={20} class="relative p-4 !duration-[0ms]">
<Pane minSize={20} size={66} class="relative p-4 !duration-[0ms]">
<slot />
</Pane>
<Pane minSize={20} class="px-2 py-2 h-full !duration-[0ms]">
@@ -44,7 +44,7 @@
function importJson() {
Object.assign($flowStore, JSON.parse(pendingJson))
initFlow($flowStore)
initFlow($flowStore, undefined)
sendUserToast('OpenFlow imported from JSON')
drawers.json?.toggleDrawer()
}
+15 -15
View File
@@ -20,21 +20,20 @@
const hubId = $page.url.searchParams.get('hub')
const templatePath = $page.url.searchParams.get('template')
let selectedId: string | undefined
async function loadFlow() {
let flow: Flow =
initialState != undefined
? decodeState(initialState)
: {
path: '',
summary: '',
value: { modules: [] },
edited_by: '',
edited_at: '',
archived: false,
extra_perms: {},
schema: emptySchema()
}
let state = initialState ? decodeState(initialState) : undefined
let flow: Flow = state?.flow ?? {
path: '',
summary: '',
value: { modules: [] },
edited_by: '',
edited_at: '',
archived: false,
extra_perms: {},
schema: emptySchema()
}
if (templatePath) {
const template = await FlowService.getFlowByPath({
@@ -50,7 +49,8 @@
flow = flow
$page.url.searchParams.delete('hub')
}
initFlow(flow)
selectedId = state?.selectedId
await initFlow(flow, state?.flowState)
}
loadFlow()
@@ -58,4 +58,4 @@
$dirtyStore = true
</script>
<FlowBuilder />
<FlowBuilder {selectedId} />
@@ -17,7 +17,9 @@
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
const initialState = $page.url.searchParams.get('state')
let flowLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined
let stateLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined
let selectedId: string | undefined = undefined
let flow: Flow = {
path: $page.params.path,
@@ -32,19 +34,20 @@
let initialPath: string = ''
initFlow(flow)
initFlow(flow, undefined)
async function loadFlow(): Promise<void> {
flow =
flowLoadedFromUrl != undefined && flowLoadedFromUrl.path == flow.path
? flowLoadedFromUrl
stateLoadedFromUrl != undefined && stateLoadedFromUrl?.flow?.path == flow.path
? stateLoadedFromUrl.flow
: await FlowService.getFlowByPath({
workspace: $workspaceStore!,
path: flow.path
})
initialPath = flow.path
initFlow(flow)
await initFlow(flow, stateLoadedFromUrl?.flowState)
selectedId = stateLoadedFromUrl?.selectedId
$dirtyStore = false
}
@@ -53,8 +56,6 @@
loadFlow()
}
}
</script>
<FlowBuilder {initialPath} />
<FlowBuilder {initialPath} {selectedId} />