ui: redesign applications & settings

fix: follow logs
This commit is contained in:
Andras Bacsai 2022-09-22 12:30:28 +02:00
parent 6dd7f6274a
commit 9066952759
17 changed files with 875 additions and 778 deletions

View File

@ -156,6 +156,7 @@ prisma.setting.findFirst().then(async (settings) => {
setInterval(async () => { setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:copySSLCertificates") scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:copySSLCertificates")
}, 2000) }, 2000)
// cleanupPrismaEngines // cleanupPrismaEngines
// setInterval(async () => { // setInterval(async () => {
// scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupPrismaEngines") // scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupPrismaEngines")

View File

@ -9,8 +9,8 @@ Bree.extend(TSBree);
const options: any = { const options: any = {
defaultExtension: 'js', defaultExtension: 'js',
// logger: new Cabin(), logger: new Cabin(),
logger: false, // logger: false,
workerMessageHandler: async ({ name, message }) => { workerMessageHandler: async ({ name, message }) => {
if (name === 'deployApplication' && message?.deploying) { if (name === 'deployApplication' && message?.deploying) {
if (scheduler.workers.has('autoUpdater') || scheduler.workers.has('cleanupStorage')) { if (scheduler.workers.has('autoUpdater') || scheduler.workers.has('cleanupStorage')) {

View File

@ -312,7 +312,7 @@
</div> </div>
<div class="drawer-side"> <div class="drawer-side">
<label for="main-drawer" class="drawer-overlay w-full" /> <label for="main-drawer" class="drawer-overlay w-full" />
<ul class="menu bg-coolgray-300 w-60 p-2 space-y-3 pt-4 "> <ul class="menu bg-coolgray-200 w-60 p-2 space-y-3 pt-4 ">
<li> <li>
<a <a
class="no-underline icons hover:text-white hover:bg-pink-500" class="no-underline icons hover:text-white hover:bg-pink-500"

View File

@ -0,0 +1,21 @@
<script lang="ts">
import { page } from '$app/stores';
</script>
<ul class="menu border bg-coolgray-100 border-coolgray-200 rounded-box p-2 space-y-2">
<li class="menu-title">
<span>General</span>
</li>
<li class="rounded" class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}`}>
<a href={`/applications/${$page.params.id}`} class="no-underline w-full">Build & Deploy</a>
</li>
<li class="menu-title">
<span>Other</span>
</li>
<li
class="rounded"
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/features`}
>
<a href={`/applications/${$page.params.id}/features`} class="no-underline w-full">Features</a>
</li>
</ul>

View File

@ -72,6 +72,7 @@
} from '$lib/store'; } from '$lib/store';
import { errorNotification, handlerNotFoundLoad } from '$lib/common'; import { errorNotification, handlerNotFoundLoad } from '$lib/common';
import Tooltip from '$lib/components/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip.svelte';
import Menu from './_Menu.svelte';
let statusInterval: any; let statusInterval: any;
let forceDelete = false; let forceDelete = false;
@ -188,79 +189,33 @@
}); });
</script> </script>
<nav class="header lg:flex-row flex-col-reverse"> <div class="mx-auto max-w-screen-2xl px-6 grid grid-cols-1 lg:grid-cols-2">
<div class="flex flex-row space-x-2 font-bold pt-10 lg:pt-0"> <nav class="header flex flex-row order-2 lg:order-1 px-0 lg:px-4">
<div class="flex flex-col items-center justify-center"> <div class="title lg:pb-10">
<div class="title"> {#if $page.url.pathname === `/applications/${id}` || $page.url.pathname === `/applications/${id}/features`}
{#if $page.url.pathname === `/applications/${id}`} Configurations
Configurations {:else if $page.url.pathname === `/applications/${id}/secrets`}
{:else if $page.url.pathname === `/applications/${id}/secrets`} Secrets
Secrets {:else if $page.url.pathname === `/applications/${id}/storages`}
{:else if $page.url.pathname === `/applications/${id}/storages`} Persistent Storages
Persistent Storages {:else if $page.url.pathname === `/applications/${id}/previews`}
{:else if $page.url.pathname === `/applications/${id}/previews`} Preview Deployments
Preview Deployments {:else if $page.url.pathname === `/applications/${id}/logs`}
{:else if $page.url.pathname === `/applications/${id}/logs`} Application Logs
Application Logs {:else if $page.url.pathname === `/applications/${id}/logs/build`}
{:else if $page.url.pathname === `/applications/${id}/logs/build`} Build Logs
Build Logs {:else if $page.url.pathname === `/applications/${id}/configuration/source`}
{:else if $page.url.pathname === `/applications/${id}/configuration/source`} Select a Git Source
Select a Git Source {:else if $page.url.pathname === `/applications/${id}/configuration/destination`}
{:else if $page.url.pathname === `/applications/${id}/configuration/destination`} Select a Destination
Select a Destination {:else if $page.url.pathname === `/applications/${id}/configuration/buildpack`}
{:else if $page.url.pathname === `/applications/${id}/configuration/buildpack`} Select a Build Pack
Select a Build Pack {/if}
{/if}
</div>
</div> </div>
{#if application.gitSource?.htmlUrl && application.repository && application.branch} </nav>
<a <div
id="git" class="header flex flex-row items-start justify-center lg:justify-end space-x-2 order-1 lg:order-2"
href="{application.gitSource.htmlUrl}/{application.repository}/tree/{application.branch}" >
target="_blank"
class="w-6 h-6 lg:w-10 lg:h-10"
>
{#if application.gitSource?.type === 'gitlab'}
<svg viewBox="0 0 128 128" class="icons">
<path
fill="#FC6D26"
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
fill="#FC6D26"
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
/><path
fill="#FCA326"
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
/><path
fill="#E24329"
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
fill="#FCA326"
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
/><path
fill="#E24329"
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
/>
</svg>
{:else if application.gitSource?.type === 'github'}
<svg viewBox="0 0 128 128" class="icons">
<g fill="#ffffff"
><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
/><path
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
/></g
>
</svg>
{/if}
</a>
<Tooltip triggeredBy="#git">Open on Git</Tooltip>
{/if}
</div>
<div class="lg:block hidden flex-1" />
<div class="flex flex-row flex-wrap space-x-3 justify-center lg:justify-start lg:py-0 px-12 lg:px-0">
{#if $location} {#if $location}
<a id="open" href={$location} target="_blank" class="icons bg-transparent" <a id="open" href={$location} target="_blank" class="icons bg-transparent"
><svg ><svg
@ -431,14 +386,15 @@
<Tooltip triggeredBy="#deploy">Deploy</Tooltip> <Tooltip triggeredBy="#deploy">Deploy</Tooltip>
</form> </form>
{/if} {/if}
<div class="hidden lg:block border border-coolgray-500 h-8" /> <div class="hidden lg:block border border-coolgray-500 h-8" />
<a <a
href={$isDeploymentEnabled ? `/applications/${id}` : null} href={$isDeploymentEnabled ? `/applications/${id}` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-yellow-500 rounded" class="hover:text-yellow-500 rounded"
class:text-yellow-500={$page.url.pathname === `/applications/${id}`} class:text-yellow-500={$page.url.pathname === `/applications/${id}` ||
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}`} $page.url.pathname === `/applications/${id}/features`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}` ||
$page.url.pathname === `/applications/${id}/features`}
> >
<button <button
disabled={!$isDeploymentEnabled} disabled={!$isDeploymentEnabled}
@ -653,5 +609,18 @@
<Tooltip triggeredBy="#delete" placement="left">Delete</Tooltip> <Tooltip triggeredBy="#delete" placement="left">Delete</Tooltip>
{/if} {/if}
</div> </div>
</nav> </div>
<slot /> <div class="mx-auto max-w-screen-2xl px-6 grid grid-cols-1 lg:grid-cols-4">
{#if $page.url.pathname === `/applications/${$page.params.id}` || $page.url.pathname === `/applications/${$page.params.id}/features`}
<nav class="header flex flex-col lg:pt-0">
<Menu />
</nav>
<div class="pt-0 px-5 col-span-0 lg:col-span-3 pb-24">
<slot />
</div>
{:else}
<div class="pt-0 px-5 col-span-0 lg:col-span-4 pb-24">
<slot />
</div>
{/if}
</div>

View File

@ -0,0 +1,160 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
export const load: Load = async ({ fetch, params, stuff, url }) => {
try {
if (stuff?.application?.id) {
return {
props: {
application: stuff.application,
settings: stuff.settings
}
};
}
const response = await get(`/applications/${params.id}`);
return {
props: {
...response
}
};
} catch (error) {
return {
status: 500,
error: new Error(`Could not load ${url}`)
};
}
};
</script>
<script lang="ts">
export let application: any;
export let settings: any;
import { page } from '$app/stores';
import { get, post } from '$lib/api';
import {
addToast,
appSession,
checkIfDeploymentEnabledApplications,
setLocation,
status,
isDeploymentEnabled
} from '$lib/store';
import { t } from '$lib/translations';
import { errorNotification, getDomain, notNodeDeployments, staticDeployments } from '$lib/common';
import Setting from '$lib/components/Setting.svelte';
const { id } = $page.params;
let debug = application.settings.debug;
let previews = application.settings.previews;
let dualCerts = application.settings.dualCerts;
let autodeploy = application.settings.autodeploy;
let isBot = application.settings.isBot;
let isDBBranching = application.settings.isDBBranching;
async function changeSettings(name: any) {
if (name === 'debug') {
debug = !debug;
}
if (name === 'previews') {
previews = !previews;
}
if (name === 'dualCerts') {
dualCerts = !dualCerts;
}
if (name === 'autodeploy') {
autodeploy = !autodeploy;
}
if (name === 'isBot') {
if ($status.application.isRunning) return;
isBot = !isBot;
application.settings.isBot = isBot;
application.fqdn = null;
setLocation(application, settings);
}
if (name === 'isDBBranching') {
isDBBranching = !isDBBranching;
}
try {
await post(`/applications/${id}/settings`, {
previews,
debug,
dualCerts,
isBot,
autodeploy,
isDBBranching,
branch: application.branch,
projectId: application.projectId
});
return addToast({
message: $t('application.settings_saved'),
type: 'success'
});
} catch (error) {
if (name === 'debug') {
debug = !debug;
}
if (name === 'previews') {
previews = !previews;
}
if (name === 'dualCerts') {
dualCerts = !dualCerts;
}
if (name === 'autodeploy') {
autodeploy = !autodeploy;
}
if (name === 'isBot') {
isBot = !isBot;
}
if (name === 'isDBBranching') {
isDBBranching = !isDBBranching;
}
return errorNotification(error);
} finally {
$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
}
}
</script>
<div class="w-full">
<div class="mx-auto w-full">
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
<div class="title font-bold pb-3">Features</div>
</div>
<div class="px-4 lg:pb-10 pb-6">
{#if !application.settings.isPublicRepository}
<div class="grid grid-cols-2 items-center">
<Setting
id="autodeploy"
isCenter={false}
bind:setting={autodeploy}
on:click={() => changeSettings('autodeploy')}
title={$t('application.enable_automatic_deployment')}
description={$t('application.enable_auto_deploy_webhooks')}
/>
</div>
{/if}
{#if !application.settings.isBot && !application.settings.isPublicRepository}
<div class="grid grid-cols-2 items-center">
<Setting
id="previews"
isCenter={false}
bind:setting={previews}
on:click={() => changeSettings('previews')}
title={$t('application.enable_mr_pr_previews')}
description={$t('application.enable_preview_deploy_mr_pr_requests')}
/>
</div>
{/if}
<div class="grid grid-cols-2 items-center w-full">
<Setting
id="debug"
isCenter={false}
bind:setting={debug}
on:click={() => changeSettings('debug')}
title={$t('application.debug_logs')}
description={$t('application.enable_debug_log_during_build')}
/>
</div>
</div>
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,8 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
const dispatch = createEventDispatcher();
import { page } from '$app/stores'; import { page } from '$app/stores';
import { get, post } from '$lib/api'; import { get, post } from '$lib/api';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import LoadingLogs from '$lib/components/LoadingLogs.svelte';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import Tooltip from '$lib/components/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip.svelte';
import { day } from '$lib/dayjs'; import { day } from '$lib/dayjs';
@ -15,19 +11,30 @@
let logs: any = []; let logs: any = [];
let currentStatus: any; let currentStatus: any;
let streamInterval: any; let streamInterval: any;
let followingBuild: any; let followingLogs: any;
let followingInterval: any; let followingInterval: any;
let logsEl: any; let logsEl: any;
let fromDb = false; let fromDb = false;
let cancelInprogress = false; let cancelInprogress = false;
let position = 0;
const { id } = $page.params; const { id } = $page.params;
const cleanAnsiCodes = (str: string) => str.replace(/\x1B\[(\d+)m/g, ''); const cleanAnsiCodes = (str: string) => str.replace(/\x1B\[(\d+)m/g, '');
function detect() {
if (position < logsEl.scrollTop) {
position = logsEl.scrollTop;
} else {
if (followingLogs) {
clearInterval(followingInterval);
followingLogs = false;
}
position = logsEl.scrollTop;
}
}
function followBuild() { function followBuild() {
followingBuild = !followingBuild; followingLogs = !followingLogs;
if (followingBuild) { if (followingLogs) {
followingInterval = setInterval(() => { followingInterval = setInterval(() => {
logsEl.scrollTop = logsEl.scrollHeight; logsEl.scrollTop = logsEl.scrollHeight;
window.scrollTo(0, document.body.scrollHeight); window.scrollTo(0, document.body.scrollHeight);
@ -63,11 +70,10 @@
status = data.status; status = data.status;
currentStatus = status; currentStatus = status;
fromDb = data.fromDb; fromDb = data.fromDb;
logs = logs.concat( logs = logs.concat(
data.logs.map((log: any) => ({ ...log, line: cleanAnsiCodes(log.line) })) data.logs.map((log: any) => ({ ...log, line: cleanAnsiCodes(log.line) }))
); );
dispatch('updateBuildStatus', { status, took: data.took });
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} }
@ -98,23 +104,18 @@
}); });
</script> </script>
<div class="relative "> <div class="relative" class:pt-10={currentStatus !== 'running'}>
{#if currentStatus === 'running'} {#if currentStatus === 'running'}
<LoadingLogs /> <div class="flex justify-start sticky top-0 pb-2 space-x-2">
{/if}
{#if currentStatus === 'queued'}
<div class="text-center font-bold text-xl">{$t('application.build.queued_waiting_exec')}</div>
{:else}
<div class="flex justify-end sticky top-0 p-2 mx-1">
<button <button
id="follow"
on:click={followBuild} on:click={followBuild}
class="bg-transparent btn btn-sm btn-link hover:text-green-500 hover:bg-coolgray-500" class="btn btn-sm bg-coollabs"
class:text-green-500={followingBuild} class:bg-coolgray-300={followingLogs}
class:text-applications={followingLogs}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="w-6 h-6 mr-2"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -128,51 +129,63 @@
<line x1="12" y1="8" x2="12" y2="16" /> <line x1="12" y1="8" x2="12" y2="16" />
<line x1="16" y1="12" x2="12" y2="16" /> <line x1="16" y1="12" x2="12" y2="16" />
</svg> </svg>
{followingLogs ? 'Following Logs...' : 'Follow Logs'}
</button> </button>
<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
{#if currentStatus === 'running'} <button
<button on:click={cancelBuild}
id="cancel" class:animation-spin={cancelInprogress}
on:click={cancelBuild} class="btn btn-sm"
class:animation-spin={cancelInprogress} class:bg-error={!cancelInprogress}
class="bg-transparent btn btn-sm btn-link hover:text-red-500 hover:bg-coolgray-500" class:bg-coolgray-300={cancelInprogress}
class:text-error={cancelInprogress}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6 mr-2"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
> >
{#if cancelInprogress} <path stroke="none" d="M0 0h24v24H0z" fill="none" />
Cancelling... <circle cx="12" cy="12" r="9" />
{:else} <path d="M10 10l4 4m0 -4l-4 4" />
<svg </svg>
xmlns="http://www.w3.org/2000/svg" {cancelInprogress ? 'Cancelling...' : 'Cancel Build'}
class="w-6 h-6" </button>
viewBox="0 0 24 24" <button id="streaming" class="btn btn-sm bg-transparent border-none loading" />
stroke-width="1.5" <Tooltip triggeredBy="#streaming">Streaming logs</Tooltip>
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="12" cy="12" r="9" />
<path d="M10 10l4 4m0 -4l-4 4" />
</svg>
{/if}
</button>
<Tooltip triggeredBy="#cancel">Cancel build</Tooltip>
{/if}
</div> </div>
{#if logs.length > 0} {/if}
<div class="font-mono w-full rounder bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded-md mb-20 flex flex-col whitespace-nowrap -mt-12 scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"> {#if currentStatus === 'queued'}
{#each logs as log} <div
{#if fromDb} class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col whitespace-nowrap scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
<div>{log.line + '\n'}</div> >
{:else} {$t('application.build.queued_waiting_exec')}
<div>[{day.unix(log.time).format('HH:mm:ss.SSS')}] {log.line + '\n'}</div> </div>
{/if} {:else if logs.length > 0}
{/each} <div
</div> bind:this={logsEl}
{:else} on:scroll={detect}
<div class="font-mono w-full rounder bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded-md mb-20 flex flex-col whitespace-nowrap -mt-12 scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"> class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
No logs found. >
{#each logs as log}
{#if fromDb}
<div>{log.line + '\n'}</div>
{:else}
<div>[{day.unix(log.time).format('HH:mm:ss.SSS')}] {log.line + '\n'}</div>
{/if}
{/each}
</div>
{:else}
<div
class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col whitespace-nowrap scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
No logs found yet.
</div> </div>
{/if}
{/if} {/if}
</div> </div>

View File

@ -107,9 +107,9 @@
} }
</script> </script>
<div class="block flex-row justify-start space-x-2 px-5 pt-6 sm:px-10 md:flex"> <div class="block flex-row justify-start space-x-2 px-5 sm:px-10 md:flex">
<div class="mb-4 min-w-[16rem] space-y-2 md:mb-0 "> <div class="mb-4 min-w-[16rem] space-y-2 md:mb-0 ">
<button class="btn btn-sm text-xs w-full bg-error" on:click={resetQueue} <button class="btn btn-sm w-full bg-error" on:click={resetQueue}
>Reset Build Queue</button >Reset Build Queue</button
> >
<div class="top-4 md:sticky"> <div class="top-4 md:sticky">
@ -167,7 +167,7 @@
<div class="flex space-x-2 pb-10"> <div class="flex space-x-2 pb-10">
<button <button
disabled={noMoreBuilds} disabled={noMoreBuilds}
class=" btn btn-sm w-full text-xs" class=" btn btn-sm w-full"
on:click={loadMoreBuilds}>{$t('application.build.load_more')}</button on:click={loadMoreBuilds}>{$t('application.build.load_more')}</button
> >
</div> </div>

View File

@ -91,26 +91,21 @@
} }
</script> </script>
<div class="flex flex-row justify-center space-x-2 px-10">
<div class="flex flex-row justify-center space-x-2 px-10 pt-6">
{#if logs.length === 0} {#if logs.length === 0}
<div class="text-xl font-bold tracking-tighter">{$t('application.build.waiting_logs')}</div> <div class="text-xl font-bold tracking-tighter">{$t('application.build.waiting_logs')}</div>
{:else} {:else}
<div class="relative w-full"> <div class="relative w-full">
<div class="text-right " /> <div class="flex justify-start sticky space-x-2 pb-2">
{#if loadLogsInterval}
<LoadingLogs />
{/if}
<div class="flex justify-end sticky top-0 p-1 mx-1">
<button <button
id="follow"
on:click={followBuild} on:click={followBuild}
class="bg-transparent btn btn-sm btn-link" class="btn btn-sm bg-coollabs"
class:text-green-500={followingLogs} class:bg-coolgray-300={followingLogs}
class:text-applications={followingLogs}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="w-6 h-6 mr-2"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -124,10 +119,18 @@
<line x1="12" y1="8" x2="12" y2="16" /> <line x1="12" y1="8" x2="12" y2="16" />
<line x1="16" y1="12" x2="12" y2="16" /> <line x1="16" y1="12" x2="12" y2="16" />
</svg> </svg>
{followingLogs ? 'Following Logs...' : 'Follow Logs'}
</button> </button>
<Tooltip triggeredBy="#follow">Follow Logs</Tooltip> {#if loadLogsInterval}
<button id="streaming" class="btn btn-sm bg-transparent border-none loading" />
<Tooltip triggeredBy="#streaming">Streaming logs</Tooltip>
{/if}
</div> </div>
<div class="font-mono w-full rounder bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded-md mb-20 flex flex-col whitespace-nowrap -mt-12 scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"> <div
bind:this={logsEl}
on:scroll={detect}
class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
{#each logs as log} {#each logs as log}
<p>{log + '\n'}</p> <p>{log + '\n'}</p>
{/each} {/each}

View File

@ -3,29 +3,22 @@
import { appSession } from '$lib/store'; import { appSession } from '$lib/store';
</script> </script>
<ul class="menu bg-coolgray-200 rounded"> <ul class="menu border bg-coolgray-100 border-coolgray-200 rounded-box p-2 space-y-2">
<li class="menu-title">
<span>General</span>
</li>
{#if $appSession.teamId === '0'} {#if $appSession.teamId === '0'}
<li <li class="rounded" class:bg-coollabs={$page.url.pathname === `/settings/coolify`}>
class="hover:bg-coollabs duration-150" <a href={`/settings/coolify`} class="no-underline w-full">Coolify Settings</a>
class:bordered={$page.url.pathname === '/settings/coolify'}
class:bg-coolgray-500={$page.url.pathname === '/settings/coolify'}
>
<a href="/settings/coolify" class="no-underline w-full">Coolify Settings</a>
</li> </li>
{/if} {/if}
<li class="menu-title">
<li <span>Keys & Certificates</span>
class="hover:bg-coollabs duration-150"
class:bordered={$page.url.pathname === '/settings/ssh'}
class:bg-coolgray-500={$page.url.pathname === '/settings/ssh'}
>
<a href="/settings/ssh" class="no-underline w-full">SSH Keys</a>
</li> </li>
<li <li class="rounded" class:bg-coollabs={$page.url.pathname === `/settings/ssh`}>
class="hover:bg-coollabs duration-150" <a href={`/settings/ssh`} class="no-underline w-full">SSH Keys</a>
class:bordered={$page.url.pathname === '/settings/certificates'} </li>
class:bg-coolgray-400={$page.url.pathname === '/settings/certificates'} <li class="rounded" class:bg-coollabs={$page.url.pathname === `/settings/certificates`}>
> <a href={`/settings/certificates`} class="no-underline w-full">SSL Certificates</a>
<a href="/settings/certificates" class="no-underline w-full">SSL Certificates</a>
</li> </li>
</ul> </ul>

View File

@ -20,12 +20,14 @@
}; };
</script> </script>
<div class="mx-auto max-w-6xl px-6 grid grid-cols-1 lg:grid-cols-4"> <div class="mx-auto max-w-screen-2xl px-6 grid grid-cols-1 lg:grid-cols-4">
<nav class="header flex flex-col"> <nav class="header flex flex-col px-0">
<div class="title pb-10">Settings</div> <div class="title pb-[3.7rem]">Settings</div>
<Menu /> <div class="px-4">
<Menu />
</div>
</nav> </nav>
<div class="pt-0 lg:pt-24 px-5 lg:px-0 col-span-0 lg:col-span-3"> <div class="pt-0 lg:pt-[7rem] px-4 lg:px-7 col-span-0 lg:col-span-3">
<slot /> <slot />
</div> </div>
</div> </div>

View File

@ -55,17 +55,20 @@
} }
</script> </script>
<div class="title font-bold pb-3">SSL Certificates</div>
<div class="w-full"> <div class="w-full">
{#if certificates.length === 0} {#if certificates.length === 0}
<div class="text-sm">No SSL Certificate found</div> <div class="text-sm">No SSL Certificate found</div>
<label <label for="my-modal" class="btn btn-primary mt-6" on:click={() => (isModalActive = true)}
for="my-modal" >Add SSL Certificate</label
class="btn btn-primary mt-6"
on:click={() => (isModalActive = true)}>Add SSL Certificate</label
> >
{:else} {:else}
<div class="mx-auto w-full p-6 bg-coolgray-200 rounded shadow-xl"> <div class="mx-auto w-full">
<div class="flex border-b border-coolgray-500 mb-6">
<div class="title font-bold pb-3 pr-4">SSL Certificates</div>
<label for="my-modal" class="btn btn-sm btn-primary" on:click={() => (isModalActive = true)}
>Add SSL Certificate</label
>
</div>
<table class="table w-full"> <table class="table w-full">
<thead> <thead>
<tr> <tr>
@ -80,7 +83,7 @@
<td>{cert.commonName}</td> <td>{cert.commonName}</td>
<td>{cert.createdAt}</td> <td>{cert.createdAt}</td>
<td <td
><button on:click={() => deleteCertificate(cert.id)} class="btn btn-error" ><button on:click={() => deleteCertificate(cert.id)} class="btn btn-sm btn-error"
>Delete</button >Delete</button
></td ></td
> >
@ -88,9 +91,6 @@
{/each} {/each}
</tbody> </tbody>
</table> </table>
<label for="my-modal" class="btn btn-primary mt-6" on:click={() => (isModalActive = true)}
>Add SSL Certificate</label
>
</div> </div>
{/if} {/if}
</div> </div>
@ -129,12 +129,9 @@
/> />
</div> </div>
<label for="my-modal"> <label for="my-modal">
<button type="submit" class="btn btn-primary mt-4">Upload</button <button type="submit" class="btn btn-sm btn-primary mt-4">Upload</button></label
></label
>
<button on:click={() => (isModalActive = false)} type="button" class="btn"
>Cancel</button
> >
<button on:click={() => (isModalActive = false)} type="button" class="btn btn-sm btn-error">Cancel</button>
</form> </form>
</div> </div>
</div> </div>

View File

@ -196,11 +196,38 @@
} }
</script> </script>
<div class="title font-bold pb-3">Coolify Settings</div> <div class="mx-auto w-full">
<form on:submit|preventDefault={handleSubmit}>
<div class="flex flex-row border-b border-coolgray-500 mb-6">
<div class="title font-bold pb-3 pr-4">Coolify Settings</div>
<div class="flex flex-row space-x-2">
<button
class="btn btn-sm btn-primary"
type="submit"
class:bg-orange-600={forceSave}
class:hover:bg-orange-400={forceSave}
class:loading={loading.save}
disabled={loading.save}
>{loading.save
? $t('forms.saving')
: forceSave
? $t('forms.confirm_continue')
: $t('forms.save')}</button
>
<div class="mx-auto w-full p-6 bg-coolgray-200 rounded shadow-xl"> {#if isFqdnSet}
<div class="flex lg:flex-row flex-col"> <button on:click|preventDefault={removeFqdn} disabled={loading.remove} class="btn"
<form on:submit|preventDefault={handleSubmit}> >{loading.remove ? $t('forms.removing') : $t('forms.remove_domain')}</button
>
{/if}
<button
on:click={restartCoolify}
class:loading={loading.restart}
class="btn btn-sm btn-error">Restart Coolify</button
>
</div>
</div>
<div class="flex lg:flex-row flex-col">
<div class="grid grid-flow-row gap-2 px-4 pr-5"> <div class="grid grid-flow-row gap-2 px-4 pr-5">
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<div> <div>
@ -208,7 +235,7 @@
<Explainer position="dropdown-bottom" explanation={$t('setting.ssl_explainer')} /> <Explainer position="dropdown-bottom" explanation={$t('setting.ssl_explainer')} />
</div> </div>
<input <input
class="w-full bg-coolgray-100" class="w-full"
bind:value={fqdn} bind:value={fqdn}
readonly={!$appSession.isAdmin || isFqdnSet} readonly={!$appSession.isAdmin || isFqdnSet}
disabled={!$appSession.isAdmin || isFqdnSet} disabled={!$appSession.isAdmin || isFqdnSet}
@ -273,7 +300,7 @@
<div class="flex flex-row items-center space-x-2"> <div class="flex flex-row items-center space-x-2">
<input <input
class="w-full px-2 bg-coolgray-100" class="w-full px-2 "
type="number" type="number"
bind:value={minPort} bind:value={minPort}
min="1024" min="1024"
@ -281,7 +308,7 @@
/> />
<p>-</p> <p>-</p>
<input <input
class="w-full px-2 bg-coolgray-100" class="w-full px-2 "
type="number" type="number"
bind:value={maxPort} bind:value={maxPort}
min={minPort} min={minPort}
@ -306,7 +333,7 @@
</div> </div>
<input <input
class="w-full bg-coolgray-100" class="w-full "
placeholder="1.1.1.1,8.8.8.8" placeholder="1.1.1.1,8.8.8.8"
bind:value={DNSServers} bind:value={DNSServers}
/> />
@ -342,36 +369,6 @@
</div> </div>
{/if} {/if}
</div> </div>
<div </div>
class="flex flex-col lg:flex-row flex-wrap items-center space-x-3 justify-center lg:justify-start pt-8" </form>
>
<div class="flex lg:flex-row lg:space-x-4 flex-col space-y-2 lg:space-y-0">
<button
class="btn btn-primary"
type="submit"
class:bg-orange-600={forceSave}
class:hover:bg-orange-400={forceSave}
class:loading={loading.save}
disabled={loading.save}
>{loading.save
? $t('forms.saving')
: forceSave
? $t('forms.confirm_continue')
: $t('forms.save')}</button
>
{#if isFqdnSet}
<button on:click|preventDefault={removeFqdn} disabled={loading.remove} class="btn"
>{loading.remove ? $t('forms.removing') : $t('forms.remove_domain')}</button
>
{/if}
<button
on:click={restartCoolify}
class:loading={loading.restart}
class="btn bg-red-600 hover:bg-red-700">Restart Coolify</button
>
</div>
</div>
</form>
</div>
</div> </div>

View File

@ -57,19 +57,20 @@
} }
</script> </script>
<div class="title font-bold pb-3">SSH Keys</div>
<div class="w-full"> <div class="w-full">
{#if sshKeys.length === 0} {#if sshKeys.length === 0}
<div class="text-sm">No SSH keys found</div> <div class="text-sm">No SSH keys found</div>
<label <label for="my-modal" class="btn btn-primary mt-6" on:click={() => (isModalActive = true)}
for="my-modal" >Add SSH Key</label
class="btn btn-primary mt-6"
on:click={() => (isModalActive = true)}>Add SSH Key</label
>
{:else}
<div
class="mx-auto w-full p-6 bg-coolgray-200 rounded shadow-xl"
> >
{:else}
<div class="mx-auto w-full">
<div class="flex border-b border-coolgray-500 mb-6">
<div class="title font-bold pb-3 pr-4">SSH Keys</div>
<label for="my-modal" class="btn btn-sm btn-primary" on:click={() => (isModalActive = true)}
>Add SSH Key</label
>
</div>
<table class="table w-full"> <table class="table w-full">
<thead> <thead>
<tr> <tr>
@ -84,7 +85,7 @@
<td>{key.name}</td> <td>{key.name}</td>
<td>{key.createdAt}</td> <td>{key.createdAt}</td>
<td <td
><button on:click={() => deleteSSHKey(key.id)} class="btn btn-error" ><button on:click={() => deleteSSHKey(key.id)} class="btn btn-sm btn-error"
>Delete</button >Delete</button
></td ></td
> >
@ -92,11 +93,6 @@
{/each} {/each}
</tbody> </tbody>
</table> </table>
<label
for="my-modal"
class="btn btn-primary mt-6"
on:click={() => (isModalActive = true)}>Add SSH Key</label
>
</div> </div>
{/if} {/if}
</div> </div>
@ -116,12 +112,7 @@
<div class="modal-action"> <div class="modal-action">
<form on:submit|preventDefault={handleSubmit}> <form on:submit|preventDefault={handleSubmit}>
<label for="name" class="">Name</label> <label for="name" class="">Name</label>
<input <input id="name" required bind:value={newSSHKey.name} class="w-full bg-coolgray-100" />
id="name"
required
bind:value={newSSHKey.name}
class="w-full bg-coolgray-100"
/>
<label for="privateKey" class="pt-4">Private Key</label> <label for="privateKey" class="pt-4">Private Key</label>
<textarea <textarea
id="privateKey" id="privateKey"
@ -132,11 +123,12 @@
rows={15} rows={15}
/> />
<label for="my-modal"> <label for="my-modal">
<button type="submit" class="btn btn-primary mt-4">Save</button <button type="submit" class="btn btn-sm btn-primary mt-4">Save</button></label
></label
> >
<button on:click={() => (isModalActive = false)} type="button" class="btn" <button
>Cancel</button on:click={() => (isModalActive = false)}
type="button"
class="btn btn-sm btn-error">Cancel</button
> >
</form> </form>
</div> </div>

View File

@ -25,10 +25,10 @@ body {
} }
input, .input { input, .input {
@apply h-12 w-96 rounded border border-transparent bg-transparent bg-coolgray-200 p-2 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-300 disabled:bg-transparent md:text-sm; @apply h-12 w-96 rounded border border-transparent bg-coolgray-200 p-2 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-200 disabled:bg-transparent disabled:bg-coolblack md:text-sm;
} }
textarea { textarea {
@apply min-w-[14rem] rounded border border-transparent bg-transparent bg-coolgray-200 p-2 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-300 disabled:bg-transparent md:text-sm; @apply min-w-[14rem] rounded border border-transparent bg-coolgray-200 p-2 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-200 disabled:bg-transparent md:text-sm;
} }
#svelte .custom-select-wrapper .selectContainer.disabled input { #svelte .custom-select-wrapper .selectContainer.disabled input {
@ -40,7 +40,7 @@ textarea {
} }
#svelte .custom-select-wrapper .selectContainer { #svelte .custom-select-wrapper .selectContainer {
@apply h-12 w-96 rounded border border-coolgray-300 bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm w-full; @apply h-12 w-96 rounded bg-coolgray-100 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm w-full ;
} }
#svelte .listContainer { #svelte .listContainer {

View File

@ -49,7 +49,7 @@ module.exports = {
"iam": "#C026D3", "iam": "#C026D3",
coollabs: '#6B16ED', coollabs: '#6B16ED',
'coollabs-100': '#7317FF', 'coollabs-100': '#7317FF',
coolblack: '#161616', coolblack: '#141414',
'coolgray-100': '#181818', 'coolgray-100': '#181818',
'coolgray-200': '#202020', 'coolgray-200': '#202020',
'coolgray-300': '#242424', 'coolgray-300': '#242424',