mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 00:02:13 +00:00
feat(frontend): App builder password and date input (#1022)
* feat: Add password input to app builder
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let inputType: 'date' | 'time' | 'datetime-local'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export const staticOutputs: string[] = ['result']
|
||||
|
||||
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let input: HTMLInputElement
|
||||
let labelValue: string = 'Title'
|
||||
let minValue: string = ''
|
||||
let maxValue: string = ''
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
result: Output<string>
|
||||
}
|
||||
|
||||
function handleInput() {
|
||||
outputs?.result.set(input.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputValue input={configuration.label} bind:value={labelValue} />
|
||||
<InputValue input={configuration.minDate} bind:value={minValue} />
|
||||
<InputValue input={configuration.maxDate} bind:value={maxValue} />
|
||||
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<label class="w-full">
|
||||
<div>
|
||||
{labelValue}
|
||||
</div>
|
||||
<input
|
||||
type={inputType}
|
||||
bind:this={input}
|
||||
on:input={handleInput}
|
||||
min={minValue}
|
||||
max={maxValue}
|
||||
placeholder="Type..."
|
||||
/>
|
||||
</label>
|
||||
</AlignWrapper>
|
||||
@@ -14,7 +14,6 @@
|
||||
export let recomputeIds: string[] | undefined = undefined
|
||||
export let extraQueryParams: Record<string, any> = {}
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
|
||||
@@ -38,7 +37,7 @@
|
||||
autoRefresh={false}
|
||||
forceSchemaDisplay={true}
|
||||
>
|
||||
<AlignWrapper {horizontalAlignment} {verticalAlignment} disableVerticalAlignment={true}>
|
||||
<AlignWrapper {horizontalAlignment}>
|
||||
<Button
|
||||
on:click={() => {
|
||||
runnableComponent?.runComponent()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined
|
||||
export let disableVerticalAlignment: boolean = false
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
|
||||
function tailwindHorizontalAlignment(horizontalAlignment) {
|
||||
switch (horizontalAlignment) {
|
||||
@@ -31,7 +30,7 @@
|
||||
'flex w-full',
|
||||
tailwindHorizontalAlignment(horizontalAlignment),
|
||||
tailwindVerticalAlignment(verticalAlignment),
|
||||
disableVerticalAlignment ? '' : 'h-full'
|
||||
verticalAlignment ? 'h-full' : ''
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import DebouncedInput from '../helpers/DebouncedInput.svelte'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export const staticOutputs: string[] = ['result']
|
||||
|
||||
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -29,17 +31,19 @@
|
||||
|
||||
<InputValue input={configuration.label} bind:value={labelValue} />
|
||||
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<label>
|
||||
<div>
|
||||
{labelValue}
|
||||
</div>
|
||||
<DebouncedInput
|
||||
bind:value={value}
|
||||
debounceDelay={300}
|
||||
type="number"
|
||||
inputmode="numeric"
|
||||
pattern="\d*"
|
||||
placeholder="Type..."
|
||||
/>
|
||||
</label>
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<label class="w-full">
|
||||
<div>
|
||||
{labelValue}
|
||||
</div>
|
||||
<DebouncedInput
|
||||
bind:value={value}
|
||||
debounceDelay={300}
|
||||
type="number"
|
||||
inputmode="numeric"
|
||||
pattern="\d*"
|
||||
placeholder="Type..."
|
||||
/>
|
||||
</label>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -3,28 +3,41 @@
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let inputType = 'text'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export const staticOutputs: string[] = ['result']
|
||||
|
||||
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let value: string
|
||||
let input: HTMLInputElement
|
||||
let labelValue: string = 'Title'
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
result: Output<string>
|
||||
}
|
||||
$: (value || !value) && outputs?.result.set(value || '')
|
||||
|
||||
function handleInput() {
|
||||
outputs?.result.set(input.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputValue input={configuration.label} bind:value={labelValue} />
|
||||
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<label>
|
||||
<div>
|
||||
{labelValue}
|
||||
</div>
|
||||
<input type="text" bind:value placeholder="Type..." />
|
||||
</label>
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<label class="w-full">
|
||||
<div>
|
||||
{labelValue}
|
||||
</div>
|
||||
<input
|
||||
type={inputType}
|
||||
bind:this={input}
|
||||
on:input={handleInput}
|
||||
placeholder="Type..."
|
||||
/>
|
||||
</label>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import CheckboxComponent from '../components/selectInputs/AppCheckbox.svelte'
|
||||
import TextInputComponent from '../components/textInputs/AppTextInput.svelte'
|
||||
import NumberInputComponent from '../components/numberInputs/AppNumberInput.svelte'
|
||||
import DateInputComponent from '../components/dateInputs/AppDateInput.svelte'
|
||||
import ComponentHeader from './ComponentHeader.svelte'
|
||||
import AppForm from '../components/form/AppForm.svelte'
|
||||
|
||||
@@ -90,6 +91,10 @@
|
||||
<CheckboxComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'textinputcomponent'}
|
||||
<TextInputComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'passwordinputcomponent'}
|
||||
<TextInputComponent inputType='password' {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'dateinputcomponent'}
|
||||
<DateInputComponent inputType='date' {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'numberinputcomponent'}
|
||||
<NumberInputComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{/if}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="bg-white h-full relative"
|
||||
on:click|preventDefault={() => ($selectedComponent = undefined)}
|
||||
on:click|preventDefault={() => $selectedComponent = undefined}
|
||||
>
|
||||
<RecomputeAllComponents />
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
'h-full w-full flex justify-center align-center',
|
||||
gridComponent.data.card ? 'border border-gray-100' : ''
|
||||
)}
|
||||
on:click|preventDefault|stopPropagation={() => {
|
||||
on:click|stopPropagation={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = dataItem.data.id
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ const inputs: ComponentSet = {
|
||||
title: 'Inputs',
|
||||
components: [
|
||||
{
|
||||
verticalAlignment: 'center',
|
||||
id: 'textinputcomponent',
|
||||
type: 'textinputcomponent',
|
||||
componentInput: undefined,
|
||||
@@ -20,6 +21,23 @@ const inputs: ComponentSet = {
|
||||
card: false
|
||||
},
|
||||
{
|
||||
verticalAlignment: 'center',
|
||||
id: 'passwordinputcomponent',
|
||||
type: 'passwordinputcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
visible: false,
|
||||
value: 'Label',
|
||||
fieldType: 'textarea',
|
||||
defaultValue: 'Label'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
verticalAlignment: 'center',
|
||||
id: 'numberinputcomponent',
|
||||
type: 'numberinputcomponent',
|
||||
componentInput: undefined,
|
||||
@@ -34,6 +52,37 @@ const inputs: ComponentSet = {
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
verticalAlignment: 'center',
|
||||
id: 'dateinputcomponent',
|
||||
type: 'dateinputcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
visible: false,
|
||||
value: 'Title',
|
||||
fieldType: 'textarea',
|
||||
defaultValue: 'Title'
|
||||
},
|
||||
minDate: {
|
||||
type: 'static',
|
||||
visible: false,
|
||||
value: '',
|
||||
fieldType: 'date',
|
||||
defaultValue: ''
|
||||
},
|
||||
maxDate: {
|
||||
type: 'static',
|
||||
visible: false,
|
||||
value: '',
|
||||
fieldType: 'date',
|
||||
defaultValue: ''
|
||||
},
|
||||
},
|
||||
card: false,
|
||||
softWrap: true
|
||||
},
|
||||
{
|
||||
...defaultAlignement,
|
||||
id: 'checkboxcomponent',
|
||||
@@ -51,7 +100,7 @@ const inputs: ComponentSet = {
|
||||
card: false
|
||||
},
|
||||
{
|
||||
...defaultAlignement,
|
||||
verticalAlignment: 'center',
|
||||
id: 'selectcomponent',
|
||||
type: 'selectcomponent',
|
||||
componentInput: undefined,
|
||||
@@ -133,7 +182,7 @@ const buttons: ComponentSet = {
|
||||
card: false
|
||||
},
|
||||
{
|
||||
...defaultAlignement,
|
||||
horizontalAlignment: 'center',
|
||||
id: 'formcomponent',
|
||||
type: 'formcomponent',
|
||||
componentInput: {
|
||||
|
||||
@@ -17,6 +17,8 @@ type BaseComponent<T extends string> = {
|
||||
|
||||
export type TextComponent = BaseComponent<'textcomponent'>
|
||||
export type TextInputComponent = BaseComponent<'textinputcomponent'>
|
||||
export type PasswordInputComponent = BaseComponent<'passwordinputcomponent'>
|
||||
export type DateInputComponent = BaseComponent<'dateinputcomponent'>
|
||||
export type NumberInputComponent = BaseComponent<'numberinputcomponent'>
|
||||
export type ButtonComponent = BaseComponent<'buttoncomponent'> & {
|
||||
recomputeIds: string[] | undefined
|
||||
@@ -67,6 +69,8 @@ export type AppComponent = BaseAppComponent &
|
||||
| RunFormComponent
|
||||
| DisplayComponent
|
||||
| TextInputComponent
|
||||
| PasswordInputComponent
|
||||
| DateInputComponent
|
||||
| NumberInputComponent
|
||||
| BarChartComponent
|
||||
| TableComponent
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
Table2,
|
||||
TextCursorInput,
|
||||
Type,
|
||||
Lock,
|
||||
Calendar,
|
||||
ToggleLeft
|
||||
} from 'lucide-svelte'
|
||||
import type { AppInput, AppInputs, InputType } from './inputType'
|
||||
@@ -121,6 +123,14 @@ export const displayData: Record<AppComponent['type'], { name: string; icon: any
|
||||
numberinputcomponent: {
|
||||
name: 'Number input',
|
||||
icon: Binary
|
||||
},
|
||||
passwordinputcomponent: {
|
||||
name: 'Password input',
|
||||
icon: Lock
|
||||
},
|
||||
dateinputcomponent: {
|
||||
name: 'Date input',
|
||||
icon: Calendar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user