mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 16:01:42 +00:00
frontend apps rename improvements
This commit is contained in:
@@ -190,7 +190,7 @@
|
||||
|
||||
$state = $state
|
||||
} catch (e) {
|
||||
sendUserToast('Error running frontend script: ' + e.message, true)
|
||||
sendUserToast(`Error running frontend script ${id}: ` + e.message, true)
|
||||
|
||||
// Manually add a fake job to the job list to show the error
|
||||
|
||||
@@ -206,8 +206,7 @@
|
||||
}
|
||||
loading = false
|
||||
return
|
||||
}
|
||||
if (noBackend) {
|
||||
} else if (noBackend) {
|
||||
if (!noToast) {
|
||||
sendUserToast('This app is not connected to a windmill backend, it is a static preview')
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
faClipboard,
|
||||
faExternalLink,
|
||||
faFileExport,
|
||||
faGlobe,
|
||||
faSave
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import {
|
||||
@@ -42,7 +41,7 @@
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { appToHubUrl, classNames, copyToClipboard, sendUserToast } from '../../../utils'
|
||||
import { classNames, copyToClipboard, sendUserToast } from '../../../utils'
|
||||
import type {
|
||||
AppInput,
|
||||
ConnectedAppInput,
|
||||
@@ -607,14 +606,14 @@
|
||||
appExport.open($app)
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Publish to Hub',
|
||||
icon: faGlobe,
|
||||
action: () => {
|
||||
const url = appToHubUrl(toStatic($app, $staticExporter, $summary))
|
||||
window.open(url.toString(), '_blank')
|
||||
}
|
||||
},
|
||||
// {
|
||||
// displayName: 'Publish to Hub',
|
||||
// icon: faGlobe,
|
||||
// action: () => {
|
||||
// const url = appToHubUrl(toStatic($app, $staticExporter, $summary))
|
||||
// window.open(url.toString(), '_blank')
|
||||
// }
|
||||
// },
|
||||
{
|
||||
displayName: 'Hub compatible JSON',
|
||||
icon: faFileExport,
|
||||
|
||||
@@ -32,7 +32,10 @@ export function dfs(
|
||||
for (const item of grid) {
|
||||
if (item.id === id) {
|
||||
return [id]
|
||||
} else if (item.data.type == 'tablecomponent' && item.data.actionButtons.find((x) => x.id)) {
|
||||
} else if (
|
||||
item.data.type == 'tablecomponent' &&
|
||||
item.data.actionButtons.find((x) => id == x.id)
|
||||
) {
|
||||
return [item.id, id]
|
||||
} else {
|
||||
for (let i = 0; i < (item.data.numberOfSubgrids ?? 0); i++) {
|
||||
@@ -133,11 +136,14 @@ export function findGridItem(app: App, id: string): GridItem | undefined {
|
||||
}
|
||||
|
||||
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
|
||||
const allIds = allItems(app.grid, app.subgrids).flatMap((x) => {
|
||||
if (x.data.type === 'tablecomponent') {
|
||||
return [x.id, ...x.data.actionButtons.map((x) => x.id)]
|
||||
} else {
|
||||
return [x.id]
|
||||
}
|
||||
})
|
||||
return getNextId(allIds)
|
||||
}
|
||||
|
||||
export function getAllRecomputeIdsForComponent(app: App, id: string | undefined) {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
export let first: boolean = false
|
||||
</script>
|
||||
|
||||
<OutputHeader selectable={false} {id} {name} color="blue" {first}>
|
||||
<OutputHeader renamable={false} selectable={true} {id} {name} color="blue" {first}>
|
||||
<ComponentOutputViewer
|
||||
componentId={id}
|
||||
on:select={({ detail }) => {
|
||||
|
||||
+97
-58
@@ -6,6 +6,8 @@
|
||||
import { getContext } from 'svelte'
|
||||
import { allsubIds, findGridItem } from '../../appUtils'
|
||||
import IdEditor from './IdEditor.svelte'
|
||||
import type { AppComponent } from '../../component'
|
||||
import type { Runnable } from '$lib/components/apps/inputType'
|
||||
|
||||
export let id: string
|
||||
export let name: string
|
||||
@@ -13,6 +15,7 @@
|
||||
export let nested: boolean = false
|
||||
export let color: 'blue' | 'indigo' = 'indigo'
|
||||
export let selectable: boolean = true
|
||||
export let renamable: boolean = true
|
||||
|
||||
const { manuallyOpened, search, hasResult } = getContext<ContextPanelContext>('ContextPanel')
|
||||
|
||||
@@ -47,66 +50,102 @@
|
||||
}
|
||||
|
||||
function renameId(newId: string): void {
|
||||
{
|
||||
const item = findGridItem($app, id)
|
||||
if (item) {
|
||||
item.data.id = newId
|
||||
item.id = newId
|
||||
}
|
||||
const oldSubgrids = Object.keys($app.subgrids ?? {}).filter((subgrid) =>
|
||||
subgrid.startsWith(id + '-')
|
||||
)
|
||||
oldSubgrids.forEach((subgrid) => {
|
||||
if ($app.subgrids) {
|
||||
$app.subgrids[subgrid.replace(id, newId)] = $app.subgrids[subgrid]
|
||||
delete $app.subgrids[subgrid]
|
||||
}
|
||||
})
|
||||
allItems($app.grid, $app.subgrids).forEach((item) => {
|
||||
if (item.data.componentInput?.type == 'connected') {
|
||||
if (item.data.componentInput.connection?.componentId === id) {
|
||||
item.data.componentInput.connection.componentId = newId
|
||||
}
|
||||
} else if (item.data.componentInput?.type == 'runnable') {
|
||||
if (
|
||||
item.data.componentInput?.runnable?.type === 'runnableByName' &&
|
||||
item.data.componentInput?.runnable?.inlineScript?.refreshOn
|
||||
?.map((x) => x.id)
|
||||
?.includes(id)
|
||||
) {
|
||||
item.data.componentInput.runnable.inlineScript.refreshOn =
|
||||
item.data.componentInput.runnable.inlineScript.refreshOn.map((x) => {
|
||||
if (x.id === id) {
|
||||
return {
|
||||
id: newId,
|
||||
key: x.key
|
||||
}
|
||||
}
|
||||
return x
|
||||
})
|
||||
}
|
||||
}
|
||||
const item = findGridItem($app, id)
|
||||
|
||||
Object.values(item.data.configuration ?? {}).forEach((config) => {
|
||||
if (config.type === 'connected') {
|
||||
if (config.connection?.componentId === id) {
|
||||
config.connection.componentId = newId
|
||||
}
|
||||
} else if (config.type == 'oneOf') {
|
||||
Object.values(config.configuration ?? {}).forEach((choices) => {
|
||||
Object.values(choices).forEach((c) => {
|
||||
if (c.type === 'connected') {
|
||||
if (c.connection?.componentId === id) {
|
||||
c.connection.componentId = newId
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.data.id = newId
|
||||
item.id = newId
|
||||
|
||||
const oldSubgrids = Object.keys($app.subgrids ?? {}).filter((subgrid) =>
|
||||
subgrid.startsWith(id + '-')
|
||||
)
|
||||
|
||||
oldSubgrids.forEach((subgrid) => {
|
||||
if ($app.subgrids) {
|
||||
$app.subgrids[subgrid.replace(id, newId)] = $app.subgrids[subgrid]
|
||||
delete $app.subgrids[subgrid]
|
||||
}
|
||||
})
|
||||
|
||||
function propagateRename(from: string, to: string) {
|
||||
allItems($app.grid, $app.subgrids).forEach((item) => {
|
||||
renameComponent(from, to, item.data)
|
||||
})
|
||||
|
||||
$app.hiddenInlineScripts.forEach((x) => {
|
||||
console.log('process', x.name, id)
|
||||
processRunnable(from, to, {
|
||||
name: x.name,
|
||||
inlineScript: x.inlineScript,
|
||||
type: 'runnableByName'
|
||||
})
|
||||
})
|
||||
$app = $app
|
||||
$selectedComponent = [newId]
|
||||
}
|
||||
propagateRename(id, newId)
|
||||
if (item?.data.type == 'tablecomponent') {
|
||||
for (let c of item.data.actionButtons) {
|
||||
let old = c.id
|
||||
c.id = c.id.replace(id + '_', newId + '_')
|
||||
propagateRename(old, c.id)
|
||||
}
|
||||
}
|
||||
|
||||
$app = $app
|
||||
$selectedComponent = [newId]
|
||||
}
|
||||
|
||||
function renameComponent(from: string, to: string, data: AppComponent) {
|
||||
if (data.type == 'tablecomponent') {
|
||||
for (let c of data.actionButtons) {
|
||||
renameComponent(from, to, c)
|
||||
}
|
||||
}
|
||||
let componentInput = data.componentInput
|
||||
if (componentInput?.type == 'connected') {
|
||||
if (componentInput.connection?.componentId === from) {
|
||||
componentInput.connection.componentId = to
|
||||
}
|
||||
} else if (componentInput?.type == 'runnable') {
|
||||
processRunnable(from, to, componentInput.runnable)
|
||||
}
|
||||
|
||||
Object.values(data.configuration ?? {}).forEach((config) => {
|
||||
if (config.type === 'connected') {
|
||||
if (config.connection?.componentId === from) {
|
||||
config.connection.componentId = to
|
||||
}
|
||||
} else if (config.type == 'oneOf') {
|
||||
Object.values(config.configuration ?? {}).forEach((choices) => {
|
||||
Object.values(choices).forEach((c) => {
|
||||
if (c.type === 'connected') {
|
||||
if (c.connection?.componentId === id) {
|
||||
c.connection.componentId = to
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function processRunnable(from: string, to: string, runnable: Runnable) {
|
||||
if (
|
||||
runnable?.type === 'runnableByName' &&
|
||||
runnable?.inlineScript?.refreshOn?.find((x) => x.id === from)
|
||||
) {
|
||||
console.log('processss')
|
||||
runnable.inlineScript.refreshOn = runnable.inlineScript.refreshOn.map((x) => {
|
||||
console.log('renaming', x)
|
||||
if (x.id === from) {
|
||||
return {
|
||||
id: to,
|
||||
key: x.key
|
||||
}
|
||||
}
|
||||
return x
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -161,7 +200,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
{#if selectable && ($selectedComponent?.includes(id) || $hoverStore === id)}
|
||||
{#if selectable && renamable && ($selectedComponent?.includes(id) || $hoverStore === id)}
|
||||
<IdEditor
|
||||
{id}
|
||||
on:selected={() => ($selectedComponent = [id])}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
export let first: boolean = false
|
||||
</script>
|
||||
|
||||
<OutputHeader {id} name={'Table action'} {first}>
|
||||
<OutputHeader renamable={false} {id} name={'Table action'} {first}>
|
||||
<ComponentOutputViewer
|
||||
componentId={id}
|
||||
on:select={({ detail }) => {
|
||||
|
||||
@@ -236,7 +236,6 @@
|
||||
<TableActions id={component.id} bind:components={componentSettings.item.data.actionButtons} />
|
||||
{/if}
|
||||
|
||||
<AlignmentEditor bind:component={componentSettings.item.data} />
|
||||
{#if componentSettings.item.data.type === 'buttoncomponent' || componentSettings.item.data.type === 'formcomponent' || componentSettings.item.data.type === 'formbuttoncomponent'}
|
||||
<Recompute
|
||||
bind:recomputeIds={componentSettings.item.data.recomputeIds}
|
||||
@@ -245,6 +244,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="grow shrink" />
|
||||
<AlignmentEditor bind:component={componentSettings.item.data} />
|
||||
|
||||
{#if Object.keys(ccomponents[component.type].customCss ?? {}).length > 0}
|
||||
<PanelSection title="Styling">
|
||||
|
||||
+2
-2
@@ -156,13 +156,13 @@
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex flex-row gap-2 flex-wrap">
|
||||
<div class="flex flex-row gap-2 flex-wrap mt-2">
|
||||
{#each frontendDependencies as label, index}
|
||||
<span class={classNames(badgeClass, colors['blue'])}>
|
||||
{label}
|
||||
<button
|
||||
on:click={() => deleteDep(index)}
|
||||
class="bg-red-300 cursor-pointer hover:bg-red-400 ml-1 rounded-md"
|
||||
class="bg-blue-300 cursor-pointer hover:bg-blue-400 ml-1 rounded-md"
|
||||
>
|
||||
<X size={18} class="p-0.5" />
|
||||
</button>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
displayDaysAgo,
|
||||
emptyString,
|
||||
encodeState,
|
||||
flowToHubUrl,
|
||||
sendUserToast
|
||||
} from '$lib/utils'
|
||||
import {
|
||||
@@ -19,7 +18,6 @@
|
||||
faClipboard,
|
||||
faCodeFork,
|
||||
faEdit,
|
||||
faGlobe,
|
||||
faList,
|
||||
faPlay,
|
||||
faShare,
|
||||
@@ -249,7 +247,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="flex gap-2 flex-wrap mt-2">
|
||||
<Button
|
||||
<!-- <Button
|
||||
target="_blank"
|
||||
href={flowToHubUrl(flow).toString()}
|
||||
variant="border"
|
||||
@@ -258,7 +256,7 @@
|
||||
startIcon={{ icon: faGlobe }}
|
||||
>
|
||||
Publish to Hub
|
||||
</Button>
|
||||
</Button> -->
|
||||
<Button
|
||||
on:click={() => shareModal.openDrawer(flow?.path ?? '', 'flow')}
|
||||
variant="border"
|
||||
|
||||
Reference in New Issue
Block a user