ui: change tooltips and info boxes

This commit is contained in:
Andras Bacsai 2022-09-01 11:20:22 +02:00
parent e1697848a5
commit f6bb14f7c4
28 changed files with 428 additions and 290 deletions

View File

@ -14,15 +14,20 @@
"format": "prettier --write --plugin-search-dir=. ."
},
"devDependencies": {
"@floating-ui/dom": "1.0.1",
"@playwright/test": "1.25.1",
"@popperjs/core": "2.11.6",
"@sveltejs/kit": "1.0.0-next.405",
"@types/js-cookie": "3.0.2",
"@typescript-eslint/eslint-plugin": "5.35.1",
"@typescript-eslint/parser": "5.35.1",
"autoprefixer": "10.4.8",
"classnames": "2.3.1",
"eslint": "8.22.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-svelte3": "4.0.0",
"flowbite": "1.5.2",
"flowbite-svelte": "0.26.2",
"postcss": "8.4.16",
"prettier": "2.7.1",
"prettier-plugin-svelte": "2.7.0",

View File

@ -0,0 +1,37 @@
<script lang="ts">
import { onMount } from 'svelte';
import Tooltip from './Tooltip.svelte';
export let isLink = false;
export let explanation = '';
let id: any;
let self: any;
onMount(() => {
id = `info-${self.offsetLeft}-${self.offsetTop}`;
});
</script>
<div {id} class="inline-block mx-2 text-pink-500 cursor-pointer" bind:this={self}>
<svg
fill="none"
height="18"
shape-rendering="geometricPrecision"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
viewBox="0 0 24 24"
width="18"
><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z" /><path
d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3"
/><circle cx="12" cy="17" r=".5" />
</svg>
</div>
{#if id}
{#if isLink}
LINK
{:else}
<Tooltip triggeredBy={`#${id}`}>{@html explanation}</Tooltip>
{/if}
{/if}

View File

@ -1,6 +1,8 @@
<script lang="ts">
import Explainer from '$lib/components/Explainer.svelte';
import DocLink from './DocLink.svelte';
import Tooltip from './Tooltip.svelte';
export let id: any;
export let setting: any;
export let title: any;
export let description: any;
@ -8,22 +10,17 @@
export let disabled = false;
export let dataTooltip: any = null;
export let loading = false;
let triggeredBy = `#${id}`;
</script>
<div class="flex items-center py-4 pr-8 max-w-xs">
<div class="flex items-center py-4 pr-8">
<div class="flex w-96 flex-col">
<div class="text-xs font-bold text-stone-100 md:text-base">{title}</div>
<Explainer text={description} />
<div class="text-xs font-bold text-stone-100 md:text-base">
{title}<DocLink explanation={description} />
</div>
</div>
</div>
<div
class:tooltip-right={dataTooltip}
class:tooltip-primary={dataTooltip}
class:tooltip={dataTooltip}
class:text-center={isCenter}
data-tip={dataTooltip}
class="flex justify-center"
>
<div class:text-center={isCenter} class="flex justify-center">
<div
on:click
aria-pressed="false"
@ -32,6 +29,7 @@
class:bg-green-600={!loading && setting}
class:bg-stone-700={!loading && !setting}
class:bg-yellow-500={loading}
{id}
>
<span class="sr-only">Use setting</span>
<span
@ -72,3 +70,7 @@
</span>
</div>
</div>
{#if dataTooltip}
<Tooltip {triggeredBy} placement="top">{dataTooltip}</Tooltip>
{/if}

View File

@ -0,0 +1,8 @@
<script lang="ts">
import { Tooltip } from 'flowbite-svelte';
export let placement = 'bottom';
export let color = 'bg-coollabs text-left';
export let triggeredBy = '#tooltip-default';
</script>
<Tooltip {triggeredBy} {placement} arrow={false} {color} style="custom"><slot /></Tooltip>

View File

@ -209,7 +209,7 @@
"expose_a_port": "Expose a port",
"enable_preview_deploy_mr_pr_requests": "Enable preview deployments from pull or merge requests.",
"debug_logs": "Debug Logs",
"enable_debug_log_during_build": "Enable debug logs during build phase.<br><span class='text-red-500 font-bold'>Sensitive information</span> could be visible and saved in logs.",
"enable_debug_log_during_build": "Enable debug logs during build phase.<br><span class='text-settings font-bold'>Sensitive information</span> could be visible and saved in logs.",
"cant_activate_auto_deploy_without_repo": "Cannot activate automatic deployments until only one application is defined for this repository / branch.",
"no_applications_found": "No applications found",
"secret__batch_dot_env": "Paste .env file",
@ -275,7 +275,7 @@
"application_id": "Application ID",
"group_name": "Group Name",
"oauth_id": "OAuth ID",
"oauth_id_explainer": "The OAuth ID is the unique identifier of the GitLab application. <br>You can find it <span class='font-bold text-orange-600' >in the URL</span> of your GitLab OAuth Application.",
"oauth_id_explainer": "The OAuth ID is the unique identifier of the GitLab application. <br>You can find it <span class='font-bold text-settings' >in the URL</span> of your GitLab OAuth Application.",
"register_oauth_gitlab": "Register new OAuth application on GitLab",
"gitlab": {
"self_hosted": "Instance-wide application (self-hosted)",

View File

@ -88,6 +88,7 @@
import { errorNotification } from '$lib/common';
import { appSession } from '$lib/store';
import Toasts from '$lib/components/Toasts.svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
if (userId) $appSession.userId = userId;
if (teamId) $appSession.teamId = teamId;
@ -132,12 +133,12 @@
{/if}
<div class="flex flex-col space-y-2 py-2" class:mt-2={$appSession.whiteLabeled}>
<a
id="dashboard"
sveltekit:prefetch
href="/"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200 hover:text-white"
class="icons bg-coolgray-200 hover:text-white"
class:text-white={$page.url.pathname === '/'}
class:bg-coolgray-500={$page.url.pathname === '/'}
data-tip="Dashboard"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -156,12 +157,13 @@
<path d="M16 15c-2.21 1.333 -5.792 1.333 -8 0" />
</svg>
</a>
<div class="border-t border-stone-700" />
<div class="border-t border-stone-700" />
<a
id="applications"
sveltekit:prefetch
href="/applications"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-applications={$page.url.pathname.startsWith('/applications') ||
$page.url.pathname.startsWith('/new/application')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/applications') ||
@ -186,10 +188,12 @@
<line x1="17" y1="4" x2="17" y2="10" />
</svg>
</a>
<a
id="sources"
sveltekit:prefetch
href="/sources"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-sources={$page.url.pathname.startsWith('/sources') ||
$page.url.pathname.startsWith('/new/source')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/sources') ||
@ -216,9 +220,10 @@
</svg>
</a>
<a
id="destinations"
sveltekit:prefetch
href="/destinations"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-destinations={$page.url.pathname.startsWith('/destinations') ||
$page.url.pathname.startsWith('/new/destination')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/destinations') ||
@ -251,9 +256,10 @@
</a>
<div class="border-t border-stone-700" />
<a
id="databases"
sveltekit:prefetch
href="/databases"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-databases={$page.url.pathname.startsWith('/databases') ||
$page.url.pathname.startsWith('/new/database')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/databases') ||
@ -277,9 +283,10 @@
</svg>
</a>
<a
id="services"
sveltekit:prefetch
href="/services"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-services={$page.url.pathname.startsWith('/services') ||
$page.url.pathname.startsWith('/new/service')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/services') ||
@ -306,9 +313,10 @@
<UpdateAvailable />
<div class="flex flex-col space-y-2 py-2">
<a
id="iam"
sveltekit:prefetch
href="/iam"
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-iam={$page.url.pathname.startsWith('/iam')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/iam')}
data-tip="IAM"
@ -330,9 +338,10 @@
</svg>
</a>
<a
id="settings"
sveltekit:prefetch
href={$appSession.teamId === '0' ? '/settings/global' : '/settings/ssh-keys'}
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200"
class="icons bg-coolgray-200"
class:text-settings={$page.url.pathname.startsWith('/settings')}
class:bg-coolgray-500={$page.url.pathname.startsWith('/settings')}
data-tip="Settings"
@ -356,7 +365,8 @@
</a>
<div
class="icons tooltip tooltip-primary tooltip-right bg-coolgray-200 hover:text-error"
id="logout"
class="icons bg-coolgray-200 hover:text-error"
data-tip="Logout"
on:click={logout}
>
@ -400,3 +410,16 @@
<slot />
</div>
</main>
<Tooltip triggeredBy="#dashboard" placement="right">Dashboard</Tooltip>
<Tooltip triggeredBy="#applications" placement="right" color="bg-applications">Applications</Tooltip
>
<Tooltip triggeredBy="#sources" placement="right" color="bg-sources">Git Sources</Tooltip>
<Tooltip triggeredBy="#destinations" placement="right" color="bg-destinations">Destinations</Tooltip
>
<Tooltip triggeredBy="#databases" placement="right" color="bg-databases">Databases</Tooltip>
<Tooltip triggeredBy="#services" placement="right" color="bg-services">Services</Tooltip>
<Tooltip triggeredBy="#iam" placement="right" color="bg-iam">IAM</Tooltip>
<Tooltip triggeredBy="#settings" placement="right" color="bg-settings text-black">Settings</Tooltip
>
<Tooltip triggeredBy="#logout" placement="right" color="bg-red-600">Logout</Tooltip>

View File

@ -62,6 +62,7 @@
import { t } from '$lib/translations';
import { appSession, disabledButton, status, location, setLocation, addToast } from '$lib/store';
import { errorNotification, handlerNotFoundLoad } from '$lib/common';
import Tooltip from '$lib/components/Tooltip.svelte';
let statusInterval: any;
$disabledButton =
@ -115,6 +116,10 @@
$status.application.initialLoading = true;
$status.application.loading = true;
await post(`/applications/${id}/restart`, {});
addToast({
type: 'success',
message: 'Restart successful.'
});
} catch (error) {
return errorNotification(error);
} finally {
@ -174,9 +179,10 @@
<nav class="nav-side">
{#if $location}
<a
id="open"
href={$location}
target="_blank"
class="icons tooltip-bottom flex items-center bg-transparent text-sm"
class="icons flex items-center bg-transparent text-sm"
><svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -193,14 +199,16 @@
<polyline points="15 4 20 4 20 9" />
</svg></a
>
<Tooltip triggeredBy="#open">Open</Tooltip>
<div class="border border-coolgray-500 h-8" />
{/if}
{#if $status.application.isExited}
<a
id="applicationerror"
href={!$disabledButton ? `/applications/${id}/logs` : null}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center text-error"
data-tip="Application exited with an error!"
class="icons bg-transparent text-sm flex items-center text-error"
sveltekit:prefetch
>
<svg
@ -221,10 +229,11 @@
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
</a>
<Tooltip triggeredBy="#applicationerror">Application exited with an error!</Tooltip>
{/if}
{#if $status.application.initialLoading}
<button
class="icons tooltip-bottom flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -247,13 +256,11 @@
</button>
{:else if $status.application.isRunning}
<button
id="stop"
on:click={stopApplication}
type="submit"
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2 text-error"
data-tip={$appSession.isAdmin
? 'Stop'
: $t('application.permission_denied_stop_application')}
class="icons bg-transparent text-sm flex items-center space-x-2 text-error"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -270,14 +277,14 @@
<rect x="14" y="5" width="4" height="14" rx="1" />
</svg>
</button>
<Tooltip triggeredBy="#stop">Stop</Tooltip>
<button
id="restart"
on:click={restartApplication}
type="submit"
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2 "
data-tip={$appSession.isAdmin
? 'Restart (useful for changing secrets)'
: $t('application.permission_denied_stop_application')}
class="icons bg-transparent text-sm flex items-center space-x-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -294,14 +301,14 @@
<path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" />
</svg>
</button>
<Tooltip triggeredBy="#restart">Restart (useful to change secrets)</Tooltip>
<form on:submit|preventDefault={() => handleDeploySubmit(true)}>
<button
id="forceredeploy"
type="submit"
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2"
data-tip={$appSession.isAdmin
? 'Force Rebuild without cache'
: 'You do not have permission to rebuild application.'}
class="icons bg-transparent text-sm flex items-center space-x-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -320,16 +327,15 @@
/>
</svg>
</button>
<Tooltip triggeredBy="#forceredeploy">Force redeploy (without cache)</Tooltip>
</form>
{:else}
<form on:submit|preventDefault={() => handleDeploySubmit(false)}>
<button
id="deploy"
type="submit"
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2 text-success"
data-tip={$appSession.isAdmin
? 'Deploy'
: 'You do not have permission to deploy application.'}
class="icons bg-transparent text-sm flex items-center space-x-2 text-success"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -345,22 +351,20 @@
<path d="M7 4v16l13 -8z" />
</svg>
</button>
<Tooltip triggeredBy="#deploy">Deploy</Tooltip>
</form>
{/if}
<div class="border border-coolgray-500 h-8" />
<a
id="configurations"
href={!$disabledButton ? `/applications/${id}` : null}
sveltekit:prefetch
class="hover:text-yellow-500 rounded"
class:text-yellow-500={$page.url.pathname === `/applications/${id}`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}`}
>
<button
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip="Configurations"
>
<button disabled={$disabledButton} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -385,17 +389,14 @@
></a
>
<a
id="secrets"
href={!$disabledButton ? `/applications/${id}/secrets` : null}
sveltekit:prefetch
class="hover:text-pink-500 rounded"
class:text-pink-500={$page.url.pathname === `/applications/${id}/secrets`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/secrets`}
>
<button
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip="Secrets"
>
<button disabled={$disabledButton} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -416,17 +417,14 @@
></a
>
<a
id="persistentstorages"
href={!$disabledButton ? `/applications/${id}/storages` : null}
sveltekit:prefetch
class="hover:text-pink-500 rounded"
class:text-pink-500={$page.url.pathname === `/applications/${id}/storages`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/storages`}
>
<button
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip="Persistent Storages"
>
<button disabled={$disabledButton} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -446,17 +444,14 @@
>
{#if !application.settings.isBot}
<a
id="previews"
href={!$disabledButton ? `/applications/${id}/previews` : null}
sveltekit:prefetch
class="hover:text-orange-500 rounded"
class:text-orange-500={$page.url.pathname === `/applications/${id}/previews`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/previews`}
>
<button
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip="Previews"
>
<button disabled={$disabledButton} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -479,6 +474,7 @@
{/if}
<div class="border border-coolgray-500 h-8" />
<a
id="applicationlogs"
href={!$disabledButton && $status.application.isRunning ? `/applications/${id}/logs` : null}
sveltekit:prefetch
class="hover:text-sky-500 rounded"
@ -487,8 +483,7 @@
>
<button
disabled={$disabledButton || !$status.application.isRunning}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip={$t('application.logs')}
class="icons bg-transparent text-sm"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -510,17 +505,14 @@
</button></a
>
<a
id="buildlogs"
href={!$disabledButton ? `/applications/${id}/logs/build` : null}
sveltekit:prefetch
class="hover:text-red-500 rounded"
class:text-red-500={$page.url.pathname === `/applications/${id}/logs/build`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/logs/build`}
>
<button
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip="Build Logs"
>
<button disabled={$disabledButton} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -546,16 +538,22 @@
<div class="border border-coolgray-500 h-8" />
<button
id="delete"
on:click={() => deleteApplication(application.name)}
type="submit"
disabled={!$appSession.isAdmin}
class:hover:text-red-500={$appSession.isAdmin}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip={$appSession.isAdmin
? $t('application.delete_application')
: $t('application.permission_denied_delete_application')}
class="icons bg-transparent text-sm"
>
<DeleteIcon />
</button>
</nav>
<slot />
<Tooltip triggeredBy="#configurations">Configurations</Tooltip>
<Tooltip triggeredBy="#secrets">Secrets</Tooltip>
<Tooltip triggeredBy="#persistentstorages">Persistent Storages</Tooltip>
<Tooltip triggeredBy="#previews">Previews</Tooltip>
<Tooltip triggeredBy="#applicationlogs">Application Logs</Tooltip>
<Tooltip triggeredBy="#buildlogs">Build Logs</Tooltip>
<Tooltip triggeredBy="#delete">Delete</Tooltip>

View File

@ -164,7 +164,6 @@
<div class="space-y-4">
<input
placeholder="eg: https://github.com/coollabsio/nodejs-example/tree/main"
class="text-xs"
bind:value={publicRepositoryLink}
/>
{#if branchSelectOptions.length > 0}
@ -193,7 +192,5 @@
</form>
</div>
</div>
<Explainer
text="Examples:<br><br>https://github.com/coollabsio/nodejs-example<br>https://github.com/coollabsio/nodejs-example/tree/main<br>https://gitlab.com/aleveha/fastify-example<br>https://gitlab.com/aleveha/fastify-example/-/tree/master<br><br>Only works with Github.com and Gitlab.com."
/>
</div>

View File

@ -32,7 +32,8 @@
import { errorNotification } from '$lib/common';
import { appSession } from '$lib/store';
import PublicRepository from './_PublicRepository.svelte';
import Explainer from '$lib/components/Explainer.svelte';
import Explainer from '$lib/components/Explainer.svelte';
import DocLink from '$lib/components/DocLink.svelte';
const { id } = $page.params;
const from = $page.url.searchParams.get('from');
@ -192,7 +193,6 @@ import Explainer from '$lib/components/Explainer.svelte';
</div>
{/if}
</div>
<div class="title py-4">Public Repository</div>
<PublicRepository />
<div class="title py-4">Public Repository <DocLink /></div>
<PublicRepository />
</div>

View File

@ -39,7 +39,9 @@
import { addToast, appSession, disabledButton, setLocation, status } from '$lib/store';
import { t } from '$lib/translations';
import { errorNotification, getDomain, notNodeDeployments, staticDeployments } from '$lib/common';
import Setting from './_Setting.svelte';
import Setting from '$lib/components/Setting.svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
import DocLink from '$lib/components/DocLink.svelte';
const { id } = $page.params;
$: isDisabled =
@ -281,6 +283,7 @@
</div>
{#if application.gitSource?.htmlUrl && application.repository && application.branch}
<a
id="git"
href="{application.gitSource.htmlUrl}/{application.repository}/tree/{application.branch}"
target="_blank"
class="w-10"
@ -321,6 +324,7 @@
</svg>
{/if}
</a>
<Tooltip triggeredBy="#git">Open on Git</Tooltip>
{/if}
</div>
@ -426,7 +430,7 @@
>
{/if}
</div>
<div class="grid grid-cols-2 items-center pb-8">
<div class="grid grid-cols-2 items-center">
<label for="destination" class="text-base font-bold text-stone-100"
>{$t('application.destination')}</label
>
@ -440,10 +444,15 @@
</div>
</div>
{#if application.buildCommand || application.buildPack === 'rust' || application.buildPack === 'laravel'}
<div class="grid grid-cols-2 items-center pb-8">
<div class="grid grid-cols-2 items-center">
<label for="baseBuildImage" class="text-base font-bold text-stone-100"
>{$t('application.base_build_image')}</label
>
>{$t('application.base_build_image')}
<DocLink
explanation={application.buildPack === 'laravel'
? 'For building frontend assets with webpack.'
: 'Image that will be used during the build process.'}
/>
</label>
<div class="custom-select-wrapper">
<Select
@ -457,17 +466,13 @@
isClearable={false}
/>
</div>
{#if application.buildPack === 'laravel'}
<Explainer text="For building frontend assets with webpack." />
{:else}
<Explainer text={$t('application.base_build_image_explainer')} />
{/if}
</div>
{/if}
{#if application.buildPack !== 'docker'}
<div class="grid grid-cols-2 items-center">
<label for="baseImage" class="text-base font-bold text-stone-100"
>{$t('application.base_image')}</label
>{$t('application.base_image')}
<DocLink explanation={'Image that will be used for the deployment.'} /></label
>
<div class="custom-select-wrapper">
<Select
@ -481,13 +486,15 @@
isClearable={false}
/>
</div>
<Explainer text={$t('application.base_image_explainer')} />
</div>
{/if}
{#if application.buildPack !== 'docker' && (application.buildPack === 'nextjs' || application.buildPack === 'nuxtjs')}
<div class="grid grid-cols-2 items-center pb-8">
<label for="deploymentType" class="text-base font-bold text-stone-100"
>Deployment Type</label
>Deployment Type
<DocLink
explanation={"Defines how to deploy your application. <br><br><span class='text-green-500 font-bold'>Static</span> is for static websites, <span class='text-green-500 font-bold'>node</span> is for server-side applications."}
/></label
>
<div class="custom-select-wrapper">
<Select
@ -501,9 +508,6 @@
isClearable={false}
/>
</div>
<Explainer
text="Defines how to deploy your application. <br><br><span class='text-green-500 font-bold'>Static</span> is for static websites, <span class='text-green-500 font-bold'>node</span> is for server-side applications."
/>
</div>
{/if}
</div>
@ -513,26 +517,36 @@
<div class="grid grid-flow-row gap-2 px-10">
<div class="grid grid-cols-2 items-center">
<Setting
id="isBot"
isCenter={false}
bind:setting={isBot}
on:click={() => changeSettings('isBot')}
title="Is your application a bot?"
description="You can deploy applications without domains. <br>You can also make them to listen on <span class='text-green-500 font-bold'>IP:EXPOSEDPORT</span> as well.<br></Setting><br>Useful to host <span class='text-green-500 font-bold'>Twitch bots, regular jobs, or anything that does not require an incoming connection.</span>"
description="You can deploy applications without domains or make them to listen on the <span class='text-settings font-bold'>Exposed Port</span>.<br></Setting><br>Useful to host <span class='text-settings font-bold'>Twitch bots, regular jobs, or anything that does not require an incoming HTTP connection.</span>"
disabled={$status.application.isRunning}
/>
</div>
<div class="grid grid-cols-2 items-center pb-8">
<Setting
id="dualCerts"
dataTooltip={$t('forms.must_be_stopped_to_modify')}
disabled={$status.application.isRunning}
isCenter={false}
bind:setting={dualCerts}
title={$t('application.ssl_www_and_non_www')}
description="It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-settings'>both DNS entries</span> set in advance.<br><br>Useful if you expect to have visitors on both."
on:click={() => !$status.application.isRunning && changeSettings('dualCerts')}
/>
</div>
{#if !isBot}
<div class="grid grid-cols-2">
<div class="flex-col">
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100"
>{$t('application.url_fqdn')}</label
>
{#if browser && window.location.hostname === 'demo.coolify.io'}
<Explainer
text="<span class='text-white font-bold'>You can use the predefined random url name or enter your own domain name.</span>"
>{$t('application.url_fqdn')}
<DocLink
explanation={"If you specify <span class='text-settings font-bold'>https</span>, the application will be accessible only over https.<br>SSL certificate will be generated automatically.<br><br>If you specify <span class='text-settings font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-settings font-bold'>You must set your DNS to point to the server IP in advance.</span>"}
/>
{/if}
<Explainer text={$t('application.https_explainer')} />
</label>
</div>
<div>
<input
@ -582,17 +596,6 @@
{/if}
</div>
</div>
<div class="grid grid-cols-2 items-center pb-8">
<Setting
dataTooltip={$t('forms.must_be_stopped_to_modify')}
disabled={$status.application.isRunning}
isCenter={false}
bind:setting={dualCerts}
title={$t('application.ssl_www_and_non_www')}
description={$t('application.ssl_explainer')}
on:click={() => !$status.application.isRunning && changeSettings('dualCerts')}
/>
</div>
{/if}
{#if application.buildPack === 'python'}
<div class="grid grid-cols-2 items-center">
@ -658,7 +661,11 @@
</div>
{/if}
<div class="grid grid-cols-2 items-center">
<label for="exposePort" class="text-base font-bold text-stone-100">Exposed Port</label>
<label for="exposePort" class="text-base font-bold text-stone-100"
>Exposed Port <DocLink
explanation={'You can expose your application to a port on the host system.<br><br>Useful if you would like to use your own reverse proxy or tunnel and also in development mode. Otherwise leave empty.'}
/></label
>
<input
readonly={!$appSession.isAdmin && !$status.application.isRunning}
disabled={isDisabled}
@ -667,9 +674,6 @@
bind:value={application.exposePort}
placeholder="12345"
/>
<Explainer
text={'You can expose your application to a port on the host system.<br><br>Useful if you would like to use your own reverse proxy or tunnel and also in development mode. Otherwise leave empty.'}
/>
</div>
{#if !notNodeDeployments.includes(application.buildPack)}
<div class="grid grid-cols-2 items-center pt-4">
@ -715,7 +719,9 @@
{#if application.buildPack === 'docker'}
<div class="grid grid-cols-2 items-center pt-4">
<label for="dockerFileLocation" class="text-base font-bold text-stone-100"
>Dockerfile Location</label
>Dockerfile Location <DocLink
explanation={"Should be absolute path, like <span class='text-settings font-bold'>/data/Dockerfile</span> or <span class='text-settings font-bold'>/Dockerfile.</span>"}
/></label
>
<input
disabled={isDisabled}
@ -725,9 +731,6 @@
bind:value={application.dockerFileLocation}
placeholder="default: /Dockerfile"
/>
<Explainer
text="Should be absolute path, like <span class='text-green-500 font-bold'>/data/Dockerfile</span> or <span class='text-green-500 font-bold'>/Dockerfile.</span>"
/>
</div>
{/if}
{#if application.buildPack === 'deno'}
@ -743,7 +746,11 @@
/>
</div>
<div class="grid grid-cols-2 items-center">
<label for="denoOptions" class="text-base font-bold text-stone-100">Arguments</label>
<label for="denoOptions" class="text-base font-bold text-stone-100"
>Arguments <DocLink
explanation={"List of arguments to pass to <span class='text-settings font-bold'>deno run</span> command. Could include permissions, configurations files, etc."}
/></label
>
<input
disabled={isDisabled}
readonly={!$appSession.isAdmin}
@ -752,18 +759,17 @@
bind:value={application.denoOptions}
placeholder="eg: --allow-net --allow-hrtime --config path/to/file.json"
/>
<Explainer
text="List of arguments to pass to <span class='text-green-500 font-bold'>deno run</span> command. Could include permissions, configurations files, etc."
/>
</div>
{/if}
{#if application.buildPack !== 'laravel' && application.buildPack !== 'heroku'}
<div class="grid grid-cols-2 items-center">
<div class="flex-col">
<label for="baseDirectory" class="pt-2 text-base font-bold text-stone-100"
>{$t('forms.base_directory')}</label
>{$t('forms.base_directory')}
<DocLink
explanation={"Directory to use as the base for all commands.<br>Could be useful with <span class='text-settings font-bold'>monorepos</span>."}
/></label
>
<Explainer text={$t('application.directory_to_use_explainer')} />
</div>
<input
disabled={isDisabled}
@ -779,9 +785,11 @@
<div class="grid grid-cols-2 items-center">
<div class="flex-col">
<label for="publishDirectory" class="pt-2 text-base font-bold text-stone-100"
>{$t('forms.publish_directory')}</label
>{$t('forms.publish_directory')}
<DocLink
explanation={"Directory containing all the assets for deployment. <br> For example: <span class='text-settings font-bold'>dist</span>,<span class='text-settings font-bold'>_site</span> or <span class='text-settings font-bold'>public</span>."}
/></label
>
<Explainer text={$t('application.publish_directory_explainer')} />
</div>
<input
@ -804,6 +812,7 @@
{#if !application.settings.isPublicRepository}
<div class="grid grid-cols-2 items-center">
<Setting
id="autodeploy"
isCenter={false}
bind:setting={autodeploy}
on:click={() => changeSettings('autodeploy')}
@ -815,6 +824,7 @@
{#if !application.settings.isBot}
<div class="grid grid-cols-2 items-center">
<Setting
id="previews"
isCenter={false}
bind:setting={previews}
on:click={() => changeSettings('previews')}
@ -825,6 +835,7 @@
{/if}
<div class="grid grid-cols-2 items-center">
<Setting
id="debug"
isCenter={false}
bind:setting={debug}
on:click={() => changeSettings('debug')}

View File

@ -11,6 +11,7 @@
import { t } from '$lib/translations';
import LoadingLogs from '$lib/components/LoadingLogs.svelte';
import { errorNotification } from '$lib/common';
import Tooltip from '$lib/components/Tooltip.svelte';
let logs: any = [];
let loading = true;
@ -108,9 +109,9 @@
{:else}
<div class="flex justify-end sticky top-0 p-2 mx-1">
<button
id="follow"
on:click={followBuild}
class="bg-transparent btn btn-sm btn-link tooltip tooltip-primary tooltip-bottom hover:text-green-500 hover:bg-coolgray-500"
data-tip="Follow logs"
class="bg-transparent btn btn-sm btn-linkhover:text-green-500 hover:bg-coolgray-500"
class:text-green-500={followingBuild}
>
<svg
@ -130,12 +131,13 @@
<line x1="16" y1="12" x2="12" y2="16" />
</svg>
</button>
<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
{#if currentStatus === 'running'}
<button
id="cancel"
on:click={cancelBuild}
class:animation-spin={cancelInprogress}
class="bg-transparent btn btn-sm btn-link hover:text-red-500 hover:bg-coolgray-500 tooltip tooltip-primary tooltip-bottom"
data-tip="Cancel build"
class="bg-transparent btn btn-sm btn-link hover:text-red-500 hover:bg-coolgray-500"
>
{#if cancelInprogress}
Cancelling...
@ -156,6 +158,7 @@
</svg>
{/if}
</button>
<Tooltip triggeredBy="#cancel">Cancel build</Tooltip>
{/if}
</div>
{#if logs.length > 0}

View File

@ -5,6 +5,7 @@
import { errorNotification } from '$lib/common';
import LoadingLogs from '$lib/components/LoadingLogs.svelte';
import { onMount, onDestroy } from 'svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
let application: any = {};
let logsLoading = false;
@ -146,9 +147,9 @@
{/if}
<div class="flex justify-end sticky top-0 p-1 mx-1">
<button
id="follow"
on:click={followBuild}
class="bg-transparent btn btn-sm btn-link tooltip tooltip-primary tooltip-bottom"
data-tip="Follow logs"
class="bg-transparent btn btn-sm btn-link"
class:text-green-500={followingLogs}
>
<svg
@ -168,6 +169,7 @@
<line x1="16" y1="12" x2="12" y2="16" />
</svg>
</button>
<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
</div>
<div
class="font-mono w-full leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 py-5 px-6 whitespace-pre-wrap break-words overflow-auto max-h-[80vh] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"

View File

@ -61,6 +61,7 @@
import { appSession, status, disabledButton } from '$lib/store';
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
import { onDestroy, onMount } from 'svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
const { id } = $page.params;
let statusInterval: any = false;
@ -143,9 +144,9 @@
{#if database.type && database.destinationDockerId && database.version && database.defaultDatabase}
{#if $status.database.isExited}
<a
id="exited"
href={!$disabledButton ? `/databases/${id}/logs` : null}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center text-red-500 tooltip-error"
data-tip="Service exited with an error!"
class="icons bg-transparent text-sm flex items-center text-red-500 tooltip-error"
sveltekit:prefetch
>
<svg
@ -166,10 +167,11 @@
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
</a>
<Tooltip triggeredBy="#exited">{'Service exited with an error!'}</Tooltip>
{/if}
{#if $status.database.initialLoading}
<button
class="icons tooltip-bottom flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -192,13 +194,11 @@
</button>
{:else if $status.database.isRunning}
<button
id="stop"
on:click={stopDatabase}
type="submit"
disabled={!$appSession.isAdmin}
class="icons bg-transparent tooltip tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
data-tip={$appSession.isAdmin
? $t('database.stop_database')
: $t('database.permission_denied_stop_database')}
class="icons bg-transparent text-sm flex items-center space-x-2 text-red-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -215,15 +215,14 @@
<rect x="14" y="5" width="4" height="14" rx="1" />
</svg>
</button>
<Tooltip triggeredBy="#stop">{'Stop'}</Tooltip>
{:else}
<button
id="start"
on:click={startDatabase}
type="submit"
disabled={!$appSession.isAdmin}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
data-tip={$appSession.isAdmin
? $t('database.start_database')
: $t('database.permission_denied_start_database')}
class="icons bg-transparent text-sm flex items-center space-x-2 text-green-500"
><svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -238,20 +237,19 @@
<path d="M7 4v16l13 -8z" />
</svg>
</button>
<Tooltip triggeredBy="#start">{'Start'}</Tooltip>
{/if}
{/if}
<div class="border border-stone-700 h-8" />
<a
id="configuration"
href="/databases/{id}"
sveltekit:prefetch
class="hover:text-yellow-500 rounded"
class:text-yellow-500={$page.url.pathname === `/databases/${id}`}
class:bg-coolgray-500={$page.url.pathname === `/databases/${id}`}
>
<button
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm disabled:text-red-500"
data-tip={$t('application.configurations')}
>
<button class="icons bg-transparent m text-sm disabled:text-red-500">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -275,19 +273,17 @@
</svg></button
></a
>
<Tooltip triggeredBy="#configuration">{'Configuration'}</Tooltip>
<div class="border border-stone-700 h-8" />
<a
id="databaselogs"
href={$status.database.isRunning ? `/databases/${id}/logs` : null}
sveltekit:prefetch
class="hover:text-pink-500 rounded"
class:text-pink-500={$page.url.pathname === `/databases/${id}/logs`}
class:bg-coolgray-500={$page.url.pathname === `/databases/${id}/logs`}
>
<button
disabled={!$status.database.isRunning}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip={$t('database.logs')}
>
<button disabled={!$status.database.isRunning} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -307,16 +303,16 @@
</svg></button
></a
>
<Tooltip triggeredBy="#databaselogs">{'Logs'}</Tooltip>
<button
id="delete"
on:click={deleteDatabase}
type="submit"
disabled={!$appSession.isAdmin}
class:hover:text-red-500={$appSession.isAdmin}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip={$appSession.isAdmin
? $t('database.delete_database')
: $t('database.permission_denied_delete_database')}><DeleteIcon /></button
class="icons bg-transparent text-sm"><DeleteIcon /></button
>
<Tooltip triggeredBy="#delete">{'Delete'}</Tooltip>
</nav>
{/if}
<slot />

View File

@ -6,6 +6,7 @@
import { get } from '$lib/api';
import { t } from '$lib/translations';
import { errorNotification } from '$lib/common';
import Tooltip from '$lib/components/Tooltip.svelte';
const { id } = $page.params;
@ -129,9 +130,9 @@
{/if}
<div class="flex justify-end sticky top-0 p-1 mx-1">
<button
id="follow"
on:click={followBuild}
class="bg-transparent btn btn-sm tooltip tooltip-primary tooltip-bottom"
data-tip="Follow logs"
class="bg-transparent btn btn-sm"
class:text-green-500={followingLogs}
>
<svg
@ -151,6 +152,7 @@
<line x1="16" y1="12" x2="12" y2="16" />
</svg>
</button>
<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
</div>
<div
class="font-mono w-full leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 py-5 px-6 whitespace-pre-wrap break-words overflow-auto max-h-[80vh] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"

View File

@ -196,14 +196,15 @@
/>
</div>
{#if $appSession.teamId === '0'}
<div class="grid lg:grid-cols-2 items-center">
<div class="grid lg:grid-cols-2 items-center px-10">
<Setting
id="changeProxySetting"
loading={loading.proxy}
disabled={cannotDisable}
bind:setting={destination.isCoolifyProxyUsed}
on:click={changeProxySetting}
title={$t('destination.use_coolify_proxy')}
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration. Databases will have their own proxy. <br><br>${
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration.${
cannotDisable
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
: ''

View File

@ -33,11 +33,7 @@
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
<div class="flex items-center space-x-2 pb-5">
<div class="title font-bold">{$t('forms.configuration')}</div>
<button
type="submit"
class="btn btn-sm bg-destinations"
class:loading={loading}
disabled={loading}
<button type="submit" class="btn btn-sm bg-destinations" class:loading disabled={loading}
>{loading
? payload.isCoolifyProxyUsed
? $t('destination.new.saving_and_configuring_proxy')
@ -69,12 +65,13 @@
/>
</div>
{#if $appSession.teamId === '0'}
<div class="grid grid-cols-2 items-center">
<div class="grid grid-cols-2 items-center px-10">
<Setting
id="changeProxySetting"
bind:setting={payload.isCoolifyProxyUsed}
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
title={$t('destination.use_coolify_proxy')}
description={$t('destination.new.install_proxy')}
description={'This will install a proxy on the destination to allow you to access your applications and services without any manual configuration.'}
/>
</div>
{/if}

View File

@ -33,18 +33,14 @@
customClass="max-w-[32rem]"
text="Remote Docker Engines are using <span class='text-white font-bold'>SSH</span> to communicate with the remote docker engine.
You need to setup an <span class='text-white font-bold'>SSH key</span> in advance on the server and install Docker.
<br>See <a class='text-white' href='https://docs.coollabs.io/coolify/destinations#remote-docker-engine'>docs</a> for more details."
<br>See <a class='text-white' href='https://docs.coollabs.io/coolify/destinations#remote-docker-engine' target='blank'>docs</a> for more details."
/>
</div>
<div class="flex justify-center px-6 pb-8">
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
<div class="flex items-center space-x-2 pb-5">
<div class="title font-bold">{$t('forms.configuration')}</div>
<button
type="submit"
class="btn btn-sm bg-destinations"
class:loading={loading}
disabled={loading}
<button type="submit" class="btn btn-sm bg-destinations" class:loading disabled={loading}
>{loading
? payload.isCoolifyProxyUsed
? $t('destination.new.saving_and_configuring_proxy')
@ -97,12 +93,13 @@
bind:value={payload.network}
/>
</div>
<div class="grid grid-cols-2 items-center">
<div class="grid grid-cols-2 items-center px-10">
<Setting
id="isCoolifyProxyUsed"
bind:setting={payload.isCoolifyProxyUsed}
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
title={$t('destination.use_coolify_proxy')}
description={$t('destination.new.install_proxy')}
description={'This will install a proxy on the destination to allow you to access your applications and services without any manual configuration.'}
/>
</div>
</form>

View File

@ -259,14 +259,15 @@
/></a
>
</div>
<div class="grid grid-cols-2 items-center">
<div class="grid grid-cols-2 items-center px-10">
<Setting
id="changeProxySetting"
disabled={cannotDisable}
loading={loading.proxy}
bind:setting={destination.isCoolifyProxyUsed}
on:click={changeProxySetting}
title={$t('destination.use_coolify_proxy')}
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration. Databases will have their own proxy. <br><br>${
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration.${
cannotDisable
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
: ''

View File

@ -40,7 +40,7 @@
}
};
} catch (error) {
console.log(error)
console.log(error);
return handlerNotFoundLoad(error, url);
}
};
@ -56,12 +56,16 @@
import { errorNotification, handlerNotFoundLoad } from '$lib/common';
import { appSession } from '$lib/store';
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
const { id } = $page.params;
const isDestinationDeletable = destination?.application.length === 0 && destination?.database.length === 0 && destination?.service.length === 0
const isDestinationDeletable =
destination?.application.length === 0 &&
destination?.database.length === 0 &&
destination?.service.length === 0;
async function deleteDestination(destination: any) {
if (!isDestinationDeletable) return
if (!isDestinationDeletable) return;
const sure = confirm($t('application.confirm_to_delete', { name: destination.name }));
if (sure) {
try {
@ -74,12 +78,12 @@
}
function deletable() {
if (!isDestinationDeletable) {
return "Please delete all resources before deleting this."
return 'Please delete all resources before deleting this.';
}
if ($appSession.isAdmin) {
return $t('destination.delete_destination')
return $t('destination.delete_destination');
} else {
return $t('destination.permission_denied_delete_destination')
return $t('destination.permission_denied_delete_destination');
}
}
</script>
@ -87,14 +91,15 @@
{#if id !== 'new'}
<nav class="nav-side">
<button
id="delete"
on:click={() => deleteDestination(destination)}
type="submit"
disabled={!$appSession.isAdmin && isDestinationDeletable}
class:hover:text-red-500={$appSession.isAdmin && isDestinationDeletable}
class="icons tooltip tooltip-primary tooltip-left bg-transparent text-sm"
class:text-stone-600={!isDestinationDeletable}
data-tip={deletable()}><DeleteIcon /></button
class="icons bg-transparent text-sm"
class:text-stone-600={!isDestinationDeletable}><DeleteIcon /></button
>
</nav>
<Tooltip triggeredBy="#delete">{deletable()}</Tooltip>
{/if}
<slot />

View File

@ -35,6 +35,7 @@
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
import { goto } from '$app/navigation';
import Cookies from 'js-cookie';
import Tooltip from '$lib/components/Tooltip.svelte';
const { id } = $page.params;
async function deleteTeam() {
@ -69,15 +70,14 @@
<nav class="nav-side">
{#if team.id !== '0'}
<button
id="delete"
on:click={deleteTeam}
type="submit"
disabled={!$appSession.isAdmin}
class:hover:text-red-500={$appSession.isAdmin}
class="icons tooltip tooltip-primary tooltip-left bg-transparent text-sm"
data-tip={$appSession.isAdmin
? 'Delete'
: $t('destination.permission_denied_delete_destination')}><DeleteIcon /></button
class="icons bg-transparent text-sm"><DeleteIcon /></button
>
<Tooltip triggeredBy="#delete">Delete</Tooltip>
{/if}
</nav>
{/if}

View File

@ -62,6 +62,7 @@
import { errorNotification, handlerNotFoundLoad } from '$lib/common';
import { appSession, disabledButton, status, location, setLocation } from '$lib/store';
import { onDestroy, onMount } from 'svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
const { id } = $page.params;
export let service: any;
@ -108,7 +109,7 @@
}
async function startService() {
$status.service.initialLoading = true;
$status.service.loading = true
$status.service.loading = true;
try {
await post(`/services/${service.id}/${service.type}/start`, {});
} catch (error) {
@ -152,9 +153,10 @@
{#if service.type && service.destinationDockerId && service.version}
{#if $location}
<a
id="open"
href={$location}
target="_blank"
class="icons tooltip-bottom flex items-center bg-transparent text-sm"
class="icons flex items-center bg-transparent text-sm"
><svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -171,13 +173,14 @@
<polyline points="15 4 20 4 20 9" />
</svg></a
>
<Tooltip triggeredBy="#open">Open</Tooltip>
<div class="border border-stone-700 h-8" />
{/if}
{#if $status.service.isExited}
<a
id="error"
href={!$disabledButton ? `/services/${id}/logs` : null}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center text-red-500 tooltip-error"
data-tip="Service exited with an error!"
class="icons bg-transparent text-sm flex items-center text-red-500 tooltip-error"
sveltekit:prefetch
>
<svg
@ -198,10 +201,11 @@
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
</a>
<Tooltip triggeredBy="#error">Service exited with an error!</Tooltip>
{/if}
{#if $status.service.initialLoading}
<button
class="icons tooltip-bottom flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -224,13 +228,11 @@
</button>
{:else if $status.service.isRunning}
<button
id="stop"
on:click={stopService}
type="submit"
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
data-tip={$appSession.isAdmin
? $t('service.stop_service')
: $t('service.permission_denied_stop_service')}
class="icons bg-transparent text-sm flex items-center space-x-2 text-red-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -247,15 +249,14 @@
<rect x="14" y="5" width="4" height="14" rx="1" />
</svg>
</button>
<Tooltip triggeredBy="#stop">Stop</Tooltip>
{:else}
<button
id="start"
on:click={startService}
type="submit"
disabled={$disabledButton}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
data-tip={$appSession.isAdmin
? $t('service.start_service')
: $t('service.permission_denied_start_service')}
class="icons bg-transparent text-sm flex items-center space-x-2 text-green-500"
><svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -270,21 +271,20 @@
<path d="M7 4v16l13 -8z" />
</svg>
</button>
<Tooltip triggeredBy="#start">Start</Tooltip>
{/if}
<div class="border border-stone-700 h-8" />
{/if}
{#if service.type && service.destinationDockerId && service.version}
<a
id="configuration"
href="/services/{id}"
sveltekit:prefetch
class="hover:text-yellow-500 rounded"
class:text-yellow-500={$page.url.pathname === `/services/${id}`}
class:bg-coolgray-500={$page.url.pathname === `/services/${id}`}
>
<button
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm disabled:text-red-500"
data-tip={$t('application.configurations')}
>
<button class="icons bg-transparent text-sm disabled:text-red-500">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -308,17 +308,16 @@
</svg></button
></a
>
<Tooltip triggeredBy="#configuration">Configuration</Tooltip>
<a
id="secrets"
href="/services/{id}/secrets"
sveltekit:prefetch
class="hover:text-pink-500 rounded"
class:text-pink-500={$page.url.pathname === `/services/${id}/secrets`}
class:bg-coolgray-500={$page.url.pathname === `/services/${id}/secrets`}
>
<button
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm disabled:text-red-500"
data-tip={$t('application.secret')}
>
<button class="icons bg-transparent text-sm disabled:text-red-500">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -338,17 +337,16 @@
</svg></button
></a
>
<Tooltip triggeredBy="#secrets">Secrets</Tooltip>
<a
id="persistentstorage"
href="/services/{id}/storages"
sveltekit:prefetch
class="hover:text-pink-500 rounded"
class:text-pink-500={$page.url.pathname === `/services/${id}/storages`}
class:bg-coolgray-500={$page.url.pathname === `/services/${id}/storages`}
>
<button
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm disabled:text-red-500"
data-tip="Persistent Storage"
>
<button class="icons bg-transparent text-sm disabled:text-red-500">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
@ -366,19 +364,17 @@
</svg>
</button></a
>
<Tooltip triggeredBy="#persistentstorage">Persistent Storage</Tooltip>
<div class="border border-stone-700 h-8" />
<a
id="logs"
href={!$disabledButton && $status.service.isRunning ? `/services/${id}/logs` : null}
sveltekit:prefetch
class="hover:text-pink-500 rounded"
class:text-pink-500={$page.url.pathname === `/services/${id}/logs`}
class:bg-coolgray-500={$page.url.pathname === `/services/${id}/logs`}
>
<button
disabled={!$status.service.isRunning}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip={$t('service.logs')}
>
<button disabled={!$status.service.isRunning} class="icons bg-transparent text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -398,16 +394,16 @@
</svg></button
></a
>
<Tooltip triggeredBy="#logs">Logs</Tooltip>
{/if}
<button
id="delete"
on:click={deleteService}
type="submit"
disabled={!$appSession.isAdmin}
class:hover:text-red-500={$appSession.isAdmin}
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
data-tip={$appSession.isAdmin
? $t('service.delete_service')
: $t('service.permission_denied_delete_service')}><DeleteIcon /></button
class="icons bg-transparent text-sm"><DeleteIcon /></button
>
<Tooltip triggeredBy="#delete">Delete</Tooltip>
</nav>
<slot />

View File

@ -5,6 +5,7 @@
import { t } from '$lib/translations';
import { errorNotification } from '$lib/common';
import { onDestroy, onMount } from 'svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
let service: any = {};
let logsLoading = false;
@ -126,9 +127,9 @@
{/if}
<div class="flex justify-end sticky top-0 p-1 mx-1">
<button
id="follow"
on:click={followBuild}
class="bg-transparent btn btn-sm tooltip tooltip-primary tooltip-bottom"
data-tip="Follow logs"
class="bg-transparent btn btn-sm"
class:text-green-500={followingLogs}
>
<svg
@ -148,6 +149,7 @@
<line x1="16" y1="12" x2="12" y2="16" />
</svg>
</button>
<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
</div>
<div
class="font-mono w-full leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 py-5 px-6 whitespace-pre-wrap break-words overflow-auto max-h-[80vh] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"

View File

@ -26,6 +26,7 @@
import { addToast, appSession, features } from '$lib/store';
import { errorNotification, getDomain } from '$lib/common';
import Menu from './_Menu.svelte';
import DocLink from '$lib/components/DocLink.svelte';
let isRegistrationEnabled = settings.isRegistrationEnabled;
let dualCerts = settings.dualCerts;
@ -195,8 +196,8 @@
<div class="flex-col">
<div class="pt-2 text-base font-bold text-stone-100">
{$t('application.url_fqdn')}
<DocLink explanation={$t('setting.ssl_explainer')} />
</div>
<Explainer text={$t('setting.ssl_explainer')} />
</div>
<div class="justify-start text-left">
<input
@ -250,8 +251,8 @@
<div class="flex-col">
<div class="pt-2 text-base font-bold text-stone-100">
{$t('forms.public_port_range')}
<DocLink explanation={$t('forms.public_port_range_explainer')} />
</div>
<Explainer text={$t('forms.public_port_range_explainer')} />
</div>
<div class="mx-auto flex-row items-center justify-center space-y-2">
<input
@ -273,6 +274,7 @@
</div>
<div class="grid grid-cols-2 items-center">
<Setting
id="isDNSCheckEnabled"
bind:setting={isDNSCheckEnabled}
title={$t('setting.is_dns_check_enabled')}
description={$t('setting.is_dns_check_enabled_explainer')}
@ -280,18 +282,19 @@
/>
</div>
<div class="grid grid-cols-2 items-center">
<div class="flex-col">
<div class="pt-2 text-base font-bold text-stone-100">
Custom DNS servers
</div>
<Explainer text="You can specify a custom DNS server to verify your domains all over Coolify.<br><br>By default, the OS defined DNS servers are used." />
<div class="text-base font-bold text-stone-100">
Custom DNS servers <DocLink
explanation="You can specify a custom DNS server to verify your domains all over Coolify.<br><br>By default, the OS defined DNS servers are used."
/>
</div>
<div class="mx-auto flex-row items-center justify-center space-y-2">
<div class="flex-row items-center justify-center">
<input placeholder="1.1.1.1,8.8.8.8" bind:value={DNSServers} />
</div>
</div>
<div class="grid grid-cols-2 items-center">
<Setting
id="dualCerts"
dataTooltip={$t('setting.must_remove_domain_before_changing')}
disabled={isFqdnSet}
bind:setting={dualCerts}

View File

@ -8,6 +8,7 @@
import { dashify, errorNotification, getDomain } from '$lib/common';
import { addToast, appSession } from '$lib/store';
import { dev } from '$app/env';
import DocLink from '$lib/components/DocLink.svelte';
const { id } = $page.params;
@ -115,7 +116,9 @@
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
</div>
<div class="grid lg:grid-cols-2 items-center">
<label for="customPort" class="text-base font-bold text-stone-100">Custom SSH Port</label>
<label for="customPort" class="text-base font-bold text-stone-100">Custom SSH Port <DocLink
explanation={"If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."}
/></label>
<input
name="customPort"
id="customPort"
@ -124,18 +127,15 @@
required
value={source.customPort}
/>
<Explainer
text="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."
/>
</div>
<div class="grid lg:grid-cols-2">
<div class="flex flex-col">
<label for="organization" class="pt-2 text-base font-bold text-stone-100"
>Organization</label
>Organization
<DocLink
explanation={"Fill it if you would like to use an organization's as your Git Source. Otherwise your user will be used."}
/></label
>
<Explainer
text="Fill it if you would like to use an organization's as your Git Source. Otherwise your user will be used."
/>
</div>
<input
name="organization"

View File

@ -11,6 +11,7 @@
import { t } from '$lib/translations';
import { errorNotification } from '$lib/common';
import { addToast, appSession } from '$lib/store';
import DocLink from '$lib/components/DocLink.svelte';
const { id } = $page.params;
let url = settings.fqdn ? settings.fqdn : window.location.origin;
@ -148,10 +149,8 @@
<div class="flex space-x-1 pb-7">
<div class="title">General</div>
{#if $appSession.isAdmin}
<button
type="submit"
class="btn btn-sm bg-sources"
disabled={loading}>{loading ? $t('forms.saving') : $t('forms.save')}</button
<button type="submit" class="btn btn-sm bg-sources" disabled={loading}
>{loading ? $t('forms.saving') : $t('forms.save')}</button
>
{#if source.gitlabAppId}
<button class="btn btn-sm" on:click|preventDefault={changeSettings}
@ -166,16 +165,12 @@
</div>
<div class="grid grid-flow-row gap-2 px-10">
{#if !source.gitlabAppId}
<Explainer
customClass="w-full"
text="<span class='font-bold text-base text-white'>Scopes required:</span>
<br>- <span class='text-sources font-bold'>api</span> (Access the authenticated user's API)
<br>- <span class='text-sources font-bold'>read_repository</span> (Allows read-only access to the repository)
<br>- <span class='text-sources font-bold'>email</span> (Allows read-only access to the user's primary email address using OpenID Connect)
<br>
<br>For extra security, you can set <span class='text-sources font-bold'>Expire Access Tokens</span>
<br><br>Webhook URL: <span class='text-sources font-bold'>{url}/webhooks/gitlab</span>"
/>
<a
href="https://docs.coollabs.io/coolify/sources#how-to-integrate-with-gitlab"
class="font-bold "
target="_blank"
rel="noopener noreferrer">Documentation and detailed instructions.</a
>
<div class="grid grid-cols-2 items-center">
<label for="type" class="text-base font-bold text-stone-100">Application Type</label>
<select name="type" id="type" class="w-96" bind:value={applicationType}>
@ -245,7 +240,11 @@
</div>
{#if selfHosted}
<div class="grid grid-cols-2 items-center">
<label for="customPort" class="text-base font-bold text-stone-100">Custom SSH Port</label>
<label for="customPort" class="text-base font-bold text-stone-100"
>Custom SSH Port <DocLink
explanation={'If you use a self-hosted version of Git, you can provide custom port for all the Git related actions.'}
/></label
>
<input
name="customPort"
id="customPort"
@ -254,19 +253,16 @@
required
bind:value={source.customPort}
/>
<Explainer
text="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."
/>
</div>
{/if}
<div class="grid grid-cols-2 items-start">
<div class="flex-col">
<label for="oauthId" class="pt-2 text-base font-bold text-stone-100"
>{$t('source.oauth_id')}</label
>{$t('source.oauth_id')}
{#if !source.gitlabAppId}
<DocLink explanation={$t('source.oauth_id_explainer')} />
{/if}</label
>
{#if !source.gitlabAppId}
<Explainer text={$t('source.oauth_id_explainer')} />
{/if}
</div>
<input
disabled={source.gitlabAppId}

View File

@ -37,6 +37,7 @@
import { appSession } from '$lib/store';
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
import { goto } from '$app/navigation';
import Tooltip from '$lib/components/Tooltip.svelte';
const { id } = $page.params;
async function deleteSource(name: string) {
@ -55,15 +56,14 @@
{#if id !== 'new'}
<nav class="nav-side">
<button
id="delete"
on:click={() => deleteSource(source.name)}
type="submit"
disabled={!$appSession.isAdmin}
class:hover:text-red-500={$appSession.isAdmin}
class="icons tooltip tooltip-primary tooltip-bottom bg-transparent text-sm"
data-tip={$appSession.isAdmin
? $t('source.delete_git_source')
: $t('source.permission_denied')}><DeleteIcon /></button
class="icons bg-transparent text-sm"><DeleteIcon /></button
>
</nav>
<Tooltip triggeredBy="#delete">Delete</Tooltip>
{/if}
<slot />

View File

@ -1,15 +1,15 @@
const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = {
content: ['./**/*.html', './src/**/*.{js,jsx,ts,tsx,svelte}'],
important: true,
content: ['./**/*.html', './src/**/*.{js,jsx,ts,tsx,svelte}', "./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",],
important: true,
daisyui: {
themes: [
{
coollabs: {
"base-100":"#323232",
"base-200":"#242424",
"base-300":"#181818",
"base-100": "#323232",
"base-200": "#242424",
"base-300": "#181818",
"primary": "#6d28d9",
"primary-content": "#fff",
"secondary": "#343232",
@ -40,13 +40,13 @@ module.exports = {
sans: ['Poppins', ...defaultTheme.fontFamily.sans]
},
colors: {
"applications":"#16A34A",
"databases":"#9333EA",
"destinations":"#0284C7",
"sources":"#EA580C",
"services":"#DB2777",
"settings":"#FEE440",
"iam":"#C026D3",
"applications": "#16A34A",
"databases": "#9333EA",
"destinations": "#0284C7",
"sources": "#EA580C",
"services": "#DB2777",
"settings": "#FEE440",
"iam": "#C026D3",
coollabs: '#6B16ED',
'coollabs-100': '#7317FF',
coolblack: '#161616',
@ -62,5 +62,6 @@ module.exports = {
scrollbar: ['dark'],
extend: {}
},
darkMode: 'class',
plugins: [require('tailwindcss-scrollbar'), require('daisyui'), require("@tailwindcss/typography")]
};

55
pnpm-lock.yaml generated
View File

@ -131,7 +131,9 @@ importers:
apps/ui:
specifiers:
'@floating-ui/dom': ^1.0.1
'@playwright/test': 1.25.1
'@popperjs/core': ^2.11.6
'@sveltejs/adapter-static': 1.0.0-next.39
'@sveltejs/kit': 1.0.0-next.405
'@tailwindcss/typography': ^0.5.4
@ -139,11 +141,14 @@ importers:
'@typescript-eslint/eslint-plugin': 5.35.1
'@typescript-eslint/parser': 5.35.1
autoprefixer: 10.4.8
classnames: ^2.3.1
cuid: 2.1.8
daisyui: 2.24.0
eslint: 8.22.0
eslint-config-prettier: 8.5.0
eslint-plugin-svelte3: 4.0.0
flowbite: ^1.5.2
flowbite-svelte: ^0.26.2
js-cookie: 3.0.1
p-limit: 4.0.0
postcss: 8.4.16
@ -169,15 +174,20 @@ importers:
svelte-select: 4.4.7
sveltekit-i18n: 2.2.2_svelte@3.49.0
devDependencies:
'@floating-ui/dom': 1.0.1
'@playwright/test': 1.25.1
'@popperjs/core': 2.11.6
'@sveltejs/kit': 1.0.0-next.405_svelte@3.49.0+vite@3.0.5
'@types/js-cookie': 3.0.2
'@typescript-eslint/eslint-plugin': 5.35.1_ktjxjibzrfqejavile4bhmzhjq
'@typescript-eslint/parser': 5.35.1_4rv7y5c6xz3vfxwhbrcxxi73bq
autoprefixer: 10.4.8_postcss@8.4.16
classnames: 2.3.1
eslint: 8.22.0
eslint-config-prettier: 8.5.0_eslint@8.22.0
eslint-plugin-svelte3: 4.0.0_laaqauvsmoyypsiqkozwyi2fn4
flowbite: 1.5.2
flowbite-svelte: 0.26.2
postcss: 8.4.16
prettier: 2.7.1
prettier-plugin-svelte: 2.7.0_o3ioganyptcsrh6x4hnxvjkpqi
@ -369,6 +379,16 @@ packages:
- supports-color
dev: false
/@floating-ui/core/1.0.1:
resolution: {integrity: sha512-bO37brCPfteXQfFY0DyNDGB3+IMe4j150KFQcgJ5aBP295p9nBGeHEs/p0czrRbtlHq4Px/yoPXO/+dOCcF4uA==}
dev: true
/@floating-ui/dom/1.0.1:
resolution: {integrity: sha512-wBDiLUKWU8QNPNOTAFHiIAkBv1KlHauG2AhqjSeh2H+wR8PX+AArXfz8NkRexH5PgMJMmSOS70YS89AbWYh5dA==}
dependencies:
'@floating-ui/core': 1.0.1
dev: true
/@humanwhocodes/config-array/0.10.4:
resolution: {integrity: sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==}
engines: {node: '>=10.10.0'}
@ -458,6 +478,10 @@ packages:
playwright-core: 1.25.1
dev: true
/@popperjs/core/2.11.6:
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
dev: true
/@prisma/client/3.15.2_prisma@3.15.2:
resolution: {integrity: sha512-ErqtwhX12ubPhU4d++30uFY/rPcyvjk+mdifaZO5SeM21zS3t4jQrscy8+6IyB0GIYshl5ldTq6JSBo1d63i8w==}
engines: {node: '>=12.6'}
@ -2000,6 +2024,10 @@ packages:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false
/classnames/2.3.1:
resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==}
dev: true
/clean-stack/4.2.0:
resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==}
engines: {node: '>=12'}
@ -3461,6 +3489,24 @@ packages:
resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==}
dev: true
/flowbite-svelte/0.26.2:
resolution: {integrity: sha512-CpZ33fyMuzrYvECKN2rD5zNa/ZY0c4cDMcY6wE/hvajFybbCqwMYzd0AkA88zTNm5fknEN0/E23TVmD4Qkhzzw==}
engines: {node: '>=16.0.0', npm: '>=7.0.0'}
dependencies:
'@floating-ui/dom': 1.0.1
'@popperjs/core': 2.11.6
classnames: 2.3.1
flowbite: 1.5.2
svelte-heros: 2.3.5
dev: true
/flowbite/1.5.2:
resolution: {integrity: sha512-oSKhPkg0bYb4dZG4ypSh++dPrFM3IOSER6HOwJHYRFPW5u9PXL4AQFMQh7Kytgws2xrDQyl/zqefZmymeWt2IA==}
dependencies:
'@popperjs/core': 2.11.6
mini-svg-data-uri: 1.4.4
dev: true
/follow-redirects/1.15.0:
resolution: {integrity: sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==}
engines: {node: '>=4.0'}
@ -4482,6 +4528,11 @@ packages:
engines: {node: '>=4'}
dev: true
/mini-svg-data-uri/1.4.4:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
hasBin: true
dev: true
/minimalistic-assert/1.0.1:
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
dev: false
@ -5856,6 +5907,10 @@ packages:
- sugarss
dev: true
/svelte-heros/2.3.5:
resolution: {integrity: sha512-08PdccaeRPP1pVa90AGieTwGzrNtXpC1Fry+i95OTvcR3xbGRU/hxK4rnaFYvGgk1Pxj9YT6GKGTEX8uXE9XJQ==}
dev: true
/svelte-hmr/0.14.12_svelte@3.49.0:
resolution: {integrity: sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}