* New Version: 3.0.0
This commit is contained in:
Andras Bacsai
2022-07-06 11:02:36 +02:00
committed by GitHub
parent 9137e8bc32
commit 87ba4560ad
491 changed files with 16824 additions and 20459 deletions

View File

@@ -0,0 +1,25 @@
<script lang="ts">
export let destination: any;
export let settings: any;
export let state: any;
import LocalDocker from './_LocalDocker.svelte';
import RemoteDocker from './_RemoteDocker.svelte';
</script>
<div class="flex h-20 items-center space-x-2 p-5 px-6 font-bold">
<div class="-mb-5 flex-col">
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
Configuration
</div>
<span class="text-xs">{destination.name}</span>
</div>
</div>
<div class="mx-auto max-w-4xl px-6">
{#if destination.remoteEngine}
<RemoteDocker bind:destination {settings} {state} />
{:else}
<LocalDocker bind:destination {settings} {state} />
{/if}
</div>

View File

@@ -0,0 +1,202 @@
<script lang="ts">
export let destination: any;
export let settings: any;
export let state: any;
import { toast } from '@zerodevx/svelte-toast';
import { page } from '$app/stores';
import { post } from '$lib/api';
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
import { onMount } from 'svelte';
import { t } from '$lib/translations';
import { errorNotification } from '$lib/common';
import { appSession } from '$lib/store';
import Setting from '$lib/components/Setting.svelte';
const { id } = $page.params;
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
let loading = false;
let loadingProxy = false;
let restarting = false;
async function handleSubmit() {
loading = true;
try {
return await post(`/destinations/${id}`, { ...destination });
} catch (error) {
return errorNotification(error);
} finally {
loading = false;
}
}
onMount(async () => {
if (state === false && destination.isCoolifyProxyUsed === true) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try {
await post(`/destinations/${id}/settings`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
engine: destination.engine
});
await stopProxy();
} catch (error) {
return errorNotification(error);
}
} else if (state === true && destination.isCoolifyProxyUsed === false) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try {
await post(`/destinations/${id}/settings`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
engine: destination.engine
});
await startProxy();
} catch (error) {
return errorNotification(error);
}
}
});
async function changeProxySetting() {
if (!cannotDisable) {
const isProxyActivated = destination.isCoolifyProxyUsed;
if (isProxyActivated) {
const sure = confirm(
`Are you sure you want to ${
destination.isCoolifyProxyUsed ? 'disable' : 'enable'
} Coolify proxy? It will remove the proxy for all configured networks and all deployments on '${
destination.engine
}'! Nothing will be reachable if you do it!`
);
if (!sure) return;
}
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try {
loadingProxy = true;
await post(`/destinations/${id}/settings`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
engine: destination.engine
});
if (isProxyActivated) {
await stopProxy();
} else {
await startProxy();
}
} catch ({ error }) {
return errorNotification(error);
} finally {
loadingProxy = false;
}
}
}
async function stopProxy() {
try {
await post(`/destinations/${id}/stop`, { engine: destination.engine });
return toast.push($t('destination.coolify_proxy_stopped'));
} catch ({ error }) {
return errorNotification(error);
}
}
async function startProxy() {
try {
await post(`/destinations/${id}/start`, { engine: destination.engine });
return toast.push($t('destination.coolify_proxy_started'));
} catch ({ error }) {
return errorNotification(error);
}
}
async function forceRestartProxy() {
const sure = confirm($t('destination.confirm_restart_proxy'));
if (sure) {
try {
restarting = true;
toast.push($t('destination.coolify_proxy_restarting'));
await post(`/destinations/${id}/restart`, {
engine: destination.engine,
fqdn: settings.fqdn
});
} catch ({ error }) {
setTimeout(() => {
window.location.reload();
}, 5000);
} finally {
restarting = false;
}
}
}
</script>
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
<div class="flex space-x-1 pb-5">
<div class="title font-bold">{$t('forms.configuration')}</div>
{#if $appSession.isAdmin}
<button
type="submit"
class="bg-sky-600 hover:bg-sky-500"
class:bg-sky-600={!loading}
class:hover:bg-sky-500={!loading}
disabled={loading}
>{loading ? $t('forms.saving') : $t('forms.save')}
</button>
<button
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
disabled={restarting}
on:click|preventDefault={forceRestartProxy}
>{restarting
? $t('destination.restarting_please_wait')
: $t('destination.force_restart_proxy')}</button
>
{/if}
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
>Scan for applications</button
> -->
</div>
<div class="grid grid-cols-2 items-center px-10 ">
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
<input
name="name"
placeholder={$t('forms.name')}
disabled={!$appSession.isAdmin}
readonly={!$appSession.isAdmin}
bind:value={destination.name}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
<CopyPasswordField
id="engine"
readonly
disabled
name="engine"
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
value={destination.engine}
/>
</div>
<!-- <div class="flex items-center">
<label for="remoteEngine">Remote Engine?</label>
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
</div> -->
<div class="grid grid-cols-2 items-center px-10">
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
<CopyPasswordField
id="network"
readonly
disabled
name="network"
placeholder="{$t('forms.default')}: coolify"
value={destination.network}
/>
</div>
{#if $appSession.teamId === '0'}
<div class="grid grid-cols-2 items-center">
<Setting
loading={loadingProxy}
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>${
cannotDisable
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
: ''
}`}
/>
</div>
{/if}
</form>

View File

@@ -0,0 +1,57 @@
<script lang="ts">
import cuid from 'cuid';
import { t } from '$lib/translations';
import NewLocalDocker from './_NewLocalDocker.svelte';
import NewRemoteDocker from './_NewRemoteDocker.svelte';
let payload = {};
let selected = 'localDocker';
function setPredefined(type: any) {
selected = type;
switch (type) {
case 'localDocker':
payload = {
name: t.get('sources.local_docker'),
engine: '/var/run/docker.sock',
remoteEngine: false,
network: cuid(),
isCoolifyProxyUsed: true
};
break;
case 'remoteDocker':
payload = {
name: $t('sources.remote_docker'),
remoteEngine: true,
ipAddress: null,
user: 'root',
port: 22,
sshPrivateKey: null,
network: cuid(),
isCoolifyProxyUsed: true
};
break;
default:
break;
}
}
</script>
<div class="flex space-x-1 p-6 font-bold">
<div class="mr-4 text-2xl tracking-tight">{$t('destination.new.add_new_destination')}</div>
</div>
<div class="flex-col space-y-2 pb-10 text-center">
<div class="text-xl font-bold text-white">{$t('destination.new.predefined_destinations')}</div>
<div class="flex justify-center space-x-2">
<button class="w-32" on:click={() => setPredefined('localDocker')}
>{$t('sources.local_docker')}</button
>
<!-- <button class="w-32" on:click={() => setPredefined('remoteDocker')}>Remote Docker</button> -->
<!-- <button class="w-32" on:click={() => setPredefined('kubernetes')}>Kubernetes</button> -->
</div>
</div>
{#if selected === 'localDocker'}
<NewLocalDocker {payload} />
{:else if selected === 'remoteDocker'}
<NewRemoteDocker {payload} />
{:else}
<div class="text-center font-bold text-4xl py-10">{$t('index.not_implemented_yet')}</div>
{/if}

View File

@@ -0,0 +1,82 @@
<script lang="ts">
export let payload: any;
import { goto } from '$app/navigation';
import { post } from '$lib/api';
import { errorNotification } from '$lib/common';
import Setting from '$lib/components/Setting.svelte';
import { appSession } from '$lib/store';
import { t } from '$lib/translations';
let loading = false;
async function handleSubmit() {
if (loading) return;
try {
loading = true;
await post(`/destinations/check`, { network: payload.network });
const { id } = await post(`/destinations/new`, {
...payload
});
await goto(`/destinations/${id}`);
window.location.reload();
} catch (error) {
return errorNotification(error);
} finally {
loading = false;
}
}
</script>
<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:bg-sky-600={!loading}
class:hover:bg-sky-500={!loading}
disabled={loading}
>{loading
? payload.isCoolifyProxyUsed
? $t('destination.new.saving_and_configuring_proxy')
: $t('forms.saving')
: $t('forms.save')}</button
>
</div>
<div class="mt-2 grid grid-cols-2 items-center px-10">
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
<input required name="name" placeholder={$t('forms.name')} bind:value={payload.name} />
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
<input
required
name="engine"
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
bind:value={payload.engine}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
<input
required
name="network"
placeholder="{$t('forms.default')}: coolify"
bind:value={payload.network}
/>
</div>
{#if $appSession.teamId === '0'}
<div class="grid grid-cols-2 items-center">
<Setting
bind:setting={payload.isCoolifyProxyUsed}
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
title={$t('destination.use_coolify_proxy')}
description={$t('destination.new.install_proxy')}
/>
</div>
{/if}
</form>
</div>

View File

@@ -0,0 +1,99 @@
<script lang="ts">
export let payload: any;
import { goto } from '$app/navigation';
import { post } from '$lib/api';
import { errorNotification } from '$lib/common';
import Setting from '$lib/components/Setting.svelte';
import { t } from '$lib/translations';
let loading = false;
async function handleSubmit() {
try {
const { id } = await post('/new/destination/docker', {
...payload
});
return await goto(`/destinations/${id}`);
} catch (error) {
return errorNotification(error);
}
}
</script>
<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:bg-sky-600={!loading}
class:hover:bg-sky-500={!loading}
disabled={loading}
>{loading
? payload.isCoolifyProxyUsed
? $t('destination.new.saving_and_configuring_proxy')
: $t('forms.saving')
: $t('forms.save')}</button
>
</div>
<div class="mt-2 grid grid-cols-2 items-center px-10">
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
<input required name="name" placeholder={$t('forms.name')} bind:value={payload.name} />
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="ipAddress" class="text-base font-bold text-stone-100"
>{$t('forms.ip_address')}</label
>
<input
required
name="ipAddress"
placeholder="{$t('forms.eg')}: 192.168..."
bind:value={payload.ipAddress}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="user" class="text-base font-bold text-stone-100">{$t('forms.user')}</label>
<input required name="user" placeholder="{$t('forms.eg')}: root" bind:value={payload.user} />
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
<input required name="port" placeholder="{$t('forms.eg')}: 22" bind:value={payload.port} />
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="sshPrivateKey" class="text-base font-bold text-stone-100"
>{$t('forms.ssh_private_key')}</label
>
<textarea
rows="10"
class="resize-none"
required
name="sshPrivateKey"
placeholder="{$t('forms.eg')}: -----BEGIN...."
bind:value={payload.sshPrivateKey}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
<input
required
name="network"
placeholder="{$t('forms.default')}: coolify"
bind:value={payload.network}
/>
</div>
<div class="grid grid-cols-2 items-center">
<Setting
bind:setting={payload.isCoolifyProxyUsed}
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
title={$t('destination.use_coolify_proxy')}
description={$t('destination.new.install_proxy')}
/>
</div>
</form>
</div>

View File

@@ -0,0 +1,226 @@
<script lang="ts">
export let destination: any;
export let settings: any
export let state: any
import { toast } from '@zerodevx/svelte-toast';
import { page, session } from '$app/stores';
import Setting from '$lib/components/Setting.svelte';
import { post } from '$lib/api';
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
import { onMount } from 'svelte';
import { t } from '$lib/translations';
import { errorNotification, generateRemoteEngine } from '$lib/common';
import { appSession } from '$lib/store';
const { id } = $page.params;
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
// let scannedApps = [];
let loading = false;
let restarting = false;
async function handleSubmit() {
loading = true;
try {
return await post(`/destinations/${id}.json`, { ...destination });
} catch (error ) {
return errorNotification(error);
} finally {
loading = false;
}
}
// async function scanApps() {
// scannedApps = [];
// const data = await fetch(`/destinations/${id}/scan.json`);
// const { containers } = await data.json();
// scannedApps = containers;
// }
onMount(async () => {
if (state === false && destination.isCoolifyProxyUsed === true) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try {
await post(`/destinations/${id}/settings.json`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
engine: destination.engine
});
await stopProxy();
} catch (error ) {
return errorNotification(error);
}
} else if (state === true && destination.isCoolifyProxyUsed === false) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try {
await post(`/destinations/${id}/settings.json`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
engine: destination.engine
});
await startProxy();
} catch ( error ) {
return errorNotification(error);
}
}
});
async function changeProxySetting() {
if (!cannotDisable) {
const isProxyActivated = destination.isCoolifyProxyUsed;
if (isProxyActivated) {
const sure = confirm(
`Are you sure you want to ${
destination.isCoolifyProxyUsed ? 'disable' : 'enable'
} Coolify proxy? It will remove the proxy for all configured networks and all deployments on '${
destination.engine
}'! Nothing will be reachable if you do it!`
);
if (!sure) return;
}
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try {
await post(`/destinations/${id}/settings.json`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
engine: destination.engine
});
if (isProxyActivated) {
await stopProxy();
} else {
await startProxy();
}
} catch ({ error }) {
return errorNotification(error);
}
}
}
async function stopProxy() {
try {
const engine = generateRemoteEngine(destination);
await post(`/destinations/${id}/stop.json`, { engine });
return toast.push($t('destination.coolify_proxy_stopped'));
} catch ({ error }) {
return errorNotification(error);
}
}
async function startProxy() {
try {
const engine = generateRemoteEngine(destination);
await post(`/destinations/${id}/start.json`, { engine });
return toast.push($t('destination.coolify_proxy_started'));
} catch ({ error }) {
return errorNotification(error);
}
}
async function forceRestartProxy() {
const sure = confirm($t('destination.confirm_restart_proxy'));
if (sure) {
try {
restarting = true;
toast.push($t('destination.coolify_proxy_restarting'));
await post(`/destinations/${id}/restart.json`, {
engine: destination.engine,
fqdn: settings.fqdn
});
} catch ({ error }) {
setTimeout(() => {
window.location.reload();
}, 5000);
}
}
}
</script>
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
<div class="flex space-x-1 pb-5">
<div class="title font-bold">{$t('forms.configuration')}</div>
{#if $appSession.isAdmin}
<button
type="submit"
class="bg-sky-600 hover:bg-sky-500"
class:bg-sky-600={!loading}
class:hover:bg-sky-500={!loading}
disabled={loading}
>{loading ? $t('forms.saving') : $t('forms.save')}
</button>
<button
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
disabled={restarting}
on:click|preventDefault={forceRestartProxy}
>{restarting
? $t('destination.restarting_please_wait')
: $t('destination.force_restart_proxy')}</button
>
{/if}
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
>Scan for applications</button
> -->
</div>
<div class="grid grid-cols-2 items-center px-10 ">
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
<input
name="name"
placeholder={$t('forms.name')}
disabled={!$appSession.isAdmin}
readonly={!$appSession.isAdmin}
bind:value={destination.name}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
<CopyPasswordField
id="engine"
readonly
disabled
name="engine"
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
value={destination.engine}
/>
</div>
<!-- <div class="flex items-center">
<label for="remoteEngine">Remote Engine?</label>
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
</div> -->
<div class="grid grid-cols-2 items-center px-10">
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
<CopyPasswordField
id="network"
readonly
disabled
name="network"
placeholder="{$t('forms.default')}: coolify"
value={destination.network}
/>
</div>
<div class="grid grid-cols-2 items-center">
<Setting
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>${
cannotDisable
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
: ''
}`}
/>
</div>
</form>
<!-- <div class="flex justify-center">
{#if payload.isCoolifyProxyUsed}
{#if state}
<button on:click={stopProxy}>Stop proxy</button>
{:else}
<button on:click={startProxy}>Start proxy</button>
{/if}
{/if}
</div> -->
<!-- {#if scannedApps.length > 0}
<div class="flex justify-center px-6 pb-10">
<div class="flex space-x-2 h-8 items-center">
<div class="font-bold text-xl text-white">Found applications</div>
</div>
</div>
<div class="max-w-4xl mx-auto px-6">
<div class="flex space-x-2 justify-center">
{#each scannedApps as app}
<FoundApp {app} />
{/each}
</div>
</div>
{/if} -->

View File

@@ -0,0 +1,71 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
export const load: Load = async ({ fetch, url, params }) => {
try {
const { id } = params;
const response = await get(`/destinations/${id}`);
const { destination, settings, state } = response;
if (id !== 'new' && (!destination || Object.entries(destination).length === 0)) {
return {
status: 302,
redirect: '/destinations'
};
}
return {
props: {
destination
},
stuff: {
destination,
settings,
state
}
};
} catch (error) {
return handlerNotFoundLoad(error, url);
}
};
</script>
<script lang="ts">
export let destination: any;
import { del, get } from '$lib/api';
import { t } from '$lib/translations';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { errorNotification, handlerNotFoundLoad } from '$lib/common';
import { appSession } from '$lib/store';
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
const { id } = $page.params;
async function deleteDestination(destination: any) {
const sure = confirm($t('application.confirm_to_delete', { name: destination.name }));
if (sure) {
try {
await del(`/destinations/${destination.id}`, { id: destination.id });
return await goto('/destinations');
} catch (error) {
return errorNotification(error);
}
}
}
</script>
{#if id !== 'new'}
<nav class="nav-side">
<button
on:click={() => deleteDestination(destination)}
title={$t('source.delete_git_source')}
type="submit"
disabled={!$appSession.isAdmin}
class:hover:text-red-500={$appSession.isAdmin}
class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip={$appSession.isAdmin
? $t('destination.delete_destination')
: $t('destination.permission_denied_delete_destination')}><DeleteIcon /></button
>
</nav>
{/if}
<slot />

View File

@@ -0,0 +1,24 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
export const load: Load = async ({ fetch, params, stuff }) => {
return {
props: { ...stuff }
};
};
</script>
<script lang="ts">
export let destination: any;
export let settings: any;
export let state: any;
import { page } from '$app/stores';
import New from './_New.svelte';
import Destination from './_Destination.svelte';
const { id } = $page.params;
</script>
{#if id === 'new'}
<New />
{:else}
<Destination bind:destination bind:state bind:settings />
{/if}

View File

@@ -0,0 +1,99 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
export const load: Load = async () => {
try {
const response = await get(`/destinations`);
return {
props: {
...response
}
};
} catch (error: any) {
return {
status: 500,
error: new Error(error)
};
}
};
</script>
<script lang="ts">
export let destinations: any[];
import { t } from '$lib/translations';
import { appSession } from '$lib/store';
import { get } from '$lib/api';
const ownDestinations = destinations.filter((destination) => {
if (destination.teams[0].id === $appSession.teamId) {
return destination;
}
});
const otherDestinations = destinations.filter((destination) => {
if (destination.teams[0].id !== $appSession.teamId) {
return destination;
}
});
</script>
<div class="flex space-x-1 p-6 font-bold">
<div class="mr-4 text-2xl tracking-tight">{$t('index.destinations')}</div>
{#if $appSession.isAdmin}
<a href="/destinations/new" class="add-icon bg-sky-600 hover:bg-sky-500">
<svg
class="w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/></svg
>
</a>
{/if}
</div>
<div class="flex-col justify-center">
{#if !destinations || ownDestinations.length === 0}
<div class="flex-col">
<div class="text-center text-xl font-bold">{$t('destination.no_destination_found')}</div>
</div>
{/if}
{#if ownDestinations.length > 0 || otherDestinations.length > 0}
<div class="flex flex-col">
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row">
{#each ownDestinations as destination}
<a href="/destinations/{destination.id}" class="w-96 p-2 no-underline">
<div class="box-selection hover:bg-sky-600">
<div class="truncate text-center text-xl font-bold">{destination.name}</div>
{#if $appSession.teamId === '0' && otherDestinations.length > 0}
<div class="truncate text-center">{destination.teams[0].name}</div>
{/if}
<div class="truncate text-center">{destination.network}</div>
</div>
</a>
{/each}
</div>
{#if otherDestinations.length > 0 && $appSession.teamId === '0'}
<div class="px-6 pb-5 pt-10 text-xl font-bold">Other Destinations</div>
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row">
{#each otherDestinations as destination}
<a href="/destinations/{destination.id}" class="w-96 p-2 no-underline">
<div class="box-selection hover:bg-sky-600">
<div class="truncate text-center text-xl font-bold">{destination.name}</div>
{#if $appSession.teamId === '0'}
<div class="truncate text-center">{destination.teams[0].name}</div>
{/if}
<div class="truncate text-center">{destination.network}</div>
</div>
</a>
{/each}
</div>
{/if}
</div>
{/if}
</div>