mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
refactor components to ease adding custom components
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
const requireHtmlApproval = getContext<boolean | undefined>(IS_APP_PUBLIC_CONTEXT_KEY)
|
||||
let result: any = undefined
|
||||
@@ -18,7 +18,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
let zoomable = false
|
||||
let pannable = false
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = 'left'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
|
||||
@@ -68,25 +68,15 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<svelte:element
|
||||
this={component}
|
||||
class="whitespace-pre-wrap {classes}"
|
||||
style={extraStyle}
|
||||
>
|
||||
<svelte:element this={component} class="whitespace-pre-wrap {classes}" style={extraStyle}>
|
||||
{String(result)}
|
||||
</svelte:element>
|
||||
{#if copyButton && result}
|
||||
<Popover notClickable>
|
||||
<Button
|
||||
size="xs"
|
||||
btnClasses="!px-2"
|
||||
on:click={() => copyToClipboard(result)}
|
||||
>
|
||||
<Button size="xs" btnClasses="!px-2" on:click={() => copyToClipboard(result)}>
|
||||
<Clipboard size={14} strokeWidth={2} />
|
||||
</Button>
|
||||
<svelte:fragment slot="text">
|
||||
Copy to clipboard
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="text">Copy to clipboard</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext, BaseAppComponent, ButtonComponent } from '../../types'
|
||||
import type { AppEditorContext, BaseAppComponent } from '../../types'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
@@ -13,12 +13,13 @@
|
||||
import AppTableFooter from './AppTableFooter.svelte'
|
||||
import { tableOptions } from './tableOptions'
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import type { ButtonComponent } from '../../editor/Component.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let actionButtons: (BaseAppComponent & ButtonComponent)[]
|
||||
export let initializing
|
||||
export let initializing: boolean | undefined = undefined
|
||||
|
||||
export const staticOutputs: string[] = [
|
||||
'selectedRow',
|
||||
@@ -211,21 +212,18 @@
|
||||
{/each}
|
||||
|
||||
{#if actionButtons.length > 0}
|
||||
<td
|
||||
class="p-2 "
|
||||
on:click={() => toggleRow(row, rowIndex)}
|
||||
>
|
||||
<div class="center-center h-full w-full flex-wrap gap-1">
|
||||
{#each actionButtons as actionButton, actionIndex (actionIndex)}
|
||||
<AppButton
|
||||
noWFull
|
||||
{...actionButton}
|
||||
extraQueryParams={{ row: row.original }}
|
||||
bind:componentInput={actionButton.componentInput}
|
||||
bind:staticOutputs={$staticOutputsStore[actionButton.id]}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<td class="p-2 " on:click={() => toggleRow(row, rowIndex)}>
|
||||
<div class="center-center h-full w-full flex-wrap gap-1">
|
||||
{#each actionButtons as actionButton, actionIndex (actionIndex)}
|
||||
<AppButton
|
||||
noWFull
|
||||
{...actionButton}
|
||||
extraQueryParams={{ row: row.original }}
|
||||
bind:componentInput={actionButton.componentInput}
|
||||
bind:staticOutputs={$staticOutputsStore[actionButton.id]}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type { AppComponent } from '../types'
|
||||
import { displayData } from '../utils'
|
||||
import { components, type AppComponent } from './Component.svelte'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
@@ -11,7 +10,7 @@
|
||||
<div class="mb-8">
|
||||
<div class="flex justify-between mb-4">
|
||||
<span class="text-sm font-bold">{component.id}</span>
|
||||
<span class="text-sm font-bold">{displayData[component.type].name}</span>
|
||||
<span class="text-sm font-bold">{components[component.type].name}</span>
|
||||
</div>
|
||||
|
||||
{#if resourceOnly && Object.keys(component.componentInput.fields).filter((fieldKey) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { ConnectedAppInput, RowAppInput, StaticAppInput, UserAppInput } from '../inputType'
|
||||
import type { AppComponent } from '../types'
|
||||
import type { AppComponent } from './Component.svelte'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
|
||||
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
|
||||
@@ -49,10 +49,11 @@
|
||||
StaticAppInput,
|
||||
UserAppInput
|
||||
} from '../inputType'
|
||||
import type { AppComponent, AppEditorContext } from '../types'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import { toStatic } from '../utils'
|
||||
import AppExportButton from './AppExportButton.svelte'
|
||||
import AppInputs from './AppInputs.svelte'
|
||||
import type { AppComponent } from './Component.svelte'
|
||||
import PanelSection from './settingsPanel/common/PanelSection.svelte'
|
||||
|
||||
async function hash(message) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,189 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { fade } from 'svelte/transition';
|
||||
import { classNames } from '$lib/utils'
|
||||
import type { AppComponent, AppEditorContext } from '../types'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import BarChartComponent from '../components/dataDisplay/AppBarChart.svelte'
|
||||
import DisplayComponent from '../components/DisplayComponent.svelte'
|
||||
import TableComponent from '../components/table/AppTable.svelte'
|
||||
import TextComponent from '../components/dataDisplay/AppText.svelte'
|
||||
import ButtonComponent from '../components/buttons/AppButton.svelte'
|
||||
import PieChartComponent from '../components/dataDisplay/AppPieChart.svelte'
|
||||
import SelectComponent from '../components/selectInputs/AppSelect.svelte'
|
||||
import CheckboxComponent from '../components/selectInputs/AppCheckbox.svelte'
|
||||
import TextInputComponent from '../components/textInputs/AppTextInput.svelte'
|
||||
import NumberInputComponent from '../components/numberInputs/AppNumberInput.svelte'
|
||||
import DateInputComponent from '../components/dateInputs/AppDateInput.svelte'
|
||||
import ComponentHeader from './ComponentHeader.svelte'
|
||||
import AppForm from '../components/form/AppForm.svelte'
|
||||
import AppScatterChart from '../components/dataDisplay/AppScatterChart.svelte'
|
||||
import AppTimeseries from '../components/dataDisplay/AppTimeseries.svelte'
|
||||
import AppHtml from '../components/dataDisplay/AppHtml.svelte'
|
||||
import AppSliderInputs from '../components/numberInputs/AppSliderInputs.svelte'
|
||||
import AppFormButton from '../components/form/AppFormButton.svelte'
|
||||
import VegaLiteHtml from '../components/dataDisplay/VegaLiteHtml.svelte'
|
||||
import PlotlyHtml from '../components/dataDisplay/PlotlyHtml.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
export let locked: boolean = false
|
||||
export let pointerdown: boolean = false
|
||||
|
||||
const { staticOutputs, mode, connectingInput } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let hover = false
|
||||
let initializing
|
||||
</script>
|
||||
|
||||
<div
|
||||
on:pointerenter={() => (hover = true)}
|
||||
on:pointerleave={() => (hover = false)}
|
||||
class="h-full flex flex-col w-full component"
|
||||
>
|
||||
{#if $mode !== 'preview'}
|
||||
<ComponentHeader {hover} {pointerdown} {component} {selected} on:delete on:lock {locked} />
|
||||
{/if}
|
||||
|
||||
<div
|
||||
on:pointerdown={(e) => {
|
||||
// Removed in https://github.com/windmill-labs/windmill/pull/1171
|
||||
// In case of a bug, try stopping propagation on the native event
|
||||
// and dispatch a custom event: `e?.stopPropagation(); dispatch('select');`
|
||||
|
||||
// if ($mode === 'preview') {
|
||||
// e?.stopPropagation()
|
||||
// }
|
||||
}}
|
||||
class={classNames(
|
||||
'border h-full bg-white',
|
||||
selected && $mode !== 'preview' ? 'border-blue-500' : 'border-white',
|
||||
!selected && $mode !== 'preview' && !component.card ? 'border-gray-100' : '',
|
||||
$mode !== 'preview' && !$connectingInput.opened ? 'hover:border-blue-500' : '',
|
||||
component.softWrap ? '' : 'overflow-auto',
|
||||
$mode != 'preview' ? 'cursor-pointer' : '',
|
||||
'relative z-auto'
|
||||
)}
|
||||
>
|
||||
{#if component.type === 'displaycomponent'}
|
||||
<DisplayComponent
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'barchartcomponent'}
|
||||
<BarChartComponent
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'timeseriescomponent'}
|
||||
<AppTimeseries
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'htmlcomponent'}
|
||||
<AppHtml
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'vegalitecomponent'}
|
||||
<VegaLiteHtml
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'plotlycomponent'}
|
||||
<PlotlyHtml
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'scatterchartcomponent'}
|
||||
<AppScatterChart
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'piechartcomponent'}
|
||||
<PieChartComponent
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
bind:componentInput={component.componentInput}
|
||||
/>
|
||||
{:else if component.type === 'tablecomponent'}
|
||||
<TableComponent
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:actionButtons={component.actionButtons}
|
||||
/>
|
||||
{:else if component.type === 'textcomponent'}
|
||||
<TextComponent
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'buttoncomponent'}
|
||||
<ButtonComponent
|
||||
{...component}
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'selectcomponent'}
|
||||
<SelectComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'formcomponent'}
|
||||
<AppForm
|
||||
{...component}
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'formbuttoncomponent'}
|
||||
<AppFormButton
|
||||
{...component}
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'checkboxcomponent'}
|
||||
<CheckboxComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'textinputcomponent'}
|
||||
<TextInputComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'passwordinputcomponent'}
|
||||
<TextInputComponent
|
||||
inputType="password"
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'dateinputcomponent'}
|
||||
<DateInputComponent
|
||||
inputType="date"
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'numberinputcomponent'}
|
||||
<NumberInputComponent {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'slidercomponent'}
|
||||
<AppSliderInputs {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if initializing}
|
||||
<div
|
||||
out:fade={{ duration: 200 }}
|
||||
class="absolute inset-0 center-center flex-col bg-white text-gray-600 border"
|
||||
>
|
||||
<Loader2 class="animate-spin" size={16} />
|
||||
<span class="text-xs mt-1">Loading</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import type { AppComponent, AppEditorContext } from '../types'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import { Anchor, Bug, Move } from 'lucide-svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import { Alert, Button } from '$lib/components/common'
|
||||
import type { AppComponent } from './Component.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
import { getContext, afterUpdate } from 'svelte'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import Grid from 'svelte-grid'
|
||||
import ComponentEditor from './ComponentEditor.svelte'
|
||||
import { classNames } from '$lib/utils'
|
||||
import { columnConfiguration, disableDrag, enableDrag, isFixed, toggleFixed } from '../gridUtils'
|
||||
|
||||
import RecomputeAllComponents from './RecomputeAllComponents.svelte'
|
||||
import type { Policy } from '$lib/gen'
|
||||
import HiddenComponent from '../components/HiddenComponent.svelte'
|
||||
import Component from './Component.svelte'
|
||||
|
||||
export let policy: Policy
|
||||
|
||||
@@ -102,11 +102,11 @@
|
||||
}
|
||||
|
||||
afterUpdate(() => {
|
||||
if($selectedComponent) {
|
||||
if ($selectedComponent) {
|
||||
const parents = document.querySelectorAll<HTMLElement>('.svlt-grid-item')
|
||||
parents.forEach((parent) => {
|
||||
const hasActiveChild = !!parent.querySelector('.active-grid-item')
|
||||
if(hasActiveChild) {
|
||||
if (hasActiveChild) {
|
||||
parent.style.setProperty('z-index', '100')
|
||||
} else {
|
||||
parent.style.removeProperty('z-index')
|
||||
@@ -170,7 +170,7 @@
|
||||
gridComponent.data.card ? 'border border-gray-100' : ''
|
||||
)}
|
||||
>
|
||||
<ComponentEditor
|
||||
<Component
|
||||
{pointerdown}
|
||||
bind:component={gridComponent.data}
|
||||
selected={$selectedComponent === dataItem.data.id}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext, TableComponent } from '../types'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import type { TableComponent } from './Component.svelte'
|
||||
import ComponentPanel from './settingsPanel/ComponentPanel.svelte'
|
||||
|
||||
export let component: TableComponent
|
||||
|
||||
@@ -1,59 +1,25 @@
|
||||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition'
|
||||
import Icon from 'svelte-awesome'
|
||||
import type { AppComponent, AppEditorContext, GridItem } from '../../types'
|
||||
import { displayData } from '../../utils'
|
||||
import { componentSets } from './data'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
|
||||
import gridHelp from 'svelte-grid/build/helper/index.mjs'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getNextId } from '$lib/components/flows/flowStateUtils'
|
||||
import type { Size } from 'svelte-grid'
|
||||
import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
|
||||
import { isOpenStore } from './store'
|
||||
import { gridColumns } from '../../gridUtils'
|
||||
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
|
||||
import {
|
||||
components as componentsRecord,
|
||||
componentSets,
|
||||
getRecommendedDimensionsByComponent,
|
||||
type AppComponent
|
||||
} from '../Component.svelte'
|
||||
|
||||
const { app, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function getRecommendedDimensionsByComponent(
|
||||
componentType: AppComponent['type'],
|
||||
column: number
|
||||
): Size {
|
||||
// Dimensions key formula: <mobile width>:<mobile height>-<desktop width>:<desktop height>
|
||||
const dimensions: Record<`${number}:${number}-${number}:${number}`, AppComponent['type'][]> = {
|
||||
'1:1-3:1': ['textcomponent'],
|
||||
'1:1-2:1': ['buttoncomponent', 'checkboxcomponent'],
|
||||
'1:2-1:2': ['htmlcomponent'],
|
||||
'2:1-3:1': [
|
||||
'textinputcomponent',
|
||||
'numberinputcomponent',
|
||||
'selectcomponent',
|
||||
'passwordinputcomponent',
|
||||
'dateinputcomponent'
|
||||
],
|
||||
'3:5-6:5': ['formcomponent'],
|
||||
'2:8-6:8': [
|
||||
'timeseriescomponent',
|
||||
'barchartcomponent',
|
||||
'piechartcomponent',
|
||||
'displaycomponent',
|
||||
'scatterchartcomponent',
|
||||
'vegalitecomponent',
|
||||
'plotlycomponent'
|
||||
],
|
||||
'3:10-6:10': ['tablecomponent']
|
||||
}
|
||||
// Finds the key that is associated with the component type and extracts the dimensions from it
|
||||
const [dimension] = Object.entries(dimensions).find(([_, value]) =>
|
||||
value.includes(componentType)
|
||||
) || ['2:1-2:1']
|
||||
|
||||
const size = dimension.split('-')[column === 3 ? 0 : 1].split(':')
|
||||
return { w: +size[0], h: +size[1] }
|
||||
}
|
||||
|
||||
function addComponent(appComponent: AppComponent) {
|
||||
function addComponent(appComponentType: AppComponent['type']) {
|
||||
$dirtyStore = true
|
||||
const grid = $app.grid ?? []
|
||||
const id = getNextId(
|
||||
@@ -61,6 +27,8 @@
|
||||
true
|
||||
)
|
||||
|
||||
const appComponent = componentsRecord[appComponentType].data
|
||||
|
||||
appComponent.id = id
|
||||
|
||||
const newComponent = {
|
||||
@@ -122,13 +90,13 @@
|
||||
{#each components as item}
|
||||
<button
|
||||
on:click={() => addComponent(item)}
|
||||
title={displayData[item.type].name}
|
||||
title={componentsRecord[item].name}
|
||||
class="border w-24 shadow-sm h-16 p-2 flex flex-col gap-2 items-center
|
||||
justify-center bg-white rounded-md hover:bg-gray-100 duration-200"
|
||||
>
|
||||
<svelte:component this={displayData[item.type].icon} />
|
||||
<svelte:component this={componentsRecord[item].icon} />
|
||||
<div class="text-xs w-full text-center ellipsize">
|
||||
{displayData[item.type].name}
|
||||
{componentsRecord[item].name}
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
|
||||
@@ -1,597 +0,0 @@
|
||||
import type { ComponentSet } from '../../types'
|
||||
import { defaultAlignement } from './componentDefaultProps'
|
||||
|
||||
const inputs: ComponentSet = {
|
||||
title: 'Inputs',
|
||||
components: [
|
||||
{
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: 'textinputcomponent',
|
||||
type: 'textinputcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
placeholder: {
|
||||
type: 'static',
|
||||
value: 'Type...',
|
||||
fieldType: 'text',
|
||||
onlyStatic: true
|
||||
},
|
||||
defaultValue: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'text'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: 'passwordinputcomponent',
|
||||
type: 'passwordinputcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
placeholder: {
|
||||
type: 'static',
|
||||
value: 'Password',
|
||||
fieldType: 'text',
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: 'numberinputcomponent',
|
||||
type: 'numberinputcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
placeholder: {
|
||||
type: 'static',
|
||||
value: 'Type...',
|
||||
fieldType: 'text',
|
||||
onlyStatic: true
|
||||
},
|
||||
defaultValue: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'number'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: 'slidercomponent',
|
||||
type: 'slidercomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
min: {
|
||||
type: 'static',
|
||||
value: 0,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
},
|
||||
max: {
|
||||
type: 'static',
|
||||
value: 42,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: 'dateinputcomponent',
|
||||
type: 'dateinputcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
minDate: {
|
||||
type: 'static',
|
||||
value: '',
|
||||
fieldType: 'date'
|
||||
},
|
||||
maxDate: {
|
||||
type: 'static',
|
||||
value: '',
|
||||
fieldType: 'date'
|
||||
},
|
||||
defaultValue: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'date'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
...defaultAlignement,
|
||||
softWrap: true,
|
||||
id: 'checkboxcomponent',
|
||||
type: 'checkboxcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
value: 'Label',
|
||||
fieldType: 'text'
|
||||
},
|
||||
defaultValue: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'boolean'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
verticalAlignment: 'center',
|
||||
id: 'selectcomponent',
|
||||
type: 'selectcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
items: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [
|
||||
{ value: 'foo', label: 'Foo' },
|
||||
{ value: 'bar', label: 'Bar' }
|
||||
]
|
||||
},
|
||||
itemKey: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
value: 'value'
|
||||
}
|
||||
},
|
||||
card: false,
|
||||
softWrap: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const buttons: ComponentSet = {
|
||||
title: 'Buttons',
|
||||
components: [
|
||||
{
|
||||
...defaultAlignement,
|
||||
softWrap: true,
|
||||
id: 'buttoncomponent',
|
||||
type: 'buttoncomponent',
|
||||
componentInput: {
|
||||
type: 'runnable',
|
||||
fieldType: 'any',
|
||||
fields: {},
|
||||
runnable: undefined
|
||||
},
|
||||
recomputeIds: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
value: 'Press me'
|
||||
},
|
||||
color: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'buttonColorOptions',
|
||||
value: 'blue'
|
||||
},
|
||||
size: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'buttonSizeOptions',
|
||||
value: 'xs'
|
||||
},
|
||||
disabled: {
|
||||
fieldType: 'boolean',
|
||||
type: 'eval',
|
||||
expr: 'false'
|
||||
}
|
||||
},
|
||||
|
||||
card: false
|
||||
},
|
||||
{
|
||||
horizontalAlignment: 'center',
|
||||
id: 'formcomponent',
|
||||
type: 'formcomponent',
|
||||
componentInput: {
|
||||
type: 'runnable',
|
||||
fieldType: 'any',
|
||||
fields: {},
|
||||
runnable: undefined
|
||||
},
|
||||
recomputeIds: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
value: 'Submit',
|
||||
fieldType: 'text'
|
||||
},
|
||||
color: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
value: 'dark',
|
||||
optionValuesKey: 'buttonColorOptions'
|
||||
},
|
||||
size: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
value: 'xs',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'buttonSizeOptions'
|
||||
}
|
||||
},
|
||||
|
||||
card: true
|
||||
},
|
||||
{
|
||||
horizontalAlignment: 'center',
|
||||
verticalAlignment: 'center',
|
||||
id: 'formbuttoncomponent',
|
||||
type: 'formbuttoncomponent',
|
||||
componentInput: {
|
||||
type: 'runnable',
|
||||
fieldType: 'any',
|
||||
fields: {},
|
||||
runnable: undefined
|
||||
},
|
||||
recomputeIds: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
value: 'Open popup',
|
||||
fieldType: 'text'
|
||||
},
|
||||
color: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
value: 'dark',
|
||||
optionValuesKey: 'buttonColorOptions'
|
||||
},
|
||||
size: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
value: 'xs',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'buttonSizeOptions'
|
||||
}
|
||||
},
|
||||
|
||||
card: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const display: ComponentSet = {
|
||||
title: 'Display',
|
||||
components: [
|
||||
{
|
||||
softWrap: false,
|
||||
id: 'htmlcomponent',
|
||||
type: 'htmlcomponent',
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'template',
|
||||
value: `<img
|
||||
src="https://images.unsplash.com/photo-1554629947-334ff61d85dc?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1024&h=1280&q=80"
|
||||
>
|
||||
<h1 class="absolute top-4 left-2 text-white">
|
||||
Hello \${ctx.username}
|
||||
</h1>`
|
||||
},
|
||||
configuration: {},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: false,
|
||||
id: 'vegalitecomponent',
|
||||
type: 'vegalitecomponent',
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: {
|
||||
data: {
|
||||
values: [
|
||||
{ a: 'A', b: 28 },
|
||||
{ a: 'B', b: 55 },
|
||||
{ a: 'C', b: 43 },
|
||||
{ a: 'D', b: 91 }
|
||||
]
|
||||
},
|
||||
mark: 'bar',
|
||||
encoding: {
|
||||
x: { field: 'a', type: 'ordinal' },
|
||||
y: { field: 'b', type: 'quantitative' }
|
||||
}
|
||||
}
|
||||
},
|
||||
configuration: {
|
||||
canvas: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
tooltip: 'use the canvas renderer instead of the svg one for more interactive plots'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: false,
|
||||
id: 'plotlycomponent',
|
||||
type: 'plotlycomponent',
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: {
|
||||
type: 'bar',
|
||||
x: [1, 2, 3, 4],
|
||||
y: [5, 10, 2, 8],
|
||||
marker: {
|
||||
color: '#C8A2C8',
|
||||
line: {
|
||||
width: 2.5
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
configuration: {},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: true,
|
||||
horizontalAlignment: 'left',
|
||||
verticalAlignment: 'top',
|
||||
id: 'textcomponent',
|
||||
type: 'textcomponent',
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'template',
|
||||
value: 'Hello ${ctx.username}'
|
||||
},
|
||||
configuration: {
|
||||
style: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'textStyleOptions',
|
||||
value: 'Body'
|
||||
},
|
||||
extraStyle: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
value: '',
|
||||
tooltip: 'CSS rules like "color: blue;"'
|
||||
},
|
||||
copyButton: {
|
||||
type: 'static',
|
||||
value: false,
|
||||
fieldType: 'boolean',
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
id: 'tablecomponent',
|
||||
type: 'tablecomponent',
|
||||
configuration: {
|
||||
search: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'tableSearchOptions',
|
||||
value: 'Disabled'
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'A cell with a long name',
|
||||
age: 42
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'A briefer cell',
|
||||
age: 84
|
||||
}
|
||||
]
|
||||
},
|
||||
card: true,
|
||||
actionButtons: []
|
||||
},
|
||||
{
|
||||
id: 'piechartcomponent',
|
||||
type: 'piechartcomponent',
|
||||
configuration: {
|
||||
theme: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'select',
|
||||
optionValuesKey: 'chartThemeOptions',
|
||||
value: 'theme1'
|
||||
},
|
||||
doughnutStyle: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: { data: [25, 50, 25], labels: ['Pie', 'Charts', '<3'] }
|
||||
},
|
||||
card: true
|
||||
},
|
||||
{
|
||||
id: 'barchartcomponent',
|
||||
type: 'barchartcomponent',
|
||||
configuration: {
|
||||
theme: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'select',
|
||||
optionValuesKey: 'chartThemeOptions',
|
||||
value: 'theme1'
|
||||
},
|
||||
line: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: { data: [25, 50, 25], labels: ['Bar', 'Charts', '<3'] }
|
||||
},
|
||||
card: true
|
||||
},
|
||||
{
|
||||
id: 'scatterchartcomponent',
|
||||
type: 'scatterchartcomponent',
|
||||
configuration: {
|
||||
zoomable: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
},
|
||||
pannable: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [
|
||||
{
|
||||
label: 'foo',
|
||||
data: [
|
||||
{ x: 25, y: 50 },
|
||||
{ x: 23, y: 23 },
|
||||
{ x: 12, y: 37 }
|
||||
],
|
||||
backgroundColor: 'rgb(255, 12, 137)'
|
||||
},
|
||||
{
|
||||
label: 'foobar',
|
||||
data: [
|
||||
{ x: 32, y: 32 },
|
||||
{ x: 25, y: 42 },
|
||||
{ x: 3, y: 27 }
|
||||
],
|
||||
backgroundColor: 'orange'
|
||||
}
|
||||
]
|
||||
},
|
||||
card: true
|
||||
},
|
||||
{
|
||||
id: 'timeseriescomponent',
|
||||
type: 'timeseriescomponent',
|
||||
configuration: {
|
||||
logarithmicScale: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
},
|
||||
zoomable: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
},
|
||||
pannable: {
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
fieldType: 'boolean',
|
||||
value: false
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [
|
||||
{
|
||||
label: 'foo',
|
||||
data: [
|
||||
{
|
||||
x: '2021-11-06 23:39:30',
|
||||
y: 50
|
||||
},
|
||||
{
|
||||
x: '2021-11-07 01:00:28',
|
||||
y: 60
|
||||
},
|
||||
{
|
||||
x: '2021-11-07 09:00:28',
|
||||
y: 20
|
||||
}
|
||||
],
|
||||
backgroundColor: 'rgb(255, 12, 137)'
|
||||
},
|
||||
{
|
||||
label: 'foobar',
|
||||
data: [
|
||||
{
|
||||
x: '2021-11-06 23:39:30',
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
x: '2021-11-07 01:00:28',
|
||||
y: 13
|
||||
},
|
||||
{
|
||||
x: '2021-11-07 09:00:28',
|
||||
y: 45
|
||||
}
|
||||
],
|
||||
backgroundColor: 'orange'
|
||||
}
|
||||
]
|
||||
},
|
||||
card: true
|
||||
},
|
||||
{
|
||||
id: 'displaycomponent',
|
||||
type: 'displaycomponent',
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: { foo: 42 }
|
||||
},
|
||||
configuration: {},
|
||||
card: false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const componentSets = [buttons, inputs, display]
|
||||
|
||||
export { componentSets }
|
||||
@@ -1,10 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores'
|
||||
import { classNames } from '$lib/utils'
|
||||
import { getContext } from 'svelte'
|
||||
import { key } from 'svelte-awesome/icons'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { displayData } from '../../utils'
|
||||
import { components } from '../Component.svelte'
|
||||
import PanelSection from '../settingsPanel/common/PanelSection.svelte'
|
||||
import ComponentOutputViewer from './ComponentOutputViewer.svelte'
|
||||
|
||||
@@ -31,7 +29,7 @@
|
||||
const component = $app.grid.find((c) => c?.data?.id === componentId)
|
||||
|
||||
if (component?.data.type) {
|
||||
return displayData[component?.data.type].name
|
||||
return components[component?.data.type].name
|
||||
} else if (componentId == 'ctx') {
|
||||
return 'Context'
|
||||
} else if (componentId.startsWith('bg_')) {
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
import { capitalize, emptySchema } from '$lib/utils'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import { fly } from 'svelte/transition'
|
||||
import { defaultCode } from '../../editorUtils'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { defaultCode } from '../Component.svelte'
|
||||
|
||||
export let name: string
|
||||
export let id: string
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Runnable } from "../../inputType"
|
||||
import type { AppComponent, GridItem } from "../../types"
|
||||
import type { GridItem } from "../../types"
|
||||
import type { AppComponent } from "../Component.svelte";
|
||||
|
||||
export interface AppScriptsList {
|
||||
inline: { name: string; id: string }[],
|
||||
@@ -30,11 +31,11 @@ export function getAppScripts(grid: GridItem[]) {
|
||||
}
|
||||
|
||||
return acc
|
||||
}, {inline: [], imported: []} as AppScriptsList)
|
||||
}, { inline: [], imported: [] } as AppScriptsList)
|
||||
}
|
||||
|
||||
function processRunnable(runnable: Runnable, id: string, list: AppScriptsList) {
|
||||
if(runnable?.type === undefined) { return }
|
||||
if (runnable?.type === undefined) { return }
|
||||
const type: keyof AppScriptsList = runnable.type === 'runnableByPath' ? 'imported' : 'inline'
|
||||
list[type].push({
|
||||
name: runnable[runnable.type === 'runnableByPath' ? 'path' : 'name'],
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
AlignStartHorizontal,
|
||||
AlignStartVertical
|
||||
} from 'lucide-svelte'
|
||||
import type { AppComponent } from '../../types'
|
||||
import type { AppComponent } from '../Component.svelte'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppComponent, AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
import InputsSpecsEditor from './InputsSpecsEditor.svelte'
|
||||
import TableActions from './TableActions.svelte'
|
||||
@@ -17,6 +17,7 @@
|
||||
import AlignmentEditor from './AlignmentEditor.svelte'
|
||||
import RunnableInputEditor from './inputEditor/RunnableInputEditor.svelte'
|
||||
import TemplateEditor from '$lib/components/TemplateEditor.svelte'
|
||||
import type { AppComponent } from '../Component.svelte'
|
||||
|
||||
export let component: AppComponent | undefined
|
||||
export let onDelete: (() => void) | undefined = undefined
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
import { faPlus, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import type { ButtonComponent, AppEditorContext, BaseAppComponent } from '../../types'
|
||||
import type { AppEditorContext, BaseAppComponent } from '../../types'
|
||||
import type { ButtonComponent } from '../Component.svelte'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
import TableActionLabel from './TableActionLabel.svelte'
|
||||
|
||||
|
||||
@@ -1,338 +0,0 @@
|
||||
import type { AppComponent } from './types'
|
||||
|
||||
export function defaultCode(component: string, language: string): string | undefined {
|
||||
return DEFAULT_CODES[component]?.[language]
|
||||
}
|
||||
|
||||
const DEFAULT_CODES: Partial<Record<AppComponent['type'], Record<'deno' | 'python3', string>>> = {
|
||||
tablecomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]`,
|
||||
},
|
||||
textcomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return "foo"
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return "foo"`,
|
||||
},
|
||||
barchartcomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return {
|
||||
"data": [
|
||||
25,
|
||||
50,
|
||||
25
|
||||
],
|
||||
"labels": [
|
||||
"Bar",
|
||||
"Charts",
|
||||
"<3"
|
||||
]
|
||||
}
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return {
|
||||
"data": [
|
||||
25,
|
||||
50,
|
||||
25
|
||||
],
|
||||
"labels": [
|
||||
"Bar",
|
||||
"Charts",
|
||||
"<3"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
displaycomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return {
|
||||
"foo": 42
|
||||
}
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return {
|
||||
"foo": 42
|
||||
}`,
|
||||
},
|
||||
htmlcomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return \`<img
|
||||
src="https://images.unsplash.com/photo-1554629947-334ff61d85dc?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1024&h=1280&q=80"
|
||||
>
|
||||
<h1 class="absolute top-4 left-2 text-white">
|
||||
Hello world
|
||||
</h1>\`
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return '''<img
|
||||
src="https://images.unsplash.com/photo-1554629947-334ff61d85dc?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1024&h=1280&q=80"
|
||||
>
|
||||
<h1 class="absolute top-4 left-2 text-white">
|
||||
Hello world
|
||||
</h1>'''`,
|
||||
},
|
||||
vegalitecomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return {
|
||||
data: {
|
||||
values: [
|
||||
{ a: "A", b: 28 },
|
||||
{ a: "B", b: 55 },
|
||||
{ a: "C", b: 43 },
|
||||
{ a: "D", b: 91 },
|
||||
],
|
||||
},
|
||||
mark: "bar",
|
||||
encoding: {
|
||||
x: { field: "a", type: "ordinal" },
|
||||
y: { field: "b", type: "quantitative" },
|
||||
},
|
||||
}
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return {
|
||||
"data": {
|
||||
"values": [
|
||||
{ "a": "A", "b": 28 },
|
||||
{ "a": "B", "b": 55 },
|
||||
{ "a": "C", "b": 43 },
|
||||
{ "a": "D", "b": 91 },
|
||||
],
|
||||
},
|
||||
"mark": "bar",
|
||||
"encoding": {
|
||||
"x": { "field": "a", "type": "ordinal" },
|
||||
"y": { "field": "b", "type": "quantitative" },
|
||||
},
|
||||
}`
|
||||
},
|
||||
plotlycomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return {
|
||||
type: 'bar',
|
||||
x: [1, 2, 3, 4],
|
||||
y: [5, 10, 2, 8],
|
||||
marker: {
|
||||
color: '#C8A2C8',
|
||||
line: {
|
||||
width: 2.5
|
||||
}
|
||||
}
|
||||
};
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return {
|
||||
"type": "bar",
|
||||
"x": [1, 2, 3, 4],
|
||||
"y": [5, 10, 2, 8],
|
||||
"marker": {
|
||||
"color": "#C8A2C8",
|
||||
"line": {
|
||||
"width": 2.5
|
||||
}
|
||||
}
|
||||
}`
|
||||
},
|
||||
piechartcomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return {
|
||||
"data": [
|
||||
25,
|
||||
50,
|
||||
25
|
||||
],
|
||||
"labels": [
|
||||
"Pie",
|
||||
"Charts",
|
||||
"<3"
|
||||
]
|
||||
}
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return {
|
||||
"data": [
|
||||
25,
|
||||
50,
|
||||
25
|
||||
],
|
||||
"labels": [
|
||||
"Pie",
|
||||
"Charts",
|
||||
"<3"
|
||||
]
|
||||
}`,
|
||||
},
|
||||
scatterchartcomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return [
|
||||
{
|
||||
"label": "foo",
|
||||
"data": [
|
||||
{ "x": 25, "y": 50 },
|
||||
{ "x": 23, "y": 23 },
|
||||
{ "x": 12, "y": 37 }
|
||||
],
|
||||
"backgroundColor": "rgb(255, 12, 137)"
|
||||
},
|
||||
{
|
||||
"label": "bar",
|
||||
"data": [
|
||||
{ "x": 32, "y": 32 },
|
||||
{ "x": 25, "y": 42 },
|
||||
{ "x": 3, "y": 27 }
|
||||
],
|
||||
"backgroundColor": "orange"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return [
|
||||
{
|
||||
"label": "foo",
|
||||
"data": [
|
||||
{ "x": 25, "y": 50 },
|
||||
{ "x": 23, "y": 23 },
|
||||
{ "x": 12, "y": 37 }
|
||||
],
|
||||
"backgroundColor": "rgb(255, 12, 137)"
|
||||
},
|
||||
{
|
||||
"label": "bar",
|
||||
"data": [
|
||||
{ "x": 32, "y": 32 },
|
||||
{ "x": 25, "y": 42 },
|
||||
{ "x": 3, "y": 27 }
|
||||
],
|
||||
"backgroundColor": "orange"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
timeseriescomponent: {
|
||||
deno:
|
||||
`export async function main() {
|
||||
return [
|
||||
{
|
||||
"label": "foo",
|
||||
"data": [
|
||||
{
|
||||
"x": "2021-11-06 23:39:30",
|
||||
"y": 50
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 01:00:28",
|
||||
"y": 60
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 09:00:28",
|
||||
"y": 20
|
||||
}
|
||||
],
|
||||
"backgroundColor": "rgb(255, 12, 137)"
|
||||
},
|
||||
{
|
||||
"label": "bar",
|
||||
"data": [
|
||||
{
|
||||
"x": "2021-11-06 23:39:30",
|
||||
"y": 20
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 01:00:28",
|
||||
"y": 13
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 09:00:28",
|
||||
"y": 45
|
||||
}
|
||||
],
|
||||
"backgroundColor": "orange"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
python3:
|
||||
`def main():
|
||||
return [
|
||||
{
|
||||
"label": "foo",
|
||||
"data": [
|
||||
{
|
||||
"x": "2021-11-06 23:39:30",
|
||||
"y": 50
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 01:00:28",
|
||||
"y": 60
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 09:00:28",
|
||||
"y": 20
|
||||
}
|
||||
],
|
||||
"backgroundColor": "rgb(255, 12, 137)"
|
||||
},
|
||||
{
|
||||
"label": "bar",
|
||||
"data": [
|
||||
{
|
||||
"x": "2021-11-06 23:39:30",
|
||||
"y": 20
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 01:00:28",
|
||||
"y": 13
|
||||
},
|
||||
{
|
||||
"x": "2021-11-07 09:00:28",
|
||||
"y": 45
|
||||
}
|
||||
],
|
||||
"backgroundColor": "orange"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
} as const
|
||||
@@ -2,6 +2,7 @@ import type { Schema } from '$lib/common'
|
||||
import type { Preview } from '$lib/gen'
|
||||
import type { FilledItem } from 'svelte-grid'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import type { AppComponent } from './editor/Component.svelte'
|
||||
import type {
|
||||
AppInput,
|
||||
ConnectedAppInput,
|
||||
@@ -13,46 +14,6 @@ import type {
|
||||
} from './inputType'
|
||||
import type { World } from './rx'
|
||||
|
||||
type BaseComponent<T extends string> = {
|
||||
type: T
|
||||
}
|
||||
|
||||
export type TextComponent = BaseComponent<'textcomponent'>
|
||||
export type TextInputComponent = BaseComponent<'textinputcomponent'>
|
||||
export type PasswordInputComponent = BaseComponent<'passwordinputcomponent'>
|
||||
export type DateInputComponent = BaseComponent<'dateinputcomponent'>
|
||||
export type NumberInputComponent = BaseComponent<'numberinputcomponent'>
|
||||
export type SliderComponent = BaseComponent<'slidercomponent'>
|
||||
export type HtmlComponent = BaseComponent<'htmlcomponent'>
|
||||
export type VegaLiteComponent = BaseComponent<'vegalitecomponent'>
|
||||
export type PlotlyComponent = BaseComponent<'plotlycomponent'>
|
||||
export type TimeseriesComponent = BaseComponent<'timeseriescomponent'>
|
||||
export type ButtonComponent = BaseComponent<'buttoncomponent'> & {
|
||||
recomputeIds: string[] | undefined
|
||||
}
|
||||
|
||||
export type FormComponent = BaseComponent<'formcomponent'> & {
|
||||
recomputeIds: string[] | undefined
|
||||
}
|
||||
|
||||
export type FormButtonComponent = BaseComponent<'formbuttoncomponent'> & {
|
||||
recomputeIds: string[] | undefined
|
||||
}
|
||||
|
||||
export type RunFormComponent = BaseComponent<'runformcomponent'>
|
||||
export type BarChartComponent = BaseComponent<'barchartcomponent'>
|
||||
export type PieChartComponent = BaseComponent<'piechartcomponent'>
|
||||
export type ScatterChartComponent = BaseComponent<'scatterchartcomponent'>
|
||||
export type TableComponent = BaseComponent<'tablecomponent'> & {
|
||||
actionButtons: (BaseAppComponent & ButtonComponent)[]
|
||||
}
|
||||
|
||||
export type DisplayComponent = BaseComponent<'displaycomponent'>
|
||||
export type ImageComponent = BaseComponent<'imagecomponent'>
|
||||
export type InputComponent = BaseComponent<'inputcomponent'>
|
||||
export type SelectComponent = BaseComponent<'selectcomponent'>
|
||||
export type CheckboxComponent = BaseComponent<'checkboxcomponent'>
|
||||
export type RadioComponent = BaseComponent<'radiocomponent'>
|
||||
|
||||
export type HorizontalAlignment = 'left' | 'center' | 'right'
|
||||
export type VerticalAlignment = 'top' | 'center' | 'bottom'
|
||||
@@ -82,38 +43,11 @@ export interface BaseAppComponent extends Partial<Aligned> {
|
||||
softWrap?: boolean
|
||||
}
|
||||
|
||||
export type AppComponent = BaseAppComponent &
|
||||
(
|
||||
| RunFormComponent
|
||||
| DisplayComponent
|
||||
| TextInputComponent
|
||||
| PasswordInputComponent
|
||||
| DateInputComponent
|
||||
| NumberInputComponent
|
||||
| SliderComponent
|
||||
| BarChartComponent
|
||||
| TimeseriesComponent
|
||||
| HtmlComponent
|
||||
| TableComponent
|
||||
| TextComponent
|
||||
| TableComponent
|
||||
| ButtonComponent
|
||||
| PieChartComponent
|
||||
| ScatterChartComponent
|
||||
| ImageComponent
|
||||
| InputComponent
|
||||
| SelectComponent
|
||||
| CheckboxComponent
|
||||
| RadioComponent
|
||||
| FormComponent
|
||||
| FormButtonComponent
|
||||
| VegaLiteComponent
|
||||
| PlotlyComponent
|
||||
)
|
||||
|
||||
|
||||
export type ComponentSet = {
|
||||
title: string
|
||||
components: AppComponent[]
|
||||
components: AppComponent['type'][]
|
||||
}
|
||||
|
||||
type SectionID = string
|
||||
|
||||
@@ -2,31 +2,11 @@ import type { Schema } from '$lib/common'
|
||||
import { FlowService, ScriptService } from '$lib/gen'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import {
|
||||
BarChart4,
|
||||
Binary,
|
||||
CircleDot,
|
||||
FormInput,
|
||||
Inspect,
|
||||
List,
|
||||
Monitor,
|
||||
PieChart,
|
||||
Play,
|
||||
Table2,
|
||||
Image,
|
||||
TextCursorInput,
|
||||
Type,
|
||||
Lock,
|
||||
Calendar,
|
||||
ToggleLeft,
|
||||
GripHorizontal,
|
||||
Code2,
|
||||
SlidersHorizontal,
|
||||
PlusSquare
|
||||
} from 'lucide-svelte'
|
||||
import type { AppComponent } from './editor/Component.svelte'
|
||||
|
||||
import type { AppInput, InputType, ResultAppInput, StaticAppInput } from './inputType'
|
||||
import type { Output } from './rx'
|
||||
import type { App, AppComponent, GridItem } from './types'
|
||||
import type { App, GridItem } from './types'
|
||||
|
||||
export async function loadSchema(
|
||||
workspace: string,
|
||||
@@ -85,104 +65,7 @@ export function schemaToInputsSpec(
|
||||
}, {})
|
||||
}
|
||||
|
||||
export const displayData: Record<AppComponent['type'], { name: string; icon: any }> = {
|
||||
displaycomponent: {
|
||||
name: 'Result',
|
||||
icon: Monitor
|
||||
},
|
||||
textcomponent: {
|
||||
name: 'Text',
|
||||
icon: Type
|
||||
},
|
||||
buttoncomponent: {
|
||||
name: 'Button',
|
||||
icon: Inspect
|
||||
},
|
||||
formcomponent: {
|
||||
name: 'Form',
|
||||
icon: FormInput
|
||||
},
|
||||
formbuttoncomponent: {
|
||||
name: 'Modal Form',
|
||||
icon: PlusSquare
|
||||
},
|
||||
piechartcomponent: {
|
||||
name: 'Pie Chart',
|
||||
icon: PieChart
|
||||
},
|
||||
barchartcomponent: {
|
||||
name: 'Bar/Line Chart',
|
||||
icon: BarChart4
|
||||
},
|
||||
htmlcomponent: {
|
||||
name: 'HTML',
|
||||
icon: Code2
|
||||
},
|
||||
vegalitecomponent: {
|
||||
name: 'Vega Lite',
|
||||
icon: PieChart
|
||||
},
|
||||
plotlycomponent: {
|
||||
name: 'Plotly',
|
||||
icon: PieChart
|
||||
},
|
||||
timeseriescomponent: {
|
||||
name: 'Timeseries',
|
||||
icon: GripHorizontal
|
||||
},
|
||||
scatterchartcomponent: {
|
||||
name: 'Scatter Chart',
|
||||
icon: GripHorizontal
|
||||
},
|
||||
tablecomponent: {
|
||||
name: 'Table',
|
||||
icon: Table2
|
||||
},
|
||||
checkboxcomponent: {
|
||||
name: 'Toggle',
|
||||
icon: ToggleLeft
|
||||
},
|
||||
textinputcomponent: {
|
||||
name: 'Text Input',
|
||||
icon: TextCursorInput
|
||||
},
|
||||
imagecomponent: {
|
||||
name: 'Image',
|
||||
icon: Image
|
||||
},
|
||||
inputcomponent: {
|
||||
name: 'Input',
|
||||
icon: FormInput
|
||||
},
|
||||
radiocomponent: {
|
||||
name: 'Radio Button',
|
||||
icon: CircleDot
|
||||
},
|
||||
runformcomponent: {
|
||||
name: 'Run Form',
|
||||
icon: Play
|
||||
},
|
||||
selectcomponent: {
|
||||
name: 'Select',
|
||||
icon: List
|
||||
},
|
||||
numberinputcomponent: {
|
||||
name: 'Number',
|
||||
icon: Binary
|
||||
},
|
||||
slidercomponent: {
|
||||
name: 'Slider',
|
||||
icon: SlidersHorizontal
|
||||
},
|
||||
passwordinputcomponent: {
|
||||
name: 'Password',
|
||||
icon: Lock
|
||||
},
|
||||
dateinputcomponent: {
|
||||
name: 'Date Input',
|
||||
icon: Calendar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function accessPropertyByPath<T>(object: T, path: string): T | undefined {
|
||||
// convert indexes to properties
|
||||
|
||||
Vendored
+1
-1
@@ -46,7 +46,7 @@ declare module 'svelte-grid' {
|
||||
default: { item: ItemLayout; dataItem: Item<T> & { data: AppComponent } }
|
||||
}
|
||||
|
||||
export default class Grid<T = {}> extends SvelteComponentTyped<Props<T>, {}, Slots<T>> {}
|
||||
export default class Grid<T = {}> extends SvelteComponentTyped<Props<T>, {}, Slots<T>> { }
|
||||
}
|
||||
|
||||
declare module 'svelte-grid/build/helper/index.mjs' {
|
||||
|
||||
Reference in New Issue
Block a user