Compare commits
30 Commits
v1.69.0
...
rf/flatten
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b1bfed090 | ||
|
|
2125d119ff | ||
|
|
d3f1ef92ea | ||
|
|
26296ee05c | ||
|
|
7e4179a741 | ||
|
|
52adaa4cb5 | ||
|
|
a94f266743 | ||
|
|
9d680e6744 | ||
|
|
5060c37fed | ||
|
|
15c2bdcdae | ||
|
|
45ce630a75 | ||
|
|
d50734cbb3 | ||
|
|
b08b559eec | ||
|
|
5742bf2235 | ||
|
|
c56176ec91 | ||
|
|
dd7e8c742c | ||
|
|
640242b713 | ||
|
|
2f78132e08 | ||
|
|
c696f3b6cf | ||
|
|
0041411c06 | ||
|
|
54955b710c | ||
|
|
1eb5a0d1d3 | ||
|
|
ddda14c52b | ||
|
|
5123c9365c | ||
|
|
834e7b1d1c | ||
|
|
6e9a5b026e | ||
|
|
7ad8879b09 | ||
|
|
27cac3ffe6 | ||
|
|
705703a5e2 | ||
|
|
fac31c6628 |
@@ -14,7 +14,6 @@ BigInt.prototype.toJSON = function () {
|
||||
};
|
||||
|
||||
export { pgSql, pgClient } from './pg.ts'
|
||||
export { mySql, mysqlClient } from './mysql.ts'
|
||||
|
||||
export type Sql = string
|
||||
export type Email = string
|
||||
|
||||
@@ -396,7 +396,7 @@
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
initialPath=""
|
||||
namePlaceholder="my_{resource_type}"
|
||||
namePlaceholder="{resource_type}"
|
||||
kind="resource"
|
||||
/>
|
||||
|
||||
@@ -433,7 +433,7 @@
|
||||
{:else}
|
||||
<Path
|
||||
initialPath=""
|
||||
namePlaceholder="my_{resource_type}"
|
||||
namePlaceholder="{resource_type}"
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
kind="resource"
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import FolderEditor from './FolderEditor.svelte'
|
||||
import GroupEditor from './GroupEditor.svelte'
|
||||
import { random_adj } from './random_positive_adjetive'
|
||||
|
||||
type PathKind = 'resource' | 'script' | 'variable' | 'flow' | 'schedule' | 'app'
|
||||
let meta: Meta | undefined = undefined
|
||||
@@ -69,15 +70,23 @@
|
||||
|
||||
export async function reset() {
|
||||
if (path == '' || path == 'u//') {
|
||||
meta = { ownerKind: 'user', name: namePlaceholder, owner: '' }
|
||||
meta = {
|
||||
ownerKind: 'user',
|
||||
name: random_adj() + '_' + namePlaceholder,
|
||||
owner: ''
|
||||
}
|
||||
|
||||
meta.owner = $userStore!.username.split('@')[0]
|
||||
|
||||
let i = 1
|
||||
while (await pathExists(metaToPath(meta), kind)) {
|
||||
meta.name = `${namePlaceholder}_${i}`
|
||||
i += 1
|
||||
let newMeta = { ...meta }
|
||||
while (await pathExists(metaToPath(newMeta), kind)) {
|
||||
disabled = true
|
||||
error = 'finding an available name...'
|
||||
newMeta.name = random_adj() + '_' + namePlaceholder
|
||||
}
|
||||
error = ''
|
||||
disabled = false
|
||||
meta = newMeta
|
||||
path = metaToPath(meta)
|
||||
} else {
|
||||
meta = pathToMeta(path)
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
disabled={!can_write}
|
||||
bind:path
|
||||
{initialPath}
|
||||
namePlaceholder="my_resource"
|
||||
namePlaceholder="resource"
|
||||
kind="resource"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
{initialPath}
|
||||
namePlaceholder={'my_schedule'}
|
||||
namePlaceholder="schedule"
|
||||
kind="schedule"
|
||||
/>
|
||||
<div class="mb-8" />
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
bind:path={script.path}
|
||||
{initialPath}
|
||||
on:enter={() => changeStep(2)}
|
||||
namePlaceholder="my_script"
|
||||
namePlaceholder="script"
|
||||
kind="script"
|
||||
/>
|
||||
<h2 class="border-b pb-1 mt-12 mb-4">Summary</h2>
|
||||
@@ -245,7 +245,7 @@
|
||||
>
|
||||
<LanguageIcon lang="pgsql" /><span class="ml-2 py-4">PostgreSQL</span>
|
||||
</Button>
|
||||
<Button
|
||||
<!-- <Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={template == 'mysql' ? 'blue' : 'dark'}
|
||||
@@ -257,7 +257,7 @@
|
||||
}}
|
||||
>
|
||||
<LanguageIcon lang="mysql" /><span class="ml-2 py-4">MySQL</span>
|
||||
</Button>
|
||||
</Button> -->
|
||||
</div>
|
||||
<div class="mt-16 mb-4">
|
||||
<Button
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
{initialPath}
|
||||
namePlaceholder="my_variable"
|
||||
namePlaceholder="variable"
|
||||
kind="variable"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let subGrids: GridItem[][] | undefined = undefined
|
||||
export let componentContainerHeight: number
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
const { focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let noPadding: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = []
|
||||
const { app, focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let result: string[] | undefined = undefined
|
||||
let gridContent: string[] | undefined = undefined
|
||||
|
||||
function onFocus() {
|
||||
@@ -29,15 +26,16 @@
|
||||
$: $selectedComponent === id && onFocus()
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
|
||||
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
|
||||
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if subGrids && subGrids[0]}
|
||||
<SubGridEditor
|
||||
bind:subGrid={subGrids[0]}
|
||||
containerHeight={componentContainerHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
{noPadding}
|
||||
bind:subGrid={$app.subgrids[`${id}-0`]}
|
||||
containerHeight={componentContainerHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -6,27 +6,24 @@
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let subGrids: GridItem[][] | undefined = undefined
|
||||
export let componentContainerHeight: number
|
||||
export let tabs: string[]
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result', 'selectedTabIndex']
|
||||
const { worldStore, focusedGrid, selectedComponent } =
|
||||
export const staticOutputs: string[] = ['selectedTabIndex']
|
||||
const { app, worldStore, focusedGrid, selectedComponent } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let result: string[] | undefined = undefined
|
||||
let gridContent: string[] | undefined = undefined
|
||||
let selected: string = ''
|
||||
let noPadding: boolean | undefined = undefined
|
||||
|
||||
$: selectedIndex = result?.indexOf(selected) ?? -1
|
||||
$: selectedIndex = tabs?.indexOf(selected) ?? -1
|
||||
|
||||
$: if (result && selected === '') {
|
||||
selected = result[0]
|
||||
$: if ((tabs && selected === '') || !tabs.includes(selected)) {
|
||||
selected = tabs[0]
|
||||
}
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
@@ -38,6 +35,7 @@
|
||||
}
|
||||
|
||||
$: selectedIndex >= 0 && handleTabSelection()
|
||||
|
||||
let tabHeight: number = 0
|
||||
|
||||
function onFocus() {
|
||||
@@ -50,24 +48,27 @@
|
||||
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
|
||||
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
|
||||
<InputValue {id} input={configuration.tabs} bind:value={tabs} />
|
||||
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
|
||||
|
||||
<div>
|
||||
<div bind:clientHeight={tabHeight}>
|
||||
<Tabs bind:selected>
|
||||
{#each result ?? [] as res}
|
||||
{#each tabs ?? [] as res}
|
||||
<Tab value={res}>
|
||||
<span class="font-semibold">{res}</span>
|
||||
</Tab>
|
||||
{/each}
|
||||
</Tabs>
|
||||
</div>
|
||||
{#if subGrids && subGrids[selectedIndex]}
|
||||
{#if $app.subgrids?.[`${id}-${selectedIndex}`]}
|
||||
<SubGridEditor
|
||||
bind:subGrid={subGrids[selectedIndex]}
|
||||
bind:subGrid={$app.subgrids[`${id}-${selectedIndex}`]}
|
||||
{noPadding}
|
||||
containerHeight={componentContainerHeight - tabHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
bind:error={pathError}
|
||||
bind:path={newPath}
|
||||
initialPath=""
|
||||
namePlaceholder="my_app"
|
||||
namePlaceholder="app"
|
||||
kind="app"
|
||||
/>
|
||||
|
||||
@@ -467,8 +467,8 @@
|
||||
<div>{`Sub grid: ${$focusedGrid.parentComponentId} (${$focusedGrid.subGridIndex})`}</div>
|
||||
<button
|
||||
on:click={() => {
|
||||
$focusedGrid = undefined
|
||||
$selectedComponent = undefined
|
||||
$focusedGrid = undefined
|
||||
}}
|
||||
>
|
||||
<X size={14} />
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
const disabledGridItem = fct(gridItem)
|
||||
|
||||
if (disabledGridItem.data.subGrids) {
|
||||
disabledGridItem.data.subGrids = disabledGridItem.data.subGrids.map((subgrid: GridItem[]) =>
|
||||
subgrid.map((subgridItem: GridItem) => fct(subgridItem))
|
||||
disabledGridItem.data.subGrids = disabledGridItem.data.subGrids.map(
|
||||
(subgrid: GridItem[]) => subgrid?.map((subgridItem: GridItem) => fct(subgridItem)) ?? []
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
function selectComponent(id: string) {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = id
|
||||
$focusedGrid = undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
<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 TablePanel from './TablePanel.svelte'
|
||||
|
||||
const { selectedComponent, lazyGrid, app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { selectedComponent, app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
$: subgridKeys = Object.keys($app.subgrids ?? {})
|
||||
</script>
|
||||
|
||||
{#each $lazyGrid as gridItem (gridItem.data.id)}
|
||||
{#each $app.grid as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel bind:component={gridItem.data} />
|
||||
<ComponentPanel parent={undefined} bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.type === 'tablecomponent'}
|
||||
<TablePanel bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.subGrids}
|
||||
{#each gridItem.data.subGrids as subGrid}
|
||||
{#each subGrid as subGridItem, index (subGridItem.data.id)}
|
||||
{#if subGridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel
|
||||
bind:component={subGridItem.data}
|
||||
onDelete={() => {
|
||||
subGrid.splice(index, 1)
|
||||
subGrid = subGrid
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{/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}`}
|
||||
<PanelSection title={`Background script inputs`}>
|
||||
|
||||
@@ -6,8 +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 id: string
|
||||
export let subGrid: GridItem[] = []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -35,6 +37,12 @@
|
||||
onComponent = id
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = id
|
||||
/*
|
||||
$focusedGrid = {
|
||||
parentComponentId: parentId,
|
||||
subGridIndex: index
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,33 +55,12 @@
|
||||
|
||||
// @ts-ignore
|
||||
let container
|
||||
|
||||
$: if ($focusedGrid?.parentComponentId !== $selectedComponent) {
|
||||
const gridItemIds = $app.grid
|
||||
.map((gridItem: GridItem) => {
|
||||
if (gridItem.data.id === $focusedGrid?.parentComponentId) {
|
||||
const subGrids = gridItem.data.subGrids ?? []
|
||||
return [
|
||||
gridItem.data.id,
|
||||
...subGrids.map((subGrid: GridItem[]) =>
|
||||
subGrid.map((gridItem: GridItem) => gridItem.data.id)
|
||||
)
|
||||
]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
})
|
||||
.flat(2)
|
||||
|
||||
if (!gridItemIds.includes($selectedComponent)) {
|
||||
$focusedGrid = undefined
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative w-full subgrid " bind:this={container}>
|
||||
<div
|
||||
class="px-4 pt-4 overflow-auto {$connectingInput?.opened ? '' : ''}"
|
||||
class:px-2={!noPadding}
|
||||
class="py-2 overflow-auto {$connectingInput?.opened ? '' : ''}"
|
||||
on:pointerdown|stopPropagation={onpointerdown}
|
||||
on:pointerleave={onpointerup}
|
||||
on:pointerup={onpointerup}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
{#each component.actionButtons as actionButton (actionButton.id)}
|
||||
{#if actionButton.id === $selectedComponent}
|
||||
<ComponentPanel
|
||||
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
|
||||
}
|
||||
@@ -73,7 +73,9 @@ export type IconComponent = BaseComponent<'iconcomponent'>
|
||||
export type HorizontalDividerComponent = BaseComponent<'horizontaldividercomponent'>
|
||||
export type VerticalDividerComponent = BaseComponent<'verticaldividercomponent'>
|
||||
export type FileInputComponent = BaseComponent<'fileinputcomponent'>
|
||||
export type TabsComponent = BaseComponent<'tabscomponent'>
|
||||
export type TabsComponent = BaseComponent<'tabscomponent'> & {
|
||||
tabs: string[]
|
||||
}
|
||||
export type ContainerComponent = BaseComponent<'containercomponent'>
|
||||
|
||||
export type AppComponent = BaseAppComponent &
|
||||
@@ -150,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
|
||||
}
|
||||
@@ -161,18 +163,19 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
dims: '2:8-6:8',
|
||||
data: {
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: '',
|
||||
type: 'containercomponent',
|
||||
configuration: {},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'text',
|
||||
value: ['First Tab', 'Second Tab']
|
||||
configuration: {
|
||||
noPadding: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
subGrids: [[]]
|
||||
numberOfSubgrids: 1
|
||||
}
|
||||
},
|
||||
textcomponent: {
|
||||
@@ -1012,18 +1015,20 @@ Hello \${ctx.username}
|
||||
dims: '2:8-6:8',
|
||||
data: {
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: '',
|
||||
type: 'tabscomponent',
|
||||
configuration: {},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'text',
|
||||
value: ['First Tab', 'Second Tab']
|
||||
configuration: {
|
||||
noPadding: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
subGrids: [[], []]
|
||||
numberOfSubgrids: 2,
|
||||
tabs: ['First tab', 'Second tab']
|
||||
}
|
||||
},
|
||||
iconcomponent: {
|
||||
@@ -1195,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,6 +2,7 @@
|
||||
import { classNames } from '$lib/utils'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { findGridItem } from '../appUtils'
|
||||
import { components } from '../component'
|
||||
import PanelSection from '../settingsPanel/common/PanelSection.svelte'
|
||||
import ComponentOutputViewer from './ComponentOutputViewer.svelte'
|
||||
@@ -26,7 +27,7 @@
|
||||
}
|
||||
|
||||
function getComponentNameById(componentId: string) {
|
||||
const component = $app.grid.find((c) => c?.data?.id === componentId)
|
||||
const component = findGridItem($app, componentId)
|
||||
|
||||
if (component?.data.type) {
|
||||
return components[component?.data.type].name
|
||||
|
||||
@@ -164,13 +164,13 @@
|
||||
createInlineScriptByLanguage(Script.language.DENO, name, 'pgsql')
|
||||
}}
|
||||
/>
|
||||
<FlowScriptPicker
|
||||
<!-- <FlowScriptPicker
|
||||
label={`MySQL`}
|
||||
lang="mysql"
|
||||
on:click={() => {
|
||||
createInlineScriptByLanguage(Script.language.DENO, name, 'mysql')
|
||||
}}
|
||||
/>
|
||||
/> -->
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
import SplitPanesWrapper from '$lib/components/splitPanes/SplitPanesWrapper.svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import InlineScriptsPanelList from './InlineScriptsPanelList.svelte'
|
||||
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
import EmptyInlineScript from './EmptyInlineScript.svelte'
|
||||
import { allItems } from '../../utils'
|
||||
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
|
||||
|
||||
const { lazyGrid, app, staticOutputs, runnableComponents } =
|
||||
const { app, staticOutputs, runnableComponents } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let selectedScriptComponentId: string | undefined = undefined
|
||||
@@ -23,16 +24,17 @@
|
||||
{#if !selectedScriptComponentId}
|
||||
<span class="p-2 text-sm text-gray-600">Select a script on the left panel</span>
|
||||
{/if}
|
||||
{#each $lazyGrid as gridComponent, index (index)}
|
||||
{#if gridComponent.data.id === selectedScriptComponentId}
|
||||
|
||||
{#each allItems($app.grid, $app.subgrids) as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={gridComponent.data.id}
|
||||
bind:componentInput={gridComponent.data.componentInput}
|
||||
id={gridItem.data.id}
|
||||
bind:componentInput={gridItem.data.componentInput}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if gridComponent.data.type === 'tablecomponent'}
|
||||
{#each gridComponent.data.actionButtons as actionButton, index (index)}
|
||||
{#if gridItem.data.type === 'tablecomponent'}
|
||||
{#each gridItem.data.actionButtons as actionButton, index (index)}
|
||||
{#if actionButton.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={actionButton.id}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { faCopy, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
import InputsSpecsEditor from './InputsSpecsEditor.svelte'
|
||||
import TableActions from './TableActions.svelte'
|
||||
@@ -10,14 +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,
|
||||
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'
|
||||
@@ -27,81 +20,43 @@
|
||||
import type { AppComponent } from '../component'
|
||||
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 onDelete: (() => void) | undefined = undefined
|
||||
export let component: AppComponent
|
||||
export let rowColumns = false
|
||||
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
|
||||
if (onDelete && component) {
|
||||
delete $staticOutputs[component.id]
|
||||
$staticOutputs = $staticOutputs
|
||||
|
||||
delete $runnableComponents[component.id]
|
||||
$runnableComponents = $runnableComponents
|
||||
|
||||
onDelete()
|
||||
// Delete static inputs
|
||||
} else {
|
||||
if (component) {
|
||||
$app.grid = $app.grid.filter((gridComponent) => gridComponent.data.id !== component?.id)
|
||||
|
||||
// Delete static inputs
|
||||
delete $staticOutputs[component.id]
|
||||
$staticOutputs = $staticOutputs
|
||||
|
||||
delete $runnableComponents[component.id]
|
||||
$runnableComponents = $runnableComponents
|
||||
$focusedGrid = undefined
|
||||
if (component && !noGrid) {
|
||||
let ids = deleteGridItem($app, component, parent)
|
||||
for (const key in ids) {
|
||||
delete $staticOutputs[key]
|
||||
delete $runnableComponents[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
component &&
|
||||
component.componentInput?.type === 'runnable' &&
|
||||
component.componentInput?.runnable?.type === 'runnableByName'
|
||||
) {
|
||||
const { name, inlineScript } = component.componentInput.runnable
|
||||
delete $staticOutputs[component.id]
|
||||
delete $runnableComponents[component.id]
|
||||
$app = $app
|
||||
$staticOutputs = $staticOutputs
|
||||
$runnableComponents = $runnableComponents
|
||||
|
||||
if (inlineScript) {
|
||||
if (!$app.unusedInlineScripts) {
|
||||
$app.unusedInlineScripts = []
|
||||
}
|
||||
|
||||
$app.unusedInlineScripts.push({
|
||||
name,
|
||||
inlineScript
|
||||
})
|
||||
}
|
||||
}
|
||||
onDelete?.()
|
||||
}
|
||||
|
||||
$: extraLib =
|
||||
@@ -140,18 +95,7 @@
|
||||
|
||||
<div class="flex flex-col w-full gap-2 my-2">
|
||||
{#if component.componentInput.type === 'static'}
|
||||
<StaticInputEditor
|
||||
bind:componentInput={component.componentInput}
|
||||
on:deleteArrayItem={(e) => {
|
||||
if (component?.type === 'tabscomponent') {
|
||||
const deletedIndex = e.detail.index
|
||||
|
||||
if (component.subGrids) {
|
||||
component.subGrids.splice(deletedIndex, 1)
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<StaticInputEditor bind:componentInput={component.componentInput} />
|
||||
{:else if component.componentInput.type === 'template' && component.componentInput !== undefined}
|
||||
<div class="py-1 min-h-[28px] rounded border border-1 border-gray-500">
|
||||
<TemplateEditor fontSize={12} bind:code={component.componentInput.eval} {extraLib} />
|
||||
@@ -204,6 +148,10 @@
|
||||
</PanelSection>
|
||||
{/if}
|
||||
|
||||
{#if component.type === 'tabscomponent'}
|
||||
<GridTab bind:tabs={component.tabs} {component} />
|
||||
{/if}
|
||||
|
||||
{#if component.type === 'tablecomponent' && Array.isArray(component.actionButtons)}
|
||||
<TableActions id={component.id} bind:components={component.actionButtons} />
|
||||
{/if}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<script lang="ts">
|
||||
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 } from '../../types'
|
||||
import { deleteGridItem } from '../appUtils'
|
||||
import type { AppComponent } from '../component'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
|
||||
export let tabs: string[]
|
||||
export let component: AppComponent
|
||||
|
||||
const { app, staticOutputs, runnableComponents } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function addTab() {
|
||||
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) {
|
||||
tabs.splice(index, 1)
|
||||
tabs = tabs
|
||||
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>
|
||||
|
||||
<PanelSection title={`Tabs ${tabs.length > 0 ? `(${tabs.length})` : ''}`}>
|
||||
{#if tabs.length == 0}
|
||||
<span class="text-xs text-gray-500">No Tabs</span>
|
||||
{/if}
|
||||
<div class="flex gap-2 flex-col mt-2">
|
||||
{#each tabs as value, index (index)}
|
||||
<div class="flex flex-row gap-2 items-center relative">
|
||||
<input type="text" bind:value />
|
||||
|
||||
<div class="absolute top-1 right-1">
|
||||
<Button
|
||||
size="xs"
|
||||
color="light"
|
||||
variant="border"
|
||||
on:click={() => {
|
||||
deleteSubgrid(index)
|
||||
}}
|
||||
iconOnly
|
||||
btnClasses="!text-red-500"
|
||||
startIcon={{ icon: faTrashAlt }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
<Button
|
||||
size="xs"
|
||||
color="light"
|
||||
variant="border"
|
||||
startIcon={{ icon: faPlus }}
|
||||
on:click={addTab}
|
||||
iconOnly
|
||||
/>
|
||||
</div>
|
||||
</PanelSection>
|
||||
@@ -95,17 +95,28 @@
|
||||
}}
|
||||
on:keypress
|
||||
>
|
||||
<Badge color="dark-indigo">
|
||||
{component.id}
|
||||
</Badge>
|
||||
|
||||
<div>
|
||||
<TableActionLabel componentInput={component.configuration.label} />
|
||||
</div>
|
||||
<div>
|
||||
<Button variant="border" color="red" on:click={() => deleteComponent(component.id)}>
|
||||
<Icon class="h-3" data={faTrashAlt} />
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<TableActionLabel componentInput={component.configuration.label} />
|
||||
</div>
|
||||
<Badge color="dark-indigo">
|
||||
{component.id}
|
||||
</Badge>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="w-full">
|
||||
<Button
|
||||
btnClasses="w-full"
|
||||
color="light"
|
||||
variant="border"
|
||||
startIcon={{ icon: faPlus }}
|
||||
on:click={addComponent}
|
||||
iconOnly
|
||||
/>
|
||||
</div>
|
||||
</PanelSection>
|
||||
|
||||
@@ -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,19 +2,65 @@ 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(
|
||||
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) {
|
||||
parentItems.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
delete staticOutputs[component.id]
|
||||
delete runnableComponents[component.id]
|
||||
|
||||
if (
|
||||
component.componentInput?.type === 'runnable' &&
|
||||
component.componentInput?.runnable?.type === 'runnableByName'
|
||||
) {
|
||||
const { name, inlineScript } = component.componentInput.runnable
|
||||
|
||||
if (inlineScript) {
|
||||
if (!app.unusedInlineScripts) {
|
||||
app.unusedInlineScripts = []
|
||||
}
|
||||
|
||||
app.unusedInlineScripts.push({
|
||||
name,
|
||||
inlineScript
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
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,
|
||||
@@ -218,101 +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 {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -142,12 +142,12 @@
|
||||
dispatch('new', { language: RawScript.language.DENO, kind, subkind: 'pgsql' })}
|
||||
/>
|
||||
|
||||
<FlowScriptPicker
|
||||
<!-- <FlowScriptPicker
|
||||
label={`MySQL`}
|
||||
lang="mysql"
|
||||
on:click={() =>
|
||||
dispatch('new', { language: RawScript.language.DENO, kind, subkind: 'mysql' })}
|
||||
/>
|
||||
/> -->
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -42,12 +42,7 @@
|
||||
<svelte:fragment slot="content">
|
||||
<TabContent value="settings-metadata" class="p-4 h-full">
|
||||
<div class="overflow-auto h-full">
|
||||
<Path
|
||||
bind:path={$flowStore.path}
|
||||
{initialPath}
|
||||
namePlaceholder="my_flow"
|
||||
kind="flow"
|
||||
/>
|
||||
<Path bind:path={$flowStore.path} {initialPath} namePlaceholder="flow" kind="flow" />
|
||||
|
||||
<label class="block my-4">
|
||||
<span class="text-gray-700 text-sm">Summary <Required required={false} /></span>
|
||||
|
||||
962
frontend/src/lib/components/random_positive_adjetive.ts
Normal file
962
frontend/src/lib/components/random_positive_adjetive.ts
Normal file
@@ -0,0 +1,962 @@
|
||||
const adjectives = ["abundant",
|
||||
"accessible",
|
||||
"accommodative",
|
||||
"accomplished",
|
||||
"accurate",
|
||||
"achievable",
|
||||
"adaptable",
|
||||
"adaptive",
|
||||
"adequate",
|
||||
"adjustable",
|
||||
"admirable",
|
||||
"admiring",
|
||||
"adorable",
|
||||
"adored",
|
||||
"adoring",
|
||||
"adroit",
|
||||
"adulatory",
|
||||
"advanced",
|
||||
"advantageous",
|
||||
"adventuresome",
|
||||
"adventurous",
|
||||
"affable",
|
||||
"affectionate",
|
||||
"affirmative",
|
||||
"affluent",
|
||||
"affordable",
|
||||
"agile",
|
||||
"agreeable",
|
||||
"alluring",
|
||||
"altruistic",
|
||||
"amazed",
|
||||
"amazing",
|
||||
"ambitious",
|
||||
"amenable",
|
||||
"amiable",
|
||||
"amicable",
|
||||
"ample",
|
||||
"amusing",
|
||||
"angelic",
|
||||
"appealing",
|
||||
"appreciable",
|
||||
"appreciated",
|
||||
"appreciative",
|
||||
"appropriate",
|
||||
"ardent",
|
||||
"articulate",
|
||||
"artistic",
|
||||
"assuring",
|
||||
"astonished",
|
||||
"astonishing",
|
||||
"astounded",
|
||||
"astounding",
|
||||
"athletic",
|
||||
"attentive",
|
||||
"attractive",
|
||||
"audible",
|
||||
"auspicious",
|
||||
"authentic",
|
||||
"authoritative",
|
||||
"autonomous",
|
||||
"available",
|
||||
"avid",
|
||||
"awed",
|
||||
"awesome",
|
||||
"awestruck",
|
||||
"balanced",
|
||||
"beauteous",
|
||||
"beautiful",
|
||||
"believable",
|
||||
"beloved",
|
||||
"beneficent",
|
||||
"beneficial",
|
||||
"beneficiary",
|
||||
"benevolent",
|
||||
"best",
|
||||
"best_known",
|
||||
"best_performing",
|
||||
"best_selling",
|
||||
"better",
|
||||
"better_known",
|
||||
"better_than_expected",
|
||||
"blameless",
|
||||
"blissful",
|
||||
"blithe",
|
||||
"bonny",
|
||||
"booming",
|
||||
"boundless",
|
||||
"bountiful",
|
||||
"brainiest",
|
||||
"brainy",
|
||||
"brand_new",
|
||||
"brave",
|
||||
"breathtaking",
|
||||
"bright",
|
||||
"brighter",
|
||||
"brightest",
|
||||
"brilliant",
|
||||
"brisk",
|
||||
"brotherly",
|
||||
"bullish",
|
||||
"buoyant",
|
||||
"calm",
|
||||
"calming",
|
||||
"capable",
|
||||
"captivating",
|
||||
"carefree",
|
||||
"catchy",
|
||||
"celebrated",
|
||||
"celebratory",
|
||||
"champion",
|
||||
"charismatic",
|
||||
"charitable",
|
||||
"charming",
|
||||
"chaste",
|
||||
"cheaper",
|
||||
"cheapest",
|
||||
"cheerful",
|
||||
"cheery",
|
||||
"cherished",
|
||||
"chivalrous",
|
||||
"classic",
|
||||
"classy",
|
||||
"clean",
|
||||
"cleaner",
|
||||
"cleanest",
|
||||
"cleanly",
|
||||
"clear",
|
||||
"clear_cut",
|
||||
"cleared",
|
||||
"clearer",
|
||||
"clever",
|
||||
"coherent",
|
||||
"cohesive",
|
||||
"colorful",
|
||||
"comely",
|
||||
"comfortable",
|
||||
"comforting",
|
||||
"comfy",
|
||||
"commendable",
|
||||
"commodious",
|
||||
"compact",
|
||||
"compassionate",
|
||||
"compatible",
|
||||
"competitive",
|
||||
"complementary",
|
||||
"compliant",
|
||||
"complimentary",
|
||||
"comprehensive",
|
||||
"conciliatory",
|
||||
"concise",
|
||||
"confident",
|
||||
"congenial",
|
||||
"congratulatory",
|
||||
"conscientious",
|
||||
"considerate",
|
||||
"consistent",
|
||||
"constructive",
|
||||
"consummate",
|
||||
"contrasty",
|
||||
"convenient",
|
||||
"convincing",
|
||||
"cool",
|
||||
"coolest",
|
||||
"cooperative",
|
||||
"correct",
|
||||
"cost_effective",
|
||||
"cost_saving",
|
||||
"courageous",
|
||||
"courteous",
|
||||
"courtly",
|
||||
"cozy",
|
||||
"creative",
|
||||
"credible",
|
||||
"crisp",
|
||||
"crisper",
|
||||
"cure_all",
|
||||
"cushy",
|
||||
"cute",
|
||||
"daring",
|
||||
"darling",
|
||||
"dashing",
|
||||
"dauntless",
|
||||
"dazzled",
|
||||
"dazzling",
|
||||
"dead_cheap",
|
||||
"dead_on",
|
||||
"decent",
|
||||
"decisive",
|
||||
"dedicated",
|
||||
"defeated",
|
||||
"deft",
|
||||
"delectable",
|
||||
"delicate",
|
||||
"delicious",
|
||||
"delighted",
|
||||
"delightful",
|
||||
"dependable",
|
||||
"deserving",
|
||||
"desirable",
|
||||
"desirous",
|
||||
"detachable",
|
||||
"devout",
|
||||
"dexterous",
|
||||
"dextrous",
|
||||
"dignified",
|
||||
"diligent",
|
||||
"diplomatic",
|
||||
"dirt_cheap",
|
||||
"distinctive",
|
||||
"distinguished",
|
||||
"diversified",
|
||||
"divine",
|
||||
"dominated",
|
||||
"dumbfounded",
|
||||
"dumbfounding",
|
||||
"dummy_proof",
|
||||
"durable",
|
||||
"dynamic",
|
||||
"eager",
|
||||
"earnest",
|
||||
"eased",
|
||||
"easier",
|
||||
"easiest",
|
||||
"easy",
|
||||
"easy_to_use",
|
||||
"easygoing",
|
||||
"ebullient",
|
||||
"economical",
|
||||
"ecstatic",
|
||||
"educated",
|
||||
"effective",
|
||||
"effectual",
|
||||
"efficacious",
|
||||
"efficient",
|
||||
"effortless",
|
||||
"effusive",
|
||||
"elated",
|
||||
"elegant",
|
||||
"elite",
|
||||
"eloquent",
|
||||
"eminent",
|
||||
"enchanted",
|
||||
"enchanting",
|
||||
"encouraging",
|
||||
"endearing",
|
||||
"endorsed",
|
||||
"energetic",
|
||||
"energy_efficient",
|
||||
"energy_saving",
|
||||
"engaging",
|
||||
"engrossing",
|
||||
"enhanced",
|
||||
"enjoyable",
|
||||
"enough",
|
||||
"enraptured",
|
||||
"enterprising",
|
||||
"entertaining",
|
||||
"enthralled",
|
||||
"enthusiastic",
|
||||
"enticing",
|
||||
"entranced",
|
||||
"entrancing",
|
||||
"enviable",
|
||||
"envious",
|
||||
"equitable",
|
||||
"err_free",
|
||||
"erudite",
|
||||
"ethical",
|
||||
"euphoric",
|
||||
"evaluative",
|
||||
"eventful",
|
||||
"everlasting",
|
||||
"evocative",
|
||||
"exalted",
|
||||
"exalting",
|
||||
"exceeding",
|
||||
"excellent",
|
||||
"exceptional",
|
||||
"excited",
|
||||
"exciting",
|
||||
"exemplary",
|
||||
"exhilarating",
|
||||
"expansive",
|
||||
"exquisite",
|
||||
"extraordinary",
|
||||
"exuberant",
|
||||
"exultant",
|
||||
"eye_catching",
|
||||
"fabulous",
|
||||
"fair",
|
||||
"faithful",
|
||||
"famed",
|
||||
"famous",
|
||||
"fancier",
|
||||
"fancy",
|
||||
"fantastic",
|
||||
"fascinating",
|
||||
"fashionable",
|
||||
"fast",
|
||||
"fast_growing",
|
||||
"fast_paced",
|
||||
"faster",
|
||||
"fastest",
|
||||
"fastest_growing",
|
||||
"faultless",
|
||||
"favorable",
|
||||
"favored",
|
||||
"favorite",
|
||||
"fearless",
|
||||
"feasible",
|
||||
"feature_rich",
|
||||
"feisty",
|
||||
"felicitous",
|
||||
"fertile",
|
||||
"fervent",
|
||||
"fervid",
|
||||
"festive",
|
||||
"fiery",
|
||||
"fine",
|
||||
"fine_looking",
|
||||
"finer",
|
||||
"finest",
|
||||
"firmer",
|
||||
"first_class",
|
||||
"first_in_class",
|
||||
"first_rate",
|
||||
"flashy",
|
||||
"flatter",
|
||||
"flattering",
|
||||
"flawless",
|
||||
"flexible",
|
||||
"flourishing",
|
||||
"fluent",
|
||||
"fond",
|
||||
"foolproof",
|
||||
"foremost",
|
||||
"formidable",
|
||||
"fortuitous",
|
||||
"fortunate",
|
||||
"fragrant",
|
||||
"free",
|
||||
"freed",
|
||||
"fresh",
|
||||
"fresher",
|
||||
"freshest",
|
||||
"friendly",
|
||||
"frugal",
|
||||
"fruitful",
|
||||
"fun",
|
||||
"funny",
|
||||
"futuristic",
|
||||
"gainful",
|
||||
"gallant",
|
||||
"galore",
|
||||
"generous",
|
||||
"genial",
|
||||
"gentle",
|
||||
"gentlest",
|
||||
"genuine",
|
||||
"gifted",
|
||||
"glad",
|
||||
"glamorous",
|
||||
"gleeful",
|
||||
"glimmering",
|
||||
"glistening",
|
||||
"glorious",
|
||||
"glowing",
|
||||
"god_given",
|
||||
"godlike",
|
||||
"gold",
|
||||
"golden",
|
||||
"good",
|
||||
"goodly",
|
||||
"gorgeous",
|
||||
"graceful",
|
||||
"gracious",
|
||||
"grand",
|
||||
"grateful",
|
||||
"gratified",
|
||||
"gratifying",
|
||||
"great",
|
||||
"greatest",
|
||||
"groundbreaking",
|
||||
"guiltless",
|
||||
"gutsy",
|
||||
"halcyon",
|
||||
"hale",
|
||||
"hallowed",
|
||||
"handier",
|
||||
"hands_down",
|
||||
"handsome",
|
||||
"handy",
|
||||
"happier",
|
||||
"happy",
|
||||
"hard_working",
|
||||
"hardier",
|
||||
"hardy",
|
||||
"harmless",
|
||||
"harmonious",
|
||||
"healthful",
|
||||
"healthy",
|
||||
"heartening",
|
||||
"heartfelt",
|
||||
"heartwarming",
|
||||
"heavenly",
|
||||
"helpful",
|
||||
"heroic",
|
||||
"high_quality",
|
||||
"high_spirited",
|
||||
"hilarious",
|
||||
"holy",
|
||||
"honest",
|
||||
"honorable",
|
||||
"honored",
|
||||
"hopeful",
|
||||
"hospitable",
|
||||
"hot",
|
||||
"hottest",
|
||||
"humane",
|
||||
"humble",
|
||||
"humorous",
|
||||
"humourous",
|
||||
"ideal",
|
||||
"idolized",
|
||||
"idyllic",
|
||||
"illuminating",
|
||||
"illustrious",
|
||||
"imaginative",
|
||||
"immaculate",
|
||||
"immense",
|
||||
"impartial",
|
||||
"impassioned",
|
||||
"impeccable",
|
||||
"important",
|
||||
"impressed",
|
||||
"impressive",
|
||||
"improved",
|
||||
"improving",
|
||||
"incredible",
|
||||
"indebted",
|
||||
"individualized",
|
||||
"indulgent",
|
||||
"industrious",
|
||||
"inestimable",
|
||||
"inexpensive",
|
||||
"infallible",
|
||||
"influential",
|
||||
"ingenious",
|
||||
"ingenuous",
|
||||
"innocuous",
|
||||
"innovative",
|
||||
"insightful",
|
||||
"inspirational",
|
||||
"inspiring",
|
||||
"instructive",
|
||||
"instrumental",
|
||||
"integral",
|
||||
"integrated",
|
||||
"intelligent",
|
||||
"intelligible",
|
||||
"interesting",
|
||||
"intimate",
|
||||
"intricate",
|
||||
"intriguing",
|
||||
"intuitive",
|
||||
"invaluable",
|
||||
"inventive",
|
||||
"invigorating",
|
||||
"invincible",
|
||||
"inviolable",
|
||||
"inviolate",
|
||||
"invulnerable",
|
||||
"irreplaceable",
|
||||
"irreproachable",
|
||||
"irresistible",
|
||||
"issue_free",
|
||||
"jaw_dropping",
|
||||
"jolly",
|
||||
"jovial",
|
||||
"joyful",
|
||||
"joyous",
|
||||
"jubilant",
|
||||
"judicious",
|
||||
"keen",
|
||||
"kid_friendly",
|
||||
"kindly",
|
||||
"knowledgeable",
|
||||
"large_capacity",
|
||||
"laudable",
|
||||
"lavish",
|
||||
"law_abiding",
|
||||
"lawful",
|
||||
"leading",
|
||||
"lean",
|
||||
"legendary",
|
||||
"light_hearted",
|
||||
"lighter",
|
||||
"likable",
|
||||
"like",
|
||||
"liked",
|
||||
"lionhearted",
|
||||
"lively",
|
||||
"logical",
|
||||
"long_lasting",
|
||||
"lovable",
|
||||
"loved",
|
||||
"lovely",
|
||||
"loving",
|
||||
"low_cost",
|
||||
"low_price",
|
||||
"low_priced",
|
||||
"low_risk",
|
||||
"lower_priced",
|
||||
"loyal",
|
||||
"lucid",
|
||||
"luckier",
|
||||
"luckiest",
|
||||
"lucky",
|
||||
"lucrative",
|
||||
"luminous",
|
||||
"lush",
|
||||
"lustrous",
|
||||
"luxuriant",
|
||||
"luxurious",
|
||||
"luxury",
|
||||
"lyrical",
|
||||
"magic",
|
||||
"magical",
|
||||
"magnanimous",
|
||||
"magnificent",
|
||||
"majestic",
|
||||
"manageable",
|
||||
"maneuverable",
|
||||
"marvellous",
|
||||
"marvelous",
|
||||
"masterful",
|
||||
"matchless",
|
||||
"mature",
|
||||
"meaningful",
|
||||
"memorable",
|
||||
"merciful",
|
||||
"meritorious",
|
||||
"merry",
|
||||
"mesmerized",
|
||||
"mesmerizing",
|
||||
"meticulous",
|
||||
"mighty",
|
||||
"mind_blowing",
|
||||
"miraculous",
|
||||
"modern",
|
||||
"modest",
|
||||
"momentous",
|
||||
"monumental",
|
||||
"motivated",
|
||||
"multi_purpose",
|
||||
"navigable",
|
||||
"neat",
|
||||
"neatest",
|
||||
"nice",
|
||||
"nicer",
|
||||
"nicest",
|
||||
"nifty",
|
||||
"nimble",
|
||||
"noble",
|
||||
"noiseless",
|
||||
"non_violent",
|
||||
"noteworthy",
|
||||
"nourishing",
|
||||
"observant",
|
||||
"obtainable",
|
||||
"optimal",
|
||||
"optimistic",
|
||||
"opulent",
|
||||
"orderly",
|
||||
"organized",
|
||||
"outstanding",
|
||||
"overjoyed",
|
||||
"pain_free",
|
||||
"painless",
|
||||
"palatial",
|
||||
"pampered",
|
||||
"panoramic",
|
||||
"paramount",
|
||||
"passionate",
|
||||
"patient",
|
||||
"patri",
|
||||
"otic",
|
||||
"peaceable",
|
||||
"peaceful",
|
||||
"peerless",
|
||||
"peppy",
|
||||
"perfect",
|
||||
"permissible",
|
||||
"personalized",
|
||||
"phenomenal",
|
||||
"picturesque",
|
||||
"playful",
|
||||
"pleasant",
|
||||
"pleased",
|
||||
"pleasing",
|
||||
"pleasurable",
|
||||
"plentiful",
|
||||
"plush",
|
||||
"poetic",
|
||||
"poignant",
|
||||
"poised",
|
||||
"polished",
|
||||
"polite",
|
||||
"popular",
|
||||
"portable",
|
||||
"posh",
|
||||
"positive",
|
||||
"powerful",
|
||||
"praiseworthy",
|
||||
"praising",
|
||||
"pre_eminent",
|
||||
"precious",
|
||||
"precise",
|
||||
"preeminent",
|
||||
"preferable",
|
||||
"premier",
|
||||
"prestigious",
|
||||
"pretty",
|
||||
"priceless",
|
||||
"principled",
|
||||
"privileged",
|
||||
"prize",
|
||||
"proactive",
|
||||
"problem_free",
|
||||
"prodigious",
|
||||
"productive",
|
||||
"proficient",
|
||||
"profound",
|
||||
"profuse",
|
||||
"progressive",
|
||||
"prolific",
|
||||
"prominent",
|
||||
"promised",
|
||||
"promising",
|
||||
"prompt",
|
||||
"proper",
|
||||
"propitious",
|
||||
"prosperous",
|
||||
"protective",
|
||||
"proud",
|
||||
"proven",
|
||||
"prudent",
|
||||
"punctual",
|
||||
"pure",
|
||||
"purposeful",
|
||||
"quaint",
|
||||
"qualified",
|
||||
"quicker",
|
||||
"quiet",
|
||||
"quieter",
|
||||
"radiant",
|
||||
"rapid",
|
||||
"rapt",
|
||||
"rapturous",
|
||||
"rational",
|
||||
"razor_sharp",
|
||||
"reachable",
|
||||
"readable",
|
||||
"ready",
|
||||
"realistic",
|
||||
"realizable",
|
||||
"reasonable",
|
||||
"reasoned",
|
||||
"receptive",
|
||||
"recommended",
|
||||
"record_setting",
|
||||
"redeeming",
|
||||
"refined",
|
||||
"reformed",
|
||||
"refreshed",
|
||||
"refreshing",
|
||||
"regal",
|
||||
"rejoicing",
|
||||
"relaxed",
|
||||
"reliable",
|
||||
"remarkable",
|
||||
"renewed",
|
||||
"renowned",
|
||||
"replaceable",
|
||||
"reputable",
|
||||
"resilient",
|
||||
"resolute",
|
||||
"resounding",
|
||||
"resourceful",
|
||||
"respectable",
|
||||
"respectful",
|
||||
"resplendent",
|
||||
"responsive",
|
||||
"restful",
|
||||
"restored",
|
||||
"retractable",
|
||||
"reverent",
|
||||
"revolutionary",
|
||||
"rewarding",
|
||||
"rich",
|
||||
"richer",
|
||||
"right",
|
||||
"righteous",
|
||||
"rightful",
|
||||
"risk_free",
|
||||
"robust",
|
||||
"rock_star",
|
||||
"romantic",
|
||||
"roomier",
|
||||
"roomy",
|
||||
"rosy",
|
||||
"safe",
|
||||
"saintly",
|
||||
"salutary",
|
||||
"sane",
|
||||
"satisfactory",
|
||||
"satisfied",
|
||||
"satisfying",
|
||||
"scenic",
|
||||
"seamless",
|
||||
"seasoned",
|
||||
"secure",
|
||||
"selective",
|
||||
"self_determination",
|
||||
"self_respect",
|
||||
"self_satisfaction",
|
||||
"self_sufficiency",
|
||||
"self_sufficient",
|
||||
"sensational",
|
||||
"sensible",
|
||||
"sensitive",
|
||||
"serene",
|
||||
"sexy",
|
||||
"sharp",
|
||||
"sharper",
|
||||
"sharpest",
|
||||
"shiny",
|
||||
"significant",
|
||||
"silent",
|
||||
"simpler",
|
||||
"simplest",
|
||||
"simplified",
|
||||
"sincere",
|
||||
"skilled",
|
||||
"skillful",
|
||||
"sleek",
|
||||
"slick",
|
||||
"smart",
|
||||
"smarter",
|
||||
"smartest",
|
||||
"smiling",
|
||||
"smitten",
|
||||
"smooth",
|
||||
"smoother",
|
||||
"smoothest",
|
||||
"snappy",
|
||||
"snazzy",
|
||||
"sociable",
|
||||
"soft",
|
||||
"softer",
|
||||
"solicitous",
|
||||
"solid",
|
||||
"sophisticated",
|
||||
"soulful",
|
||||
"spacious",
|
||||
"sparkling",
|
||||
"spectacular",
|
||||
"speedy",
|
||||
"spellbinding",
|
||||
"spellbound",
|
||||
"spirited",
|
||||
"spiritual",
|
||||
"splendid",
|
||||
"spontaneous",
|
||||
"sporty",
|
||||
"spotless",
|
||||
"sprightly",
|
||||
"stable",
|
||||
"stainless",
|
||||
"state_of_the_art",
|
||||
"stately",
|
||||
"statuesque",
|
||||
"staunch",
|
||||
"steadfast",
|
||||
"steadiest",
|
||||
"steady",
|
||||
"stellar",
|
||||
"stimulating",
|
||||
"stimulative",
|
||||
"straightforward",
|
||||
"streamlined",
|
||||
"striking",
|
||||
"strong",
|
||||
"stronger",
|
||||
"strongest",
|
||||
"stunned",
|
||||
"stunning",
|
||||
"stupendous",
|
||||
"sturdier",
|
||||
"sturdy",
|
||||
"stylish",
|
||||
"stylized",
|
||||
"suave",
|
||||
"sublime",
|
||||
"subsidized",
|
||||
"substantive",
|
||||
"succeeding",
|
||||
"successful",
|
||||
"sufficient",
|
||||
"suitable",
|
||||
"sumptuous",
|
||||
"super",
|
||||
"superb",
|
||||
"superior",
|
||||
"supple",
|
||||
"supported",
|
||||
"supporting",
|
||||
"supportive",
|
||||
"supreme",
|
||||
"surreal",
|
||||
"sustainable",
|
||||
"swank",
|
||||
"swankier",
|
||||
"swankiest",
|
||||
"swanky",
|
||||
"sweeping",
|
||||
"sweet",
|
||||
"sweetheart",
|
||||
"swift",
|
||||
"talented",
|
||||
"tantalizing",
|
||||
"tempting",
|
||||
"tenacious",
|
||||
"tender",
|
||||
"terrific",
|
||||
"thankful",
|
||||
"thinner",
|
||||
"thoughtful",
|
||||
"thrifty",
|
||||
"thrilled",
|
||||
"thrilling",
|
||||
"thriving",
|
||||
"thumb_up",
|
||||
"thumbs_up",
|
||||
"tidy",
|
||||
"time_honored",
|
||||
"timely",
|
||||
"titillating",
|
||||
"tolerable",
|
||||
"toll_free",
|
||||
"top",
|
||||
"top_notch",
|
||||
"top_quality",
|
||||
"topnotch",
|
||||
"tops",
|
||||
"tough",
|
||||
"tougher",
|
||||
"toughest",
|
||||
"tranquil",
|
||||
"transparent",
|
||||
"trendy",
|
||||
"triumphal",
|
||||
"triumphant",
|
||||
"trouble_free",
|
||||
"trusted",
|
||||
"trusting",
|
||||
"trustworthy",
|
||||
"trusty",
|
||||
"truthful",
|
||||
"twinkly",
|
||||
"ultra_crisp",
|
||||
"unabashed",
|
||||
"unaffected",
|
||||
"unassailable",
|
||||
"unbeatable",
|
||||
"unbiased",
|
||||
"unbound",
|
||||
"uncomplicated",
|
||||
"unconditional",
|
||||
"undamaged",
|
||||
"undaunted",
|
||||
"understandable",
|
||||
"undisputable",
|
||||
"undisputed",
|
||||
"unencumbered",
|
||||
"unequivocal",
|
||||
"unfettered",
|
||||
"unforgettable",
|
||||
"unlimited",
|
||||
"unmatched",
|
||||
"unparalleled",
|
||||
"unquestionable",
|
||||
"unreal",
|
||||
"unrestricted",
|
||||
"unrivaled",
|
||||
"unselfish",
|
||||
"unwavering",
|
||||
"upbeat",
|
||||
"upscale",
|
||||
"usable",
|
||||
"useable",
|
||||
"useful",
|
||||
"user_friendly",
|
||||
"user_replaceable",
|
||||
"valiant",
|
||||
"valuable",
|
||||
"verifiable",
|
||||
"veritable",
|
||||
"versatile",
|
||||
"vibrant",
|
||||
"victorious",
|
||||
"viewable",
|
||||
"vigilant",
|
||||
"virtuous",
|
||||
"visionary",
|
||||
"vivacious",
|
||||
"vivid",
|
||||
"warm",
|
||||
"warmer",
|
||||
"warmhearted",
|
||||
"wealthy",
|
||||
"welcome",
|
||||
"well",
|
||||
"well_backlit",
|
||||
"well_balanced",
|
||||
"well_behaved",
|
||||
"well_being",
|
||||
"well_bred",
|
||||
"well_connected",
|
||||
"well_educated",
|
||||
"well_established",
|
||||
"well_informed",
|
||||
"well_intentioned",
|
||||
"well_known",
|
||||
"well_made",
|
||||
"well_managed",
|
||||
"well_mannered",
|
||||
"well_positioned",
|
||||
"well_received",
|
||||
"well_regarded",
|
||||
"well_rounded",
|
||||
"well_run",
|
||||
"well_wishers",
|
||||
"wholesome",
|
||||
"wieldy",
|
||||
"willing",
|
||||
"winning",
|
||||
"wise",
|
||||
"witty",
|
||||
"won",
|
||||
"wonderful",
|
||||
"wondrous",
|
||||
"workable",
|
||||
"world_famous",
|
||||
"worth",
|
||||
"worthwhile",
|
||||
"worthy",
|
||||
"young",
|
||||
"youthful",
|
||||
"zippy"]
|
||||
|
||||
export function random_adj() { return adjectives[Math.floor(Math.random() * adjectives.length)] }
|
||||
@@ -98,7 +98,7 @@ export async function main(
|
||||
export const MYSQL_INIT_CODE = `import {
|
||||
mySql,
|
||||
type Resource
|
||||
} from "https://deno.land/x/windmill@v${__pkg__.version}/mod.ts";
|
||||
} from "https://deno.land/x/windmill@v${__pkg__.version}/mysql.ts";
|
||||
|
||||
// MySQL parameterized statement. No SQL injection is possible.
|
||||
export async function main(
|
||||
|
||||
Reference in New Issue
Block a user