diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 76fd67296b..5179ccf80a 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -4892,6 +4892,7 @@ dependencies = [ "lazy_static", "phf", "regex", + "serde_json", "unicode-general-category", "windmill-common", "windmill-parser", diff --git a/backend/parsers/windmill-parser-bash/Cargo.toml b/backend/parsers/windmill-parser-bash/Cargo.toml index 0ae341ef8b..22579e82c3 100644 --- a/backend/parsers/windmill-parser-bash/Cargo.toml +++ b/backend/parsers/windmill-parser-bash/Cargo.toml @@ -16,4 +16,5 @@ unicode-general-category.workspace = true itertools.workspace = true anyhow.workspace = true regex.workspace = true -lazy_static.workspace = true \ No newline at end of file +lazy_static.workspace = true +serde_json.workspace = true \ No newline at end of file diff --git a/backend/parsers/windmill-parser-bash/src/lib.rs b/backend/parsers/windmill-parser-bash/src/lib.rs index fdd5f26fe6..a43e079cb7 100644 --- a/backend/parsers/windmill-parser-bash/src/lib.rs +++ b/backend/parsers/windmill-parser-bash/src/lib.rs @@ -1,6 +1,8 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming +use anyhow::anyhow; use regex::Regex; +use serde_json::json; use std::collections::HashMap; use windmill_parser::{Arg, MainArgSignature, Typ}; @@ -17,19 +19,32 @@ pub fn parse_bash_sig(code: &str) -> windmill_common::error::Result anyhow::Result>> { - let mut hm = HashMap::new(); - let re = Regex::new(r#"(?m)^(\w+)="\$(\d+)"$"#).unwrap(); - for cap in re.captures_iter(code) { - hm.insert(cap[2].parse::()?, cap[1].to_string()); + let mut hm: HashMap)> = HashMap::new(); + for cap in RE.captures_iter(code) { + hm.insert( + cap.get(2) + .or(cap.get(3)) + .and_then(|x| x.as_str().parse::().ok()) + .ok_or_else(|| anyhow!("Impossible to parse arg digit"))?, + ( + cap[1].to_string(), + cap.get(4).map(|x| x.as_str().to_string()), + ), + ); } let mut args = vec![]; for i in 1..20 { if hm.contains_key(&i) { + let (name, default) = hm.get(&i).unwrap(); args.push(Arg { - name: hm[&i].clone(), + name: name.clone(), typ: Typ::Str(None), - default: None, + default: default.clone().map(|x| json!(x)), otyp: None, has_default: false, }); @@ -43,6 +58,8 @@ fn parse_file(code: &str) -> anyhow::Result>> { #[cfg(test)] mod tests { + use serde_json::json; + use super::*; #[test] @@ -50,8 +67,7 @@ mod tests { let code = r#" token="$1" image="$2" -digest="${3:-latest}" -foo="$4" +digest="${3:-latest with spaces}" "#; //println!("{}", serde_json::to_string()?); @@ -74,6 +90,13 @@ foo="$4" typ: Typ::Str(None), default: None, has_default: false + }, + Arg { + otyp: None, + name: "digest".to_string(), + typ: Typ::Str(None), + default: Some(json!("latest with spaces")), + has_default: false } ] } 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/GroupEditor.svelte b/frontend/src/lib/components/GroupEditor.svelte index 3075102d58..7d24311595 100644 --- a/frontend/src/lib/components/GroupEditor.svelte +++ b/frontend/src/lib/components/GroupEditor.svelte @@ -234,6 +234,14 @@ name, requestBody: { username: member_name } }) + await GranularAclService.removeGranularAcls({ + workspace: $workspaceStore ?? '', + path: name, + kind: 'group_', + requestBody: { + owner: 'u/' + member_name + } + }) loadGroup() }}>remove diff --git a/frontend/src/lib/components/ResourcePicker.svelte b/frontend/src/lib/components/ResourcePicker.svelte index 2e12def37b..6e3033f72d 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} @@ -87,7 +88,7 @@ }} items={collection} class="text-clip grow min-w-0" - placeholder="{resourceType} resource" + placeholder="{resourceType ?? 'any'} resource" inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles} containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles} /> 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..ca6279d0ca 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, @@ -470,8 +471,8 @@ { $app = undo(history, $app) }} 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..ccf06d287f 100644 --- a/frontend/src/lib/components/apps/editor/AppPreview.svelte +++ b/frontend/src/lib/components/apps/editor/AppPreview.svelte @@ -5,6 +5,7 @@ import type { App, AppEditorContext, + AppViewerContext, ConnectingInput, EditorBreakpoint, EditorMode @@ -40,7 +41,7 @@ const runnableComponents = writable Promise>>({}) - setContext('AppEditorContext', { + setContext('AppViewerContext', { worldStore, staticOutputs, app: appStore, @@ -61,9 +62,13 @@ openDebugRun: writable(undefined), focusedGrid: writable(undefined), stateId: writable(0), - parentWidth: writable(0), - history: writable(undefined), - componentControl: writable({}) + parentWidth: writable(0) + }) + + setContext('AppEditorContext', { + history: undefined, + componentControl: writable({}), + pickVariableCallback: writable(undefined) }) 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..1a280e5ed4 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..18b3e2b664 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 @@ -222,7 +222,7 @@ recomputeIds={component.recomputeIds} {render} /> - {:else if component.type === 'selectcomponent'} + {:else if component.type === 'selectcomponent' || component.type === 'resourceselectcomponent'} import { getContext } from 'svelte' - import type { AppEditorContext, EditorBreakpoint, GridItem } from '../../types' + import type { AppEditorContext, AppViewerContext, EditorBreakpoint, GridItem } from '../../types' import { findGridItemParentId } from '../appUtils' - const { app, selectedComponent, breakpoint, componentControl, focusedGrid } = - getContext('AppEditorContext') + const { app, selectedComponent, breakpoint, focusedGrid } = + getContext('AppViewerContext') + + const { componentControl } = getContext('AppEditorContext') function getSortedGridItemsOfChildren(): GridItem[] { if (!$focusedGrid) { diff --git a/frontend/src/lib/components/apps/editor/component/components.ts b/frontend/src/lib/components/apps/editor/component/components.ts index 91d431765f..3f4eab49a5 100644 --- a/frontend/src/lib/components/apps/editor/component/components.ts +++ b/frontend/src/lib/components/apps/editor/component/components.ts @@ -74,7 +74,8 @@ export type AggridComponent = BaseComponent<'aggridcomponent'> export type DisplayComponent = BaseComponent<'displaycomponent'> export type ImageComponent = BaseComponent<'imagecomponent'> export type InputComponent = BaseComponent<'inputcomponent'> -export type SelectComponent = BaseComponent<'selectcomponent'> +export type SelectComponent = BaseComponent<'resourceselectcomponent'> +export type ResourceSelectComponent = BaseComponent<'selectcomponent'> export type MultiSelectComponent = BaseComponent<'multiselectcomponent'> export type CheckboxComponent = BaseComponent<'checkboxcomponent'> export type RadioComponent = BaseComponent<'radiocomponent'> @@ -116,6 +117,7 @@ export type AppComponent = BaseAppComponent & | PieChartComponent | ScatterChartComponent | SelectComponent + | ResourceSelectComponent | MultiSelectComponent | CheckboxComponent | FormComponent @@ -911,7 +913,7 @@ Hello \${ctx.username} } }, multiselectcomponent: { - name: 'MultiSelect', + name: 'Multi Select', icon: List, dims: '2:1-3:1', data: { @@ -940,6 +942,36 @@ Hello \${ctx.username} softWrap: true } }, + resourceselectcomponent: { + name: 'Resource Select', + icon: List, + dims: '2:1-3:1', + data: { + verticalAlignment: 'center', + id: '', + type: 'resourceselectcomponent', + componentInput: undefined, + configuration: { + items: { + type: 'static', + fieldType: 'array', + subFieldType: 'labeledresource', + value: [] + }, + placeholder: { + type: 'static', + fieldType: 'text', + value: 'Select an item', + onlyStatic: true + } + }, + customCss: { + input: { style: '' } + } as const, + card: false, + softWrap: true + } + }, numberinputcomponent: { name: 'Number', icon: Binary, diff --git a/frontend/src/lib/components/apps/editor/component/default-codes.ts b/frontend/src/lib/components/apps/editor/component/default-codes.ts index e9ee2f82a1..fbd1ad66f4 100644 --- a/frontend/src/lib/components/apps/editor/component/default-codes.ts +++ b/frontend/src/lib/components/apps/editor/component/default-codes.ts @@ -72,14 +72,14 @@ return { }, displaycomponent: { deno: `export async function main() { -return { - "foo": 42 -} + return { + "foo": 42 + } }`, python3: `def main(): -return { - "foo": 42 -}` + return { + "foo": 42 + }` }, htmlcomponent: { deno: `export async function main() { diff --git a/frontend/src/lib/components/apps/editor/component/sets.ts b/frontend/src/lib/components/apps/editor/component/sets.ts index 7677acfb10..59662af0dc 100644 --- a/frontend/src/lib/components/apps/editor/component/sets.ts +++ b/frontend/src/lib/components/apps/editor/component/sets.ts @@ -32,6 +32,7 @@ const inputs: ComponentSet = { 'fileinputcomponent', 'checkboxcomponent', 'selectcomponent', + 'resourceselectcomponent', 'multiselectcomponent', ] } as const diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/ComponentList.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/ComponentList.svelte index 438f7a1826..83f017173e 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/ComponentList.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/ComponentList.svelte @@ -1,5 +1,5 @@ {#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'} -