new app component: currency + improved select

This commit is contained in:
Ruben Fiszel
2023-02-16 23:40:58 +01:00
parent 868cb339a7
commit 34c34fa998
14 changed files with 209 additions and 34 deletions
+2
View File
@@ -1774,6 +1774,8 @@ for k, v in list(args.items()):
try:
res = inner_script.main(**args)
if type(res).__name__ == 'DataFrame':
res = res.values.tolist()
res_json = json.dumps(res, separators=(',', ':'), default=str).replace('\n', '')
with open("result.json", 'w') as f:
f.write(res_json)
+11
View File
@@ -8,6 +8,7 @@
"name": "windmill",
"version": "1.64.0",
"dependencies": {
"@canutin/svelte-currency-input": "^0.8.0",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@leeoniya/ufuzzy": "^0.9.1",
@@ -205,6 +206,11 @@
"node": ">=4"
}
},
"node_modules/@canutin/svelte-currency-input": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@canutin/svelte-currency-input/-/svelte-currency-input-0.8.0.tgz",
"integrity": "sha512-u/ywCjAQzBTU1GvoljNgVzA/xV6UjVXsFbe4KISxk3cZJOA3eN35qaGtNMJhWQ0JI+QbFjxv2I2nHbdzmmn1Nw=="
},
"node_modules/@csstools/selector-specificity": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz",
@@ -7278,6 +7284,11 @@
}
}
},
"@canutin/svelte-currency-input": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@canutin/svelte-currency-input/-/svelte-currency-input-0.8.0.tgz",
"integrity": "sha512-u/ywCjAQzBTU1GvoljNgVzA/xV6UjVXsFbe4KISxk3cZJOA3eN35qaGtNMJhWQ0JI+QbFjxv2I2nHbdzmmn1Nw=="
},
"@csstools/selector-specificity": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz",
+1
View File
@@ -61,6 +61,7 @@
},
"type": "module",
"dependencies": {
"@canutin/svelte-currency-input": "^0.8.0",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@leeoniya/ufuzzy": "^0.9.1",
+3
View File
@@ -23,6 +23,9 @@
display: none !important;
}
.svelte-select-list {
z-index: 1000 !important;
}
.nowrap pre code.hljs {
whitespace: normal !important;
}
@@ -417,7 +417,7 @@
</div>
{/if}
{/if}
{#if resource_type == 'postgresql' || resource_type == 'mysql'}
{#if resource_type == 'postgresql' || resource_type == 'mysql' || resource_type == 'mongodb'}
<WhitelistIp />
{/if}
@@ -0,0 +1,64 @@
<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 InputDefaultValue from '../helpers/InputDefaultValue.svelte'
import InputValue from '../helpers/InputValue.svelte'
import CurrencyInput from '@canutin/svelte-currency-input'
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')
let defaultValue: number | undefined = undefined
let isNegativeAllowed: boolean | undefined = undefined
let currency: string | undefined = undefined
let locale: string | undefined = undefined
let value: number | undefined = undefined
$: outputs = $worldStore?.outputsById[id] as {
result: Output<number | null>
}
function handleInput() {
outputs?.result.set(value ?? null)
}
function handleDefault() {
value = defaultValue
}
$: value && handleInput()
$: defaultValue && handleDefault()
</script>
<InputValue {id} input={configuration.defaultValue} bind:value={defaultValue} />
<InputValue {id} input={configuration.isNegativeAllowed} bind:value={isNegativeAllowed} />
<InputValue {id} input={configuration.currency} bind:value={currency} />
<InputValue {id} input={configuration.locale} bind:value={locale} />
<AlignWrapper {verticalAlignment}>
{#key isNegativeAllowed}
{#key locale}
{#key currency}
<CurrencyInput
inputClasses={{ formatted: 'p-0' }}
bind:value
{currency}
{locale}
on:focus={(e) => {
e?.stopPropagation()
}}
{isNegativeAllowed}
/>
{/key}
{/key}
{/key}
</AlignWrapper>
@@ -18,6 +18,10 @@
let defaultValue: number | undefined = undefined
let placeholder: string | undefined = undefined
let min: number | undefined = undefined
let max: number | undefined = undefined
let step = 1
$: outputs = $worldStore?.outputsById[id] as {
result: Output<number | null>
}
@@ -31,6 +35,9 @@
$: input && handleInput()
</script>
<InputValue {id} input={configuration.step} bind:value={step} />
<InputValue {id} input={configuration.min} bind:value={min} />
<InputValue {id} input={configuration.max} bind:value={max} />
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
<InputValue {id} input={configuration.defaultValue} bind:value={defaultValue} />
<InputDefaultValue bind:input {defaultValue} />
@@ -43,6 +50,9 @@
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
}}
{min}
{max}
{step}
type="number"
inputmode="numeric"
pattern="\d*"
@@ -18,6 +18,8 @@
let label: string
let items: string[]
let itemKey: string
let multiple: boolean = false
let placeholder: string = 'Select an item'
$: outputs = $worldStore?.outputsById[id] as {
result: Output<string | undefined>
@@ -35,24 +37,30 @@
<InputValue {id} input={configuration.label} bind:value={label} />
<InputValue {id} input={configuration.items} bind:value={items} />
<InputValue {id} input={configuration.itemKey} bind:value={itemKey} />
<InputValue {id} input={configuration.multiple} bind:value={multiple} />
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
<Select
--height="34px"
class="select"
on:clear={onChange}
on:change={onChange}
on:focus={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
}}
items={Array.isArray(items) ? items : []}
{value}
placeholder="Select an item"
on:click={() => {
if (!$connectingInput.opened) {
$selectedComponent = id
}
}}
/>
<div class="app-select w-full" style="height: 34px" on:pointerdown|stopPropagation>
<Select
--height="34px"
{multiple}
on:clear={onChange}
on:change={onChange}
items={Array.isArray(items) ? items : []}
{value}
{placeholder}
on:click={() => {
if (!$connectingInput.opened) {
$selectedComponent = id
}
}}
/>
</div>
</AlignWrapper>
<style global>
.app-select .value-container {
@apply p-0 !important;
}
</style>
@@ -16,7 +16,8 @@
GripHorizontal,
Code2,
SlidersHorizontal,
PlusSquare
PlusSquare,
DollarSign
} from 'lucide-svelte'
import type { Size } from 'svelte-grid'
@@ -38,6 +39,7 @@
export type PasswordInputComponent = BaseComponent<'passwordinputcomponent'>
export type DateInputComponent = BaseComponent<'dateinputcomponent'>
export type NumberInputComponent = BaseComponent<'numberinputcomponent'>
export type CurrencyComponent = BaseComponent<'currencycomponent'>
export type SliderComponent = BaseComponent<'slidercomponent'>
export type RangeComponent = BaseComponent<'rangecomponent'>
export type HtmlComponent = BaseComponent<'htmlcomponent'>
@@ -74,6 +76,7 @@
| PasswordInputComponent
| DateInputComponent
| NumberInputComponent
| CurrencyComponent
| SliderComponent
| RangeComponent
| BarChartComponent
@@ -679,6 +682,18 @@
type: 'static',
fieldType: 'text',
value: 'value'
},
multiple: {
type: 'static',
fieldType: 'boolean',
value: false,
onlyStatic: true
},
placeholder: {
type: 'static',
fieldType: 'text',
value: 'Select an item',
onlyStatic: true
}
},
card: false,
@@ -706,6 +721,64 @@
type: 'static',
value: undefined,
fieldType: 'number'
},
min: {
type: 'static',
value: undefined,
fieldType: 'number',
onlyStatic: true
},
max: {
type: 'static',
value: undefined,
fieldType: 'number',
onlyStatic: true
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
onlyStatic: true
}
},
card: false
}
},
currencycomponent: {
name: 'Currency',
icon: DollarSign,
dims: '2:1-3:1',
data: {
softWrap: true,
verticalAlignment: 'center',
id: '',
type: 'currencycomponent',
componentInput: undefined,
configuration: {
defaultValue: {
type: 'static',
value: undefined,
fieldType: 'number'
},
isNegativeAllowed: {
type: 'static',
value: false,
fieldType: 'boolean',
onlyStatic: true
},
currency: {
type: 'static',
value: 'USD',
fieldType: 'select',
onlyStatic: true,
optionValuesKey: 'currencyOptions'
},
locale: {
type: 'static',
value: 'en-US',
fieldType: 'select',
onlyStatic: true,
optionValuesKey: 'localeOptions'
}
},
card: false
@@ -854,6 +927,7 @@
'textinputcomponent',
'passwordinputcomponent',
'numberinputcomponent',
'currencycomponent',
'slidercomponent',
'rangecomponent',
'dateinputcomponent',
@@ -1241,6 +1315,7 @@
import PlotlyHtml from '../components/dataDisplay/PlotlyHtml.svelte'
import { defaultAlignement } from './componentsPanel/componentDefaultProps'
import AppRangeInput from '../components/numberInputs/AppRangeInput.svelte'
import AppCurrencyInput from '../components/numberInputs/AppCurrencyInput.svelte'
export let component: AppComponent
export let selected: boolean
@@ -1389,6 +1464,8 @@
/>
{:else if component.type === 'numberinputcomponent'}
<AppNumberInput {...component} bind:staticOutputs={$staticOutputs[component.id]} />
{:else if component.type === 'currencycomponent'}
<AppCurrencyInput {...component} bind:staticOutputs={$staticOutputs[component.id]} />
{:else if component.type === 'slidercomponent'}
<AppSliderInputs {...component} bind:staticOutputs={$staticOutputs[component.id]} />
{:else if component.type === 'rangecomponent'}
@@ -116,7 +116,7 @@
})
</script>
<div class="pb-2 relative w-full z-20">
<div class="pb-2 relative w-full z-20 overflow-visible border">
<div
class="w-full sticky top-0 flex justify-between border-l border-r border-b {$connectingInput?.opened
? ''
@@ -22,10 +22,7 @@
function addComponent(appComponentType: AppComponent['type']) {
$dirtyStore = true
const grid = $app.grid ?? []
const id = getNextId(
grid.map((gridItem) => gridItem.data.id),
true
)
const id = getNextId(grid.map((gridItem) => gridItem.data.id))
const appComponent = componentsRecord[appComponentType].data
@@ -7,5 +7,8 @@ export const staticValues = {
buttonSizeOptions: ['xs', 'sm', 'md', 'lg', 'xl'],
tableSearchOptions: ['By Component', 'By Runnable', 'Disabled'],
chartThemeOptions: ['theme1', 'theme2', 'theme3'],
textStyleOptions: ['Title', 'Subtitle', 'Body', 'Label', 'Caption']
textStyleOptions: ['Title', 'Subtitle', 'Body', 'Label', 'Caption'],
currencyOptions: ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'JPY', 'CNY', 'INR', 'BRL'],
localeOptions: ['en-US', 'en-GB', 'en-IE', 'de-DE', 'fr-FR', 'br-FR', 'ja-JP', 'pt-TL', 'fr-CA', 'en-CA']
} as const
@@ -32,7 +32,7 @@ export async function loadFlowModuleState(flowModule: FlowModule): Promise<FlowM
export const idMutex = new Mutex()
export function getNextId(currentKeys: string[], skipTilde: boolean = false): string {
export function getNextId(currentKeys: string[]): string {
const max = currentKeys.reduce((acc, key) => {
if (key === 'failure' || key.includes('branch') || key.includes('loop')) {
return acc
+6 -7
View File
@@ -179,9 +179,9 @@ export function emptyFlowModuleState(): FlowModuleState {
const aCharCode = 'a'.charCodeAt(0)
export function numberToChars(n: number, skipTilde: boolean = false) {
export function numberToChars(n: number) {
if (n < 0) {
return "-" + numberToChars(-n, skipTilde)
return "-" + numberToChars(-n)
}
var b = [n],
sp,
@@ -190,12 +190,11 @@ export function numberToChars(n: number, skipTilde: boolean = false) {
div
sp = 0
const basisInc = skipTilde ? -1 : 0
while (sp < b.length) {
if (b[sp] > (25 + basisInc)) {
div = Math.floor(b[sp] / (27 + basisInc))
if (b[sp] > (25)) {
div = Math.floor(b[sp] / (26))
b[sp + 1] = div - 1
b[sp] %= (27 + basisInc)
b[sp] %= (26)
}
sp += 1
}
@@ -203,7 +202,7 @@ export function numberToChars(n: number, skipTilde: boolean = false) {
out = ''
for (i = 0; i < b.length; i += 1) {
let charCode = aCharCode + b[i]
out = (b[i] == 26 ? "-" : String.fromCharCode(charCode)) + out
out = String.fromCharCode(charCode) + out
}
return out