Fix app tutorials (#6728)

* Fix tutorial basic

* fix other tutorials

* nit fix bug with button shrinking

* tutorial works backwards

* nit delete field on prev

* remove empty app duplication and magic code

* fix norefreshbar auto binding to false, making app dirty

* fix and improve app tutorial

* fix background runnable tutorial scroll

* fix connection tutorial

* mistake

* isCurrentlyInTutorial global state

* disable component navigation when in tutorial

* ci
This commit is contained in:
Diego Imbert
2025-10-02 12:09:30 +02:00
committed by GitHub
parent 259ee6903b
commit 65cdcff28c
14 changed files with 195 additions and 345 deletions
@@ -166,7 +166,13 @@
<div class="flex text-2xs gap-8 items-center">
<div class="py-2 pr-2 text-secondary flex gap-1 items-center">
Hide bar on view
<Toggle size="xs" bind:checked={$app.norefreshbar} />
<Toggle
size="xs"
bind:checked={
() => $app.norefreshbar ?? false,
(v) => ($app.norefreshbar !== undefined || v) && ($app.norefreshbar = v)
}
/>
</div>
<div>
{policy.on_behalf_of ? `Author ${policy.on_behalf_of_email}` : ''}
@@ -13,6 +13,8 @@ import {
ccomponents,
components,
getRecommendedDimensionsByComponent,
presets,
processDimension,
type AppComponent,
type BaseComponent,
type InitialAppComponent,
@@ -36,17 +38,18 @@ import { sendUserToast } from '$lib/toast'
import { getNextId } from '$lib/components/flows/idUtils'
import { enterpriseLicense } from '$lib/stores'
import gridHelp from '../svelte-grid/utils/helper'
import { DEFAULT_THEME } from './componentsPanel/themeUtils'
type GridItemLocation =
| {
type: 'grid'
gridItemIndex: number
}
type: 'grid'
gridItemIndex: number
}
| {
type: 'subgrid'
subgridItemIndex: number
subgridKey: string
}
type: 'subgrid'
subgridItemIndex: number
subgridKey: string
}
interface GridItemWithLocation {
location: GridItemLocation
item: GridItem
@@ -187,7 +190,7 @@ export function selectId(
selectedComponent: Writable<string[] | undefined>,
app: App
) {
; (document?.activeElement as HTMLElement)?.blur()
;(document?.activeElement as HTMLElement)?.blur()
if (e.shiftKey) {
selectedComponent.update((old) => {
if (old && old?.[0]) {
@@ -492,11 +495,11 @@ export function appComponentFromType<T extends keyof typeof components>(
xData:
type === 'plotlycomponentv2' || type === 'chartjscomponentv2'
? {
type: 'evalv2',
fieldType: 'array',
expr: '[1, 2, 3, 4]',
connections: []
}
type: 'evalv2',
fieldType: 'array',
expr: '[1, 2, 3, 4]',
connections: []
}
: undefined,
...(extra ?? {})
}
@@ -845,33 +848,33 @@ export type InitConfig<
| EvalAppInput
| EvalV2AppInput
| {
type: 'oneOf'
selected: string
configuration: Record<
string,
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
>
}
type: 'oneOf'
selected: string
configuration: Record<
string,
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
>
}
>
> = {
[Property in keyof T]: T[Property] extends StaticAppInput
[Property in keyof T]: T[Property] extends StaticAppInput
? T[Property]['value'] | undefined
: T[Property] extends { type: 'oneOf' }
? {
type: 'oneOf'
selected: keyof T[Property]['configuration']
configuration: {
[Choice in keyof T[Property]['configuration']]: {
[IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput
? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand
? () => Promise<T[Property]['configuration'][Choice][IT]['value'] | undefined>
: T[Property]['configuration'][Choice][IT]['value'] | undefined
: undefined
? {
type: 'oneOf'
selected: keyof T[Property]['configuration']
configuration: {
[Choice in keyof T[Property]['configuration']]: {
[IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput
? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand
? () => Promise<T[Property]['configuration'][Choice][IT]['value'] | undefined>
: T[Property]['configuration'][Choice][IT]['value'] | undefined
: undefined
}
}
}
}
}
: undefined
}
: undefined
}
export function initConfig<
T extends Record<
@@ -880,13 +883,13 @@ export function initConfig<
| EvalAppInput
| EvalV2AppInput
| {
type: 'oneOf'
selected: string
configuration: Record<
string,
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
>
}
type: 'oneOf'
selected: string
configuration: Record<
string,
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
>
}
>
>(
r: T,
@@ -894,13 +897,13 @@ export function initConfig<
string,
| StaticAppInput
| {
type: 'oneOf'
selected: string
configuration: Record<
string,
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput | boolean>
>
}
type: 'oneOf'
selected: string
configuration: Record<
string,
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput | boolean>
>
}
| any
>
): InitConfig<T> {
@@ -910,31 +913,31 @@ export function initConfig<
Object.entries(r).map(([key, value]) =>
value.type == 'static'
? [
key,
configuration?.[key]?.type == 'static' ? configuration?.[key]?.['value'] : undefined
]
key,
configuration?.[key]?.type == 'static' ? configuration?.[key]?.['value'] : undefined
]
: value.type == 'oneOf'
? [
key,
{
selected: value.selected,
type: 'oneOf',
configuration: Object.fromEntries(
Object.entries(value.configuration).map(([choice, config]) => {
const conf = initConfig(
config,
configuration?.[key]?.configuration?.[choice]
)
Object.entries(config).forEach(([innerKey, innerValue]) => {
if (innerValue.type === 'static' && !(innerKey in conf)) {
conf[innerKey] = innerValue.value
}
key,
{
selected: value.selected,
type: 'oneOf',
configuration: Object.fromEntries(
Object.entries(value.configuration).map(([choice, config]) => {
const conf = initConfig(
config,
configuration?.[key]?.configuration?.[choice]
)
Object.entries(config).forEach(([innerKey, innerValue]) => {
if (innerValue.type === 'static' && !(innerKey in conf)) {
conf[innerKey] = innerValue.value
}
})
return [choice, conf]
})
return [choice, conf]
})
)
}
]
)
}
]
: [key, undefined]
)
) as any
@@ -1395,3 +1398,45 @@ export function animateTo(start: number, end: number, onUpdate: (newValue: numbe
function easeInOut(t: number) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
}
export function emptyApp(): App {
let value: App = {
grid: [],
fullscreen: false,
unusedInlineScripts: [],
hiddenInlineScripts: [],
theme: {
type: 'path',
path: DEFAULT_THEME
}
}
const preset = presets['topbarcomponent']
const id = insertNewGridItem(
value,
appComponentFromType(preset.targetComponent, preset.configuration, undefined, {
customCss: {
container: {
class: '!p-0' as any,
style: ''
}
}
}) as (id: string) => AppComponent,
undefined,
undefined,
'topbar',
{ x: 0, y: 0 },
{
3: processDimension(preset.dims, 3),
12: processDimension(preset.dims, 12)
},
true,
true
)
setUpTopBarComponentContent(id, value)
value.hideLegacyTopBar = true
value.mobileViewOnSmallerScreens = false
return value
}
@@ -11,6 +11,7 @@
left
} from './componentCallbacks.svelte'
import type { AppEditorContext, AppViewerContext } from '../../types'
import { isCurrentlyInTutorial } from '$lib/stores'
const { history, movingcomponents, jobsDrawerOpen, runnableJobEditorPanel } =
getContext<AppEditorContext>('AppEditorContext') as AppEditorContext
@@ -33,7 +34,8 @@
if (
(typeof classes === 'string' && classes.includes('inputarea')) ||
['INPUT', 'TEXTAREA'].includes(document.activeElement?.tagName!) ||
$runnableJobEditorPanel.focused
$runnableJobEditorPanel.focused ||
isCurrentlyInTutorial.val
) {
return
}
@@ -52,7 +52,7 @@
{#if render && object != undefined && Object.keys(object).length > 0}
{#if $hasResult[componentId] || $search == ''}
<div class="pl-2 !cursor-pointer" data-connection-button>
<div class="pl-2 !cursor-pointer component-output-viewer-{componentId}" data-connection-button>
<ObjectViewer
json={filtered}
on:select
@@ -11,14 +11,14 @@
import { Building, GitFork, Globe2 } from 'lucide-svelte'
import { createEventDispatcher } from 'svelte'
import { fly } from 'svelte/transition'
import { defaultCode } from '../component'
import WorkspaceScriptList from '../settingsPanel/mainInput/WorkspaceScriptList.svelte'
import RunnableSelector from '../settingsPanel/mainInput/RunnableSelector.svelte'
import { defaultScripts } from '$lib/stores'
import { defaultScripts, isCurrentlyInTutorial } from '$lib/stores'
import DefaultScripts from '$lib/components/DefaultScripts.svelte'
import type { Preview } from '$lib/gen'
import type { InlineScript } from '../../types'
import { twMerge } from 'tailwind-merge'
interface Props {
componentType?: string | undefined
@@ -133,8 +133,10 @@
</Drawer>
<div
class="flex flex-col px-4 gap-2 text-sm"
in:fly={{ duration: 50 }}
class={twMerge(
'flex flex-col px-4 gap-2 text-sm',
isCurrentlyInTutorial.val ? 'h-full overflow-y-clip' : ''
)}
id="app-editor-empty-runnable"
>
<div class="mt-2 flex justify-between gap-4" id="app-editor-runnable-header">
@@ -193,6 +193,7 @@
{openConnection}
isOpen={!!$connectingInput.opened}
btnWrapperClasses={'h-6 w-8 opacity-0 group-hover:opacity-100 transition-opacity'}
id="schema-plug-{key}"
/>
<ToggleButtonGroup
class="h-6"
@@ -11,6 +11,7 @@
export let openConnection: () => void
export let closeConnection: () => void
export let btnWrapperClasses = ''
export let id: string | undefined = undefined
let selected = false
@@ -83,7 +84,7 @@
color="light"
title="Connect"
on:click={() => handleConnect(true)}
id="schema-plug"
{id}
wrapperClasses={twMerge(btnWrapperClasses, selected ? 'opacity-100' : '')}
btnClasses="p-0"
>
@@ -6,10 +6,12 @@
import SkipTutorials from './SkipTutorials.svelte'
import TutorialControls from './TutorialControls.svelte'
import TutorialInner from './TutorialInner.svelte'
import { isCurrentlyInTutorial } from '$lib/stores'
export let index: number = 0
export let name: string = 'action'
export let tainted: boolean = false
export let onDestroyed: (() => void) | undefined = undefined
type Options = {
indexToInsertAt?: number
@@ -111,6 +113,7 @@
dispatch('error', { detail: name })
return
}
isCurrentlyInTutorial.val = true
tutorial = driver({
allowClose: true,
@@ -122,9 +125,11 @@
renderControls({ config, state })
},
onDestroyed: () => {
onDestroyed?.()
if (!tutorial?.hasNextStep()) {
$ignoredTutorials = Array.from(new Set([...$ignoredTutorials, index]))
}
isCurrentlyInTutorial.val = false
}
})
@@ -13,14 +13,15 @@
updateInlineRunnableCode
} from '../utils'
import { updateProgress } from '$lib/tutorialUtils'
import { type DriveStep } from 'driver.js'
import { wait } from '$lib/utils'
export let name: string
export let index: number
let tutorial: Tutorial | undefined = undefined
const { app, selectedComponent, focusedGrid, connectingInput } =
getContext<AppViewerContext>('AppViewerContext')
const { app, selectedComponent, focusedGrid } = getContext<AppViewerContext>('AppViewerContext')
const { history } = getContext<AppEditorContext>('AppEditorContext')
export function runTutorial() {
@@ -49,7 +50,7 @@
on:skipAll
tainted={isAppTainted($app)}
getSteps={(driver) => {
const steps = [
const steps: DriveStep[] = [
{
popover: {
title: 'App editor tutorial',
@@ -112,7 +113,7 @@
popover: {
title: 'Component input',
description:
'There are several ways to set the input of a component. It can be static, the result of a JS expression, connected to the output of another component, or the result of a inline runnable. Here we will create an inline runnable that will convert the text to uppercase.',
'There are several ways to set the input of a component. It can be static, the result of a JS expression, connected to the output of another component, or the result of an inline runnable. Here we will create an inline runnable that will convert the text to uppercase.',
onNextClick: () => {
clickFirstButtonBySelector('#component-input')
setTimeout(() => {
@@ -143,9 +144,7 @@
description: "Let's create an inline script.",
onNextClick: () => {
clickButtonBySelector('#app-editor-create-inline-script')
setTimeout(() => {
driver.moveNext()
})
setTimeout(() => driver.moveNext())
}
}
},
@@ -155,7 +154,7 @@
popover: {
title: 'Choose a language',
description:
'You can choose the language of your runnable. They are two type of runnables: frontend and backend.'
'You can choose the language of your runnable. There are two type of runnables: frontend and backend.'
}
},
@@ -177,87 +176,71 @@
},
{
element: '#create-deno-script',
onHighlighted: () => {
document.querySelector('#schema-plug-x')?.parentElement?.classList.remove('opacity-0')
},
popover: {
title: 'Create a deno script',
description:
"Let's create a simple deno script. For the sake of this tutorial, we will create a script that converts the text to uppercase.",
onNextClick: () => {
onNextClick: async () => {
clickButtonBySelector('#create-deno-script')
setTimeout(() => {
if ($selectedComponent?.[0]) {
updateInlineRunnableCode(
$app,
$selectedComponent[0],
`export async function main(x: string) {
return x?.toLocaleUpperCase();
}
`
)
}
await wait(50)
if ($selectedComponent?.[0]) {
updateInlineRunnableCode(
$app,
$selectedComponent[0],
'export function main(x: string) {\n return x?.toLocaleUpperCase();\n}'
)
}
driver.moveNext()
})
driver.moveNext()
}
}
},
{
element: '#schema-plug',
element: '#schema-plug-x',
onHighlighted: () => {
document.querySelector('#schema-plug-x')?.parentElement?.classList.remove('opacity-0')
},
popover: {
title: 'Connect the function input',
description:
"The function we created has an string input 'x'. We can connect the output of the text component to it.",
onNextClick: () => {
clickButtonBySelector('#schema-plug')
clickButtonBySelector('#schema-plug-x')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
element: '#connect-output-d',
element: '#connect-output-a',
popover: {
title: 'Select the output',
description: ' ',
description: 'Open the output selector of the text input component.',
onNextClick: () => {
$connectingInput.opened = false
$connectingInput.input = undefined
clickButtonBySelector('#connect-output-a')
setTimeout(() => {
driver.moveNext()
})
},
onPopoverRender: (popover, opts) => {
const wrapper = document.createElement('div')
wrapper.classList.add('flex', 'flex-col', 'gap-2', 'w-full', 'items-start')
const p1 = document.createElement('p')
p1.innerText =
'You can now select the output in the output menu. Click on the little red button to open the menu.'
const id = document.createElement('div')
id.innerHTML = `<button class="bg-red-500/70 border border-red-600 px-1 py-0.5" title="Outputs" aria-label="Open output"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide-icon lucide lucide-plug-2 "><path d="M9 2v6"></path><path d="M15 2v6"></path><path d="M12 17v5"></path><path d="M5 8h14"></path><path d="M6 11V8h12v3a6 6 0 1 1-12 0v0Z"></path></svg></button>`
const p2 = document.createElement('p')
p2.innerText =
'Once opened, you can select the output you want to connect to. Here we will connect the result output of the text component to the input "x" of the inline runnable.'
const objectViewer = document.createElement('div')
objectViewer.innerHTML = `<div class="rounded-lg shadow-md border p-4 bg-surface"><span class="s-UNyBDXJ1E286"> <ul class="w-full pl-2 border-none s-UNyBDXJ1E286"><li class="s-UNyBDXJ1E286"><button class="whitespace-nowrap s-UNyBDXJ1E286"><span class="key border font-semibold rounded px-1 hover:bg-surface-hover text-2xs text-secondary s-UNyBDXJ1E286">result</span> :</button> <button class="val rounded px-1 hover:bg-blue-100 string s-UNyBDXJ1E286"><span title="" class="text-2xs s-UNyBDXJ1E286">""</span></button></li> </ul> </span> <span class="border border-blue-600 rounded px-1 cursor-pointer hover:bg-gray-200 s-UNyBDXJ1E286 hidden">{...}</span> </div>`
wrapper.appendChild(p1)
wrapper.appendChild(id)
wrapper.appendChild(p2)
wrapper.appendChild(objectViewer)
popover.description.appendChild(wrapper)
tutorial?.renderControls(opts)
}
}
},
{
element: '.component-output-viewer-a li *:has(> button[title="result"])',
popover: {
title: 'Select the output',
description: "Let's select the result of the text input component.",
onNextClick: () => {
setTimeout(async () => {
clickButtonBySelector('.component-output-viewer-a li button[title="result"]')
driver.moveNext()
})
}
}
},
{
element: '.wm-app-viewer',
popover: {
@@ -1,5 +1,6 @@
<script lang="ts">
import { updateProgress } from '$lib/tutorialUtils'
import { type DriveStep } from 'driver.js'
import Tutorial from '../Tutorial.svelte'
import { clickButtonBySelector } from '../utils'
@@ -20,7 +21,7 @@
on:error
on:skipAll
getSteps={(driver, options) => {
const steps = [
const steps: DriveStep[] = [
{
element: '#app-editor-runnable-panel',
popover: {
@@ -37,10 +38,7 @@
'Click here to create a runnable. Runnables are scripts that can be executed in the background. You can add as many runnables as you want.',
onNextClick: () => {
clickButtonBySelector('#create-background-runnable')
setTimeout(() => {
driver.moveNext()
})
setTimeout(() => driver.moveNext())
}
}
},
@@ -68,12 +68,12 @@
}
},
{
element: '#plug',
element: '[data-connection-button] button[title="Connect"]',
popover: {
title: 'Connect the text component',
description: 'Click on the plug icon to connect the text component',
onNextClick: () => {
clickButtonBySelector('#plug')
clickButtonBySelector('[data-connection-button] button[title="Connect"]')
setTimeout(() => {
driver.moveNext()
})
+2 -160
View File
@@ -1,6 +1,6 @@
import type { FlowModule, OpenFlow } from '$lib/gen'
import { deepEqual } from 'fast-equals'
import { findGridItem } from '../apps/editor/appUtils'
import { emptyApp, findGridItem } from '../apps/editor/appUtils'
import type { App } from '../apps/types'
export function setInputBySelector(selector: string, value: string) {
@@ -52,155 +52,6 @@ export function isFlowTainted(flow: OpenFlow) {
)
}
const emptyApp = {
grid: [
{
'3': {
fixed: false,
x: 0,
y: 0,
fullHeight: false,
w: 6,
h: 2
},
'12': {
fixed: false,
x: 0,
y: 0,
fullHeight: false,
w: 12,
h: 2
},
data: {
type: 'containercomponent',
configuration: {},
customCss: {
container: {
class: '!p-0',
style: ''
}
},
numberOfSubgrids: 1,
id: 'a'
},
id: 'a'
}
],
fullscreen: false,
unusedInlineScripts: [],
hiddenInlineScripts: [],
theme: {
type: 'path',
path: 'f/app_themes/theme_0'
},
subgrids: {
'a-0': [
{
'3': {
fixed: false,
x: 0,
y: 0,
fullHeight: false,
w: 6,
h: 1
},
'12': {
fixed: false,
x: 0,
y: 0,
fullHeight: false,
w: 6,
h: 1
},
data: {
type: 'textcomponent',
configuration: {
style: {
type: 'static',
value: 'Body'
},
copyButton: {
type: 'static',
value: false
},
tooltip: {
type: 'evalv2',
value: '',
fieldType: 'text',
expr: '`Author: ${ctx.author}`',
connections: [
{
componentId: 'ctx',
id: 'author'
}
]
},
disableNoText: {
type: 'static',
value: true,
fieldType: 'boolean'
}
},
componentInput: {
type: 'templatev2',
fieldType: 'template',
eval: '${ctx.summary}',
connections: [
{
id: 'summary',
componentId: 'ctx'
}
]
},
customCss: {
text: {
class: 'text-xl font-semibold whitespace-nowrap truncate',
style: ''
},
container: {
class: '',
style: ''
}
},
horizontalAlignment: 'left',
verticalAlignment: 'center',
id: 'b'
},
id: 'b'
},
{
'3': {
fixed: false,
x: 0,
y: 1,
fullHeight: false,
w: 3,
h: 1
},
'12': {
fixed: false,
x: 6,
y: 0,
fullHeight: false,
w: 6,
h: 1
},
data: {
type: 'recomputeallcomponent',
configuration: {},
menuItems: [],
horizontalAlignment: 'right',
verticalAlignment: 'center',
id: 'c'
},
id: 'c'
}
]
},
hideLegacyTopBar: true,
norefreshbar: false
}
export function isAppTainted(app: App) {
if (app.hideLegacyTopBar === true) {
// An empty app should have only have a topbar and no hidden inline scripts
@@ -215,7 +66,7 @@ export function isAppTainted(app: App) {
}
// Check if the current app is different from an empty app
return !deepEqual(app, emptyApp)
return !deepEqual(app, emptyApp())
} else {
// For older apps,
return !(app.grid?.length === 0 && app.hiddenInlineScripts?.length === 0)
@@ -247,8 +98,6 @@ export function updateFlowModuleById(
}
dfs(flow.value.modules)
flow = flow
}
export function updateBackgroundRunnableCode(app: App, index: number, newCode: string) {
@@ -256,13 +105,10 @@ export function updateBackgroundRunnableCode(app: App, index: number, newCode: s
if (script.type === 'runnableByName' && script.inlineScript) {
script.inlineScript.content = newCode
}
app = app
}
export function updateInlineRunnableCode(app: App, componentId: string, newCode: string) {
const gridItem = findGridItem(app, componentId)
if (gridItem?.data.componentInput?.type === 'runnable') {
if (
gridItem.data.componentInput.runnable?.type === 'runnableByName' &&
@@ -271,8 +117,6 @@ export function updateInlineRunnableCode(app: App, componentId: string, newCode:
gridItem.data.componentInput.runnable.inlineScript.content = newCode
}
}
app = app
}
export function connectComponentSourceToOutput(app: App, componentId: string, targetId: string) {
@@ -292,8 +136,6 @@ export function connectComponentSourceToOutput(app: App, componentId: string, ta
]
}
}
app = app
}
export function connectInlineRunnableInputToComponentOutput(
+4 -1
View File
@@ -12,8 +12,9 @@ import {
type WorkspaceDefaultScripts,
WorkspaceService
} from './gen'
import { getLocalSetting } from './utils'
import { getLocalSetting, type StateStore } from './utils'
import { workspaceAIClients } from './components/copilot/lib'
import { createState } from './svelte5Utils.svelte'
export interface UserExt {
email: string
@@ -277,6 +278,8 @@ export const workspaceColor: Readable<string | null | undefined> = derived(
}
)
export const isCurrentlyInTutorial: StateStore<boolean> = createState({ val: false })
export function getFlatTableNamesFromSchema(dbSchema: DBSchema | undefined): string[] {
const schema = dbSchema?.schema ?? {}
const tableNames: string[] = []
@@ -13,16 +13,7 @@
import { goto } from '$lib/navigation'
import { sendUserToast } from '$lib/toast'
import { DEFAULT_THEME } from '$lib/components/apps/editor/componentsPanel/themeUtils'
import {
presets,
processDimension,
type AppComponent
} from '$lib/components/apps/editor/component'
import {
appComponentFromType,
insertNewGridItem,
setUpTopBarComponentContent
} from '$lib/components/apps/editor/appUtils'
import { emptyApp } from '$lib/components/apps/editor/appUtils'
let nodraft = $page.url.searchParams.get('nodraft')
const hubId = $page.url.searchParams.get('hub')
@@ -118,36 +109,7 @@
])
value = decodeState(appState)
} else {
const preset = presets['topbarcomponent']
const id = insertNewGridItem(
value,
appComponentFromType(preset.targetComponent, preset.configuration, undefined, {
customCss: {
container: {
class: '!p-0' as any,
style: ''
}
}
}) as (id: string) => AppComponent,
undefined,
undefined,
'topbar',
{ x: 0, y: 0 },
{
3: processDimension(preset.dims, 3),
12: processDimension(preset.dims, 12)
},
true,
true
)
setUpTopBarComponentContent(id, value)
value.hideLegacyTopBar = true
value.mobileViewOnSmallerScreens = false
value = value
value = emptyApp()
}
}
</script>