ui: fixes

feat: restart coolify button
This commit is contained in:
Andras Bacsai
2022-08-26 12:46:20 +02:00
parent 05ee35b6bc
commit 7528ca18d8
4 changed files with 92 additions and 40 deletions

View File

@@ -73,6 +73,23 @@ export async function update(request: FastifyRequest<Update>) {
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
export async function restartCoolify(request: FastifyRequest<any>) {
try {
const teamId = request.user.teamId;
if (teamId === '0') {
if (!isDev) {
await asyncExecShell(`docker restart coolify`);
return {};
} else {
console.log('Restarting Coolify')
return {};
}
}
throw { status: 500, message: 'You are not authorized to restart Coolify.' };
} catch ({ status, message }) {
return errorHandler({ status, message })
}
}
export async function showUsage() { export async function showUsage() {
try { try {
return { return {

View File

@@ -1,5 +1,5 @@
import { FastifyPluginAsync } from 'fastify'; import { FastifyPluginAsync } from 'fastify';
import { checkUpdate, login, showDashboard, update, showUsage, getCurrentUser, cleanupManually } from './handlers'; import { checkUpdate, login, showDashboard, update, showUsage, getCurrentUser, cleanupManually, restartCoolify } from './handlers';
import { GetCurrentUser } from './types'; import { GetCurrentUser } from './types';
export interface Update { export interface Update {
@@ -47,6 +47,10 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
onRequest: [fastify.authenticate] onRequest: [fastify.authenticate]
}, async () => await showUsage()); }, async () => await showUsage());
fastify.post('/internal/restart', {
onRequest: [fastify.authenticate]
}, async (request) => await restartCoolify(request));
fastify.post('/internal/cleanup', { fastify.post('/internal/cleanup', {
onRequest: [fastify.authenticate] onRequest: [fastify.authenticate]
}, async () => await cleanupManually()); }, async () => await cleanupManually());

View File

@@ -20,7 +20,8 @@
let usageInterval: any; let usageInterval: any;
let loading = { let loading = {
usage: false, usage: false,
cleanup: false cleanup: false,
restart: false
}; };
import { addToast, appSession } from '$lib/store'; import { addToast, appSession } from '$lib/store';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
@@ -33,6 +34,25 @@
usage = data.usage; usage = data.usage;
loading.usage = false; loading.usage = false;
} }
async function restartCoolify() {
const sure = confirm(
'Are you sure you would like to restart Coolify? Currently running deployments will be stopped and restarted.'
);
if (sure) {
loading.restart = true;
try {
await post(`/internal/restart`, {});
addToast({
type: 'success',
message: 'Coolify restarted successfully. It will take a moment.'
});
} catch (error) {
return errorNotification(error);
} finally {
loading.restart = false;
}
}
}
onDestroy(() => { onDestroy(() => {
clearInterval(usageInterval); clearInterval(usageInterval);
}); });
@@ -67,51 +87,56 @@
<div class="w-full"> <div class="w-full">
<div class="flex items-center"> <div class="flex items-center">
<h1 class="title text-4xl">Hardware Details</h1> <h1 class="title text-4xl">Hardware Details</h1>
{#if $appSession.teamId === '0'} <div class="flex space-x-4">
<button on:click={manuallyCleanupStorage} class:loading={loading.cleanup} class="btn btn-sm" {#if $appSession.teamId === '0'}
>Cleanup Storage</button <button on:click={manuallyCleanupStorage} class:loading={loading.cleanup} class="btn btn-sm"
> >Cleanup Storage</button
{/if} >
<button
on:click={restartCoolify}
class:loading={loading.restart}
class="btn btn-sm bg-red-600 hover:bg-red-500">Restart Coolify</button
>
{/if}
</div>
</div> </div>
<div class="divider" /> <div class="divider" />
<div class="grid grid-flow-col gap-4 grid-rows-3 lg:grid-rows-1"> <div class="grid grid-flow-col gap-4 grid-rows-3 lg:grid-rows-1">
<div <div class="stats stats-vertical lg:stats-horizontal w-full mb-5 bg-transparent rounded">
class="stats stats-vertical lg:stats-horizontal shadow w-full mb-5 bg-coolgray-200 rounded" <div class="font-bold flex lg:justify-center">Memory</div>
>
<div class="stat"> <div class="stat">
<div class="stat-title">Total Memory</div> <div class="stat-title">Total</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{(usage?.memory.totalMemMb).toFixed(0)}<span class="text-sm">MB</span> {(usage?.memory.totalMemMb).toFixed(0)}<span class="text-sm">MB</span>
</div> </div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">Used Memory</div> <div class="stat-title">Used</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{(usage?.memory.usedMemMb).toFixed(0)}<span class="text-sm">MB</span> {(usage?.memory.usedMemMb).toFixed(0)}<span class="text-sm">MB</span>
</div> </div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">Free Memory</div> <div class="stat-title">Free</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{usage?.memory.freeMemPercentage}<span class="text-sm">%</span> {usage?.memory.freeMemPercentage}<span class="text-sm">%</span>
</div> </div>
</div> </div>
</div> </div>
<div <div class="stats stats-vertical lg:stats-horizontal w-full mb-5 bg-transparent rounded">
class="stats stats-vertical lg:stats-horizontal shadow w-full mb-5 bg-coolgray-200 rounded" <div class="font-bold flex lg:justify-center">CPU</div>
>
<div class="stat"> <div class="stat">
<div class="stat-title">Total CPUs</div> <div class="stat-title">Total</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{usage?.cpu.count} {usage?.cpu.count}
</div> </div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">CPU Usage</div> <div class="stat-title">Usage</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{usage?.cpu.usage}<span class="text-sm">%</span> {usage?.cpu.usage}<span class="text-sm">%</span>
</div> </div>
@@ -122,26 +147,24 @@
<div class="stat-value text-2xl">{usage?.cpu.load}</div> <div class="stat-value text-2xl">{usage?.cpu.load}</div>
</div> </div>
</div> </div>
<div class="stats stats-vertical lg:stats-horizontal w-full mb-5 bg-transparent rounded">
<div <div class="font-bold flex lg:justify-center">Disk</div>
class="stats stats-vertical lg:stats-horizontal shadow w-full mb-5 bg-coolgray-200 rounded"
>
<div class="stat"> <div class="stat">
<div class="stat-title">Total Disk</div> <div class="stat-title">Total</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{usage?.disk.totalGb}<span class="text-sm">GB</span> {usage?.disk.totalGb}<span class="text-sm">GB</span>
</div> </div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">Used Disk</div> <div class="stat-title">Used</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{usage?.disk.usedGb}<span class="text-sm">GB</span> {usage?.disk.usedGb}<span class="text-sm">GB</span>
</div> </div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">Free Disk</div> <div class="stat-title">Free</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl">
{usage?.disk.freePercentage}<span class="text-sm">%</span> {usage?.disk.freePercentage}<span class="text-sm">%</span>
</div> </div>

View File

@@ -86,7 +86,7 @@
<div class="grid grid-col gap-4 auto-cols-max grid-cols-1 lg:grid-cols-3"> <div class="grid grid-col gap-4 auto-cols-max grid-cols-1 lg:grid-cols-3">
{#each applications as application} {#each applications as application}
<a class="no-underline mb-5" href={`/applications/${application.id}`}> <a class="no-underline mb-5" href={`/applications/${application.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-coolgray-300 indicator"> <div class="w-full rounded p-5 bg-coolgray-100 hover:bg-coolgray-300 indicator">
{#await getStatus(application)} {#await getStatus(application)}
<span class="indicator-item badge bg-yellow-500 badge-xs" /> <span class="indicator-item badge bg-yellow-500 badge-xs" />
{:then status} {:then status}
@@ -99,15 +99,18 @@
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
<ApplicationsIcons {application} isAbsolute={false} /> <ApplicationsIcons {application} isAbsolute={false} />
<div class="w-full flex flex-col ml-5"> <div class="w-full flex flex-col ml-5">
<span> <h1 class="font-bold text-lg">
Application {application.name}
{#if application.settings.isBot} {#if application.settings.isBot}
| BOT | BOT
{/if} {/if}
</span> </h1>
<h1 class="font-bold text-lg">{application.name}</h1> {#if application?.fqdn}
<div class="divider" /> <h2>{application?.fqdn}</h2>
<div class="flex justify-end space-x-2"> {:else if !application.settings.isBot && !application?.fqdn}
<h2 class="text-red-500">Not configured</h2>
{/if}
<div class="flex justify-end space-x-2 pt-2">
{#if application.fqdn} {#if application.fqdn}
<a href={application.fqdn} target="_blank" class="icons"> <a href={application.fqdn} target="_blank" class="icons">
<svg <svg
@@ -157,12 +160,14 @@
</a> </a>
{/each} {/each}
</div> </div>
{/if}
{#if services.length > 0}
<h1 class="title text-4xl mt-10">Services</h1> <h1 class="title text-4xl mt-10">Services</h1>
<div class="divider" /> <div class="divider" />
<div class="grid grid-col gap-4 auto-cols-max grid-cols-1 lg:grid-cols-3"> <div class="grid grid-col gap-4 auto-cols-max grid-cols-1 lg:grid-cols-3">
{#each services as service} {#each services as service}
<a class="no-underline mb-5" href={`/services/${service.id}`}> <a class="no-underline mb-5" href={`/services/${service.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-coolgray-300 indicator"> <div class="w-full rounded p-5 bg-coolgray-100 hover:bg-coolgray-300 indicator">
{#await getStatus(service)} {#await getStatus(service)}
<span class="indicator-item badge bg-yellow-500 badge-xs" /> <span class="indicator-item badge bg-yellow-500 badge-xs" />
{:then status} {:then status}
@@ -175,10 +180,13 @@
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
<ServiceIcons type={service.type} isAbsolute={false} /> <ServiceIcons type={service.type} isAbsolute={false} />
<div class="w-full flex flex-col ml-5"> <div class="w-full flex flex-col ml-5">
<span> Service </span>
<h1 class="font-bold text-lg">{service.name}</h1> <h1 class="font-bold text-lg">{service.name}</h1>
<div class="divider" /> {#if service?.fqdn}
<div class="flex justify-end space-x-2"> <h2>{service?.fqdn}</h2>
{:else}
<h2 class="text-red-500">Not configured</h2>
{/if}
<div class="flex justify-end space-x-2 pt-2">
{#if service.fqdn} {#if service.fqdn}
<a href={service.fqdn} target="_blank" class="icons"> <a href={service.fqdn} target="_blank" class="icons">
<svg <svg
@@ -205,12 +213,14 @@
</a> </a>
{/each} {/each}
</div> </div>
{/if}
{#if databases.length > 0}
<h1 class="title text-4xl mt-10">Databases</h1> <h1 class="title text-4xl mt-10">Databases</h1>
<div class="divider" /> <div class="divider" />
<div class="grid grid-col gap-4 auto-cols-max grid-cols-1 lg:grid-cols-3"> <div class="grid grid-col gap-4 auto-cols-max grid-cols-1 lg:grid-cols-3">
{#each databases as database} {#each databases as database}
<a class="no-underline mb-5" href={`/databases/${database.id}`}> <a class="no-underline mb-5" href={`/databases/${database.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-coolgray-300 indicator"> <div class="w-full rounded p-5 bg-coolgray-100 hover:bg-coolgray-300 indicator">
{#await getStatus(database)} {#await getStatus(database)}
<span class="indicator-item badge bg-yellow-500 badge-xs" /> <span class="indicator-item badge bg-yellow-500 badge-xs" />
{:then status} {:then status}
@@ -220,12 +230,10 @@
<span class="indicator-item badge bg-error badge-xs" /> <span class="indicator-item badge bg-error badge-xs" />
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row pt-2">
<DatabaseIcons type={database.type} isAbsolute={false} /> <DatabaseIcons type={database.type} isAbsolute={false} />
<div class="w-full flex flex-col ml-5"> <div class="w-full flex flex-col ml-5">
<span> Service </span>
<h1 class="font-bold text-lg">{database.name}</h1> <h1 class="font-bold text-lg">{database.name}</h1>
<div class="divider" />
</div> </div>
</div> </div>
</div> </div>