From 10be98005806293e49b941bb57ddccd7014fdf2f Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 19 Feb 2026 09:31:38 +0000 Subject: [PATCH] internal: instant npm run check --- frontend/.gitignore | 4 +- frontend/CLAUDE.md | 5 + frontend/package.json | 1 + .../src/lib/components/ApiConnectForm.svelte | 3 +- frontend/src/lib/components/ArgInput.svelte | 3 +- frontend/src/lib/components/DiffEditor.svelte | 8 +- .../lib/components/InputTransformForm.svelte | 71 +++++----- .../lib/components/InstanceSettings.svelte | 4 +- .../components/SchemaFormWithArgPicker.svelte | 82 +++++++---- frontend/src/lib/components/SqlRepl.svelte | 3 +- frontend/src/lib/components/Toast.svelte | 12 +- .../src/lib/components/VariableEditor.svelte | 3 +- .../WorkspaceDependenciesEditor.svelte | 131 +++++++++++------- .../lib/components/assets/AssetButtons.svelte | 6 +- .../src/lib/components/diffEditorTypes.ts | 7 + .../content/FlowEnvironmentVariables.svelte | 5 +- .../components/flows/content/FlowLoop.svelte | 9 +- .../flows/content/FlowModuleComponent.svelte | 5 +- .../flows/propPicker/FlowPropPicker.svelte | 80 ----------- .../flows/propPicker/OutputPicker.svelte | 4 +- .../flows/propPicker/PropPickerWrapper.svelte | 25 ++-- frontend/src/lib/components/flows/types.ts | 2 +- .../graph/renderers/nodes/AssetNode.svelte | 3 +- frontend/src/lib/components/home/Item.svelte | 23 +-- frontend/src/lib/components/prop_picker.ts | 3 - .../propertyPicker/PropPicker.svelte | 110 +++++++-------- .../raw_apps/RawAppInlineScriptEditor.svelte | 2 +- .../sidebar/CriticalAlertModalInner.svelte | 66 +++++---- .../CustomInstanceDbWizardModal.svelte | 3 +- .../workspaceSettings/StorageSettings.svelte | 2 +- frontend/src/lib/stores.ts | 3 +- frontend/src/lib/toast.ts | 5 +- .../(root)/(logged)/assets/+page.svelte | 2 +- .../(root)/(logged)/resources/+page.svelte | 4 +- frontend/svelte-fast-check.config.ts | 5 + frontend/tsconfig.json | 10 -- 36 files changed, 348 insertions(+), 366 deletions(-) create mode 100644 frontend/src/lib/components/diffEditorTypes.ts delete mode 100644 frontend/src/lib/components/flows/propPicker/FlowPropPicker.svelte create mode 100644 frontend/svelte-fast-check.config.ts diff --git a/frontend/.gitignore b/frontend/.gitignore index 9795c44865..972b0f540f 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -25,4 +25,6 @@ src/lib/components/copilot/chat/__tests__/app/results/ /playwright/.cache/ /playwright/.auth/ e2e/auth.json -e2e/*.png \ No newline at end of file +e2e/*.png + +.fast-check/ \ No newline at end of file diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 35fa075087..4ce27aa1ae 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -97,6 +97,11 @@ The `resource()` utility: After making frontend changes, you MUST run the following and fix all errors and warnings before considering the work done: +```bash +npm run check:fast +``` + +At the end of a PR to do final validation, you can do the longer one (2s for fast vs 50s for the slow one): ```bash npm run check ``` diff --git a/frontend/package.json b/frontend/package.json index a60fa1466e..1cd33c839d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,6 +7,7 @@ "build:utils": "vite build --config sharedUtils/vite.sharedUtils.config.js", "preview": "vite preview", "postinstall": "node -e \"if (require('fs').existsSync('./scripts/untar_ui_builder.js')) { require('child_process').execSync('node ./scripts/untar_ui_builder.js', {stdio: 'inherit'}) }\"", + "check:fast": "bun --bun svelte-fast-check --no-svelte-warnings --incremental", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --threshold warning", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", diff --git a/frontend/src/lib/components/ApiConnectForm.svelte b/frontend/src/lib/components/ApiConnectForm.svelte index be82752f24..a557b15b4a 100644 --- a/frontend/src/lib/components/ApiConnectForm.svelte +++ b/frontend/src/lib/components/ApiConnectForm.svelte @@ -3,7 +3,6 @@ import { workspaceStore } from '$lib/stores' import { emptySchema, emptyString } from '$lib/utils' import SchemaForm from './SchemaForm.svelte' - import type SimpleEditor from './SimpleEditor.svelte' import Toggle from './Toggle.svelte' import TestConnection from './TestConnection.svelte' import SupabaseIcon from './icons/SupabaseIcon.svelte' @@ -115,7 +114,7 @@ } } - let rawCodeEditor: SimpleEditor | undefined = $state(undefined) + let rawCodeEditor: { setCode: (code: string) => void } | undefined = $state(undefined) let textFileContent: string | undefined = $state(undefined) function parseTextFileContent() { diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index c88c63b54e..3fc1a772e3 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -20,7 +20,6 @@ import ObjectResourceInput from './ObjectResourceInput.svelte' import Range from './Range.svelte' import ResourcePicker from './ResourcePicker.svelte' - import type SimpleEditor from './SimpleEditor.svelte' import Toggle from './Toggle.svelte' import type VariableEditor from './VariableEditor.svelte' import { twMerge } from 'tailwind-merge' @@ -97,7 +96,7 @@ title?: string | undefined placeholder?: string | undefined order?: string[] | undefined - editor?: SimpleEditor | undefined + editor?: any | undefined orderEditable?: boolean shouldDispatchChanges?: boolean noDefaultOnSelectFirst?: boolean diff --git a/frontend/src/lib/components/DiffEditor.svelte b/frontend/src/lib/components/DiffEditor.svelte index 277cc66bda..1d252d082a 100644 --- a/frontend/src/lib/components/DiffEditor.svelte +++ b/frontend/src/lib/components/DiffEditor.svelte @@ -11,16 +11,10 @@ import EditorTheme from './EditorTheme.svelte' import Button from '$lib/components/common/button/Button.svelte' import { twMerge } from 'tailwind-merge' - import type { ButtonType } from './common' + import type { ButtonProp } from './diffEditorTypes' const SIDE_BY_SIDE_MIN_WIDTH = 700 - export interface ButtonProp { - text: string - color?: ButtonType.Color - onClick: () => void - } - interface Props { open?: boolean className?: string diff --git a/frontend/src/lib/components/InputTransformForm.svelte b/frontend/src/lib/components/InputTransformForm.svelte index 3ea8560261..7f6352241f 100644 --- a/frontend/src/lib/components/InputTransformForm.svelte +++ b/frontend/src/lib/components/InputTransformForm.svelte @@ -11,7 +11,7 @@
@@ -99,7 +117,7 @@
- + {@render children?.()}
@@ -108,14 +126,16 @@
{#if selectedTab === 'history'} - -
- historicInputs?.refresh()} - /> -
-
+ {#snippet action()} + +
+ historicInputs?.refresh()} + /> +
+
+ {/snippet} {:else if selectedTab === 'captures'} - -
- -
-
+ {#snippet action()} + +
+ +
+
+ {/snippet}
import { CornerDownLeft, Loader2 } from 'lucide-svelte' import Button from './common/button/Button.svelte' - import type Editor from './Editor.svelte' import { runScriptAndPollResult } from './jobs/utils' import { workspaceStore } from '$lib/stores' import { sendUserToast } from '$lib/toast' @@ -161,7 +160,7 @@ isRunning = false } } - let editor = $state(null) + let editor = $state(null) diff --git a/frontend/src/lib/components/Toast.svelte b/frontend/src/lib/components/Toast.svelte index 44281db0d1..13e857ed6f 100644 --- a/frontend/src/lib/components/Toast.svelte +++ b/frontend/src/lib/components/Toast.svelte @@ -10,13 +10,13 @@ let hover = Object.values(toastStates).some((state) => state.hover) for (const toastId in toastStates) { - const state = toastStates[toastId] + const st = toastStates[toastId] if (hover) continue - if (state.elapsed >= state.duration) { + if (st.elapsed >= st.duration) { delete toastStates[toastId] continue } - state.elapsed += delta + st.elapsed += delta } lastTime = time @@ -36,18 +36,16 @@ }) } } - - export type ToastType = AlertType diff --git a/frontend/src/lib/components/WorkspaceDependenciesEditor.svelte b/frontend/src/lib/components/WorkspaceDependenciesEditor.svelte index fd202e2272..b643c7e86e 100644 --- a/frontend/src/lib/components/WorkspaceDependenciesEditor.svelte +++ b/frontend/src/lib/components/WorkspaceDependenciesEditor.svelte @@ -1,13 +1,16 @@
@@ -353,15 +372,20 @@ numpy>=1.24.0 {#if showWarning && currentImportedPath} opt.value === workspaceDependencies.language)?.label || workspaceDependencies.language} + language={LANGUAGE_OPTIONS.find((opt) => opt.value === workspaceDependencies.language) + ?.label || workspaceDependencies.language} /> {/if} - +
{#if hasWorkspaceDefault(workspaceDependencies.language) && !edit} @@ -385,7 +409,10 @@ numpy>=1.24.0
{:else} - + {#snippet children({ item })} =1.24.0 {/if}
- Default Enforced Dependencies are used when no specific Dependencies are referenced from runnables. - Named dependencies can be referenced by scripts using + Default Enforced Dependencies are used when no specific Dependencies are referenced from + runnables. Named dependencies can be referenced by scripts using =1.24.0 />
- {edit ? 'Language cannot be changed after creation.' : 'Select the programming language these dependencies are for. This will load a default template.'} + {edit + ? 'Language cannot be changed after creation.' + : 'Select the programming language these dependencies are for. This will load a default template.'}
@@ -450,7 +479,8 @@ numpy>=1.24.0 class="input" />
- Provide a brief description to help others understand the purpose of these enforced dependencies. + Provide a brief description to help others understand the purpose of these enforced + dependencies.
@@ -476,9 +506,8 @@ numpy>=1.24.0 {/await}
-
- + {#snippet actions()}
{ const config = { - insertionMode: CONNECT, onSelect: (code) => { setExpr(code) return true @@ -405,7 +404,7 @@ notSelectable pickableProperties={stepPropPicker.pickableProperties} on:select={({ detail }) => { - if ($flowPropPickerConfig?.insertionMode == CONNECT) { + if ($flowPropPickerConfig) { setExpr(detail) flowPropPickerConfig.set(undefined) return diff --git a/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte b/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte index a0f3ede833..42ad317a32 100644 --- a/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte +++ b/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte @@ -36,7 +36,8 @@ import FlowModuleMockTransitionMessage from './FlowModuleMockTransitionMessage.svelte' import Tooltip from '$lib/components/Tooltip.svelte' import { SecondsInput } from '$lib/components/common' - import DiffEditor, { type ButtonProp } from '$lib/components/DiffEditor.svelte' + import DiffEditor from '$lib/components/DiffEditor.svelte' + import type { ButtonProp } from '$lib/components/diffEditorTypes' import FlowModuleTimeout from './FlowModuleTimeout.svelte' import HighlightCode from '$lib/components/HighlightCode.svelte' import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte' @@ -140,7 +141,7 @@ } ]) - let editor: Editor | undefined = $state() + let editor: any | undefined = $state() let diffEditor: DiffEditor | undefined = $state() let modulePreview: ModulePreview | undefined = $state() let websocketAlive = $state({ diff --git a/frontend/src/lib/components/flows/propPicker/FlowPropPicker.svelte b/frontend/src/lib/components/flows/propPicker/FlowPropPicker.svelte deleted file mode 100644 index 5a0524eae7..0000000000 --- a/frontend/src/lib/components/flows/propPicker/FlowPropPicker.svelte +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - -
- { - if ($flowPropPickerConfig?.onSelect(detail)) { - $flowPropPickerConfig?.clearFocus() - } - }} - allowCopy={!$flowPropPickerConfig} - /> -
-
- - - diff --git a/frontend/src/lib/components/flows/propPicker/OutputPicker.svelte b/frontend/src/lib/components/flows/propPicker/OutputPicker.svelte index 14701b1799..cdbfe8d153 100644 --- a/frontend/src/lib/components/flows/propPicker/OutputPicker.svelte +++ b/frontend/src/lib/components/flows/propPicker/OutputPicker.svelte @@ -50,9 +50,7 @@ const zoom = $derived.by(useSvelteFlow().getZoom) - let showConnecting = $derived( - isConnectingCandidate && $flowPropPickerConfig?.insertionMode === 'connect' - ) + let showConnecting = $derived(isConnectingCandidate && $flowPropPickerConfig != undefined) function selectConnection(value: string) { if ($flowPropPickerConfig?.onSelect(value)) { diff --git a/frontend/src/lib/components/flows/propPicker/PropPickerWrapper.svelte b/frontend/src/lib/components/flows/propPicker/PropPickerWrapper.svelte index a151b31509..6910fabbb5 100644 --- a/frontend/src/lib/components/flows/propPicker/PropPickerWrapper.svelte +++ b/frontend/src/lib/components/flows/propPicker/PropPickerWrapper.svelte @@ -6,18 +6,14 @@ propName?: string onSelect: SelectCallback clearFocus: () => void - insertionMode: 'append' | 'connect' | 'insert' } export type PropPickerWrapperContext = { propPickerConfig: Writable inputMatches: Writable<{ word: string; value: string }[] | undefined> - focusProp: ( - propName: string, - insertionMode: 'append' | 'connect' | 'insert', - onSelect: SelectCallback - ) => void - clearFocus: () => void + connectProp: (propName: string, onSelect: SelectCallback) => void + clearConnect: () => void + exprBeingEdited: Writable } @@ -77,10 +73,9 @@ setContext('PropPickerWrapper', { propPickerConfig, inputMatches, - focusProp: (propName, insertionMode, onSelect) => { + connectProp: (propName, onSelect) => { const config = { propName, - insertionMode, onSelect, clearFocus: () => { propPickerConfig.set(undefined) @@ -98,10 +93,11 @@ }) } }, - clearFocus: () => { + clearConnect: () => { flowPropPickerConfig.set(undefined) propPickerConfig.set(undefined) - } + }, + exprBeingEdited: writable([]) }) async function getPropPickerElements(): Promise { @@ -134,14 +130,11 @@
{#if result != undefined && !pickableProperties} diff --git a/frontend/src/lib/components/flows/types.ts b/frontend/src/lib/components/flows/types.ts index bb2ac57a7c..eace554bf6 100644 --- a/frontend/src/lib/components/flows/types.ts +++ b/frontend/src/lib/components/flows/types.ts @@ -13,7 +13,7 @@ import type { Asset, AssetWithAccessType } from '../assets/lib' import type S3FilePicker from '../S3FilePicker.svelte' import type ResourceEditorDrawer from '../ResourceEditorDrawer.svelte' import type { ModulesTestStates } from '../modulesTest.svelte' -import type { ButtonProp } from '$lib/components/DiffEditor.svelte' +import type { ButtonProp } from '$lib/components/diffEditorTypes' import type { SelectionManager } from '../graph/selectionUtils.svelte' import type { InferAssetsSqlQueryDetails } from '$lib/infer' diff --git a/frontend/src/lib/components/graph/renderers/nodes/AssetNode.svelte b/frontend/src/lib/components/graph/renderers/nodes/AssetNode.svelte index 15efe7e98e..7b144a3fb6 100644 --- a/frontend/src/lib/components/graph/renderers/nodes/AssetNode.svelte +++ b/frontend/src/lib/components/graph/renderers/nodes/AssetNode.svelte @@ -225,7 +225,6 @@ type AssetWithAltAccessType } from '$lib/components/assets/lib' import { twMerge } from 'tailwind-merge' - import type { FlowGraphAssetContext } from '$lib/components/flows/types' import { getContext } from 'svelte' import ExploreAssetButton, { assetCanBeExplored } from '../../../ExploreAssetButton.svelte' import { Tooltip } from '$lib/components/meltComponents' @@ -243,7 +242,7 @@ data: AssetN['data'] } - const flowGraphAssetsCtx = getContext('FlowGraphAssetContext') + const flowGraphAssetsCtx = getContext('FlowGraphAssetContext') let { data }: Props = $props() diff --git a/frontend/src/lib/components/home/Item.svelte b/frontend/src/lib/components/home/Item.svelte index 5f1cd8f964..b4a57175cd 100644 --- a/frontend/src/lib/components/home/Item.svelte +++ b/frontend/src/lib/components/home/Item.svelte @@ -11,19 +11,22 @@ import { createEventDispatcher } from 'svelte' import { ArrowBigUp } from 'lucide-svelte' - export let item - export let depth: number = 0 - const dispatch = createEventDispatcher() - let deleteConfirmedCallback: (() => void) | undefined = undefined - let shareModal: ShareModal - let moveDrawer: MoveDrawer - let deploymentDrawer: DeployWorkspaceDrawer + let deleteConfirmedCallback: (() => void) | undefined = $state(undefined) + let shareModal: any | undefined = $state() + let moveDrawer: any | undefined = $state() + let deploymentDrawer: any | undefined = $state() - let menuOpen: boolean = false - export let showCode: (path: string, summary: string) => void - export let showEditButton: boolean = true + let menuOpen: boolean = $state(false) + interface Props { + item: any + depth?: number + showCode: (path: string, summary: string) => void + showEditButton?: boolean + } + + let { item, depth = 0, showCode, showEditButton = true }: Props = $props() {#if item.type == 'script'} diff --git a/frontend/src/lib/components/prop_picker.ts b/frontend/src/lib/components/prop_picker.ts index 4940f92244..ced6a5e890 100644 --- a/frontend/src/lib/components/prop_picker.ts +++ b/frontend/src/lib/components/prop_picker.ts @@ -1,10 +1,7 @@ import type { Writable } from 'svelte/store' import type { PickableProperties } from '$lib/components/flows/previousResults' -type InsertionMode = 'append' | 'connect' | 'insert' - export type FlowPropPickerConfig = { - insertionMode: InsertionMode clearFocus: () => void onSelect: (path: string) => boolean } diff --git a/frontend/src/lib/components/propertyPicker/PropPicker.svelte b/frontend/src/lib/components/propertyPicker/PropPicker.svelte index fd4f99e29f..d04683e226 100644 --- a/frontend/src/lib/components/propertyPicker/PropPicker.svelte +++ b/frontend/src/lib/components/propertyPicker/PropPicker.svelte @@ -1,7 +1,7 @@ @@ -119,7 +137,7 @@
Go to the - Instance settings + Instance settings page to configure critical alert channels.
@@ -145,7 +163,7 @@
{`${totalNumberOfAlerts === 1000 ? '1000+' : (totalNumberOfAlerts ?? '?')} items`}
- +
diff --git a/frontend/src/lib/components/workspaceSettings/CustomInstanceDbWizardModal.svelte b/frontend/src/lib/components/workspaceSettings/CustomInstanceDbWizardModal.svelte index 5f7eddcef5..4e3a1ab601 100644 --- a/frontend/src/lib/components/workspaceSettings/CustomInstanceDbWizardModal.svelte +++ b/frontend/src/lib/components/workspaceSettings/CustomInstanceDbWizardModal.svelte @@ -15,7 +15,6 @@ import type { ResourceReturn } from 'runed' import type { ConfirmationModalHandle } from '../common/confirmationModal/asyncConfirmationModal.svelte' import ExploreAssetButton from '../ExploreAssetButton.svelte' - import type DBManagerDrawer from '../DBManagerDrawer.svelte' import { ArrowRight, InfoIcon } from 'lucide-svelte' import type { Snippet } from 'svelte' import { truncate } from '$lib/utils' @@ -25,7 +24,7 @@ type Props = { customInstanceDbs: ResourceReturn confirmationModal: ConfirmationModalHandle - dbManagerDrawer: DBManagerDrawer | undefined + dbManagerDrawer: any | undefined bottomHint?: Snippet | undefined opened: { status: CustomInstanceDb | undefined; dbname: string } | undefined tag?: CustomInstanceDbTag diff --git a/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte b/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte index c382948b09..db17250222 100644 --- a/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte +++ b/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte @@ -48,7 +48,7 @@ | { open: false } | { open: true; storage: S3ResourceSettingsItem } = $state({ open: false }) - let s3FileViewer: S3FilePicker | undefined = $state() + let s3FileViewer: any | undefined = $state() async function editWindmillLFSSettings(): Promise { const large_file_storage = convertFrontendToBackendSetting(s3ResourceSettings) diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index 7b08be90a2..a397cb4b7f 100644 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -14,7 +14,6 @@ import { import { getLocalSetting, type StateStore } from './utils' import { createState } from './svelte5Utils.svelte' import { DEFAULT_HUB_BASE_URL } from './hub' -import type DBManagerDrawer from './components/DBManagerDrawer.svelte' export interface UserExt { email: string @@ -127,7 +126,7 @@ export const codeCompletionSessionEnabled = writable( export const usedTriggerKinds = writable([]) -export let globalDbManagerDrawer: StateStore = createState({ +export let globalDbManagerDrawer: StateStore = createState({ val: undefined }) diff --git a/frontend/src/lib/toast.ts b/frontend/src/lib/toast.ts index 244794a5cc..af09f01e5e 100644 --- a/frontend/src/lib/toast.ts +++ b/frontend/src/lib/toast.ts @@ -1,7 +1,10 @@ -import Toast, { type ToastType } from '$lib/components/Toast.svelte' +import Toast from '$lib/components/Toast.svelte' import { toast } from '@zerodevx/svelte-toast' import type { ComponentProps } from 'svelte' import type { Button } from './components/common' +import type { AlertType } from '$lib/components/common/alert/model' + +export type ToastType = AlertType export type ToastAction = { label: string diff --git a/frontend/src/routes/(root)/(logged)/assets/+page.svelte b/frontend/src/routes/(root)/(logged)/assets/+page.svelte index 380d6dc29a..5679187c1e 100644 --- a/frontend/src/routes/(root)/(logged)/assets/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/assets/+page.svelte @@ -82,7 +82,7 @@ let assets = $derived(_assets.current?.flatMap((page) => page.assets)) let s3FilePicker: S3FilePicker | undefined = $state() - let dbManagerDrawer = $derived(globalDbManagerDrawer.val) + let dbManagerDrawer = $derived(globalDbManagerDrawer.val) as any let assetsUsageDropdown: AssetsUsageDrawer | undefined = $state() let allS3Storages = resource( diff --git a/frontend/src/routes/(root)/(logged)/resources/+page.svelte b/frontend/src/routes/(root)/(logged)/resources/+page.svelte index c06708d961..b3028f9844 100644 --- a/frontend/src/routes/(root)/(logged)/resources/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/resources/+page.svelte @@ -481,7 +481,7 @@ } }) - let dbManagerDrawer = $derived(globalDbManagerDrawer.val) + let dbManagerDrawer = $derived(globalDbManagerDrawer.val) as any let filterUserFolders = $state(false) let filterUserFoldersType: 'only f/*' | 'u/username and f/*' | undefined = $derived( @@ -755,7 +755,7 @@
{/if} - showCreateButtons = v} /> + (showCreateButtons = v)} />