From 3be96d877346f1150a4c412ae7a686ec37b4eabf Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Fri, 10 Mar 2023 18:41:27 +0100 Subject: [PATCH] feat(frontend-apps): add variable picker for static string input on apps --- backend/windmill-api/src/apps.rs | 20 +++++++ .../src/lib/components/ResourcePicker.svelte | 1 + .../apps/components/buttons/AppButton.svelte | 4 +- .../apps/components/buttons/AppForm.svelte | 4 +- .../components/buttons/AppFormButton.svelte | 4 +- .../components/display/AppBarChart.svelte | 4 +- .../display/AppDisplayComponent.svelte | 4 +- .../apps/components/display/AppHtml.svelte | 4 +- .../apps/components/display/AppIcon.svelte | 4 +- .../apps/components/display/AppImage.svelte | 4 +- .../apps/components/display/AppMap.svelte | 4 +- .../apps/components/display/AppPdf.svelte | 4 +- .../components/display/AppPieChart.svelte | 4 +- .../components/display/AppScatterChart.svelte | 4 +- .../apps/components/display/AppText.svelte | 4 +- .../components/display/AppTimeseries.svelte | 4 +- .../display/table/AppAggridTable.svelte | 4 +- .../components/display/table/AppTable.svelte | 4 +- .../apps/components/helpers/InputValue.svelte | 4 +- .../helpers/NonRunnableComponent.svelte | 4 +- .../components/helpers/RefreshButton.svelte | 4 +- .../components/helpers/ResizeWrapper.svelte | 4 +- .../helpers/RunnableComponent.svelte | 4 +- .../components/helpers/RunnableWrapper.svelte | 4 +- .../apps/components/inputs/AppCheckbox.svelte | 4 +- .../components/inputs/AppDateInput.svelte | 4 +- .../components/inputs/AppFileInput.svelte | 4 +- .../components/inputs/AppMultiSelect.svelte | 4 +- .../components/inputs/AppNumberInput.svelte | 4 +- .../components/inputs/AppRangeInput.svelte | 4 +- .../apps/components/inputs/AppSelect.svelte | 4 +- .../components/inputs/AppSliderInputs.svelte | 4 +- .../components/inputs/AppTextInput.svelte | 4 +- .../inputs/currency/AppCurrencyInput.svelte | 4 +- .../components/layout/AppContainer.svelte | 4 +- .../apps/components/layout/AppDivider.svelte | 4 +- .../apps/components/layout/AppDrawer.svelte | 4 +- .../components/layout/AppSplitpanes.svelte | 7 ++- .../apps/components/layout/AppTabs.svelte | 8 ++- .../components/apps/editor/AppEditor.svelte | 59 +++++++++++++++++-- .../apps/editor/AppEditorHeader.svelte | 11 ++-- .../components/apps/editor/AppInputs.svelte | 4 +- .../components/apps/editor/AppPreview.svelte | 8 +-- .../apps/editor/ComponentHeader.svelte | 4 +- .../components/apps/editor/GridEditor.svelte | 7 ++- .../components/apps/editor/GridPanel.svelte | 4 +- .../apps/editor/RecomputeAllComponents.svelte | 30 +++++----- .../apps/editor/SettingsPanel.svelte | 4 +- .../apps/editor/SubGridEditor.svelte | 16 ++--- .../apps/editor/component/Component.svelte | 4 +- .../component/ComponentNavigation.svelte | 8 ++- .../apps/editor/component/default-codes.ts | 12 ++-- .../componentsPanel/ComponentList.svelte | 7 ++- .../editor/componentsPanel/CssSettings.svelte | 4 +- .../contextPanel/ComponentOutputViewer.svelte | 4 +- .../editor/contextPanel/ContextPanel.svelte | 4 +- .../EmptyInlineScript.svelte | 4 +- .../InlineScriptEditor.svelte | 4 +- .../InlineScriptsPanel.svelte | 4 +- .../InlineScriptsPanelList.svelte | 4 +- .../ComponentInputTypeEditor.svelte | 4 +- .../settingsPanel/ComponentPanel.svelte | 9 +-- .../apps/editor/settingsPanel/GridPane.svelte | 4 +- .../apps/editor/settingsPanel/GridTab.svelte | 4 +- .../settingsPanel/InputsSpecEditor.svelte | 1 + .../settingsPanel/InputsSpecsEditor.svelte | 4 +- .../settingsPanel/MoveToOtherGrid.svelte | 5 +- .../editor/settingsPanel/Recompute.svelte | 4 +- .../settingsPanel/SelectedRunnable.svelte | 4 +- .../editor/settingsPanel/TableActions.svelte | 4 +- .../inputEditor/ConnectedInputEditor.svelte | 4 +- .../inputEditor/EvalInputEditor.svelte | 4 +- .../inputEditor/StaticInputEditor.svelte | 36 ++++++++--- .../mainInput/RunnableSelector.svelte | 4 +- frontend/src/lib/components/apps/types.ts | 7 ++- 75 files changed, 291 insertions(+), 189 deletions(-) diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index afe569cba6..9c4cb54f9e 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -733,6 +733,9 @@ fn build_args( path: String, args: &Map, ) -> Result> { + // disallow var and res access in args coming from the user for security reasons + args.into_iter() + .try_for_each(|x| disallow_var_res_access(x.1))?; let static_args = policy .triggerables .get(&path) @@ -753,3 +756,20 @@ fn build_args( } Ok(args) } + +fn disallow_var_res_access(args: &serde_json::Value) -> Result<()> { + match args { + Value::Object(v) => v.into_iter().try_for_each(|x| disallow_var_res_access(x.1)), + Value::Array(arr) => arr.into_iter().try_for_each(|v| disallow_var_res_access(v)), + Value::String(s) => { + if s.starts_with("$var:") || s.starts_with("$res:") { + Err(Error::BadRequest(format!( + "For security reasons, variable or resource access is not allowed as dynamic argument" + ))) + } else { + Ok(()) + } + } + _ => Ok(()), + } +} diff --git a/frontend/src/lib/components/ResourcePicker.svelte b/frontend/src/lib/components/ResourcePicker.svelte index 2e12def37b..67ec0185e3 100644 --- a/frontend/src/lib/components/ResourcePicker.svelte +++ b/frontend/src/lib/components/ResourcePicker.svelte @@ -58,6 +58,7 @@ on:refresh={async (e) => { await loadResources(resourceType) value = e.detail + valueSelect = { value: e.detail, label: e.detail } }} newPageOAuth bind:this={appConnect} diff --git a/frontend/src/lib/components/apps/components/buttons/AppButton.svelte b/frontend/src/lib/components/apps/components/buttons/AppButton.svelte index da67a9a738..4256e86729 100644 --- a/frontend/src/lib/components/apps/components/buttons/AppButton.svelte +++ b/frontend/src/lib/components/apps/components/buttons/AppButton.svelte @@ -3,7 +3,7 @@ import { getContext } from 'svelte' import type { AppInput } from '../../inputType' import type { Output } from '../../rx' - import type { AppEditorContext, ComponentCustomCSS } from '../../types' + import type { AppViewerContext, ComponentCustomCSS } from '../../types' import AlignWrapper from '../helpers/AlignWrapper.svelte' import InputValue from '../helpers/InputValue.svelte' import type RunnableComponent from '../helpers/RunnableComponent.svelte' @@ -26,7 +26,7 @@ export const staticOutputs: string[] = ['loading', 'result'] - const { runnableComponents, worldStore, app } = getContext('AppEditorContext') + const { runnableComponents, worldStore, app } = getContext('AppViewerContext') let labelValue: string let color: ButtonType.Color diff --git a/frontend/src/lib/components/apps/components/buttons/AppForm.svelte b/frontend/src/lib/components/apps/components/buttons/AppForm.svelte index 78944e7790..7cf3ca59a4 100644 --- a/frontend/src/lib/components/apps/components/buttons/AppForm.svelte +++ b/frontend/src/lib/components/apps/components/buttons/AppForm.svelte @@ -5,7 +5,7 @@ import { Icon } from 'svelte-awesome' import type { AppInput } from '../../inputType' import type { Output } from '../../rx' - import type { AppEditorContext, ComponentCustomCSS } from '../../types' + import type { AppViewerContext, ComponentCustomCSS } from '../../types' import { concatCustomCss } from '../../utils' import AlignWrapper from '../helpers/AlignWrapper.svelte' import InputValue from '../helpers/InputValue.svelte' @@ -24,7 +24,7 @@ export const staticOutputs: string[] = ['loading', 'result'] const { app, runnableComponents, worldStore, stateId } = - getContext('AppEditorContext') + getContext('AppViewerContext') let labelValue: string = 'Default label' let color: ButtonType.Color diff --git a/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte b/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte index 8b54393951..3e03bbe555 100644 --- a/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte +++ b/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte @@ -5,7 +5,7 @@ import { Icon } from 'svelte-awesome' import type { AppInput } from '../../inputType' import type { Output } from '../../rx' - import type { AppEditorContext, ComponentCustomCSS } from '../../types' + import type { AppViewerContext, ComponentCustomCSS } from '../../types' import AlignWrapper from '../helpers/AlignWrapper.svelte' import InputValue from '../helpers/InputValue.svelte' import type RunnableComponent from '../helpers/RunnableComponent.svelte' @@ -26,7 +26,7 @@ export const staticOutputs: string[] = ['loading', 'result'] - const { app, runnableComponents, worldStore } = getContext('AppEditorContext') + const { app, runnableComponents, worldStore } = getContext('AppViewerContext') let labelValue: string = 'Default label' let color: ButtonType.Color diff --git a/frontend/src/lib/components/apps/components/display/AppBarChart.svelte b/frontend/src/lib/components/apps/components/display/AppBarChart.svelte index 3dc5aa6140..7cccf90641 100644 --- a/frontend/src/lib/components/apps/components/display/AppBarChart.svelte +++ b/frontend/src/lib/components/apps/components/display/AppBarChart.svelte @@ -17,7 +17,7 @@ import InputValue from '../helpers/InputValue.svelte' import { concatCustomCss } from '../../utils' import { getContext } from 'svelte' - import type { AppEditorContext, ComponentCustomCSS } from '../../types' + import type { AppViewerContext, ComponentCustomCSS } from '../../types' export let id: string export let componentInput: AppInput | undefined @@ -27,7 +27,7 @@ export let render: boolean export const staticOutputs: string[] = ['loading', 'result'] - const { app } = getContext('AppEditorContext') + const { app } = getContext('AppViewerContext') ChartJS.register( Title, diff --git a/frontend/src/lib/components/apps/components/display/AppDisplayComponent.svelte b/frontend/src/lib/components/apps/components/display/AppDisplayComponent.svelte index 99c2a0f832..eb970d233c 100644 --- a/frontend/src/lib/components/apps/components/display/AppDisplayComponent.svelte +++ b/frontend/src/lib/components/apps/components/display/AppDisplayComponent.svelte @@ -5,7 +5,7 @@ import type { AppInput } from '../../inputType' import { IS_APP_PUBLIC_CONTEXT_KEY, - type AppEditorContext, + type AppViewerContext, type ComponentCustomCSS } from '../../types' import RunnableWrapper from '../helpers/RunnableWrapper.svelte' @@ -17,7 +17,7 @@ export let render: boolean const requireHtmlApproval = getContext(IS_APP_PUBLIC_CONTEXT_KEY) - const { app } = getContext('AppEditorContext') + const { app } = getContext('AppViewerContext') let result: any = undefined export const staticOutputs: string[] = ['result', 'loading'] diff --git a/frontend/src/lib/components/apps/components/display/AppHtml.svelte b/frontend/src/lib/components/apps/components/display/AppHtml.svelte index 8ce2ef735c..a8e5c45eb0 100644 --- a/frontend/src/lib/components/apps/components/display/AppHtml.svelte +++ b/frontend/src/lib/components/apps/components/display/AppHtml.svelte @@ -1,7 +1,7 @@ @@ -284,3 +300,36 @@ {:else} App editor not available to operators {/if} + + { + $pickVariableCallback?.(path) + }} + itemName="Variable" + extraField="path" + loadItems={async () => + (await VariableService.listVariable({ workspace: $workspaceStore ?? '' })).map((x) => ({ + name: x.path, + ...x + }))} +> +
+ +
+
+ + diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index 04500d811e..754b2ad88d 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -27,7 +27,7 @@ import Tooltip from '$lib/components/Tooltip.svelte' import { AppService, Job, Policy } from '$lib/gen' import { redo, undo } from '$lib/history' - import { userStore, workspaceStore } from '$lib/stores' + import { workspaceStore } from '$lib/stores' import { faBug, faClipboard, @@ -61,7 +61,7 @@ StaticAppInput, UserAppInput } from '../inputType' - import type { AppEditorContext } from '../types' + import type { AppEditorContext, AppViewerContext } from '../types' import { allItems, toStatic } from '../utils' import AppExportButton from './AppExportButton.svelte' import AppInputs from './AppInputs.svelte' @@ -90,9 +90,10 @@ errorByComponent, openDebugRun, focusedGrid, - selectedComponent, - history - } = getContext('AppEditorContext') + selectedComponent + } = getContext('AppViewerContext') + + const { history } = getContext('AppEditorContext') const loading = { publish: false, diff --git a/frontend/src/lib/components/apps/editor/AppInputs.svelte b/frontend/src/lib/components/apps/editor/AppInputs.svelte index 6fed2e3b78..15c5afeef8 100644 --- a/frontend/src/lib/components/apps/editor/AppInputs.svelte +++ b/frontend/src/lib/components/apps/editor/AppInputs.svelte @@ -2,11 +2,11 @@ import { Alert } from '$lib/components/common' import Toggle from '$lib/components/Toggle.svelte' import { getContext } from 'svelte' - import type { AppEditorContext } from '../types' + import type { AppViewerContext } from '../types' import AppComponentInput from './AppComponentInput.svelte' import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte' - const { app } = getContext('AppEditorContext') + const { app } = getContext('AppViewerContext') let resourceOnly: boolean = true diff --git a/frontend/src/lib/components/apps/editor/AppPreview.svelte b/frontend/src/lib/components/apps/editor/AppPreview.svelte index dbd360beee..8d926d51be 100644 --- a/frontend/src/lib/components/apps/editor/AppPreview.svelte +++ b/frontend/src/lib/components/apps/editor/AppPreview.svelte @@ -4,7 +4,7 @@ import { buildWorld, type World } from '../rx' import type { App, - AppEditorContext, + AppViewerContext, ConnectingInput, EditorBreakpoint, EditorMode @@ -40,7 +40,7 @@ const runnableComponents = writable Promise>>({}) - setContext('AppEditorContext', { + setContext('AppViewerContext', { worldStore, staticOutputs, app: appStore, @@ -61,9 +61,7 @@ openDebugRun: writable(undefined), focusedGrid: writable(undefined), stateId: writable(0), - parentWidth: writable(0), - history: writable(undefined), - componentControl: writable({}) + parentWidth: writable(0) }) let mounted = false diff --git a/frontend/src/lib/components/apps/editor/ComponentHeader.svelte b/frontend/src/lib/components/apps/editor/ComponentHeader.svelte index 509610ab0f..4a13c27ed8 100644 --- a/frontend/src/lib/components/apps/editor/ComponentHeader.svelte +++ b/frontend/src/lib/components/apps/editor/ComponentHeader.svelte @@ -1,6 +1,6 @@ diff --git a/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte b/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte index 8483406854..b87c49e738 100644 --- a/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte +++ b/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte @@ -3,9 +3,9 @@ import { ChevronDown, RefreshCw } from 'lucide-svelte' import { getContext, onMount } from 'svelte' import Button from '../../common/button/Button.svelte' - import type { AppEditorContext } from '../types' + import type { AppViewerContext } from '../types' - const { runnableComponents } = getContext('AppEditorContext') + const { runnableComponents } = getContext('AppViewerContext') let loading: boolean = false let timeout: NodeJS.Timer | undefined = undefined let interval: number | undefined = undefined @@ -14,14 +14,14 @@ $: componentNumber = Object.keys($runnableComponents).length function onClick(stopAfterClear = true) { - if(timeout) { + if (timeout) { clearInterval(timeout) timeout = undefined shouldRefresh = false - if(stopAfterClear) return; + if (stopAfterClear) return } refresh() - if(interval) { + if (interval) { shouldRefresh = true timeout = setInterval(refresh, interval) } @@ -44,12 +44,12 @@ } function visChange() { - if(document.visibilityState === 'hidden') { - if(timeout) { + if (document.visibilityState === 'hidden') { + if (timeout) { clearInterval(timeout) timeout = undefined } - } else if(shouldRefresh) { + } else if (shouldRefresh) { timeout = setInterval(refresh, interval) } } @@ -58,7 +58,7 @@ document.addEventListener('visibilitychange', visChange) return () => { document.removeEventListener('visibilitychange', visChange) - if(timeout) clearInterval(timeout) + if (timeout) clearInterval(timeout) } }) @@ -66,17 +66,19 @@
({ displayName: `Every ${i * 5} seconds`, action: () => setInter(i * 5000) - })), + })) ]} > {interval ? `${interval / 1000}s` : 'once'} diff --git a/frontend/src/lib/components/apps/editor/SettingsPanel.svelte b/frontend/src/lib/components/apps/editor/SettingsPanel.svelte index 6c17ef905c..0222cb9735 100644 --- a/frontend/src/lib/components/apps/editor/SettingsPanel.svelte +++ b/frontend/src/lib/components/apps/editor/SettingsPanel.svelte @@ -1,11 +1,11 @@ {#if $app.grid} diff --git a/frontend/src/lib/components/apps/editor/SubGridEditor.svelte b/frontend/src/lib/components/apps/editor/SubGridEditor.svelte index c5e305683e..d4cfe0f5c2 100644 --- a/frontend/src/lib/components/apps/editor/SubGridEditor.svelte +++ b/frontend/src/lib/components/apps/editor/SubGridEditor.svelte @@ -4,7 +4,7 @@ import Grid from '@windmill-labs/svelte-grid' import { twMerge } from 'tailwind-merge' import { columnConfiguration, isFixed, toggleFixed } from '../gridUtils' - import type { AppEditorContext, GridItem } from '../types' + import type { AppEditorContext, AppViewerContext, GridItem } from '../types' import Component from './component/Component.svelte' import { expandGriditem, findGridItem } from './appUtils' import { push } from '$lib/history' @@ -22,16 +22,10 @@ const dispatch = createEventDispatcher() - const { - app, - connectingInput, - selectedComponent, - focusedGrid, - mode, - parentWidth, - breakpoint, - history - } = getContext('AppEditorContext') + const { app, connectingInput, selectedComponent, focusedGrid, mode, parentWidth, breakpoint } = + getContext('AppViewerContext') + + const { history } = getContext('AppEditorContext') $: highlight = id === $focusedGrid?.parentComponentId && shouldHighlight diff --git a/frontend/src/lib/components/apps/editor/component/Component.svelte b/frontend/src/lib/components/apps/editor/component/Component.svelte index dd6188bb75..375814ac31 100644 --- a/frontend/src/lib/components/apps/editor/component/Component.svelte +++ b/frontend/src/lib/components/apps/editor/component/Component.svelte @@ -3,7 +3,7 @@ import { fade } from 'svelte/transition' import { Loader2 } from 'lucide-svelte' import { twMerge } from 'tailwind-merge' - import type { AppEditorContext } from '../../types' + import type { AppViewerContext } from '../../types' import ComponentHeader from '../ComponentHeader.svelte' import type { AppComponent } from './components' import { @@ -49,7 +49,7 @@ export let render: boolean const { staticOutputs, mode, connectingInput, app, errorByComponent } = - getContext('AppEditorContext') + getContext('AppViewerContext') let hover = false let initializing: boolean | undefined = undefined let componentContainerHeight: number = 0 diff --git a/frontend/src/lib/components/apps/editor/component/ComponentNavigation.svelte b/frontend/src/lib/components/apps/editor/component/ComponentNavigation.svelte index 564b9115ba..641e2cc7d0 100644 --- a/frontend/src/lib/components/apps/editor/component/ComponentNavigation.svelte +++ b/frontend/src/lib/components/apps/editor/component/ComponentNavigation.svelte @@ -1,10 +1,12 @@ {#if inputSpecs} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/MoveToOtherGrid.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/MoveToOtherGrid.svelte index 298da5962d..7aec63cfaa 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/MoveToOtherGrid.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/MoveToOtherGrid.svelte @@ -4,7 +4,7 @@ import { push } from '$lib/history' import { faCopy } from '@fortawesome/free-solid-svg-icons' import { getContext } from 'svelte' - import type { App, AppEditorContext } from '../../types' + import type { App, AppEditorContext, AppViewerContext } from '../../types' import { createNewGridItem, deleteGridItem, @@ -19,7 +19,8 @@ let selectedOption: string - const { app, history } = getContext('AppEditorContext') + const { app } = getContext('AppViewerContext') + const { history } = getContext('AppEditorContext') function listAllSubGrids(app: App) { return app.subgrids ? Object.keys(app.subgrids) : [] diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/Recompute.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/Recompute.svelte index 90f05cdbde..d474caefee 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/Recompute.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/Recompute.svelte @@ -1,13 +1,13 @@ {#if componentInput?.type === 'static'} {#if componentInput.fieldType === 'number'} - + {:else if componentInput.fieldType === 'textarea'} -