Compare commits
17 Commits
dev-docker
...
rf/flatten
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b1bfed090 | ||
|
|
2125d119ff | ||
|
|
d3f1ef92ea | ||
|
|
26296ee05c | ||
|
|
7e4179a741 | ||
|
|
52adaa4cb5 | ||
|
|
a94f266743 | ||
|
|
9d680e6744 | ||
|
|
5060c37fed | ||
|
|
15c2bdcdae | ||
|
|
45ce630a75 | ||
|
|
d50734cbb3 | ||
|
|
b08b559eec | ||
|
|
5742bf2235 | ||
|
|
c56176ec91 | ||
|
|
640242b713 | ||
|
|
c696f3b6cf |
@@ -7,12 +7,12 @@
|
||||
|
||||
export let id: string
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let subGrids: GridItem[][] | undefined = undefined
|
||||
export let componentContainerHeight: number
|
||||
|
||||
let noPadding: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = []
|
||||
const { focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let gridContent: string[] | undefined = undefined
|
||||
|
||||
@@ -27,15 +27,13 @@
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
|
||||
|
||||
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
|
||||
{#if subGrids && subGrids[0]}
|
||||
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
{noPadding}
|
||||
bind:subGrid={subGrids[0]}
|
||||
bind:subGrid={$app.subgrids[`${id}-0`]}
|
||||
containerHeight={componentContainerHeight}
|
||||
parentId={id}
|
||||
index={0}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let subGrids: GridItem[][] | undefined = undefined
|
||||
export let componentContainerHeight: number
|
||||
export let tabs: string[]
|
||||
|
||||
export const staticOutputs: string[] = ['selectedTabIndex']
|
||||
const { worldStore, focusedGrid, selectedComponent } =
|
||||
const { app, worldStore, focusedGrid, selectedComponent } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let selected: string = ''
|
||||
@@ -36,6 +35,7 @@
|
||||
}
|
||||
|
||||
$: selectedIndex >= 0 && handleTabSelection()
|
||||
|
||||
let tabHeight: number = 0
|
||||
|
||||
function onFocus() {
|
||||
@@ -46,7 +46,6 @@
|
||||
}
|
||||
|
||||
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
|
||||
$: console.log(subGrids)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.tabs} bind:value={tabs} />
|
||||
@@ -62,12 +61,10 @@
|
||||
{/each}
|
||||
</Tabs>
|
||||
</div>
|
||||
{#if subGrids && subGrids[selectedIndex]}
|
||||
{#if $app.subgrids?.[`${id}-${selectedIndex}`]}
|
||||
<SubGridEditor
|
||||
parentId={id}
|
||||
index={selectedIndex}
|
||||
bind:subGrid={$app.subgrids[`${id}-${selectedIndex}`]}
|
||||
{noPadding}
|
||||
bind:subGrid={subGrids[selectedIndex]}
|
||||
containerHeight={componentContainerHeight - tabHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
import UnsavedConfirmationModal from '$lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte'
|
||||
import { page } from '$app/stores'
|
||||
import CssSettings from './componentsPanel/CssSettings.svelte'
|
||||
import { findGridItem } from './appUtils'
|
||||
|
||||
export let app: App
|
||||
export let path: string
|
||||
|
||||
@@ -1,14 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import { allItems, allItemsWithParent } from '../utils'
|
||||
import PanelSection from './settingsPanel/common/PanelSection.svelte'
|
||||
import ComponentPanel from './settingsPanel/ComponentPanel.svelte'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
import SettingsPanelRec from './SettingsPanelRec.svelte'
|
||||
import TablePanel from './TablePanel.svelte'
|
||||
|
||||
const { selectedComponent, app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
$: subgridKeys = Object.keys($app.subgrids ?? {})
|
||||
</script>
|
||||
|
||||
<SettingsPanelRec bind:gridItems={$app.grid} />
|
||||
{#each $app.grid as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel parent={undefined} bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.type === 'tablecomponent'}
|
||||
<TablePanel bind:component={gridItem.data} />
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#if $app.subgrids}
|
||||
{#each subgridKeys as key (key)}
|
||||
{#each $app.subgrids[key] as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel parent={key} bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.type === 'tablecomponent'}
|
||||
<TablePanel bind:component={gridItem.data} />
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
{#each $app?.hiddenInlineScripts ?? [] as script, index (script.name)}
|
||||
{#if $selectedComponent === `bg_${index}`}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { GridItem } from '../types'
|
||||
|
||||
import SettingsPanelRec from './SettingsPanelRec.svelte'
|
||||
|
||||
export let subgrids: GridItem[][]
|
||||
|
||||
let elems = subgrids
|
||||
$: subgrids = elems
|
||||
</script>
|
||||
|
||||
{#if subgrids}
|
||||
{#each elems as subGrid, i (i)}
|
||||
<SettingsPanelRec bind:gridItems={subGrid} />
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -1,24 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
|
||||
import ComponentPanel from './settingsPanel/ComponentPanel.svelte'
|
||||
import SettingsPanelList from './SettingsPanelList.svelte'
|
||||
import TablePanel from './TablePanel.svelte'
|
||||
|
||||
const { selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
export let gridItems: GridItem[]
|
||||
</script>
|
||||
|
||||
{#if gridItems}
|
||||
{#each gridItems as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel {gridItems} bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.type === 'tablecomponent'}
|
||||
<TablePanel bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.subGrids}
|
||||
<SettingsPanelList bind:subgrids={gridItem.data.subGrids} />
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -6,11 +6,10 @@
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
import Component from './component/Component.svelte'
|
||||
|
||||
export let subGrid: GridItem[]
|
||||
export let containerHeight: number
|
||||
export let noPadding = false
|
||||
export let parentId: string
|
||||
export let index: number
|
||||
//export let id: string
|
||||
export let subGrid: GridItem[] = []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -38,10 +37,12 @@
|
||||
onComponent = id
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = id
|
||||
/*
|
||||
$focusedGrid = {
|
||||
parentComponentId: parentId,
|
||||
subGridIndex: index
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
{#each component.actionButtons as actionButton (actionButton.id)}
|
||||
{#if actionButton.id === $selectedComponent}
|
||||
<ComponentPanel
|
||||
gridItems={undefined}
|
||||
parent={undefined}
|
||||
noGrid
|
||||
rowColumns
|
||||
bind:component={actionButton}
|
||||
onDelete={() => {
|
||||
|
||||
182
frontend/src/lib/components/apps/editor/appUtils.ts
Normal file
182
frontend/src/lib/components/apps/editor/appUtils.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { getNextId } from '$lib/components/flows/flowStateUtils'
|
||||
import type { App, FocusedGrid, GridItem } from '../types'
|
||||
import { Component, getRecommendedDimensionsByComponent, type AppComponent } from './component'
|
||||
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
|
||||
import { gridColumns } from '../gridUtils'
|
||||
import { allItems } from '../utils'
|
||||
|
||||
function findGridItemById(
|
||||
root: GridItem[],
|
||||
subGrids: Record<string, GridItem[]> | undefined,
|
||||
id: string
|
||||
): GridItem | undefined {
|
||||
for (const gridItem of root) {
|
||||
if (gridItem.id === id) {
|
||||
return gridItem
|
||||
}
|
||||
|
||||
if (subGrids) {
|
||||
const numberOfSubgrids = gridItem.data.numberOfSubgrids
|
||||
|
||||
if (numberOfSubgrids) {
|
||||
for (let i = 0; i < numberOfSubgrids; i++) {
|
||||
const subgrid = subGrids[`${gridItem.id}-${i}`] ?? []
|
||||
const found = findGridItemById(subgrid, subGrids, id)
|
||||
|
||||
if (found) {
|
||||
return found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function findGridItem(app: App, id: string): GridItem | undefined {
|
||||
return findGridItemById(app.grid, app.subgrids, id)
|
||||
}
|
||||
|
||||
export function getNextGridItemId(app: App): string {
|
||||
const subgridsKeys = allItems(app.grid, app.subgrids).map((x) => x.id)
|
||||
const withoutDash = subgridsKeys.map((element) => element.split('-')[0])
|
||||
const id = getNextId([...new Set(withoutDash)])
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
|
||||
const appComponent = data
|
||||
|
||||
appComponent.id = id
|
||||
|
||||
const newComponent = {
|
||||
fixed: false,
|
||||
resizable: true,
|
||||
draggable: true,
|
||||
customDragger: false,
|
||||
customResizer: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
|
||||
|
||||
const newItem: GridItem = {
|
||||
data: newData,
|
||||
id: id
|
||||
}
|
||||
|
||||
gridColumns.forEach((column) => {
|
||||
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
|
||||
|
||||
newItem[column] = {
|
||||
...newComponent,
|
||||
min: { w: 1, h: 1 },
|
||||
max: { w: column, h: 100 },
|
||||
w: rec.w,
|
||||
h: rec.h
|
||||
}
|
||||
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
|
||||
newItem[column] = { ...newItem[column], ...position }
|
||||
})
|
||||
|
||||
return newItem
|
||||
}
|
||||
|
||||
export function insertNewGridItem(
|
||||
app: App,
|
||||
data: AppComponent,
|
||||
focusedGrid: FocusedGrid | undefined
|
||||
) {
|
||||
const id = getNextGridItemId(app)
|
||||
|
||||
if (!focusedGrid) {
|
||||
const newItem = createNewGridItem(app.grid, id, data)
|
||||
app.grid.push(newItem)
|
||||
} else {
|
||||
const { parentComponentId, subGridIndex } = focusedGrid
|
||||
|
||||
if (!app.subgrids) {
|
||||
app.subgrids = {}
|
||||
}
|
||||
|
||||
const subGrid = app.subgrids[`${parentComponentId}-${subGridIndex}`] ?? []
|
||||
const newItem = createNewGridItem(subGrid, id, data)
|
||||
const key = `${parentComponentId}-${subGridIndex ?? 0}`
|
||||
|
||||
if (!app.subgrids[key]) {
|
||||
app.subgrids[key] = [newItem]
|
||||
} else {
|
||||
app.subgrids[key].push(newItem)
|
||||
}
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
export function getAllSubgridsAndComponentIds(
|
||||
app: App,
|
||||
component: AppComponent
|
||||
): [string[], string[]] {
|
||||
const subgrids: string[] = []
|
||||
let components: string[] = [component.id]
|
||||
if (app.subgrids && component.numberOfSubgrids) {
|
||||
for (let i = 0; i < component.numberOfSubgrids; i++) {
|
||||
const subgrid = app.subgrids[`${component.id}-${i}`]
|
||||
if (subgrid) {
|
||||
for (const item of subgrid) {
|
||||
let [recSubgrids, recComponents] = getAllSubgridsAndComponentIds(app, item.data)
|
||||
subgrids.push(...recSubgrids)
|
||||
components.push(...recComponents)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [subgrids, components]
|
||||
}
|
||||
|
||||
export function deleteGridItem(
|
||||
app: App,
|
||||
component: AppComponent,
|
||||
parent: string | undefined
|
||||
): string[] {
|
||||
let [subgrids, components] = getAllSubgridsAndComponentIds(app, component)
|
||||
if (app.subgrids) {
|
||||
subgrids.forEach((id) => {
|
||||
delete app.subgrids![id]
|
||||
})
|
||||
}
|
||||
if (!parent) {
|
||||
let index = app.grid.findIndex((x) => x.id == component.id)
|
||||
if (index > -1) {
|
||||
app.grid.splice(index, 1)
|
||||
}
|
||||
} else {
|
||||
let grid = app.subgrids![parent]
|
||||
let index = grid.findIndex((x) => x.id == component.id)
|
||||
if (index > -1) {
|
||||
grid.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
export function duplicateGridItem(
|
||||
app: App,
|
||||
focusedGrid: FocusedGrid | undefined,
|
||||
id: string
|
||||
): string | undefined {
|
||||
const gridItem = findGridItem(app, id)
|
||||
if (gridItem) {
|
||||
const newId = getNextGridItemId(app)
|
||||
const newItem = JSON.parse(JSON.stringify(gridItem))
|
||||
newItem.id = newId
|
||||
newItem.data.id = newId
|
||||
|
||||
return insertNewGridItem(app, newItem.data, focusedGrid)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
@@ -200,10 +200,7 @@
|
||||
<AppRangeInput {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'tabscomponent'}
|
||||
<AppTabs
|
||||
id={component.id}
|
||||
configuration={component.configuration}
|
||||
tabs={component.tabs}
|
||||
bind:subGrids={component.subGrids}
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
{componentContainerHeight}
|
||||
/>
|
||||
|
||||
@@ -152,7 +152,7 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
configuration: {},
|
||||
customCss: {
|
||||
header: { class: '', style: '' },
|
||||
container: { class: '', style: '' },
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
@@ -175,7 +175,7 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
},
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
subGrids: [[]]
|
||||
numberOfSubgrids: 1
|
||||
}
|
||||
},
|
||||
textcomponent: {
|
||||
@@ -1027,7 +1027,7 @@ Hello \${ctx.username}
|
||||
},
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
subGrids: [[], []],
|
||||
numberOfSubgrids: 2,
|
||||
tabs: ['First tab', 'Second tab']
|
||||
}
|
||||
},
|
||||
@@ -1200,4 +1200,4 @@ Hello \${ctx.username}
|
||||
card: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,20 @@
|
||||
<script lang="ts">
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getNextId } from '$lib/components/flows/flowStateUtils'
|
||||
import { isOpenStore } from './store'
|
||||
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
|
||||
import { components as componentsRecord, COMPONENT_SETS, type AppComponent } from '../component'
|
||||
import ListItem from './ListItem.svelte'
|
||||
import { insertNewGridItem, createNewGridItem, getNextGridItemId } from '../../utils'
|
||||
import { insertNewGridItem } from '../appUtils'
|
||||
|
||||
const TITLE_PREFIX = 'Component.' as const
|
||||
const { app, selectedComponent, focusedGrid } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function addComponent(appComponentType: AppComponent['type']): void {
|
||||
// When a new component is added, we need to mark the app as dirty,
|
||||
// so a confirmation modal will appear if the user tries to leave the page
|
||||
$dirtyStore = true
|
||||
|
||||
const grid = $app.grid ?? []
|
||||
const id = getNextGridItemId(grid)
|
||||
|
||||
const data = componentsRecord[appComponentType].data
|
||||
|
||||
if ($focusedGrid) {
|
||||
const { parentComponentId, subGridIndex } = $focusedGrid
|
||||
|
||||
$app.grid = insertNewGridItem($app.grid, parentComponentId, subGridIndex, id, data)
|
||||
} else {
|
||||
const newItem = createNewGridItem(grid, id, data)
|
||||
$app.grid = [...grid, newItem]
|
||||
}
|
||||
const id = insertNewGridItem($app, data, $focusedGrid)
|
||||
|
||||
$selectedComponent = id
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { classNames } from '$lib/utils'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { findParent } from '../../utils'
|
||||
import { findGridItem } from '../appUtils'
|
||||
import { components } from '../component'
|
||||
import PanelSection from '../settingsPanel/common/PanelSection.svelte'
|
||||
import ComponentOutputViewer from './ComponentOutputViewer.svelte'
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
|
||||
function getComponentNameById(componentId: string) {
|
||||
const component = findParent($app.grid, componentId)
|
||||
const component = findGridItem($app, componentId)
|
||||
|
||||
if (component?.data.type) {
|
||||
return components[component?.data.type].name
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { GridItem } from '../../types'
|
||||
import InlineScriptEditorRec from './InlineScriptEditorRec.svelte'
|
||||
|
||||
export let subgrids: GridItem[][]
|
||||
export let selectedScriptComponentId: string | undefined = undefined
|
||||
|
||||
let elems = subgrids
|
||||
$: subgrids = elems
|
||||
</script>
|
||||
|
||||
{#if subgrids}
|
||||
{#each elems as subGrid, i (i)}
|
||||
<InlineScriptEditorRec {selectedScriptComponentId} bind:gridItems={subGrid} />
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -8,7 +8,7 @@
|
||||
import { emptySchema, getScriptByPath } from '$lib/utils'
|
||||
import { faCodeBranch, faExternalLinkAlt, faEye, faPen } from '@fortawesome/free-solid-svg-icons'
|
||||
import type { AppInput, RunnableByPath } from '../../inputType'
|
||||
import { clearResultAppInput, schemaToInputsSpec } from '../../utils'
|
||||
import { clearResultAppInput } from '../../utils'
|
||||
import EmptyInlineScript from './EmptyInlineScript.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
import { computeFields } from './utils'
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { GridItem } from '../../types'
|
||||
import InlineScriptEditorList from './InlineScriptEditorList.svelte'
|
||||
|
||||
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
|
||||
|
||||
export let gridItems: GridItem[]
|
||||
|
||||
export let selectedScriptComponentId: string | undefined = undefined
|
||||
</script>
|
||||
|
||||
{gridItems}
|
||||
{#if gridItems}
|
||||
{#each gridItems as gridComponent, index (index)}
|
||||
{#if gridComponent.data}
|
||||
{#if gridComponent.data.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={gridComponent.data.id}
|
||||
bind:componentInput={gridComponent.data.componentInput}
|
||||
/>
|
||||
{:else if gridComponent.data.subGrids}
|
||||
<!-- <InlineScriptEditorList
|
||||
{selectedScriptComponentId}
|
||||
bind:subgrids={gridComponent.data.subGrids}
|
||||
/> -->
|
||||
{/if}
|
||||
|
||||
{#if gridComponent.data.type === 'tablecomponent'}
|
||||
{#each gridComponent.data.actionButtons as actionButton, index (index)}
|
||||
{#if actionButton.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={actionButton.id}
|
||||
bind:componentInput={actionButton.componentInput}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -6,7 +6,8 @@
|
||||
import InlineScriptsPanelList from './InlineScriptsPanelList.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
import EmptyInlineScript from './EmptyInlineScript.svelte'
|
||||
import InlineScriptEditorRec from './InlineScriptEditorRec.svelte'
|
||||
import { allItems } from '../../utils'
|
||||
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
|
||||
|
||||
const { app, staticOutputs, runnableComponents } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -24,7 +25,25 @@
|
||||
<span class="p-2 text-sm text-gray-600">Select a script on the left panel</span>
|
||||
{/if}
|
||||
|
||||
<InlineScriptEditorRec {selectedScriptComponentId} bind:gridItems={$app.grid} />
|
||||
{#each allItems($app.grid, $app.subgrids) as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={gridItem.data.id}
|
||||
bind:componentInput={gridItem.data.componentInput}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if gridItem.data.type === 'tablecomponent'}
|
||||
{#each gridItem.data.actionButtons as actionButton, index (index)}
|
||||
{#if actionButton.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={actionButton.id}
|
||||
bind:componentInput={actionButton.componentInput}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
{/each}
|
||||
{#each $app.unusedInlineScripts as unusedInlineScript, index (index)}
|
||||
{#if `unused-${index}` === selectedScriptComponentId}
|
||||
<InlineScriptEditor
|
||||
|
||||
@@ -10,15 +10,7 @@
|
||||
import ConnectedInputEditor from './inputEditor/ConnectedInputEditor.svelte'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import { capitalize, classNames } from '$lib/utils'
|
||||
import {
|
||||
buildExtraLib,
|
||||
createNewGridItem,
|
||||
deleteComponent,
|
||||
fieldTypeToTsType,
|
||||
findParent,
|
||||
getNextGridItemId,
|
||||
insertNewGridItem
|
||||
} from '../../utils'
|
||||
import { buildExtraLib, fieldTypeToTsType } from '../../utils'
|
||||
import Recompute from './Recompute.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import ComponentInputTypeEditor from './ComponentInputTypeEditor.svelte'
|
||||
@@ -29,46 +21,38 @@
|
||||
import CssProperty from '../componentsPanel/CssProperty.svelte'
|
||||
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
|
||||
import GridTab from './GridTab.svelte'
|
||||
import { duplicateGridItem } from '../appUtils'
|
||||
import { deleteGridItem } from '../appUtils'
|
||||
|
||||
export let component: AppComponent | undefined
|
||||
export let component: AppComponent
|
||||
export let rowColumns = false
|
||||
export let gridItems: GridItem[] | undefined
|
||||
export let onDelete: (() => void) | undefined = undefined
|
||||
export let parent: string | undefined
|
||||
export let noGrid = false
|
||||
|
||||
const { app, staticOutputs, runnableComponents, selectedComponent, worldStore, focusedGrid } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function duplicateElement(id: string) {
|
||||
const parent = findParent($app.grid, id)
|
||||
|
||||
if (!parent) {
|
||||
return
|
||||
}
|
||||
|
||||
const data: AppComponent = JSON.parse(JSON.stringify(parent.data))
|
||||
$dirtyStore = true
|
||||
|
||||
const grid = $app.grid ?? []
|
||||
const newId = getNextGridItemId(grid)
|
||||
|
||||
if ($focusedGrid) {
|
||||
const { parentComponentId, subGridIndex } = $focusedGrid
|
||||
|
||||
$app.grid = insertNewGridItem($app.grid, parentComponentId, subGridIndex, newId, data)
|
||||
} else {
|
||||
const newItem = createNewGridItem(grid, newId, data)
|
||||
$app.grid = [...grid, newItem]
|
||||
}
|
||||
|
||||
const newId = duplicateGridItem($app, $focusedGrid, id)
|
||||
$selectedComponent = newId
|
||||
}
|
||||
|
||||
function removeGridElement() {
|
||||
$selectedComponent = undefined
|
||||
$focusedGrid = undefined
|
||||
if (component) {
|
||||
deleteComponent(gridItems, component, $app, $staticOutputs, $runnableComponents)
|
||||
if (component && !noGrid) {
|
||||
let ids = deleteGridItem($app, component, parent)
|
||||
for (const key in ids) {
|
||||
delete $staticOutputs[key]
|
||||
delete $runnableComponents[key]
|
||||
}
|
||||
}
|
||||
|
||||
delete $staticOutputs[component.id]
|
||||
delete $runnableComponents[component.id]
|
||||
$app = $app
|
||||
$staticOutputs = $staticOutputs
|
||||
$runnableComponents = $runnableComponents
|
||||
|
||||
@@ -164,8 +148,8 @@
|
||||
</PanelSection>
|
||||
{/if}
|
||||
|
||||
{#if component.type === 'tabscomponent' && Array.isArray(component.subGrids)}
|
||||
<GridTab bind:tabs={component.tabs} bind:subGrids={component.subGrids} />
|
||||
{#if component.type === 'tabscomponent'}
|
||||
<GridTab bind:tabs={component.tabs} {component} />
|
||||
{/if}
|
||||
|
||||
{#if component.type === 'tablecomponent' && Array.isArray(component.actionButtons)}
|
||||
|
||||
@@ -2,33 +2,41 @@
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { faPlus, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import { deleteComponent } from '../../utils'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { deleteGridItem } from '../appUtils'
|
||||
import type { AppComponent } from '../component'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
|
||||
export let tabs: string[]
|
||||
export let subGrids: GridItem[][]
|
||||
export let component: AppComponent
|
||||
|
||||
const { runnableComponents, staticOutputs, app, focusedGrid } =
|
||||
const { app, staticOutputs, runnableComponents } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function addTab() {
|
||||
tabs = [...tabs, `Tab ${tabs.length + 1}`]
|
||||
subGrids = [...subGrids, []]
|
||||
const numberOfTabs = tabs.length
|
||||
tabs = [...tabs, `Tab ${numberOfTabs + 1}`]
|
||||
|
||||
if (!$app.subgrids) {
|
||||
$app.subgrids = {}
|
||||
}
|
||||
|
||||
$app.subgrids[`${component.id}-${numberOfTabs}`] = []
|
||||
component.numberOfSubgrids = tabs.length
|
||||
}
|
||||
|
||||
function deleteSubgrid(index: number) {
|
||||
$focusedGrid = undefined
|
||||
subGrids[index].forEach((x) => {
|
||||
deleteComponent(undefined, x.data, $app, $staticOutputs, $runnableComponents)
|
||||
})
|
||||
tabs.splice(index, 1)
|
||||
subGrids.splice(index, 1)
|
||||
tabs = tabs
|
||||
subGrids = subGrids
|
||||
$app.grid = $app.grid
|
||||
$staticOutputs = $staticOutputs
|
||||
$runnableComponents = $runnableComponents
|
||||
let subgrid = `${component.id}-${index}`
|
||||
for (const item of $app!.subgrids![subgrid]) {
|
||||
const components = deleteGridItem($app, item.data, subgrid)
|
||||
for (const key in components) {
|
||||
delete $staticOutputs[key]
|
||||
delete $runnableComponents[key]
|
||||
}
|
||||
}
|
||||
delete $app!.subgrids![subgrid]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ export interface BaseAppComponent extends Partial<Aligned> {
|
||||
* *For example when the component has a popup like `Select`*
|
||||
*/
|
||||
softWrap?: boolean
|
||||
subGrids?: GridItem[][]
|
||||
// Number of subgrids
|
||||
numberOfSubgrids?: number
|
||||
}
|
||||
|
||||
export type ComponentSet = {
|
||||
@@ -99,6 +100,7 @@ export type App = {
|
||||
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
}>
|
||||
css?: Record<'viewer' | 'grid' | AppComponent['type'], ComponentCustomCSS>
|
||||
subgrids?: Record<string, GridItem[]>
|
||||
}
|
||||
|
||||
export type ConnectingInput = {
|
||||
@@ -132,7 +134,6 @@ export type AppEditorContext = {
|
||||
}
|
||||
|
||||
export type FocusedGrid = { parentComponentId: string; subGridIndex: number }
|
||||
|
||||
export type EditorMode = 'dnd' | 'preview'
|
||||
export type EditorBreakpoint = 'sm' | 'lg'
|
||||
|
||||
|
||||
@@ -2,30 +2,20 @@ import type { Schema } from '$lib/common'
|
||||
import { FlowService, ScriptService } from '$lib/gen'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import type { AppComponent, AppComponentConfig } from './editor/component'
|
||||
|
||||
import {
|
||||
components as componentsRecord,
|
||||
getRecommendedDimensionsByComponent
|
||||
} from './editor/component'
|
||||
import { gridColumns } from './gridUtils'
|
||||
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
|
||||
import type { AppComponent } from './editor/component'
|
||||
|
||||
import type { AppInput, InputType, ResultAppInput, StaticAppInput } from './inputType'
|
||||
import type { Output } from './rx'
|
||||
import type { App, GridItem } from './types'
|
||||
import { getNextId } from '../flows/flowStateUtils'
|
||||
|
||||
export function deleteComponent(parentItems: GridItem[] | undefined, component: AppComponent, app: App, staticOutputs: Record<string, any>, runnableComponents: Record<string, any>) {
|
||||
(component.subGrids ?? []).forEach((subgrid) => {
|
||||
if (subgrid) {
|
||||
subgrid.forEach((item) => {
|
||||
if (item.data) {
|
||||
deleteComponent(undefined, item.data, app, staticOutputs, runnableComponents)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
/*
|
||||
export function deleteComponent(
|
||||
subgrid: string | undefined,
|
||||
component: AppComponent,
|
||||
app: App,
|
||||
staticOutputs: Record<string, any>,
|
||||
runnableComponents: Record<string, any>
|
||||
) {
|
||||
if (parentItems) {
|
||||
let index = parentItems.findIndex((item) => item.data?.id === component.id)
|
||||
if (index != -1) {
|
||||
@@ -54,6 +44,24 @@ export function deleteComponent(parentItems: GridItem[] | undefined, component:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
export function allItems(grid: GridItem[], subgrids: Record<string, GridItem[]> | undefined): GridItem[] {
|
||||
if (subgrids == undefined) {
|
||||
return grid
|
||||
}
|
||||
return [...grid, ...Object.values(subgrids).flat()]
|
||||
}
|
||||
|
||||
export function allItemsWithParent(grid: GridItem[], subgrids: Record<string, GridItem[]> | undefined): [GridItem, string | undefined][] {
|
||||
const items: [GridItem, string | undefined][] = grid.map((item) => [item, undefined])
|
||||
if (subgrids == undefined) {
|
||||
return items
|
||||
}
|
||||
return [...items, ...Object.entries(subgrids).flatMap(([k, v]) => v.map((g) => [g, k] as [GridItem, string]))]
|
||||
}
|
||||
|
||||
export async function loadSchema(
|
||||
workspace: string,
|
||||
path: string,
|
||||
@@ -256,106 +264,3 @@ export function toPascalCase(text: string) {
|
||||
export function toKebabCase(text: string) {
|
||||
return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
||||
}
|
||||
|
||||
export function findParent(root: GridItem[], id: string): GridItem | undefined {
|
||||
if (!root) {
|
||||
return undefined
|
||||
}
|
||||
for (const a of root) {
|
||||
if (a.id === id) {
|
||||
return a
|
||||
}
|
||||
|
||||
if (a.data.subGrids) {
|
||||
// Recursively search the sub-grids
|
||||
for (const subGrid of a.data.subGrids) {
|
||||
const result = findParent(subGrid, id)
|
||||
if (result) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function insertNewGridItem(
|
||||
root: GridItem[],
|
||||
id: string,
|
||||
subGridIndex: number,
|
||||
newId: string,
|
||||
data: AppComponent
|
||||
): GridItem[] {
|
||||
const parentA = findParent(root, id)
|
||||
|
||||
if (!parentA) {
|
||||
throw new Error(`Parent A object with ID ${id} not found.`)
|
||||
}
|
||||
|
||||
const subGrid = parentA.data.subGrids[subGridIndex]
|
||||
|
||||
if (!subGrid) {
|
||||
throw new Error(`Sub-grid with index ${subGridIndex} not found.`)
|
||||
}
|
||||
|
||||
const newItem = createNewGridItem(subGrid ?? [], newId, data)
|
||||
subGrid.push(newItem)
|
||||
return root
|
||||
}
|
||||
|
||||
// The grid is needed to find a space for the new component
|
||||
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
|
||||
const appComponent = data
|
||||
|
||||
appComponent.id = id
|
||||
|
||||
const newComponent = {
|
||||
fixed: false,
|
||||
resizable: true,
|
||||
draggable: true,
|
||||
customDragger: false,
|
||||
customResizer: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
|
||||
|
||||
const newItem: GridItem = {
|
||||
data: newData,
|
||||
id: id
|
||||
}
|
||||
|
||||
gridColumns.forEach((column) => {
|
||||
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
|
||||
|
||||
newItem[column] = {
|
||||
...newComponent,
|
||||
min: { w: 1, h: 1 },
|
||||
max: { w: column, h: 100 },
|
||||
w: rec.w,
|
||||
h: rec.h
|
||||
}
|
||||
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
|
||||
newItem[column] = { ...newItem[column], ...position }
|
||||
})
|
||||
|
||||
return newItem
|
||||
}
|
||||
|
||||
export function recursiveGetIds(gridItem: GridItem): string[] {
|
||||
const subGrids = gridItem.data.subGrids ?? []
|
||||
const subGridIds = subGrids
|
||||
.map((subGrid: GridItem[]) => subGrid?.map(recursiveGetIds) ?? [])
|
||||
.flat(Infinity)
|
||||
return [gridItem.data.id, ...subGridIds]
|
||||
}
|
||||
|
||||
export function getNextGridItemId(grid: GridItem[] = []): string {
|
||||
const gridItemIds = grid.map(recursiveGetIds).flat()
|
||||
const id = getNextId(gridItemIds)
|
||||
return id
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user