app improvements
This commit is contained in:
@@ -3947,7 +3947,7 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum: [script, group_, resource, schedule, variable, flow, folder]
|
||||
enum: [script, group_, resource, schedule, variable, flow, folder, app]
|
||||
responses:
|
||||
"200":
|
||||
description: acls
|
||||
@@ -3972,7 +3972,7 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum: [script, group_, resource, schedule, variable, flow, folder]
|
||||
enum: [script, group_, resource, schedule, variable, flow, folder, app]
|
||||
requestBody:
|
||||
description: acl to add
|
||||
required: true
|
||||
@@ -4008,7 +4008,7 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum: [script, group_, resource, schedule, variable, flow, folder]
|
||||
enum: [script, group_, resource, schedule, variable, flow, folder, app]
|
||||
requestBody:
|
||||
description: acl to add
|
||||
required: true
|
||||
|
||||
@@ -37,7 +37,7 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/list", get(list_apps))
|
||||
.route("/get/p/*path", get(get_app))
|
||||
.route("/get/v/*id", get(get_app_by_id))
|
||||
.route("/exists/*path", post(exists_app))
|
||||
.route("/exists/*path", get(exists_app))
|
||||
.route("/update/*path", post(update_app))
|
||||
.route("/delete/*path", delete(delete_app))
|
||||
.route("/create", post(create_app))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { Alert, Button, Drawer } from './common'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import Path from './Path.svelte'
|
||||
import { FlowService, ScriptService } from '$lib/gen'
|
||||
import { AppService, FlowService, ScriptService } from '$lib/gen'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
drawer.openDrawer()
|
||||
}
|
||||
|
||||
|
||||
async function loadOwner() {
|
||||
own = await isOwner(path, $userStore!, $workspaceStore!)
|
||||
}
|
||||
@@ -61,6 +60,14 @@
|
||||
path
|
||||
}
|
||||
})
|
||||
} else if (kind == 'app') {
|
||||
await AppService.updateApp({
|
||||
workspace: $workspaceStore!,
|
||||
path: initialPath,
|
||||
requestBody: {
|
||||
path
|
||||
}
|
||||
})
|
||||
}
|
||||
dispatch('update', path)
|
||||
drawer.closeDrawer()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { type Meta, pathToMeta } from '$lib/common'
|
||||
|
||||
import {
|
||||
AppService,
|
||||
FlowService,
|
||||
FolderService,
|
||||
GroupService,
|
||||
@@ -151,6 +152,8 @@
|
||||
})
|
||||
} else if (kind == 'schedule') {
|
||||
return await ScheduleService.existsSchedule({ workspace: $workspaceStore!, path: path })
|
||||
} else if (kind == 'app') {
|
||||
return await AppService.existsApp({ workspace: $workspaceStore!, path: path })
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
@@ -237,7 +240,7 @@
|
||||
>
|
||||
<div class="flex flex-row">
|
||||
<input class="mr-2" placeholder="New group name" bind:value={newGroupName} />
|
||||
<Button size="md" startIcon={{ icon: faPlus }} disabled={!newGroupName} on:click={addGroup}>
|
||||
<Button size="md" endIcon={{ icon: faPlus }} disabled={!newGroupName} on:click={addGroup}>
|
||||
New group
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
type Kind = 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow'
|
||||
type Kind = 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'app'
|
||||
let kind: Kind
|
||||
|
||||
let path: string = ''
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</script>
|
||||
|
||||
<Drawer bind:open={drawerOpen} size="800px">
|
||||
<DrawerContent title="Add an app" on:close={() => closeDrawer()}>
|
||||
<DrawerContent title="Create an App" on:close={() => closeDrawer()}>
|
||||
<Path bind:error={pathError} bind:path {initialPath} namePlaceholder="my_app" kind="app">
|
||||
<div slot="ownerToolkit">
|
||||
App permissions depend on their path. Select the group <span class="font-mono">all</span>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<button
|
||||
on:pointerdown|preventDefault|stopPropagation
|
||||
on:click|preventDefault|stopPropagation={refresh}
|
||||
class="center-center p-1 rounded border bg-white/60 z-40"
|
||||
class="center-center p-1 rounded border bg-white/60 hover:bg-gray-200 z-10"
|
||||
>
|
||||
<RefreshCw class={loading ? 'animate-spin' : ''} size={16} />
|
||||
</button>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
await executeComponent()
|
||||
}
|
||||
}
|
||||
executeComponent()
|
||||
})
|
||||
|
||||
let pagePath = $page.params.path
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
faHand,
|
||||
faMobileAlt
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { Eye, Laptop2, Pencil, PenTool, Smartphone } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import { sendUserToast } from '../../../utils'
|
||||
@@ -55,40 +56,37 @@
|
||||
|
||||
<div class="border-b flex flex-row justify-between py-1 px-4 items-center">
|
||||
<input class="text-sm w-64" bind:value={title} />
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex gap-8 items-center">
|
||||
<div>
|
||||
<ToggleButtonGroup bind:selected={mode}>
|
||||
<ToggleButton position="left" value="dnd" size="xs">
|
||||
<Icon data={faHand} class="h-3 mr-1" />
|
||||
Editor
|
||||
<div class="inline-flex gap-1 items-center">
|
||||
<Pencil size={14} />
|
||||
Editor
|
||||
</div>
|
||||
</ToggleButton>
|
||||
<ToggleButton position="right" value="preview" size="xs">
|
||||
<Icon data={faDisplay} class="h-4 mr-1" />
|
||||
Preview
|
||||
</ToggleButton>
|
||||
<div class="inline-flex gap-1 items-center"> <Eye size={14} /> Preview</div></ToggleButton
|
||||
>
|
||||
</ToggleButtonGroup>
|
||||
</div>
|
||||
<div>
|
||||
<ToggleButtonGroup bind:selected={breakpoint}>
|
||||
<ToggleButton
|
||||
position="left"
|
||||
value="sm"
|
||||
startIcon={{ icon: faMobileAlt }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<ToggleButton
|
||||
position="right"
|
||||
value="lg"
|
||||
startIcon={{ icon: faDesktopAlt }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<ToggleButton position="left" value="sm" size="xs">
|
||||
<Smartphone size={14} />
|
||||
</ToggleButton>
|
||||
<ToggleButton position="right" value="lg" size="xs"><Laptop2 size={14} /></ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row gap-2 w-64 justify-end">
|
||||
<Button color="dark" size="xs" variant="border" startIcon={{ icon: faExternalLink }}>
|
||||
<Button
|
||||
on:click={() => sendUserToast('Publishing apps publically at secret urls is coming soon')}
|
||||
color="dark"
|
||||
size="xs"
|
||||
variant="border"
|
||||
startIcon={{ icon: faExternalLink }}
|
||||
>
|
||||
Publish
|
||||
</Button>
|
||||
<Button loading={loading.save} on:click={save} color="dark" size="xs">Save</Button>
|
||||
|
||||
@@ -100,57 +100,52 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
on:pointerdown={onpointerdown}
|
||||
on:pointerleave={onpointerup}
|
||||
on:pointerup={onpointerup}
|
||||
class="bg-white h-full relative"
|
||||
>
|
||||
<div class="bg-white h-full relative">
|
||||
<div class="w-full flex justify-between border-b px-4 py-2 mb-4 items-center gap-4">
|
||||
<h2>{$app.title}</h2>
|
||||
<RecomputeAllComponents />
|
||||
<div class="text-2xs text-gray-600"
|
||||
>{policy.execution_mode} mode {policy.on_behalf_of
|
||||
? `on behalf of ${policy.on_behalf_of}`
|
||||
: ''}</div
|
||||
>{policy.on_behalf_of ? `on behalf of ${policy.on_behalf_of}` : ''}</div
|
||||
>
|
||||
</div>
|
||||
<Grid
|
||||
bind:items={$app.grid}
|
||||
let:dataItem
|
||||
rowHeight={46}
|
||||
cols={columnConfiguration}
|
||||
fastStart={true}
|
||||
on:pointerup={({ detail }) => selectComponent(detail.id)}
|
||||
gap={[4, 2]}
|
||||
>
|
||||
{#each $lazyGrid as gridComponent (gridComponent.id)}
|
||||
{#if gridComponent.data.id === dataItem.data.id}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class={classNames(
|
||||
'h-full w-full flex justify-center align-center',
|
||||
gridComponent.data.card ? 'border border-gray-100' : ''
|
||||
)}
|
||||
on:click|preventDefault|capture|once
|
||||
>
|
||||
<ComponentEditor
|
||||
{pointerdown}
|
||||
bind:component={gridComponent.data}
|
||||
selected={$selectedComponent === dataItem.data.id}
|
||||
locked={isFixed(gridComponent)}
|
||||
on:delete={() => removeGridElement(gridComponent.data)}
|
||||
on:lock={() => {
|
||||
let fComponent = $app.grid.find((c) => c.id === gridComponent.id)
|
||||
if (fComponent) {
|
||||
fComponent = toggleFixed(fComponent)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</Grid>
|
||||
<div on:pointerdown={onpointerdown} on:pointerleave={onpointerup} on:pointerup={onpointerup}>
|
||||
<Grid
|
||||
bind:items={$app.grid}
|
||||
let:dataItem
|
||||
rowHeight={46}
|
||||
cols={columnConfiguration}
|
||||
fastStart={true}
|
||||
on:pointerup={({ detail }) => selectComponent(detail.id)}
|
||||
gap={[4, 2]}
|
||||
>
|
||||
{#each $lazyGrid as gridComponent (gridComponent.id)}
|
||||
{#if gridComponent.data.id === dataItem.data.id}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class={classNames(
|
||||
'h-full w-full flex justify-center align-center',
|
||||
gridComponent.data.card ? 'border border-gray-100' : ''
|
||||
)}
|
||||
on:click|preventDefault|capture|once
|
||||
>
|
||||
<ComponentEditor
|
||||
{pointerdown}
|
||||
bind:component={gridComponent.data}
|
||||
selected={$selectedComponent === dataItem.data.id}
|
||||
locked={isFixed(gridComponent)}
|
||||
on:delete={() => removeGridElement(gridComponent.data)}
|
||||
on:lock={() => {
|
||||
let fComponent = $app.grid.find((c) => c.id === gridComponent.id)
|
||||
if (fComponent) {
|
||||
fComponent = toggleFixed(fComponent)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</Grid>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Dropdown from '$lib/components/Dropdown.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { RefreshCw } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../types'
|
||||
@@ -16,12 +18,26 @@
|
||||
)
|
||||
loading = false
|
||||
}
|
||||
let timeout: NodeJS.Timeout | undefined = undefined
|
||||
</script>
|
||||
|
||||
<button
|
||||
on:click|preventDefault|stopPropagation={onRefresh}
|
||||
class="center-center p-1 rounded border bg-white/60 inline-flex gap-2"
|
||||
>
|
||||
<RefreshCw class={loading ? 'animate-spin' : ''} size={20} /> ({Object.keys($runnableComponents)
|
||||
.length})
|
||||
</button>
|
||||
<div class="flex gap-4 items-center">
|
||||
<button
|
||||
on:click|preventDefault|stopPropagation={onRefresh}
|
||||
class="center-center p-1 rounded border bg-white/60 hover:bg-gray-200 inline-flex gap-2"
|
||||
>
|
||||
<RefreshCw class={loading ? 'animate-spin' : ''} size={20} /> ({Object.keys($runnableComponents)
|
||||
.length})
|
||||
</button>
|
||||
<Toggle
|
||||
size="xs"
|
||||
on:change={(e) => {
|
||||
if (e.detail) {
|
||||
timeout = setInterval(onRefresh, 15000)
|
||||
} else {
|
||||
timeout && clearInterval(timeout)
|
||||
}
|
||||
}}
|
||||
options={{ right: 'auto (15s)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
<script lang="ts">
|
||||
import Dropdown from '$lib/components/Dropdown.svelte'
|
||||
import type MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
import type ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import { AppService, type ListableApp } from '$lib/gen'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { faEdit, faEye, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import {
|
||||
faEdit,
|
||||
faEye,
|
||||
faFileExport,
|
||||
faShare,
|
||||
faTrashAlt
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { MoreVertical } from 'lucide-svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Button from '../button/Button.svelte'
|
||||
@@ -12,6 +20,8 @@
|
||||
export let app: ListableApp & { canWrite: boolean }
|
||||
export let marked: string | undefined
|
||||
export let starred: boolean
|
||||
export let shareModal: ShareModal
|
||||
export let moveDrawer: MoveDrawer
|
||||
|
||||
let { summary, path, extra_perms, canWrite, workspace_id } = app
|
||||
|
||||
@@ -48,6 +58,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<Button
|
||||
href="/apps/get/{path}"
|
||||
color="dark"
|
||||
@@ -67,6 +78,21 @@
|
||||
icon: faEye,
|
||||
href: `/apps/get/${path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Move',
|
||||
icon: faFileExport,
|
||||
action: () => {
|
||||
moveDrawer.openDrawer(path, 'app')
|
||||
},
|
||||
disabled: !canWrite
|
||||
},
|
||||
{
|
||||
displayName: canWrite ? 'Share' : 'See Permissions',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openDrawer && shareModal.openDrawer(path, 'app')
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Delete',
|
||||
icon: faTrashAlt,
|
||||
|
||||
@@ -321,6 +321,8 @@
|
||||
marked={item.marked}
|
||||
on:change={loadApps}
|
||||
app={item}
|
||||
{moveDrawer}
|
||||
{shareModal}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
</Alert>
|
||||
{/if}
|
||||
<PageHeader title="Home">
|
||||
<div class="flex flex-row gap-2 flex-wrap">
|
||||
<div class="flex flex-row gap-3 flex-wrap">
|
||||
{#if !$userStore?.operator}
|
||||
<CreateApp />
|
||||
<CreateActionsScript />
|
||||
|
||||
@@ -79,9 +79,16 @@
|
||||
placeholder="New folder name"
|
||||
bind:value={newFolderName}
|
||||
/>
|
||||
<Button size="md" startIcon={{ icon: faPlus }} disabled={!newFolderName} on:click={addFolder}>
|
||||
New folder
|
||||
</Button>
|
||||
<div>
|
||||
<Button
|
||||
size="md"
|
||||
startIcon={{ icon: faPlus }}
|
||||
disabled={!newFolderName}
|
||||
on:click={addFolder}
|
||||
>
|
||||
New folder
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
|
||||
|
||||
@@ -70,9 +70,11 @@
|
||||
placeholder="New group name"
|
||||
bind:value={newGroupName}
|
||||
/>
|
||||
<Button size="md" startIcon={{ icon: faPlus }} disabled={!newGroupName} on:click={addGroup}>
|
||||
New group
|
||||
</Button>
|
||||
<div>
|
||||
<Button size="md" startIcon={{ icon: faPlus }} disabled={!newGroupName} on:click={addGroup}>
|
||||
New group
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user