mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 00:02:03 +00:00
feat(frontend): Typography update (#725)
* feat(frontend): Add new font face * feat(frontend): Typography update * fix(frontend): Import Inter font * fix(frontend): Font fixes * fix(front): Fix spacing and font inconsistencies * fix(frontend): Visual changes and fixes * fix(frontend): Minor visual fixes * fix(frontend): Remove comment
This commit is contained in:
@@ -2,3 +2,12 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('/Inter-Variable.ttf');
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,7 @@
|
||||
import { oauthStore, userStore, workspaceStore } from '$lib/stores'
|
||||
import { faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import PageHeader from './PageHeader.svelte'
|
||||
|
||||
import { OauthService, ResourceService, VariableService, type TokenResponse } from '$lib/gen'
|
||||
|
||||
import { page } from '$app/stores'
|
||||
import { sendUserToast, truncateRev } from '$lib/utils'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@@ -209,10 +206,11 @@
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
<PageHeader title="OAuth APIs" />
|
||||
<div class="mb-1 font-semibold text-gray-700">OAuth APIs</div>
|
||||
<div class="grid sm:grid-cols-2 md:grid-cols-3 gap-x-2 gap-y-1 items-center mb-2">
|
||||
{#each Object.entries(connects).sort((a, b) => a[0].localeCompare(b[0])) as [key, values]}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={key === resource_type ? 'blue' : 'dark'}
|
||||
btnClasses={key === resource_type ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
@@ -225,11 +223,11 @@
|
||||
dispatch('click')
|
||||
}}
|
||||
>
|
||||
<IconedResourceType name={key} after={true} />
|
||||
<IconedResourceType name={key} after={true} width="20px" height="20px" />
|
||||
</Button>
|
||||
{/each}
|
||||
</div>
|
||||
<PageHeader title="Scopes" primary={false} />
|
||||
<div class="mb-1 font-semibold text-gray-700 mt-6">Scopes</div>
|
||||
{#if !manual && resource_type != ''}
|
||||
{#each scopes as v}
|
||||
<div class="flex flex-row max-w-md mb-2">
|
||||
@@ -266,7 +264,7 @@
|
||||
{:else}
|
||||
<p class="italic text-sm">Pick an OAuth API and customize the scopes here</p>
|
||||
{/if}
|
||||
<PageHeader title="Extra Params" primary={false} />
|
||||
<div class="mb-1 font-semibold text-gray-700 mt-6">Extra params</div>
|
||||
{#if !manual && resource_type != ''}
|
||||
{#each extra_params as [k, v]}
|
||||
<div class="flex flex-row max-w-md mb-2">
|
||||
@@ -306,10 +304,11 @@
|
||||
{:else}
|
||||
<p class="italic text-sm">Pick an OAuth API and customize the extra parameters here</p>
|
||||
{/if}
|
||||
<PageHeader title="Non OAuth APIs" />
|
||||
<div class="mb-1 font-semibold text-gray-700 mt-6">Non OAuth APIs</div>
|
||||
<div class="grid sm:grid-cols-2 md:grid-cols-3 gap-x-2 gap-y-1 items-center mb-2">
|
||||
{#each connectsManual as [key, instructions]}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={key === resource_type ? 'blue' : 'dark'}
|
||||
btnClasses={key === resource_type ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
@@ -319,13 +318,13 @@
|
||||
dispatch('click')
|
||||
}}
|
||||
>
|
||||
<IconedResourceType name={key} after={true} />
|
||||
<IconedResourceType name={key} after={true} width="20px" height="20px" />
|
||||
</Button>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if step == 2}
|
||||
{#if manual}
|
||||
<PageHeader title="Instructions" />
|
||||
<div class="mb-1 font-semibold text-gray-700 mt-6">Instructions</div>
|
||||
<div>
|
||||
{apiTokenApps[resource_type].instructions}
|
||||
</div>
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
btnClasses="mr-1"
|
||||
btnClasses="mr-1 !font-medium"
|
||||
on:click={contextualVariablePicker.openModal}
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
@@ -209,7 +209,7 @@
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
btnClasses="mr-1"
|
||||
btnClasses="mr-1 !font-medium"
|
||||
on:click={variablePicker.openModal}
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
@@ -221,7 +221,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
btnClasses="mx-1"
|
||||
btnClasses="mx-1 !font-medium"
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
color="light"
|
||||
@@ -235,7 +235,7 @@
|
||||
|
||||
<div>
|
||||
<Button
|
||||
btnClasses="mx-1"
|
||||
btnClasses="mx-1 !font-medium"
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
color="light"
|
||||
@@ -249,7 +249,7 @@
|
||||
|
||||
<div>
|
||||
<Button
|
||||
btnClasses="mx-1"
|
||||
btnClasses="mx-1 !font-medium"
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
color="light"
|
||||
@@ -263,7 +263,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
btnClasses="ml-1"
|
||||
btnClasses="ml-1 !font-medium"
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
color="light"
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
| undefined = undefined
|
||||
</script>
|
||||
|
||||
<h3>
|
||||
<div>
|
||||
<span class="font-semibold">
|
||||
{label}<Required {required} />
|
||||
{label}
|
||||
</span>
|
||||
<span class="text-sm italic text-indigo-800"
|
||||
>({type ?? 'any'}{contentEncoding && contentEncoding != ''
|
||||
<span class="text-sm italic text-indigo-800">
|
||||
({type ?? 'any'}{contentEncoding && contentEncoding != ''
|
||||
? `, encoding: ${contentEncoding}`
|
||||
: ''}{format && format != '' ? `, format: ${format}` : ''}{itemsType?.type
|
||||
? ` of ${itemsType?.type}s`
|
||||
: ''})</span
|
||||
>
|
||||
</h3>
|
||||
<Required {required} class="!ml-0" />
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import Icon from 'svelte-awesome'
|
||||
import { writable } from 'svelte/store'
|
||||
import CenteredPage from './CenteredPage.svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { Button } from './common'
|
||||
import { dirtyStore } from './common/confirmationModal/dirtyStore'
|
||||
import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte'
|
||||
import { OFFSET } from './CronInput.svelte'
|
||||
|
||||
@@ -54,13 +54,19 @@
|
||||
</script>
|
||||
|
||||
<Modal bind:this={modal}>
|
||||
<div slot="title">group {name}</div>
|
||||
<div slot="content">
|
||||
<PageHeader title="Summary" />
|
||||
<p>{group?.summary ?? 'No summary'}</p>
|
||||
<PageHeader title="Members">
|
||||
<div slot="title">
|
||||
{name}
|
||||
<span class="text-sm text-gray-500 ml-1">(group)</span>
|
||||
</div>
|
||||
<div slot="content" class="flex flex-col gap-6">
|
||||
<div>
|
||||
<div class="font-semibold text-gray-700 mb-1">Summary</div>
|
||||
<p>{group?.summary ?? 'No summary'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-semibold text-gray-700 mb-1">Members</div>
|
||||
{#if can_write}
|
||||
<div>
|
||||
<div class="flex items-start">
|
||||
<AutoComplete items={usernames} bind:selectedItem={username} />
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -73,34 +79,34 @@
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</PageHeader>
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th>user</th>
|
||||
<th>admin of group</th>
|
||||
<th />
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#each members as { name, isAdmin }}<tr>
|
||||
<td>{name}</td>
|
||||
<td> {isAdmin ? 'admin' : ''} </td>
|
||||
<td>
|
||||
{#if can_write}
|
||||
<button
|
||||
class="ml-2 text-red-500"
|
||||
on:click={async () => {
|
||||
await GroupService.removeUserToGroup({
|
||||
workspace: $workspaceStore ?? '',
|
||||
name: group?.name ?? '',
|
||||
requestBody: { username: name }
|
||||
})
|
||||
loadGroup()
|
||||
}}>remove</button
|
||||
>
|
||||
{/if}</td
|
||||
>
|
||||
</tr>{/each}
|
||||
</tbody></TableCustom
|
||||
>
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th>user</th>
|
||||
<th>admin of group</th>
|
||||
<th />
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#each members as { name, isAdmin }}<tr>
|
||||
<td>{name}</td>
|
||||
<td> {isAdmin ? 'admin' : ''} </td>
|
||||
<td>
|
||||
{#if can_write}
|
||||
<button
|
||||
class="ml-2 text-red-500"
|
||||
on:click={async () => {
|
||||
await GroupService.removeUserToGroup({
|
||||
workspace: $workspaceStore ?? '',
|
||||
name: group?.name ?? '',
|
||||
requestBody: { username: name }
|
||||
})
|
||||
loadGroup()
|
||||
}}>remove</button
|
||||
>
|
||||
{/if}</td
|
||||
>
|
||||
</tr>{/each}
|
||||
</tbody>
|
||||
</TableCustom>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
export let width = '24px'
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row gap-2 justify-center -pl-2 whitespace-nowrap">
|
||||
<div class="flex flex-row gap-2 justify-center items-center break-all whitespace-normal -pl-2">
|
||||
{#if !silent && !after}
|
||||
{name}
|
||||
{/if}
|
||||
@@ -44,7 +44,7 @@
|
||||
{:else if name === 'slack'}
|
||||
<Slack {height} {width} />
|
||||
{:else if name === 'github'}
|
||||
<GithubIcon />
|
||||
<GithubIcon {height} {width} />
|
||||
{:else if name === 'gmail'}
|
||||
<GmailIcon {height} {width} />
|
||||
{:else if name === 'gsheets'}
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
export let primary: boolean = true
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between mt-4 mb-2">
|
||||
<div class="flex flex-col sm:flex-row justify-between mt-4 mb-2 min-h-[48px]">
|
||||
{#if primary}
|
||||
<span class="text-xl font-bold flex items-center space-x-2">
|
||||
<span class="mr-0.5">{title}</span>
|
||||
<span class="flex items-center space-x-2">
|
||||
<h1 class="mr-0.5">{title}</h1>
|
||||
{#if tooltip}
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
{/if}
|
||||
</span>
|
||||
{:else}
|
||||
<span class="text-lg font-semibold flex items-center space-x-2">
|
||||
<span class="mr-0.5">{title}</span>
|
||||
{:else}
|
||||
<span class="flex items-center space-x-2">
|
||||
<h2 class="mr-0.5">{title}</h2>
|
||||
{#if tooltip}
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
{/if}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<label class="block text-gray-700" for="password"> {label} </label>
|
||||
<label class="block text-gray-700" for="password"> {@html label} </label>
|
||||
<div class="relative w-full">
|
||||
<div class="absolute inset-y-0 right-0 flex items-center px-2">
|
||||
<input class="hidden js-password-toggle" id="toggle" type="checkbox" />
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { sleep } from '$lib/utils'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Required from './Required.svelte'
|
||||
|
||||
type PathKind = 'resource' | 'script' | 'variable' | 'flow' | 'schedule'
|
||||
export let meta: Meta = {
|
||||
@@ -175,7 +176,7 @@
|
||||
</label>
|
||||
{#if meta.ownerKind === 'user'}
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-700">Owner</span>
|
||||
<span class="text-gray-700 text-sm">Owner</span>
|
||||
<input
|
||||
bind:value={meta.owner}
|
||||
placeholder={$userStore?.username ?? ''}
|
||||
@@ -184,7 +185,7 @@
|
||||
</label>
|
||||
{:else}
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-700">Owner</span>
|
||||
<span class="text-gray-700 text-sm">Owner</span>
|
||||
<select bind:value={meta.owner}>
|
||||
{#each groups as g}
|
||||
<option>{g.name}</option>
|
||||
@@ -193,7 +194,10 @@
|
||||
</label>
|
||||
{/if}
|
||||
<label class="block col-span-2">
|
||||
<span class="text-gray-700 text-sm">Name<span class="text-red-600 text-sm">*</span></span>
|
||||
<span class="text-gray-700 text-sm">
|
||||
Name
|
||||
<Required required={true} />
|
||||
</span>
|
||||
<input
|
||||
autofocus
|
||||
autocomplete="off"
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
</script>
|
||||
|
||||
{#if required}
|
||||
<span class="text-red-600 font-normal">*</span>
|
||||
<span class="text-red-700 font-normal {$$props.class}">*</span>
|
||||
{:else}
|
||||
<span class="text-sm text-gray-500 ml-2 font-normal"
|
||||
<span class="text-sm text-gray-500 ml-2 font-normal {$$props.class}"
|
||||
>(optional{detail != '' ? `, ${detail}` : ''})</span
|
||||
>
|
||||
{/if}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
{#if nonePickable}
|
||||
{@const isPicked = value === undefined}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={isPicked ? 'blue' : 'dark'}
|
||||
btnClasses={isPicked ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
@@ -45,13 +46,14 @@
|
||||
{#each resources as r}
|
||||
{@const isPicked = value === r}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={isPicked ? 'blue' : 'dark'}
|
||||
btnClasses={isPicked ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
disabled={notPickable}
|
||||
on:click={() => onClick(r)}
|
||||
>
|
||||
<IconedResourceType name={r} after={true} />
|
||||
<IconedResourceType name={r} after={true} width="20px" height="20px" />
|
||||
</Button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<Button
|
||||
variant="contained"
|
||||
color="blue"
|
||||
size="md"
|
||||
size="sm"
|
||||
startIcon={{ icon: faPlus }}
|
||||
on:click={() => {
|
||||
modalProperty = Object.assign({}, DEFAULT_PROPERTY)
|
||||
|
||||
@@ -98,67 +98,72 @@
|
||||
<Modal bind:this={modal} on:close={clearModal}>
|
||||
<div slot="title">Add an argument</div>
|
||||
<div slot="content">
|
||||
<div class="flex flex-col px-6 py-3 bg-gray-50">
|
||||
<label class="font-semibold text-gray-700"
|
||||
>Name<Required required={true} />
|
||||
<input
|
||||
autofocus
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="name"
|
||||
bind:value={property.name}
|
||||
class={error === ''
|
||||
? ''
|
||||
: 'border border-red-700 bg-red-100 border-opacity-30 focus:border-red-700 focus:border-opacity-30 focus-visible:ring-red-700 focus-visible:ring-opacity-25 focus-visible:border-red-700'}
|
||||
/>
|
||||
</label>
|
||||
<div class="mb-2 text-red-600 text-2xs">{error}</div>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div>
|
||||
<label class="block">
|
||||
<div class="mb-1 font-semibold text-gray-700">
|
||||
Name
|
||||
<Required required={true} />
|
||||
</div>
|
||||
<input
|
||||
autofocus
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter a name"
|
||||
bind:value={property.name}
|
||||
class={error === ''
|
||||
? ''
|
||||
: 'border border-red-700 bg-red-100 border-opacity-30 focus:border-red-700 focus:border-opacity-30 focus-visible:ring-red-700 focus-visible:ring-opacity-25 focus-visible:border-red-700'}
|
||||
/>
|
||||
</label>
|
||||
<div class="text-red-600 text-2xs">{error}</div>
|
||||
</div>
|
||||
|
||||
<label class="mb-2 font-semibold text-gray-700">
|
||||
Description
|
||||
<textarea
|
||||
class="mb-1"
|
||||
type="text"
|
||||
placeholder="Type message..."
|
||||
rows="3"
|
||||
bind:value={property.description}
|
||||
/>
|
||||
<label class="block">
|
||||
<div class="mb-1 font-semibold text-gray-700">
|
||||
Description
|
||||
<Required required={false} />
|
||||
</div>
|
||||
<textarea placeholder="Enter a description" rows="3" bind:value={property.description} />
|
||||
</label>
|
||||
<h3 class="font-semibold text-gray-700">Type<Required required={true} /></h3>
|
||||
<div class="grid sm:grid-cols-3 md:grid-cols-4 gap-x-2 gap-y-1 items-center mb-2 w-full">
|
||||
{#each ARG_TYPES as argType}
|
||||
{@const isSelected = argType == property.selectedType}
|
||||
<div>
|
||||
<div class="mb-1 font-semibold text-gray-700">Type<Required required={true} /></div>
|
||||
<div class="grid sm:grid-cols-3 md:grid-cols-4 gap-x-2 gap-y-1 items-center mb-2 w-full">
|
||||
{#each ARG_TYPES as argType}
|
||||
{@const isSelected = argType == property.selectedType}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={isSelected ? 'blue' : 'dark'}
|
||||
btnClasses={isSelected ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
on:click={() => {
|
||||
property.selectedType = argType
|
||||
property.format = undefined
|
||||
property.contentEncoding = undefined
|
||||
property.enum_ = undefined
|
||||
property.pattern = undefined
|
||||
}}
|
||||
>
|
||||
{argType}
|
||||
</Button>
|
||||
{/each}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={isSelected ? 'blue' : 'dark'}
|
||||
btnClasses={isSelected ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
color={!property.selectedType ? 'blue' : 'dark'}
|
||||
btnClasses={!property.selectedType ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
on:click={() => {
|
||||
property.selectedType = argType
|
||||
property.format = undefined
|
||||
property.contentEncoding = undefined
|
||||
property.enum_ = undefined
|
||||
property.pattern = undefined
|
||||
property.selectedType = undefined
|
||||
}}
|
||||
>
|
||||
{argType}
|
||||
any
|
||||
</Button>
|
||||
{/each}
|
||||
<Button
|
||||
variant="border"
|
||||
color={!property.selectedType ? 'blue' : 'dark'}
|
||||
btnClasses={!property.selectedType ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
on:click={() => {
|
||||
property.selectedType = undefined
|
||||
}}
|
||||
>
|
||||
Any
|
||||
</Button>
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
label={'Required'}
|
||||
textFormat={'text-md font-semibold text-gray-700'}
|
||||
class="my-2"
|
||||
class="my-2 !justify-start"
|
||||
bind:checked={property.required}
|
||||
/>
|
||||
<ArgInput
|
||||
@@ -168,27 +173,28 @@
|
||||
pattern={property.pattern}
|
||||
/>
|
||||
{#if property.selectedType !== 'boolean'}
|
||||
<h2 class="mb-2 mt-4">Advanced</h2>
|
||||
|
||||
{#if property.selectedType == 'string'}
|
||||
<StringTypeNarrowing
|
||||
bind:format={property.format}
|
||||
bind:pattern={property.pattern}
|
||||
bind:enum_={property.enum_}
|
||||
bind:contentEncoding={property.contentEncoding}
|
||||
/>
|
||||
{:else if property.selectedType == 'array'}
|
||||
<select bind:value={property.items}>
|
||||
<option value={undefined}>No specific item type</option>
|
||||
<option value={{ type: 'string' }}> Items are strings</option>
|
||||
<option value={{ type: 'number' }}>Items are numbers</option>
|
||||
</select>
|
||||
{:else if property.selectedType == 'object'}
|
||||
<h3 class="mb-2 font-bold mt-4">Resource type</h3>
|
||||
<ObjectTypeNarrowing bind:format={property.format} />
|
||||
{:else}
|
||||
<p>No advanced configuration for this type</p>
|
||||
{/if}
|
||||
<div>
|
||||
<div class="font-semibold text-gray-700 mb-1">Advanced</div>
|
||||
{#if property.selectedType == 'string'}
|
||||
<StringTypeNarrowing
|
||||
bind:format={property.format}
|
||||
bind:pattern={property.pattern}
|
||||
bind:enum_={property.enum_}
|
||||
bind:contentEncoding={property.contentEncoding}
|
||||
/>
|
||||
{:else if property.selectedType == 'array'}
|
||||
<select bind:value={property.items}>
|
||||
<option value={undefined}>No specific item type</option>
|
||||
<option value={{ type: 'string' }}> Items are strings</option>
|
||||
<option value={{ type: 'number' }}>Items are numbers</option>
|
||||
</select>
|
||||
{:else if property.selectedType == 'object'}
|
||||
<h3 class="mb-2 font-bold mt-4">Resource type</h3>
|
||||
<ObjectTypeNarrowing bind:format={property.format} />
|
||||
{:else}
|
||||
<p>No advanced configuration for this type</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -150,6 +150,8 @@
|
||||
{#if step === 1}
|
||||
<CenteredPage>
|
||||
<div class="space-y-6">
|
||||
<h1 class="mb-4">New script</h1>
|
||||
<h2 class="border-b pb-1 mt-4">General</h2>
|
||||
<Path
|
||||
bind:error={pathError}
|
||||
bind:path={script.path}
|
||||
@@ -165,7 +167,7 @@
|
||||
<a href="https://docs.windmill.dev/docs/reference/namespaces">docs</a>
|
||||
</div>
|
||||
</Path>
|
||||
<h3 class="text-gray-700 border-b">Language</h3>
|
||||
<h2 class="border-b pb-1 mt-4">Language</h2>
|
||||
<div class="max-w-md">
|
||||
<RadioButton
|
||||
label="Language"
|
||||
@@ -178,7 +180,7 @@
|
||||
bind:value={script.language}
|
||||
/>
|
||||
</div>
|
||||
<h4 class="text-gray-700 border-b">
|
||||
<h2 class="border-b pb-1 mt-4">
|
||||
Script Kind <Tooltip
|
||||
>In most cases, you will want the General Script. <br />
|
||||
Trigger are meant to be used as the first module of flows to trigger them based on watching
|
||||
@@ -188,7 +190,7 @@
|
||||
Command scripts are used when the workspace is associated with a slack workspace to be triggered
|
||||
on command.</Tooltip
|
||||
>
|
||||
</h4>
|
||||
</h2>
|
||||
|
||||
{#if script.language == 'deno'}
|
||||
<div class="max-w-lg">
|
||||
@@ -226,11 +228,11 @@
|
||||
{/if}
|
||||
|
||||
{#if script.language == 'deno' && script.kind == Script.kind.SCRIPT}
|
||||
<h4 class="text-gray-700 border-b">
|
||||
<h2 class="border-b pb-1 mt-4">
|
||||
Script Template <Tooltip
|
||||
>A template is a pre-filled script corresponding to a more specialized use-case</Tooltip
|
||||
>
|
||||
</h4>
|
||||
</h2>
|
||||
|
||||
<div class="max-w-md">
|
||||
<RadioButton
|
||||
@@ -245,44 +247,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<label class="block ">
|
||||
<span class="text-gray-700">Summary <Required required={false} /></span>
|
||||
<textarea
|
||||
bind:value={script.summary}
|
||||
class="
|
||||
mt-1
|
||||
block
|
||||
w-full
|
||||
rounded-md
|
||||
border-gray-300
|
||||
shadow-sm
|
||||
focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50
|
||||
"
|
||||
placeholder="A very short summary of the script displayed when the script is listed"
|
||||
rows="1"
|
||||
/>
|
||||
</label>
|
||||
<label class="block" for="inp">
|
||||
<span class="text-gray-700"
|
||||
>Description<Required required={false} detail="accept markdown formatting" />
|
||||
<textarea
|
||||
id="inp"
|
||||
bind:value={script.description}
|
||||
class="
|
||||
mt-1
|
||||
block
|
||||
w-full
|
||||
rounded-md
|
||||
border-gray-300
|
||||
shadow-sm
|
||||
focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50
|
||||
"
|
||||
placeholder="A description to help users understand what this script does and how to use it."
|
||||
rows="3"
|
||||
/>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="block">
|
||||
<span class="text-gray-700 mr-2"
|
||||
>Save as workspace template <Tooltip
|
||||
@@ -292,14 +256,39 @@
|
||||
<input type="checkbox" bind:checked={script.is_template} />
|
||||
</label>
|
||||
|
||||
<label class="block ">
|
||||
<span class="text-gray-700 text-sm">Summary <Required required={false} /></span>
|
||||
<textarea
|
||||
bind:value={script.summary}
|
||||
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300
|
||||
focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||
placeholder="A very short summary of the script displayed when the script is listed"
|
||||
rows="1"
|
||||
/>
|
||||
</label>
|
||||
<label class="block" for="inp">
|
||||
<span class="text-gray-700 text-sm">
|
||||
Description<Required required={false} detail="markdown" />
|
||||
<textarea
|
||||
id="inp"
|
||||
bind:value={script.description}
|
||||
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300
|
||||
focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||
placeholder="A description to help users understand what this script does and how to use it."
|
||||
rows="3"
|
||||
/>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<h3 class="text-gray-700 ">Description rendered</h3>
|
||||
<div
|
||||
class="prose mt-5 text-xs shadow-inner shadow-blue p-4 overflow-auto"
|
||||
style="max-height: 200px;"
|
||||
>
|
||||
<SvelteMarkdown source={script.description ?? ''} />
|
||||
</div>
|
||||
<div class="font-bold pb-1 mt-4">Description preview</div>
|
||||
{#if script.description}
|
||||
<div class="prose max-h-48 mt-5 text-xs shadow-inner shadow-blue p-4 overflow-auto">
|
||||
<SvelteMarkdown source={script.description} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-sm text-gray-500"> Enter a description to see the preview </div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</CenteredPage>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
import { HSplitPane, VSplitPane } from 'svelte-split-pane'
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import EditorBar from './EditorBar.svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import TestJobLoader from './TestJobLoader.svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import { Button, Kbd } from './common'
|
||||
|
||||
// Exported
|
||||
export let schema: Schema = emptySchema()
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<div class="border-b shadow-sm p-1 pr-4">
|
||||
<div class="border-b-2 shadow-sm p-1 pr-4">
|
||||
<div class="flex justify-between">
|
||||
<EditorBar {editor} {lang} {websocketAlive} />
|
||||
|
||||
@@ -159,12 +159,10 @@
|
||||
<div class="h-full overflow-auto">
|
||||
<div class="p-4">
|
||||
<div class="break-all relative font-sans">
|
||||
<div class="items-baseline text-xs text-gray-700 italic hidden md:block">
|
||||
<p>
|
||||
Move the focus outside of the text editor to recompute the input schema from
|
||||
main signature or press Ctrl/Cmd+S
|
||||
</p>
|
||||
</div>
|
||||
<p class="items-baseline break-normal text-sm text-gray-600 hidden md:block mb-3">
|
||||
To recompute the input schema press <Kbd>Ctrl/Cmd</Kbd> + <Kbd>S</Kbd> or move the
|
||||
focus outside of the text editor
|
||||
</p>
|
||||
<SchemaForm {schema} bind:args bind:isValid />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,37 +21,36 @@
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<PageHeader title="UI customisation" />
|
||||
<h1 class="mb-4">UI customisation</h1>
|
||||
|
||||
<Tabs selected="ui">
|
||||
<Tab value="ui">UI</Tab>
|
||||
<Tab value="jsonschema">JSON Schema</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
<TabContent value="ui">
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div>
|
||||
<h2 class="mb-1">Summary</h2>
|
||||
<div class="mb-2 md:mb-3 text-sm">
|
||||
<textarea bind:value={summary} placeholder="Edit summary" />
|
||||
<div class="prose text-sm">
|
||||
{summary != '' ? summary : 'No summary'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<h2 class="mb-1">Description</h2>
|
||||
<div class="mb-2 md:mb-6">
|
||||
<div class="prose text-sm">
|
||||
<textarea bind:value={description} placeholder="Edit description" />
|
||||
<div class="prose text-sm">
|
||||
<SvelteMarkdown
|
||||
source={description && description != '' ? description : 'No description'}
|
||||
/>
|
||||
<h2 class="border-b pb-1 mt-6">Display</h2>
|
||||
<div class="grid grid-cols-3 gap-2 mt-4">
|
||||
<label>
|
||||
<div class="text-gray-700 text-sm">Summary</div>
|
||||
<textarea bind:value={summary} placeholder="Edit summary" class="text-sm" />
|
||||
</label>
|
||||
<label class="col-span-2">
|
||||
<div class="text-gray-700 text-sm">Description</div>
|
||||
<textarea bind:value={description} placeholder="Edit description" class="text-sm" />
|
||||
<div class="mt-1 px-2">
|
||||
{#if description}
|
||||
<div
|
||||
class="prose !max-w-full !max-h-48 text-xs shadow-inner shadow-blue overflow-auto mt-1"
|
||||
>
|
||||
<SvelteMarkdown source={description} />
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-xs text-gray-500"> Enter a description to see the preview </div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<h2 class="border-b pb-1 mt-6">Arguments</h2>
|
||||
<div class="bg-blue-100 border-l-4 border-blue-600 text-blue-700 p-4 m-4" role="alert">
|
||||
<p class="font-bold">Synchronized with main signature</p>
|
||||
<p>
|
||||
|
||||
@@ -80,46 +80,50 @@
|
||||
</script>
|
||||
|
||||
<Modal bind:this={modal}>
|
||||
<div slot="title">Share {path}</div>
|
||||
<div slot="title">
|
||||
Share {path}
|
||||
<span class="text-sm text-gray-500 ml-1">(group)</span>
|
||||
</div>
|
||||
|
||||
<div slot="content">
|
||||
<div class="flex flex-row pb-0 mb-5 justify-between">
|
||||
<label class="block">
|
||||
<span class="text-gray-700 text-sm"> Owner Kind </span>
|
||||
|
||||
<select
|
||||
class="block mt-2 w-20"
|
||||
bind:value={ownerKind}
|
||||
on:change={() => {
|
||||
if (ownerKind === 'group') {
|
||||
owner = 'all'
|
||||
} else {
|
||||
owner = ''
|
||||
}
|
||||
}}
|
||||
>
|
||||
<option>user</option>
|
||||
<option>group</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="block grow mx-2" for="inp">
|
||||
<span class="text-sm text-gray-700">Owner</span>
|
||||
<div class="block mt-1">
|
||||
<div class="static z-50">
|
||||
<AutoComplete
|
||||
items={ownerKind === 'user' ? usernames : groups}
|
||||
bind:selectedItem={owner}
|
||||
/>
|
||||
<div class="flex flex-row flex-wrap pb-0 mb-5 justify-between">
|
||||
<div class="flex gap-4 mr-2">
|
||||
<label class="block">
|
||||
<span class="text-gray-700 text-sm"> Owner Kind </span>
|
||||
<select
|
||||
class="block mt-1 w-20"
|
||||
bind:value={ownerKind}
|
||||
on:change={() => {
|
||||
if (ownerKind === 'group') {
|
||||
owner = 'all'
|
||||
} else {
|
||||
owner = ''
|
||||
}
|
||||
}}
|
||||
>
|
||||
<option>user</option>
|
||||
<option>group</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="block" for="inp">
|
||||
<span class="text-sm text-gray-700">Owner</span>
|
||||
<div class="block mt-1">
|
||||
<div class="static z-50">
|
||||
<AutoComplete
|
||||
items={ownerKind === 'user' ? usernames : groups}
|
||||
bind:selectedItem={owner}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-700">Editor</span>
|
||||
<input class="block mt-4" type="checkbox" bind:checked={write} />
|
||||
</label>
|
||||
<Button size="sm" btnClasses="ml-2" on:click={() => addAcl(newOwner, write)}>
|
||||
Add permission
|
||||
</Button>
|
||||
</label>
|
||||
<label class="flex flex-col grow pb-3 justify-between">
|
||||
<div class="text-sm text-gray-700">Editor</div>
|
||||
<input class="block ml-1" type="checkbox" bind:checked={write} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="center-center">
|
||||
<Button size="sm" on:click={() => addAcl(newOwner, write)}>Add permission</Button>
|
||||
</div>
|
||||
</div>
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
@@ -132,11 +136,11 @@
|
||||
<tr>
|
||||
<td>{owner}</td>
|
||||
<td>{write}</td>
|
||||
<td
|
||||
><Button variant="border" color="blue" size="sm" on:click={() => deleteAcl(owner)}
|
||||
>Delete</Button
|
||||
></td
|
||||
>
|
||||
<td>
|
||||
<Button variant="border" color="red" size="sm" on:click={() => deleteAcl(owner)}>
|
||||
Delete
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
|
||||
@@ -115,59 +115,63 @@
|
||||
</div>
|
||||
|
||||
<div slot="content">
|
||||
<div class="text-gray-700 text-2xs mb-6">
|
||||
Variables have a globally unique name represented by their path. When passed to scripts, <pre
|
||||
class="inline text-red-700 bg-gray-50 rounded round-sm">/</pre
|
||||
>
|
||||
are converted to
|
||||
<pre class="inline text-red-700 bg-gray-50 rounded round-sm">_</pre>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2 ">
|
||||
<div class="flex flex-col gap-6">
|
||||
<div>
|
||||
<div class="text-gray-700 mb-0 pb-0">path</div>
|
||||
<Path
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
{initialPath}
|
||||
namePlaceholder="my_variable"
|
||||
kind="variable"
|
||||
/>
|
||||
<div>
|
||||
<div class="mb-1 font-semibold text-gray-700">General</div>
|
||||
<Path
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
{initialPath}
|
||||
namePlaceholder="my_variable"
|
||||
kind="variable"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="block">
|
||||
<span class="text-sm mr-1">Secret</span>
|
||||
<input type="checkbox" bind:checked={variable.is_secret} />
|
||||
</label>
|
||||
{#if variable.is_secret}
|
||||
<div
|
||||
class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-1 mt-1 text-sm"
|
||||
role="alert"
|
||||
>
|
||||
If the variable is a secret, you will not be able to read the value of it from the
|
||||
variable editor UI but only within scripts.
|
||||
<Tooltip>
|
||||
Within scripts, every read of the value create the audit log:
|
||||
'variables.decrypt_secret'
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="block pb-6">
|
||||
<input type="checkbox" bind:checked={variable.is_secret} />
|
||||
<span class="ml-2">Secret</span>
|
||||
{#if variable.is_secret}
|
||||
<div
|
||||
class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-1 mt-1 text-sm"
|
||||
role="alert"
|
||||
>
|
||||
When a secret, you will not be able to read this variable value from the variable editor
|
||||
UI but only within scripts. <Tooltip>
|
||||
Within scripts, every read of the value create the audit log:
|
||||
'variables.decrypt_secret'</Tooltip
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</label>
|
||||
{#if variable.is_secret}
|
||||
<div class="font-semibold text-gray-700 col-span-10 }">
|
||||
<div class="mb-1 col-span-10">
|
||||
<Password
|
||||
bind:password={variable.value}
|
||||
placeholder={'******** (only fill to update value)'}
|
||||
label={`Secret value (${variable.value.length}/3000 characters)`}
|
||||
label={`<span class="font-semibold text-gray-700">Secret value</span>
|
||||
<span class="text-sm text-gray-500">(${variable.value.length}/3000 characters)</span>`}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
<span>Variable value ({variable.value.length}/3000 characters)</span>
|
||||
<div class="mb-1">
|
||||
<span class="font-semibold text-gray-700">Variable value</span>
|
||||
<span class="text-sm text-gray-500">({variable.value.length}/3000 characters)</span>
|
||||
</div>
|
||||
<AutosizedTextarea bind:value={variable.value} minRows={5} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<span class="text-gray-700">Description<Required required={false} /></span>
|
||||
<div>
|
||||
<div class="mb-1 font-semibold text-gray-700">
|
||||
Description
|
||||
<Required required={false} />
|
||||
</div>
|
||||
<AutosizedTextarea bind:value={variable.description} placeholder={''} minRows={3} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -51,11 +51,10 @@
|
||||
variant === 'border' ? 'border' : '',
|
||||
ButtonType.FontSizeClasses[size],
|
||||
ButtonType.SpacingClasses[spacingSize],
|
||||
'focus:ring-4 font-medium',
|
||||
'focus:ring-4 font-semibold',
|
||||
'rounded-md',
|
||||
'flex justify-center items-center text-center whitespace-nowrap',
|
||||
btnClasses,
|
||||
disabled ? 'pointer-events-none cursor-default filter grayscale' : ''
|
||||
btnClasses
|
||||
),
|
||||
disabled,
|
||||
href,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<kbd
|
||||
class="mx-1 px-2 py-1.5 text-xs font-semibold text-gray-800
|
||||
class="mx-1 px-2 py-1 text-xs font-mono font-semibold text-gray-800
|
||||
bg-gray-100 border border-gray-200 rounded-lg
|
||||
dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500 {$$props.class}"
|
||||
>
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between py-2 px-4 border-b bg-gray-50 shadow-sm space-x-2 h-12 flex-nowrap"
|
||||
>
|
||||
<div class="flex items-center justify-between py-2 px-4 border-b space-x-2 h-12 flex-nowrap">
|
||||
{#if flowModule}
|
||||
<span class="text-sm w-full">
|
||||
<div class="flex items-center space-x-2">
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
/>
|
||||
{:else}
|
||||
{#if flowModule.value.type === 'rawscript'}
|
||||
<div class="flex-shrink-0 border-b p-1">
|
||||
<div class="flex-shrink-0 border-b-2 shadow-sm p-1 mb-1">
|
||||
<EditorBar
|
||||
{editor}
|
||||
lang={flowModule.value['language'] ?? 'deno'}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</Path>
|
||||
|
||||
<label class="block my-4">
|
||||
<span class="text-gray-700">Summary <Required required={false} /></span>
|
||||
<span class="text-gray-700 text-sm">Summary <Required required={false} /></span>
|
||||
<textarea
|
||||
bind:value={$flowStore.summary}
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||
@@ -46,20 +46,14 @@
|
||||
</label>
|
||||
|
||||
<label class="block my-4" for="inp">
|
||||
<span class="text-gray-700"
|
||||
>Description<Required required={false} detail="accept markdown formatting" />
|
||||
<span class="text-gray-700 text-sm">
|
||||
Description
|
||||
<Required required={false} detail="markdown" />
|
||||
<textarea
|
||||
id="inp"
|
||||
bind:value={$flowStore.description}
|
||||
class="
|
||||
mt-1
|
||||
block
|
||||
w-full
|
||||
rounded-md
|
||||
border-gray-300
|
||||
shadow-sm
|
||||
focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50
|
||||
"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300
|
||||
focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||
placeholder="A description to help users understand what this script does and how to use it."
|
||||
rows="3"
|
||||
/>
|
||||
@@ -67,13 +61,14 @@
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<h3 class="text-gray-700 ">Description rendered</h3>
|
||||
<div
|
||||
class="prose mt-5 text-xs shadow-inner shadow-blue p-4 overflow-auto"
|
||||
style="max-height: 200px;"
|
||||
>
|
||||
<SvelteMarkdown source={$flowStore.description ?? ''} />
|
||||
</div>
|
||||
<div class="font-bold pb-1 mt-4">Description preview</div>
|
||||
{#if $flowStore.description}
|
||||
<div class="prose max-h-48 mt-5 text-xs shadow-inner shadow-blue p-4 overflow-auto">
|
||||
<SvelteMarkdown source={$flowStore.description} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-sm text-gray-500"> Enter a description to see the preview </div>
|
||||
{/if}
|
||||
</div>
|
||||
</TabContent>
|
||||
<TabContent value="schedule" class="p-4">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<Menu placement="bottom-end">
|
||||
<button
|
||||
slot="trigger"
|
||||
class="flex items-center text-sm border focus:outline-none focus:ring-4 font-medium rounded-md text-gray-800 bg-white hover:bg-gray-100 focus:ring-gray-300 px-4 py-2"
|
||||
class="flex items-center text-sm border focus:outline-none focus:ring-4 rounded-md
|
||||
text-gray-800 bg-white hover:bg-gray-100 focus:ring-gray-300 px-4 py-2"
|
||||
>
|
||||
Import/Export
|
||||
</button>
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<h3 class="break-all py-2">
|
||||
<div class="break-all py-2">
|
||||
{#if job.script_path}
|
||||
<a class="pr-3" href="/run/{job.id}">{job.script_path} </a>
|
||||
{:else if 'job_kind' in job && job.job_kind == 'preview'}
|
||||
@@ -104,7 +104,7 @@
|
||||
><a href="/run/{job.parent_job}">step of flow</a></span
|
||||
>
|
||||
{/if}
|
||||
</h3>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50 ">
|
||||
<div class="flex items-center">
|
||||
<h3 class="inline-flex items-center text-lg font-medium text-gray-700 ">
|
||||
<h3 class="inline-flex items-center font-semibold">
|
||||
<HatIcon class="w-6 h-6 mr-2" />
|
||||
Getting started
|
||||
</h3>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50 dark:border-gray-600 dark:bg-gray-700">
|
||||
<div class="flex items-center">
|
||||
<h3 class="inline-flex items-center text-lg font-medium text-gray-700 ">
|
||||
<h3 class="inline-flex items-center font-semibold">
|
||||
<HatIcon class="w-6 h-6 mr-2" />
|
||||
Getting started
|
||||
</h3>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50 ">
|
||||
<div class="flex items-center">
|
||||
<h3 class="inline-flex items-center text-lg font-medium text-gray-700 ">
|
||||
<h3 class="inline-flex items-center font-semibold">
|
||||
<HatIcon class="w-6 h-6 mr-2" />
|
||||
Getting started
|
||||
</h3>
|
||||
|
||||
@@ -47,7 +47,10 @@
|
||||
<ul class="w-full">
|
||||
{#each keys as key, index}
|
||||
<li class="pt-1">
|
||||
<button on:click={() => selectProp(key)} class="key rounded px-1 hover:bg-blue-100">
|
||||
<button
|
||||
on:click={() => selectProp(key)}
|
||||
class="key font-normal rounded px-1 hover:bg-blue-100"
|
||||
>
|
||||
{!isArray ? key : index}:
|
||||
</button>
|
||||
|
||||
|
||||
@@ -28,20 +28,22 @@
|
||||
</button>
|
||||
|
||||
<div class="divide-y divide-gray-100" role="none">
|
||||
{#each $usersWorkspaceStore?.workspaces ?? [] as workspace}
|
||||
<button
|
||||
on:click={() => {
|
||||
workspaceStore.set(workspace.id)
|
||||
close()
|
||||
}}
|
||||
class="block px-4 py-2 text-xs text-gray-500 "
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span class="text-gray-300 font-mono pr-1 text-xs">{workspace.id}</span>
|
||||
{workspace.name}
|
||||
</button>
|
||||
{/each}
|
||||
<table class="w-full">
|
||||
{#each $usersWorkspaceStore?.workspaces ?? [] as workspace}
|
||||
<tr
|
||||
class="text-xs cursor-pointer"
|
||||
on:click={() => {
|
||||
workspaceStore.set(workspace.id)
|
||||
close()
|
||||
}}
|
||||
>
|
||||
<td class="text-gray-300 font-mono pl-4 pr-1 py-2 text-xs whitespace-nowrap"
|
||||
>{workspace.id}</td
|
||||
>
|
||||
<td class="text-gray-500 pr-4 py-2 w-full">{workspace.name}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
<div class="py-1" role="none">
|
||||
<a
|
||||
href="/user/create_workspace"
|
||||
|
||||
@@ -179,23 +179,24 @@
|
||||
{#each tab == 'all' ? ['personal', 'groups', 'shared', 'hub'] : [tab] as sectionTab}
|
||||
<div class="shadow p-4 my-2">
|
||||
{#if sectionTab == 'personal'}
|
||||
<h2 class="mb-2">
|
||||
Personal <span class="text-sm"
|
||||
>({`u/${$userStore?.username}`}) <Tooltip>
|
||||
<h2>
|
||||
<span class="text-lg xl:text-xl">Personal</span>
|
||||
<span class="text-sm">
|
||||
({`u/${$userStore?.username}`}) <Tooltip>
|
||||
All flows owned by you (and visible only to you if you do not explicitly share them)
|
||||
</Tooltip></span
|
||||
>
|
||||
</h2>
|
||||
{:else if sectionTab == 'groups'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Groups <Tooltip>All flows being owned by groups that you are member of</Tooltip>
|
||||
</h2>
|
||||
{:else if sectionTab == 'shared'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Shared <Tooltip>All flows visible to you because they have been shared to you</Tooltip>
|
||||
</h2>
|
||||
{:else if sectionTab == 'hub'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Approved flows from the WindmillHub <Tooltip>
|
||||
All approved Flow from the <a href="https://hub.windmill.dev">WindmillHub</a>.
|
||||
Approved flows have been potentially contributed by the community but reviewed and
|
||||
@@ -203,7 +204,7 @@
|
||||
</Tooltip>
|
||||
</h2>
|
||||
<input placeholder="Search hub flows" bind:value={hubFilter} class="search-bar mt-2" />
|
||||
<div class="relative">
|
||||
<div class="relative mt-2">
|
||||
{#if loading.hub}
|
||||
<Skeleton
|
||||
loading={loading.hub}
|
||||
@@ -249,7 +250,7 @@
|
||||
{/if}
|
||||
{#each groupedFlows.filter((x) => tabFromPath(x[0]) == sectionTab) as [section, flows]}
|
||||
{#if sectionTab != 'personal'}
|
||||
<h3 class="mt-2 mb-2">
|
||||
<div class="font-bold text-gray-700 mt-2 mb-2">
|
||||
{section}
|
||||
{#if section == 'g/all'}
|
||||
<Tooltip
|
||||
@@ -258,18 +259,18 @@
|
||||
are private user namespaces.</Tooltip
|
||||
>
|
||||
{/if}
|
||||
</h3>
|
||||
</div>
|
||||
{/if}
|
||||
{#if loading.general}
|
||||
<div class="grid gap-4 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div class="grid gap-4 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-3 mt-2">
|
||||
{#each new Array(3) as _}
|
||||
<Skeleton layout={[[7.6]]} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else if flows.length == 0 && sectionTab == 'personal'}
|
||||
<p class="text-xs text-gray-600 italic">No flows yet</p>
|
||||
<p class="text-xs text-gray-600 italic mt-2">No flows yet</p>
|
||||
{:else}
|
||||
<div class="grid md:grid-cols-2 gap-4 sm:grid-cols-1 xl:grid-cols-3">
|
||||
<div class="grid md:grid-cols-2 gap-4 sm:grid-cols-1 xl:grid-cols-3 mt-2">
|
||||
{#each flows as { summary, path, extra_perms, canWrite }}
|
||||
<div
|
||||
class="flex flex-col justify-between max-w-lg overflow-visible
|
||||
|
||||
@@ -55,15 +55,11 @@
|
||||
</script>
|
||||
|
||||
<CenteredPage>
|
||||
<h1 class="text-xl font-extrabold tracking-tight leading-none text-gray-900 md:text-3xl">Home</h1>
|
||||
<h1 class="flex items-center min-h-[48px] font-black my-4">Home</h1>
|
||||
<div class="space-y-12">
|
||||
<div>
|
||||
<h2
|
||||
class="mb-4 text-lg font-extrabold tracking-tight leading-none text-gray-900 md:text-2xl border-b py-2"
|
||||
>
|
||||
<span class="text-transparent bg-clip-text bg-gradient-to-r to-blue-500 from-blue-600">
|
||||
Scripts
|
||||
</span>
|
||||
<h2 class="border-b mb-4 py-2">
|
||||
<span class="text-blue-gradient">Scripts</span>
|
||||
</h2>
|
||||
<ScriptGettingStarted />
|
||||
|
||||
@@ -95,12 +91,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2
|
||||
class="mb-4 text-lg font-extrabold tracking-tight leading-none text-gray-900 md:text-2xl border-b py-2 "
|
||||
>
|
||||
<span class="text-transparent bg-clip-text bg-gradient-to-r to-blue-500 from-blue-600">
|
||||
Flows
|
||||
</span>
|
||||
<h2 class="border-b mb-4 py-2">
|
||||
<span class="text-blue-gradient">Flows</span>
|
||||
</h2>
|
||||
<FlowGettingStarted />
|
||||
<div class="mt-6 mb-2 text-md font-bold text-gray-900 ">Latest flows:</div>
|
||||
@@ -132,12 +124,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2
|
||||
class="mb-4 text-lg font-extrabold tracking-tight leading-none text-gray-900 md:text-2xl border-b py-2 "
|
||||
>
|
||||
<span class="text-transparent bg-clip-text bg-gradient-to-r to-blue-500 from-blue-600">
|
||||
Resources
|
||||
</span>
|
||||
<h2 class="border-b mb-4 py-2">
|
||||
<span class="text-blue-gradient">Resources</span>
|
||||
</h2>
|
||||
|
||||
{#if resources.length === 0}
|
||||
@@ -145,12 +133,8 @@
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<h2
|
||||
class="mb-4 text-lg font-extrabold tracking-tight leading-none text-gray-900 md:text-2xl border-b py-2 "
|
||||
>
|
||||
<span class="text-transparent bg-clip-text bg-gradient-to-r to-blue-500 from-blue-600">
|
||||
Runs
|
||||
</span>
|
||||
<h2 class="border-b mb-4 py-2">
|
||||
<span class="text-blue-gradient">Runs</span>
|
||||
</h2>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 my-4">
|
||||
|
||||
@@ -334,24 +334,28 @@
|
||||
<div slot="title">{resourceViewerTitle}</div>
|
||||
<div slot="content">
|
||||
{#if typeModalMode === 'create'}
|
||||
<label for="inp"
|
||||
><h3 class="font-semibold text-gray-700">Name<Required required={true} /></h3>
|
||||
<div>
|
||||
<span
|
||||
class="border border-gray-700 rounded p-1 -mr-4 text-sm bg-gray-200 inline-block w-8"
|
||||
>c_</span
|
||||
>
|
||||
<div class="inline-block">
|
||||
<input id="inp" type="text" bind:value={newResourceTypeName} />
|
||||
<div class="flex flex-col gap-6">
|
||||
<label for="inp">
|
||||
<div class="mb-1 font-semibold text-gray-700">Name<Required required={true} /></div>
|
||||
<div>
|
||||
<span
|
||||
class="border border-gray-700 rounded p-1 -mr-4 text-sm bg-gray-200 inline-block w-8"
|
||||
>c_</span
|
||||
>
|
||||
<div class="inline-block">
|
||||
<input id="inp" type="text" bind:value={newResourceTypeName} />
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label>
|
||||
<div class="mb-1 font-semibold text-gray-700">Description</div>
|
||||
<input type="text" bind:value={newResourceTypeDescription} /></label
|
||||
>
|
||||
<div>
|
||||
<div class="mb-1 font-semibold text-gray-700">Schema</div>
|
||||
<SchemaEditor bind:schema={newResourceTypeSchema} />
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
><h3 class="mt-4 font-semibold text-gray-700">Description</h3>
|
||||
<input type="text" bind:value={newResourceTypeDescription} /></label
|
||||
>
|
||||
<h3 class="mt-4 mb-2 font-semibold text-gray-700">Schema</h3>
|
||||
<SchemaEditor bind:schema={newResourceTypeSchema} />
|
||||
</div>
|
||||
{:else if typeModalMode === 'view'}
|
||||
<Highlight language={json} code={JSON.stringify(resourceViewerSchema, null, 4)} />
|
||||
{:else if typeModalMode === 'view-type'}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import JobDetail from '$lib/components/jobs/JobDetail.svelte'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import Tooltip from '../../lib/components/Tooltip.svelte'
|
||||
|
||||
let jobs: Job[] | undefined
|
||||
let error: Error | undefined
|
||||
@@ -145,17 +146,19 @@
|
||||
</script>
|
||||
|
||||
<CenteredPage>
|
||||
<PageHeader
|
||||
title="Runs {path ? `of ${path}` : ''}"
|
||||
tooltip="Below is NOT all the runs that have ever been run. You only see the runs whose execution has
|
||||
been permissioned with privilege that you are allowed to see. In most cases, it will only be
|
||||
your personal runs, scheduled runs of groups that you are member of, and runs that are
|
||||
permissioned at the group level of a group you are a member of. Hence, you can safely run
|
||||
script with sensitive logs knowing that only the users with the relevant permissions would see
|
||||
it. The permission of a run constraint the ephemeral bearer token that is passed to at
|
||||
execution time of that run. This is why runs with less permissions are less sensitive because
|
||||
the bearer token they use has less privilege."
|
||||
/>
|
||||
<div class="flex items-center min-h-[48px] my-4">
|
||||
<h1 class="mr-1">Runs {path ? `of ${path}` : ''}</h1>
|
||||
<Tooltip>
|
||||
Below is NOT all the runs that have ever been run. You only see the runs whose execution has
|
||||
been permissioned with privilege that you are allowed to see. In most cases, it will only be
|
||||
your personal runs, scheduled runs of groups that you are member of, and runs that are
|
||||
permissioned at the group level of a group you are a member of. Hence, you can safely run
|
||||
script with sensitive logs knowing that only the users with the relevant permissions would see
|
||||
it. The permission of a run constraint the ephemeral bearer token that is passed to at
|
||||
execution time of that run. This is why runs with less permissions are less sensitive because
|
||||
the bearer token they use has less privilege.
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7x">
|
||||
<div class="flex flex-row space-x-4">
|
||||
|
||||
@@ -111,11 +111,11 @@
|
||||
</script>
|
||||
|
||||
<CenteredPage>
|
||||
<PageHeader title={edit ? 'Edit schedule ' + path : 'New schedule'} />
|
||||
<h1 class="mb-4">{edit ? 'Edit schedule ' + path : 'New schedule'}</h1>
|
||||
|
||||
<div>
|
||||
{#if !edit}
|
||||
<h2>Save schedule as</h2>
|
||||
<h2 class="border-b pb-1 mt-8 mb-2">Save schedule as</h2>
|
||||
|
||||
<Path
|
||||
bind:error={pathError}
|
||||
@@ -134,7 +134,7 @@
|
||||
>
|
||||
{/if}
|
||||
|
||||
<h2 class="my-2 md:mt-6">Script</h2>
|
||||
<h2 class="border-b pb-1 mt-8 mb-2">Script</h2>
|
||||
<p class="text-xs mb-1 text-gray-600">
|
||||
Pick a script or flow to be triggered by the schedule<Required required={true} />
|
||||
</p>
|
||||
@@ -144,8 +144,8 @@
|
||||
bind:itemKind
|
||||
bind:scriptPath={script_path}
|
||||
/>
|
||||
<div class="max-w-5xl {edit ? '' : 'mt-2 md:mt-6'}">
|
||||
<h2>Arguments</h2>
|
||||
<div class={edit ? '' : 'mt-2 md:mt-6'}>
|
||||
<h2 class="border-b pb-1 mt-8 mb-2">Arguments</h2>
|
||||
{#if runnable}
|
||||
{#if runnable?.schema && runnable.schema.properties && Object.keys(runnable.schema.properties).length > 0}
|
||||
<SchemaForm schema={runnable.schema} bind:isValid bind:args />
|
||||
@@ -160,8 +160,9 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<h2 class="mt-2 md:mt-6">
|
||||
Schedule<Tooltip>Schedules use CRON syntax. Seconds are mandatory.</Tooltip>
|
||||
<h2 class="border-b pb-1 mt-8 mb-2">
|
||||
<span class="mr-1">Schedule</span>
|
||||
<Tooltip>Schedules use CRON syntax. Seconds are mandatory.</Tooltip>
|
||||
</h2>
|
||||
<CronInput bind:schedule bind:validCRON />
|
||||
<div class="flex flex-row-reverse mt-2 ">
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</script>
|
||||
|
||||
<CenteredPage>
|
||||
<PageHeader title="Schedule">
|
||||
<PageHeader title="Schedules">
|
||||
<Button size="sm" startIcon={{ icon: faPlus }} href="/schedule/add">New schedule</Button>
|
||||
</PageHeader>
|
||||
<div class="relative mt-10">
|
||||
|
||||
@@ -187,32 +187,33 @@
|
||||
{#each tab == 'all' ? ['personal', 'groups', 'shared', 'examples', 'hub'] : [tab] as sectionTab}
|
||||
<div class="shadow p-4 my-2">
|
||||
{#if sectionTab == 'personal'}
|
||||
<h2 class="mb-2">
|
||||
Personal <span class="text-sm"
|
||||
>({`u/${$userStore?.username}`}) <Tooltip>
|
||||
<h2>
|
||||
<span class="text-lg xl:text-xl">Personal</span>
|
||||
<span class="text-sm">
|
||||
({`u/${$userStore?.username}`}) <Tooltip>
|
||||
All scripts owned by you (and visible only to you if you do not explicitly share
|
||||
them)
|
||||
</Tooltip></span
|
||||
>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</h2>
|
||||
{:else if sectionTab == 'groups'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Groups <Tooltip>All scripts being owned by groups that you are member of</Tooltip>
|
||||
</h2>
|
||||
{:else if sectionTab == 'shared'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Shared <Tooltip>All scripts visible to you because they have been shared to you</Tooltip
|
||||
>
|
||||
</h2>
|
||||
{:else if sectionTab == 'examples'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Public <Tooltip>
|
||||
Template and examples shared across all workspaces of this instance. They are managed
|
||||
from a special workspace called 'starter' that only superadmin can change.
|
||||
</Tooltip>
|
||||
</h2>
|
||||
{:else if sectionTab == 'hub'}
|
||||
<h2 class="">
|
||||
<h2 class="text-lg xl:text-xl">
|
||||
Approved scripts from the WindmillHub <Tooltip>
|
||||
All approved Deno scripts from the <a href="https://hub.windmill.dev">WindmillHub</a>.
|
||||
Approved scripts have been reviewed by the Windmill team and are safe to use in
|
||||
@@ -266,7 +267,7 @@
|
||||
{/if}
|
||||
{#each sectionTab == 'examples' ? communityScripts : groupedScripts.filter((x) => tabFromPath(x[0]) == sectionTab) as [section, scripts]}
|
||||
{#if sectionTab != 'personal' && sectionTab != 'examples'}
|
||||
<h3 class="mt-2 mb-2">
|
||||
<div class="font-bold text-gray-700 mt-2 mb-2">
|
||||
{section}
|
||||
{#if section == 'g/all'}
|
||||
<Tooltip
|
||||
@@ -275,18 +276,18 @@
|
||||
are private user namespaces.</Tooltip
|
||||
>
|
||||
{/if}
|
||||
</h3>
|
||||
</div>
|
||||
{/if}
|
||||
{#if loading}
|
||||
<div class="grid gap-4 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div class="grid gap-4 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-3 mt-2">
|
||||
{#each new Array(3) as _}
|
||||
<Skeleton layout={[[8.5]]} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else if scripts.length == 0 && sectionTab == 'personal'}
|
||||
<p class="text-xs text-gray-600 italic">No scripts yet</p>
|
||||
<p class="text-xs text-gray-600 italic mt-2">No scripts yet</p>
|
||||
{:else}
|
||||
<div class="grid md:grid-cols-2 gap-4 sm:grid-cols-1 xl:grid-cols-3">
|
||||
<div class="grid md:grid-cols-2 gap-4 sm:grid-cols-1 xl:grid-cols-3 mt-2">
|
||||
{#each scripts as { summary, path, hash, language, extra_perms, canWrite, lock_error_logs, kind }}
|
||||
<div
|
||||
class="flex flex-col justify-between gap-2 max-w-lg overflow-visible shadow-sm shadow-blue-100
|
||||
|
||||
@@ -391,8 +391,8 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg mb-1 font-bold text-gray-600">
|
||||
Arguments JSON schema
|
||||
<Tooltip>
|
||||
The jsonschema defines the constraints that the payload must respect to be compatible with
|
||||
@@ -400,21 +400,21 @@
|
||||
script jsonschema. See
|
||||
<a href="https://json-schema.org/"> jsonschema documentation </a>
|
||||
</Tooltip>
|
||||
</h3>
|
||||
</h2>
|
||||
<Skeleton {loading} layout={[[15]]} />
|
||||
{#if script}
|
||||
<SchemaViewer schema={script.schema} />
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">Code</h3>
|
||||
<h2 class="text-lg mb-1 font-bold text-gray-600 border-b">Code</h2>
|
||||
<Skeleton {loading} layout={[[20]]} />
|
||||
{#if script}
|
||||
<HighlightCode language={script.language} code={script.content} />
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">Dependencies lock file</h3>
|
||||
<h2 class="text-lg mb-1 font-bold text-gray-600 border-b">Dependencies lock file</h2>
|
||||
<Skeleton {loading} layout={[[5]]} />
|
||||
{#if script}
|
||||
{#if script?.lock}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
border-gray-300
|
||||
shadow-sm
|
||||
text-sm
|
||||
font-normal
|
||||
mt-1
|
||||
hover:ring-1
|
||||
hover:ring-indigo-300
|
||||
@@ -123,7 +124,6 @@
|
||||
{#each invites as invite}
|
||||
<div
|
||||
class="
|
||||
block
|
||||
w-full
|
||||
mx-auto
|
||||
py-1
|
||||
@@ -151,7 +151,7 @@
|
||||
? `&rd=${encodeURIComponent(rd)}`
|
||||
: ''}"
|
||||
>
|
||||
accept
|
||||
Accept
|
||||
</a>
|
||||
|
||||
<button
|
||||
@@ -164,7 +164,7 @@
|
||||
loadInvites()
|
||||
}}
|
||||
>
|
||||
decline
|
||||
Decline
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -186,7 +186,7 @@
|
||||
logout()
|
||||
}}
|
||||
>
|
||||
logout
|
||||
Logout
|
||||
</Button>
|
||||
</div>
|
||||
</CenteredModal>
|
||||
|
||||
@@ -54,10 +54,10 @@
|
||||
<p>No workers seems to be available</p>
|
||||
{/if}
|
||||
{#each groupedWorkers as [section, workers]}
|
||||
<h2 class="my-5">
|
||||
<div class="mt-6">
|
||||
Instance: {section} | IP:
|
||||
<Badge large color="gray">{workers[0].ip}</Badge>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
|
||||
Binary file not shown.
+100
-16
@@ -7,7 +7,7 @@ const config = {
|
||||
"./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",
|
||||
],
|
||||
safelist: [
|
||||
'inline-highlight'
|
||||
'hljs'
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
@@ -90,6 +90,11 @@ const config = {
|
||||
900: '#312e81',
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
// add double quotes if there is space in font name
|
||||
main: ['Inter', 'sans-serif'],
|
||||
mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace']
|
||||
},
|
||||
extend: {
|
||||
maxHeight: {
|
||||
'1/2': '50vh',
|
||||
@@ -115,7 +120,12 @@ const config = {
|
||||
},
|
||||
fontSize: {
|
||||
'2xs': '0.7rem'
|
||||
}
|
||||
},
|
||||
screens: {
|
||||
'fhd': '1900px',
|
||||
'qhd': '2500px',
|
||||
'4k': '3800px',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -126,15 +136,83 @@ const config = {
|
||||
plugin(({ addBase, addComponents, addUtilities, theme }) => {
|
||||
addBase({
|
||||
'html': {
|
||||
overflowY: 'auto'
|
||||
overflowY: 'auto',
|
||||
fontFamily: theme('fontFamily.main'),
|
||||
fontSize: theme('fontSize.base'),
|
||||
fontWeight: theme('fontWeight.normal'),
|
||||
color: theme('colors.gray.900'),
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: theme('fontSize.lg'),
|
||||
},
|
||||
},
|
||||
'h1': {
|
||||
fontSize: theme('fontSize.2xl'),
|
||||
color: theme('colors.gray.700')
|
||||
fontSize: '24px',
|
||||
fontWeight: theme('fontWeight.extrabold'),
|
||||
lineHeight: '1.05',
|
||||
color: theme('colors.gray.800'),
|
||||
[`@media (min-width: ${theme('screens.lg')})`]: {
|
||||
fontSize: '26px',
|
||||
},
|
||||
[`@media (min-width: ${theme('screens.fhd')})`]: {
|
||||
fontSize: '29px',
|
||||
},
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: '34px',
|
||||
},
|
||||
},
|
||||
'h1': {
|
||||
fontSize: theme('fontSize.xl'),
|
||||
color: theme('colors.blue.500')
|
||||
'h2': {
|
||||
fontSize: '20px',
|
||||
fontWeight: theme('fontWeight.extrabold'),
|
||||
lineHeight: '1.1',
|
||||
color: theme('colors.gray.700'),
|
||||
[`@media (min-width: ${theme('screens.fhd')})`]: {
|
||||
fontSize: '22px',
|
||||
},
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: '25px',
|
||||
},
|
||||
},
|
||||
'h3': {
|
||||
fontSize: '18px',
|
||||
fontWeight: theme('fontWeight.bold'),
|
||||
lineHeight: '1.2',
|
||||
color: theme('colors.gray.600'),
|
||||
[`@media (min-width: ${theme('screens.fhd')})`]: {
|
||||
fontSize: '20px',
|
||||
},
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: '22px',
|
||||
},
|
||||
},
|
||||
'h4': {
|
||||
fontSize: '18px',
|
||||
fontWeight: theme('fontWeight.semibold'),
|
||||
lineHeight: '1.3',
|
||||
color: theme('colors.gray.600'),
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: '20px',
|
||||
},
|
||||
},
|
||||
'h5': {
|
||||
fontSize: '16px',
|
||||
fontWeight: theme('fontWeight.semibold'),
|
||||
lineHeight: '1.5',
|
||||
color: theme('colors.gray.600'),
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: '18px',
|
||||
},
|
||||
},
|
||||
'h6': {
|
||||
fontSize: '16px',
|
||||
fontWeight: theme('fontWeight.medium'),
|
||||
lineHeight: '1.5',
|
||||
color: theme('colors.gray.600'),
|
||||
[`@media (min-width: ${theme('screens.qhd')})`]: {
|
||||
fontSize: '18px',
|
||||
},
|
||||
},
|
||||
'button': {
|
||||
fontWeight: theme('fontWeight.semibold'),
|
||||
},
|
||||
'a': {
|
||||
color: theme('colors.blue.500')
|
||||
@@ -161,7 +239,14 @@ const config = {
|
||||
pointerEvents: 'none',
|
||||
cursor: 'default',
|
||||
filter: 'grayscale(1)'
|
||||
}
|
||||
},
|
||||
'pre code.hljs': {
|
||||
padding: '0px !important',
|
||||
fontFamily: theme('fontFamily.mono'),
|
||||
fontSize: theme('fontSize.sm') + ' !important',
|
||||
lineHeight: theme('lineHeight.4') + ' !important',
|
||||
whiteSpace: 'pre-wrap'
|
||||
},
|
||||
});
|
||||
addComponents({
|
||||
'#table-custom': {
|
||||
@@ -199,17 +284,16 @@ const config = {
|
||||
boxShadow: theme('boxShadow.sm'),
|
||||
padding: theme('spacing.4')
|
||||
},
|
||||
'pre code.hljs': {
|
||||
padding: '0px',
|
||||
fontSize: theme('fontSize.xs'),
|
||||
lineHeight: theme('lineHeight.4'),
|
||||
whiteSpace: 'pre-wrap'
|
||||
},
|
||||
'.animate-skeleton': {
|
||||
animation: theme('animation.pulse'),
|
||||
backgroundColor: theme('colors.blue.200'),
|
||||
borderRadius: theme('borderRadius.DEFAULT'),
|
||||
}
|
||||
},
|
||||
'.text-blue-gradient': {
|
||||
color: 'transparent',
|
||||
backgroundClip: 'text',
|
||||
backgroundImage: `linear-gradient(to right, ${theme('colors.blue.600')}, ${theme('colors.blue.500')})`
|
||||
}
|
||||
});
|
||||
addUtilities({
|
||||
'.separator': {
|
||||
|
||||
Reference in New Issue
Block a user