mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 16:02:23 +00:00
feat(frontend): Script page action row (#626)
* feat(frontend): Update button component styles * feat(frontend): Use button component * fix(frontend): Re-export button types * feat(frontend): Use action row in script page * fix(frontend): Center the action row * fix(frontend): Revert to previous event forwarding * feature(frontend): Add action row to flow page * fix(frontend): Restore button red color
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
export let applyPageWidth = false
|
||||
let classes = 'max-w-6xl mx-auto px-4 sm:px-6 md:px-8'
|
||||
</script>
|
||||
|
||||
<div class={'bg-white py-3 ' + $$props.class}>
|
||||
<div
|
||||
class={'w-full flex flex-wrap justify-between items-center gap-4 ' +
|
||||
(applyPageWidth ? classes : '')}
|
||||
>
|
||||
{#if $$slots.left}
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<slot name="left" />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.middle}
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<slot name="middle" />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.right}
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<slot name="right" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,81 +1,108 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import Icon from 'svelte-awesome'
|
||||
import type { Button } from './model'
|
||||
|
||||
export let size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'md'
|
||||
export let color: 'blue' | 'dark' | 'light' | 'red' = 'blue'
|
||||
export let variant: 'contained' | 'border' = 'contained'
|
||||
export let size: Button.Size = 'md'
|
||||
export let color: Button.Color = 'blue'
|
||||
export let variant: Button.Variant = 'contained'
|
||||
export let btnClasses: string = ''
|
||||
export let disabled: boolean = false
|
||||
export let href: string | undefined = undefined
|
||||
export let target: '_self' | '_blank' = '_self'
|
||||
export let target: Button.Target = '_self'
|
||||
|
||||
export let startIcon: { icon: any; classes?: string } | undefined = undefined
|
||||
export let endIcon: { icon: any; classes?: string } | undefined = undefined
|
||||
|
||||
function getColorClasses() {
|
||||
switch (color) {
|
||||
case 'blue':
|
||||
return 'bg-blue-500 hover:bg-blue-700 focus:ring-blue-300 text-white '
|
||||
case 'red':
|
||||
return 'bg-red-500 hover:bg-red-700 focus:ring-red-300 text-white '
|
||||
case 'light':
|
||||
return 'text-gray-800 bg-white hover:bg-gray-100 focus:ring-gray-300'
|
||||
default:
|
||||
return ''
|
||||
// Order of classes: border, border modifier, bg, bg modifier, text, text modifier, everything else
|
||||
const colorVariants: Record<Button.Color, Record<Button.Variant, string>> = {
|
||||
blue: {
|
||||
border:
|
||||
'border-blue-500 hover:border-blue-700 bg-white hover:bg-blue-100 text-blue-500 hover:text-blue-700 focus:ring-blue-300',
|
||||
contained: 'bg-blue-500 hover:bg-blue-700 text-white focus:ring-blue-300'
|
||||
},
|
||||
red: {
|
||||
border:
|
||||
'border-red-500 hover:border-red-700 bg-white hover:bg-red-100 text-red-500 hover:text-red-700 focus:ring-red-300',
|
||||
contained: 'bg-red-500 hover:bg-red-700 text-white focus:ring-red-300'
|
||||
},
|
||||
dark: {
|
||||
border:
|
||||
'border-gray-800 hover:border-gray-900 bg-white hover:bg-gray-200 text-gray-800 hover:text-gray-900 focus:ring-gray-300',
|
||||
contained: 'bg-gray-700 hover:bg-gray-900 text-white focus:ring-gray-300'
|
||||
},
|
||||
light: {
|
||||
border:
|
||||
'border-gray-700 hover:border-gray-800 bg-white hover:bg-gray-100 text-gray-700 hover:text-gray-800 focus:ring-gray-300',
|
||||
contained: 'bg-white hover:bg-gray-100 text-gray-700 focus:ring-gray-300'
|
||||
}
|
||||
}
|
||||
|
||||
function getSizeClasses() {
|
||||
switch (size) {
|
||||
case 'xs':
|
||||
return 'text-xs'
|
||||
case 'sm':
|
||||
return 'text-sm'
|
||||
case 'md':
|
||||
return 'text-md'
|
||||
case 'lg':
|
||||
return 'text-lg'
|
||||
case 'xl':
|
||||
return 'text-xl'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
const sizeClass: Record<Button.Size, string> = {
|
||||
xs: 'text-xs px-2.5 py-1',
|
||||
sm: 'text-sm px-2.5 py-1',
|
||||
md: 'text-md px-3 py-1',
|
||||
lg: 'text-lg px-4 py-2',
|
||||
xl: 'text-xl px-5 py-2'
|
||||
}
|
||||
|
||||
const iconScale: Record<Button.Size, number> = {
|
||||
xs: 0.7,
|
||||
sm: 0.8,
|
||||
md: 1,
|
||||
lg: 1.1,
|
||||
xl: 1.2
|
||||
}
|
||||
|
||||
const buttonProps = {
|
||||
class: classNames(
|
||||
getColorClasses(),
|
||||
getSizeClasses(),
|
||||
'focus:ring-4 font-medium',
|
||||
'px-4 py-2',
|
||||
'rounded-md',
|
||||
'flex justify-center items-center',
|
||||
colorVariants[color][variant],
|
||||
variant === 'border' ? 'border' : '',
|
||||
btnClasses
|
||||
sizeClass[size],
|
||||
'focus:ring-4 font-medium',
|
||||
'rounded-md',
|
||||
'flex justify-center items-center text-center',
|
||||
btnClasses,
|
||||
disabled ? 'pointer-events-none cursor-default filter grayscale' : ''
|
||||
),
|
||||
disabled
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if href}
|
||||
<a {href} {target} on:click|stopPropagation {...buttonProps}>
|
||||
<a {href} {target} tabindex={disabled ? -1 : 0} on:click|stopPropagation {...buttonProps}>
|
||||
{#if startIcon}
|
||||
<Icon data={startIcon.icon} class={classNames('mr-2', startIcon.classes)} />
|
||||
<Icon
|
||||
data={startIcon.icon}
|
||||
class={classNames('mr-2', startIcon.classes)}
|
||||
scale={iconScale[size]}
|
||||
/>
|
||||
{/if}
|
||||
<slot />
|
||||
{#if endIcon}
|
||||
<Icon data={endIcon.icon} class={classNames('ml-2', endIcon.classes)} />
|
||||
<Icon
|
||||
data={endIcon.icon}
|
||||
class={classNames('ml-2', endIcon.classes)}
|
||||
scale={iconScale[size]}
|
||||
/>
|
||||
{/if}
|
||||
</a>
|
||||
{:else}
|
||||
<button type="button" on:click|stopPropagation {...buttonProps}>
|
||||
{#if startIcon}
|
||||
<Icon data={startIcon.icon} class={classNames('mr-2', startIcon.classes)} />
|
||||
<Icon
|
||||
data={startIcon.icon}
|
||||
class={classNames('mr-2', startIcon.classes)}
|
||||
scale={iconScale[size]}
|
||||
/>
|
||||
{/if}
|
||||
<slot />
|
||||
{#if endIcon}
|
||||
<Icon data={endIcon.icon} class={classNames('ml-2', endIcon.classes)} />
|
||||
<Icon
|
||||
data={endIcon.icon}
|
||||
class={classNames('ml-2', endIcon.classes)}
|
||||
scale={iconScale[size]}
|
||||
/>
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export namespace Button {
|
||||
export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
||||
export type Color = 'blue' | 'red' | 'dark' | 'light'
|
||||
export type Variant = 'contained' | 'border'
|
||||
export type Target = '_self' | '_blank'
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export { default as ActionRow } from './actionRow/ActionRow.svelte'
|
||||
export { default as Badge } from './badge/Badge.svelte'
|
||||
export { default as Button } from './button/Button.svelte'
|
||||
export { default as Drawer } from './drawer/Drawer.svelte'
|
||||
export { default as DrawerContent } from './drawer/DrawerContent.svelte'
|
||||
export { default as Menu } from './menu/Menu.svelte'
|
||||
export { default as MenuItem } from './menu/MenuItem.svelte'
|
||||
export { default as Tab } from './tabs/Tab.svelte'
|
||||
export { default as TabContent } from './tabs/TabContent.svelte'
|
||||
export { default as Tabs } from './tabs/Tabs.svelte'
|
||||
export { default as ToggleButton } from './toggleButton/ToggleButton.svelte'
|
||||
export { default as ToggleButtonGroup } from './toggleButton/ToggleButtonGroup.svelte'
|
||||
|
||||
export * from './badge/model'
|
||||
export * from './button/model'
|
||||
@@ -38,6 +38,7 @@
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import FlowViewer from '$lib/components/FlowViewer.svelte'
|
||||
import ObjectViewer from '$lib/components/propertyPicker/ObjectViewer.svelte'
|
||||
import { Button, ActionRow } from '$lib/components/common'
|
||||
|
||||
let flow: Flow | undefined
|
||||
let schedule: Schedule | undefined
|
||||
@@ -45,6 +46,7 @@
|
||||
|
||||
let path = $page.params.path
|
||||
let shareModal: ShareModal
|
||||
let scrollY: number
|
||||
|
||||
$: {
|
||||
if ($workspaceStore && $userStore) {
|
||||
@@ -88,105 +90,101 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window bind:scrollY />
|
||||
|
||||
{#if flow}
|
||||
<ActionRow applyPageWidth class={'sticky top-0 ' + (scrollY >= 30 ? 'border-b' : '')}>
|
||||
<svelte:fragment slot="left">
|
||||
<Button
|
||||
href="/flows/run/{path}"
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faPlay }}
|
||||
>
|
||||
Run
|
||||
</Button>
|
||||
<Button
|
||||
href="/flows/edit/{path}"
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faEdit }}
|
||||
disabled={!can_write}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
<Button
|
||||
href="/flows/add?template={flow.path}"
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faCodeFork }}
|
||||
>
|
||||
Use as template/Fork
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="right">
|
||||
<Button
|
||||
href="/runs/{flow.path}"
|
||||
variant="border"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faList }}
|
||||
>
|
||||
View runs
|
||||
</Button>
|
||||
<Button
|
||||
target="_blank"
|
||||
href={flowToHubUrl(flow).toString()}
|
||||
variant="border"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faGlobe }}
|
||||
>
|
||||
Publish to Hub
|
||||
</Button>
|
||||
<Dropdown
|
||||
dropdownItems={[
|
||||
{
|
||||
displayName: 'Use as template',
|
||||
icon: faEdit,
|
||||
href: `/flows/add?template=${flow.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openModal()
|
||||
},
|
||||
disabled: !can_write
|
||||
},
|
||||
{
|
||||
displayName: 'Schedule',
|
||||
icon: faCalendar,
|
||||
href: `/schedule/add?path=${flow.path}&isFlow=true`
|
||||
},
|
||||
{
|
||||
displayName: 'Archive',
|
||||
icon: faArchive,
|
||||
type: 'delete',
|
||||
action: () => {
|
||||
flow?.path && archiveFlow()
|
||||
},
|
||||
disabled: flow.archived || !can_write
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</ActionRow>
|
||||
{/if}
|
||||
|
||||
<CenteredPage>
|
||||
<div class="flex flex-row justify-between">
|
||||
<h1>
|
||||
<a href="/flows/get/{path}">{flow?.path ?? 'Loading...'}</a>
|
||||
<h1>
|
||||
<a href="/flows/get/{path}">{flow?.path ?? 'Loading...'}</a>
|
||||
|
||||
<SharedBadge canWrite={can_write} extraPerms={flow?.extra_perms ?? {}} />
|
||||
</h1>
|
||||
|
||||
{#if flow}
|
||||
<div class="flex flex-row-reverse px-6">
|
||||
<Dropdown
|
||||
dropdownItems={[
|
||||
{
|
||||
displayName: 'Use as template',
|
||||
icon: faEdit,
|
||||
href: `/flows/add?template=${flow.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openModal()
|
||||
},
|
||||
disabled: !can_write
|
||||
},
|
||||
{
|
||||
displayName: 'Schedule',
|
||||
icon: faCalendar,
|
||||
href: `/schedule/add?path=${flow.path}&isFlow=true`
|
||||
},
|
||||
{
|
||||
displayName: 'Archive',
|
||||
icon: faArchive,
|
||||
type: 'delete',
|
||||
action: () => {
|
||||
flow?.path && archiveFlow()
|
||||
},
|
||||
disabled: flow.archived || !can_write
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<div class="px-1">
|
||||
<a
|
||||
target="_blank"
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href={flowToHubUrl(flow).toString()}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faGlobe} scale={0.5} />
|
||||
<span class="pl-1">Publish to Hub</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/runs/{flow.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faList} scale={0.5} />
|
||||
<span class="pl-1">View runs</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/flows/edit/{path}"
|
||||
class:disabled={!can_write}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faEdit} scale={0.5} />
|
||||
<span class="pl-1">Edit</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/flows/add?template={flow.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faCodeFork} scale={0.5} />
|
||||
<span class="pl-1">Use as template/Fork</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/flows/run/{path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faPlay} scale={0.5} />
|
||||
<span class="pl-1">Run</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<SharedBadge canWrite={can_write} extraPerms={flow?.extra_perms ?? {}} />
|
||||
</h1>
|
||||
|
||||
<ShareModal bind:this={shareModal} kind="flow" path={flow?.path ?? ''} />
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
scriptToHubUrl,
|
||||
copyToClipboard
|
||||
} from '$lib/utils'
|
||||
import Icon from 'svelte-awesome'
|
||||
import {
|
||||
faPlay,
|
||||
faEdit,
|
||||
@@ -43,16 +42,14 @@
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { onDestroy } from 'svelte'
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import TabContent from '$lib/components/common/tabs/TabContent.svelte'
|
||||
import { Badge, Tabs, Tab, TabContent, Button, ActionRow } from '$lib/components/common'
|
||||
|
||||
let script: Script | undefined
|
||||
let topHash: string | undefined
|
||||
let can_write = false
|
||||
let deploymentInProgress = false
|
||||
let intervalId: NodeJS.Timer
|
||||
let scrollY: number
|
||||
|
||||
let shareModal: ShareModal
|
||||
|
||||
@@ -131,6 +128,111 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window bind:scrollY />
|
||||
|
||||
{#if script}
|
||||
<ActionRow applyPageWidth class={'sticky top-0 ' + (scrollY >= 30 ? 'border-b' : '')}>
|
||||
<svelte:fragment slot="left">
|
||||
<Button
|
||||
href={`/scripts/run/${script.hash}`}
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faPlay }}
|
||||
>
|
||||
Run
|
||||
</Button>
|
||||
<Button
|
||||
href={`/scripts/edit/${script.hash}?step=2`}
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faEdit }}
|
||||
disabled={!can_write}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
{#if !topHash}
|
||||
<Button
|
||||
href={`/scripts/add?template=${script.path}`}
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faCodeFork }}
|
||||
>
|
||||
Use as template/Fork
|
||||
</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="right">
|
||||
<Button
|
||||
href={`/runs/${script.path}`}
|
||||
variant="border"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faList }}
|
||||
>
|
||||
View runs
|
||||
</Button>
|
||||
<Button
|
||||
target="_blank"
|
||||
href={scriptToHubUrl(
|
||||
script.content,
|
||||
script.summary,
|
||||
script.description ?? '',
|
||||
script.kind
|
||||
).toString()}
|
||||
variant="border"
|
||||
color="blue"
|
||||
size="md"
|
||||
startIcon={{ icon: faGlobe }}
|
||||
>
|
||||
Publish to Hub
|
||||
</Button>
|
||||
<Dropdown
|
||||
dropdownItems={[
|
||||
{
|
||||
displayName: 'Use as template',
|
||||
icon: faEdit,
|
||||
href: `/scripts/add?template=${script.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openModal()
|
||||
},
|
||||
disabled: !can_write
|
||||
},
|
||||
{
|
||||
displayName: 'Schedule',
|
||||
icon: faCalendar,
|
||||
href: `/schedule/add?path=${script.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Archive',
|
||||
icon: faArchive,
|
||||
type: 'delete',
|
||||
action: () => {
|
||||
script?.hash && archiveScript(script.hash)
|
||||
},
|
||||
disabled: script.archived || !can_write
|
||||
},
|
||||
{
|
||||
displayName: 'Delete',
|
||||
icon: faTrash,
|
||||
type: 'delete',
|
||||
action: () => {
|
||||
script?.hash && deleteScript(script.hash)
|
||||
},
|
||||
disabled: script.deleted || !($userStore?.is_admin ?? false)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</ActionRow>
|
||||
{/if}
|
||||
|
||||
<CenteredPage>
|
||||
<div class="flex flex-row flex-wrap justify-between gap-4">
|
||||
<div>
|
||||
@@ -169,115 +271,16 @@
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if script}
|
||||
<div class="flex items-start flex-wrap gap-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/run/{script.hash}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faPlay} scale={0.5} />
|
||||
<span class="pl-1">Run</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/edit/{script.hash}?step=2"
|
||||
class:disabled={!can_write}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faEdit} scale={0.5} />
|
||||
<span class="pl-1">Edit</span>
|
||||
</div>
|
||||
</a>
|
||||
{#if !topHash}
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/add?template={script.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faCodeFork} scale={0.5} />
|
||||
<span class="pl-1">Use as template/Fork</span>
|
||||
</div>
|
||||
</a>
|
||||
{/if}
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/runs/{script.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faList} scale={0.5} />
|
||||
<span class="pl-1">View runs</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
target="_blank"
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href={scriptToHubUrl(
|
||||
script.content,
|
||||
script.summary,
|
||||
script.description ?? '',
|
||||
script.kind
|
||||
).toString()}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faGlobe} scale={0.5} />
|
||||
<span class="pl-1">Publish to Hub</span>
|
||||
</div>
|
||||
</a>
|
||||
<Dropdown
|
||||
dropdownItems={[
|
||||
{
|
||||
displayName: 'Use as template',
|
||||
icon: faEdit,
|
||||
href: `/scripts/add?template=${script.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openModal()
|
||||
},
|
||||
disabled: !can_write
|
||||
},
|
||||
{
|
||||
displayName: 'Schedule',
|
||||
icon: faCalendar,
|
||||
href: `/schedule/add?path=${script.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Archive',
|
||||
icon: faArchive,
|
||||
type: 'delete',
|
||||
action: () => {
|
||||
script?.hash && archiveScript(script.hash)
|
||||
},
|
||||
disabled: script.archived || !can_write
|
||||
},
|
||||
{
|
||||
displayName: 'Delete',
|
||||
icon: faTrash,
|
||||
type: 'delete',
|
||||
action: () => {
|
||||
script?.hash && deleteScript(script.hash)
|
||||
},
|
||||
disabled: script.deleted || !($userStore?.is_admin ?? false)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<ShareModal bind:this={shareModal} kind="script" path={script?.path ?? ''} />
|
||||
|
||||
<div class="flex flex-col gap-8 max-w-7xl pb-2">
|
||||
<div class="flex flex-col gap-8 max-w-7xl pt-8 pb-2">
|
||||
{#if script === undefined}
|
||||
<p>loading</p>
|
||||
{:else}
|
||||
<div>
|
||||
<h2 class="font-bold mt-8 mb-2">{script.summary}</h2>
|
||||
<h2 class="font-bold mb-2">{script.summary}</h2>
|
||||
<div class="prose">
|
||||
<SvelteMarkdown source={defaultIfEmptyString(script.description, 'No description')} />
|
||||
</div>
|
||||
@@ -343,13 +346,15 @@
|
||||
<Badge color="dark-gray" capitalize>
|
||||
{type}
|
||||
</Badge>
|
||||
<button
|
||||
on:click|preventDefault={() => copyToClipboard(url)}
|
||||
class="flex items-center bg-blue-600 text-white rounded-md px-2 ml-2"
|
||||
<Button
|
||||
on:click={() => copyToClipboard(url)}
|
||||
color="blue"
|
||||
size="sm"
|
||||
startIcon={{ icon: faClipboard }}
|
||||
btnClasses="ml-2"
|
||||
>
|
||||
<Icon data={faClipboard} />
|
||||
<span class="ml-1">Copy</span>
|
||||
</button>
|
||||
Copy
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
|
||||
Reference in New Issue
Block a user