mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 16:01:42 +00:00
frontend(fix): rework all text inputs
This commit is contained in:
Generated
+27
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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} />
|
||||
|
||||
Reference in New Issue
Block a user