v1.0.21 (#66)
This commit is contained in:
@@ -52,8 +52,7 @@
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
// toast.push(error.error || error || 'Ooops something went wrong.');
|
||||
browser && toast.push(error.error || error || 'Ooops something went wrong.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,80 +1,83 @@
|
||||
<script>
|
||||
export let github = false;
|
||||
export let githubLoadingText = 'Loading GitHub...';
|
||||
export let fullscreen = true;
|
||||
</script>
|
||||
|
||||
{#if fullscreen}
|
||||
{#if github}
|
||||
<div class="fixed left-0 top-0 flex flex-wrap content-center h-full w-full">
|
||||
<div class="main flex justify-center items-center">
|
||||
<div class="w-64">
|
||||
<svg
|
||||
class=" w-28 animate-bounce mx-auto"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><path
|
||||
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"
|
||||
/></svg
|
||||
>
|
||||
<div class="text-xl font-bold text-center">
|
||||
{githubLoadingText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="main fixed left-0 top-0 flex flex-wrap content-center h-full">
|
||||
<span class="loader" />
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="main h-64 py-24 left-0 top-0 flex flex-wrap content-center mx-auto">
|
||||
<span class="loader" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="postcss">
|
||||
.loader {
|
||||
width: 8px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
display: block;
|
||||
margin: 20px auto;
|
||||
position: relative;
|
||||
background: currentColor;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
animation: animloader 0.3s 0.3s linear infinite alternate;
|
||||
}
|
||||
|
||||
.loader::after,
|
||||
.loader::before {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
background: currentColor;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 20px;
|
||||
box-sizing: border-box;
|
||||
animation: animloader 0.3s 0.45s linear infinite alternate;
|
||||
}
|
||||
.loader::before {
|
||||
left: -20px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
@keyframes animloader {
|
||||
0% {
|
||||
height: 48px;
|
||||
}
|
||||
100% {
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export let github = false;
|
||||
export let githubLoadingText = "Loading GitHub...";
|
||||
export let fullscreen = true;
|
||||
</script>
|
||||
|
||||
{#if fullscreen}
|
||||
{#if github}
|
||||
<div class="fixed left-0 top-0 flex flex-wrap content-center h-full w-full">
|
||||
<div class="main flex justify-center items-center">
|
||||
<div class="w-64">
|
||||
<svg
|
||||
class=" w-28 animate-bounce mx-auto"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><path
|
||||
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"
|
||||
></path></svg
|
||||
>
|
||||
<div class="text-xl font-bold text-center">
|
||||
{githubLoadingText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="main fixed left-0 top-0 flex flex-wrap content-center h-full">
|
||||
<span class=" loader"></span>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
.loader {
|
||||
width: 8px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
display: block;
|
||||
margin: 20px auto;
|
||||
position: relative;
|
||||
background: currentColor;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
animation: animloader 0.3s 0.3s linear infinite alternate;
|
||||
}
|
||||
|
||||
.loader::after,
|
||||
.loader::before {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
background: currentColor;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 20px;
|
||||
box-sizing: border-box;
|
||||
animation: animloader 0.3s 0.45s linear infinite alternate;
|
||||
}
|
||||
.loader::before {
|
||||
left: -20px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
@keyframes animloader {
|
||||
0% {
|
||||
height: 48px;
|
||||
}
|
||||
100% {
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,54 +1,56 @@
|
||||
<script>
|
||||
export let value;
|
||||
let showPassword = false;
|
||||
export let value;
|
||||
let showPassword = false;
|
||||
export let isEditable = false;
|
||||
</script>
|
||||
|
||||
<div class="relative w-full">
|
||||
<input
|
||||
type="{showPassword ? 'text' : 'password'}"
|
||||
class="w-full "
|
||||
{value}
|
||||
disabled
|
||||
/>
|
||||
<div
|
||||
class="absolute top-0 my-2 mx-2 right-0 cursor-pointer text-warmGray-600 hover:text-white"
|
||||
on:click="{() => showPassword = !showPassword}"
|
||||
>
|
||||
{#if showPassword}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
|
||||
></path>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
></path>
|
||||
</svg>
|
||||
{/if}
|
||||
</div>
|
||||
{#if showPassword}
|
||||
<input type="text" class="w-full" bind:value disabled={!isEditable} />
|
||||
{:else}
|
||||
<input type="password" class="w-full" bind:value disabled={!isEditable} />
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="absolute top-0 my-2 mx-2 right-0 cursor-pointer text-warmGray-600 hover:text-white"
|
||||
on:click={() => (showPassword = !showPassword)}
|
||||
>
|
||||
{#if showPassword}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
|
||||
/>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,2 +1,2 @@
|
||||
export const publicPages = ['/', '/api/v1/login/github/app', '/api/v1/webhooks/deploy', '/success'];
|
||||
export const VITE_GITHUB_APP_NAME = import.meta.env.VITE_GITHUB_APP_NAME;
|
||||
export const publicPages = ['/', '/api/v1/login/github/app', '/api/v1/webhooks/deploy', '/success', '/api/v1/login/email']
|
||||
export const VITE_GITHUB_APP_NAME = import.meta.env.VITE_GITHUB_APP_NAME
|
||||
|
@@ -4,12 +4,16 @@ export interface IUser extends Document {
|
||||
email: string;
|
||||
avatar?: string;
|
||||
uid: string;
|
||||
type: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
const UserSchema = new Schema({
|
||||
email: { type: String, required: true, unique: true },
|
||||
avatar: { type: String },
|
||||
uid: { type: String, required: true }
|
||||
uid: { type: String, required: true },
|
||||
type: { type: String, required: true, default: 'github' },
|
||||
password: { type: String }
|
||||
});
|
||||
|
||||
UserSchema.set('timestamps', true);
|
||||
|
@@ -23,7 +23,6 @@
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -37,8 +36,9 @@
|
||||
import Tooltip from '$components/Tooltip.svelte';
|
||||
import compareVersions from 'compare-versions';
|
||||
import packageJson from '../../package.json';
|
||||
import { dashboard } from '$store';
|
||||
import { dashboard, settings } from '$store';
|
||||
import { browser } from '$app/env';
|
||||
$settings.clientId = import.meta.env.VITE_GITHUB_APP_CLIENTID !== 'null' ? import.meta.env.VITE_GITHUB_APP_CLIENTID : null
|
||||
$dashboard = initDashboard;
|
||||
const branch =
|
||||
process.env.NODE_ENV === 'production' &&
|
||||
@@ -53,7 +53,7 @@
|
||||
let upgradeDisabled = false;
|
||||
let upgradeDone = false;
|
||||
let showAck = false;
|
||||
let globalFeatureFlag = browser && localStorage.getItem('globalFeatureFlag')
|
||||
let globalFeatureFlag = browser && localStorage.getItem('globalFeatureFlag');
|
||||
const options = {
|
||||
duration: 2000
|
||||
};
|
||||
@@ -104,7 +104,6 @@
|
||||
localStorage.setItem('automaticErrorReportsAck', 'true');
|
||||
showAck = false;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<SvelteToast {options} />
|
||||
@@ -136,69 +135,136 @@
|
||||
class:border-purple-500={$page.path === '/dashboard/databases'}
|
||||
>
|
||||
<div class="w-10 pt-4 pb-4"><img src="/favicon.png" alt="coolLabs logo" /></div>
|
||||
|
||||
<Tooltip position="right" label="Applications">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-green-500 mt-4 transition-all duration-100 cursor-pointer"
|
||||
on:click={() => goto('/dashboard/applications')}
|
||||
class:text-green-500={$page.path === '/dashboard/applications' ||
|
||||
$page.path.startsWith('/application')}
|
||||
class:bg-warmGray-700={$page.path === '/dashboard/applications' ||
|
||||
$page.path.startsWith('/application')}
|
||||
>
|
||||
<svg
|
||||
class="w-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><rect x="4" y="4" width="16" height="16" rx="2" ry="2" /><rect
|
||||
x="9"
|
||||
y="9"
|
||||
width="6"
|
||||
height="6"
|
||||
/><line x1="9" y1="1" x2="9" y2="4" /><line x1="15" y1="1" x2="15" y2="4" /><line
|
||||
x1="9"
|
||||
y1="20"
|
||||
x2="9"
|
||||
y2="23"
|
||||
/><line x1="15" y1="20" x2="15" y2="23" /><line x1="20" y1="9" x2="23" y2="9" /><line
|
||||
x1="20"
|
||||
y1="14"
|
||||
x2="23"
|
||||
y2="14"
|
||||
/><line x1="1" y1="9" x2="4" y2="9" /><line x1="1" y1="14" x2="4" y2="14" /></svg
|
||||
{#if $settings.clientId}
|
||||
<Tooltip position="right" label="Applications">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-green-500 mt-4 transition-all duration-100 cursor-pointer"
|
||||
on:click={() => goto('/dashboard/applications')}
|
||||
class:text-green-500={$page.path === '/dashboard/applications' ||
|
||||
$page.path.startsWith('/application')}
|
||||
class:bg-warmGray-700={$page.path === '/dashboard/applications' ||
|
||||
$page.path.startsWith('/application')}
|
||||
>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip position="right" label="Databases">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-purple-500 my-4 transition-all duration-100 cursor-pointer"
|
||||
on:click={() => goto('/dashboard/databases')}
|
||||
class:text-purple-500={$page.path === '/dashboard/databases' ||
|
||||
$page.path.startsWith('/database')}
|
||||
class:bg-warmGray-700={$page.path === '/dashboard/databases' ||
|
||||
$page.path.startsWith('/database')}
|
||||
>
|
||||
<svg
|
||||
class="w-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
<svg
|
||||
class="w-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><rect x="4" y="4" width="16" height="16" rx="2" ry="2" /><rect
|
||||
x="9"
|
||||
y="9"
|
||||
width="6"
|
||||
height="6"
|
||||
/><line x1="9" y1="1" x2="9" y2="4" /><line x1="15" y1="1" x2="15" y2="4" /><line
|
||||
x1="9"
|
||||
y1="20"
|
||||
x2="9"
|
||||
y2="23"
|
||||
/><line x1="15" y1="20" x2="15" y2="23" /><line
|
||||
x1="20"
|
||||
y1="9"
|
||||
x2="23"
|
||||
y2="9"
|
||||
/><line x1="20" y1="14" x2="23" y2="14" /><line x1="1" y1="9" x2="4" y2="9" /><line
|
||||
x1="1"
|
||||
y1="14"
|
||||
x2="4"
|
||||
y2="14"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip position="right" label="Databases">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-purple-500 my-4 transition-all duration-100 cursor-pointer"
|
||||
on:click={() => goto('/dashboard/databases')}
|
||||
class:text-purple-500={$page.path === '/dashboard/databases' ||
|
||||
$page.path.startsWith('/database')}
|
||||
class:bg-warmGray-700={$page.path === '/dashboard/databases' ||
|
||||
$page.path.startsWith('/database')}
|
||||
>
|
||||
<svg
|
||||
class="w-8"
|
||||
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="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<Tooltip
|
||||
position="right"
|
||||
label="Applications disabled, no GitHub Integration detected"
|
||||
size="large"
|
||||
>
|
||||
<div class="p-2 text-warmGray-700 mt-4 transition-all duration-100 cursor-pointer">
|
||||
<svg
|
||||
class="w-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Tooltip>
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><rect x="4" y="4" width="16" height="16" rx="2" ry="2" /><rect
|
||||
x="9"
|
||||
y="9"
|
||||
width="6"
|
||||
height="6"
|
||||
/><line x1="9" y1="1" x2="9" y2="4" /><line x1="15" y1="1" x2="15" y2="4" /><line
|
||||
x1="9"
|
||||
y1="20"
|
||||
x2="9"
|
||||
y2="23"
|
||||
/><line x1="15" y1="20" x2="15" y2="23" /><line
|
||||
x1="20"
|
||||
y1="9"
|
||||
x2="23"
|
||||
y2="9"
|
||||
/><line x1="20" y1="14" x2="23" y2="14" /><line x1="1" y1="9" x2="4" y2="9" /><line
|
||||
x1="1"
|
||||
y1="14"
|
||||
x2="4"
|
||||
y2="14"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip position="right" label="Databases disabled, no GitHub Integration detected" size="large">
|
||||
<div
|
||||
class="p-2 text-warmGray-700 my-4 transition-all duration-100 cursor-pointer"
|
||||
>
|
||||
<svg
|
||||
class="w-8"
|
||||
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="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
<Tooltip position="right" label="Services">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-blue-500 transition-all duration-100 cursor-pointer"
|
||||
@@ -226,29 +292,29 @@
|
||||
</Tooltip>
|
||||
<div class="flex-1" />
|
||||
{#if globalFeatureFlag}
|
||||
<Tooltip position="right" label="Server(s)">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-red-500 mb-4 transition-all duration-100 cursor-pointer"
|
||||
on:click={() => goto('/servers')}
|
||||
class:text-red-500={$page.path === '/servers' || $page.path.startsWith('/servers')}
|
||||
class:bg-warmGray-700={$page.path === '/servers' || $page.path.startsWith('/servers')}
|
||||
>
|
||||
<svg
|
||||
class="w-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
<Tooltip position="right" label="Servers">
|
||||
<div
|
||||
class="p-2 hover:bg-warmGray-700 rounded hover:text-red-500 mb-4 transition-all duration-100 cursor-pointer"
|
||||
on:click={() => goto('/servers')}
|
||||
class:text-red-500={$page.path === '/servers' || $page.path.startsWith('/servers')}
|
||||
class:bg-warmGray-700={$page.path === '/servers' || $page.path.startsWith('/servers')}
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<svg
|
||||
class="w-8"
|
||||
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="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<Tooltip position="right" label="Settings">
|
||||
<button
|
||||
|
103
src/routes/api/v1/login/email.ts
Normal file
103
src/routes/api/v1/login/email.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import mongoose from 'mongoose';
|
||||
import Settings from '$models/Settings';
|
||||
import User from '$models/User';
|
||||
import bcrypt from 'bcrypt';
|
||||
import cuid from 'cuid';
|
||||
import jsonwebtoken from 'jsonwebtoken';
|
||||
import type { Request } from '@sveltejs/kit';
|
||||
|
||||
const saltRounds = 15;
|
||||
|
||||
export async function post(request: Request) {
|
||||
const { email, password } = request.body
|
||||
const { JWT_SIGN_KEY } = process.env;
|
||||
const settings = await Settings.findOne({ applicationName: 'coolify' });
|
||||
const registeredUsers = await User.find().countDocuments();
|
||||
const foundUser = await User.findOne({ email });
|
||||
try {
|
||||
let uid = cuid();
|
||||
if (foundUser) {
|
||||
if (foundUser.type === 'github') {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
error: 'Wrong password or email address.'
|
||||
}
|
||||
};
|
||||
}
|
||||
uid = foundUser.uid;
|
||||
if (!await bcrypt.compare(password, foundUser.password)) {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
error: 'Wrong password or email address.'
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (registeredUsers === 0) {
|
||||
const newUser = new User({
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
email,
|
||||
uid,
|
||||
type: 'email',
|
||||
password: await bcrypt.hash(password, saltRounds)
|
||||
});
|
||||
const defaultSettings = new Settings({
|
||||
_id: new mongoose.Types.ObjectId()
|
||||
});
|
||||
try {
|
||||
await newUser.save();
|
||||
await defaultSettings.save();
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
error: error.message || error
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (!settings?.allowRegistration) {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
error: 'Registration disabled, enable it in settings.'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
const newUser = new User({
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
email,
|
||||
uid,
|
||||
type: 'email',
|
||||
password: await bcrypt.hash(password, saltRounds)
|
||||
});
|
||||
try {
|
||||
await newUser.save();
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
error: error.message || error
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const coolToken = jsonwebtoken.sign({}, JWT_SIGN_KEY, {
|
||||
expiresIn: 15778800,
|
||||
algorithm: 'HS256',
|
||||
audience: 'coolLabs',
|
||||
issuer: 'coolLabs',
|
||||
jwtid: uid,
|
||||
subject: `User:${uid}`,
|
||||
notBefore: -1000
|
||||
});
|
||||
request.locals.session.data = { coolToken, ghToken: null };
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
};
|
||||
} catch (error) {
|
||||
return { status: 500, body: { error: error.message || error } };
|
||||
}
|
||||
|
||||
}
|
@@ -33,7 +33,8 @@ export async function get(request: Request) {
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
email,
|
||||
avatar: avatar_url,
|
||||
uid
|
||||
uid,
|
||||
type: 'github'
|
||||
});
|
||||
const defaultSettings = new Settings({
|
||||
_id: new mongoose.Types.ObjectId()
|
||||
@@ -68,7 +69,8 @@ export async function get(request: Request) {
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
email,
|
||||
avatar: avatar_url,
|
||||
uid
|
||||
uid,
|
||||
type: 'github'
|
||||
});
|
||||
try {
|
||||
await newUser.save();
|
||||
|
@@ -1,3 +1,18 @@
|
||||
<script context="module" lang="ts">
|
||||
/**
|
||||
* @type {import('@sveltejs/kit').Load}
|
||||
*/
|
||||
export async function load(session) {
|
||||
if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) {
|
||||
return {
|
||||
status: 301,
|
||||
redirect: '/dashboard/services'
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { application, initialApplication, initConf, dashboard, prApplication } from '$store';
|
||||
import { onDestroy } from 'svelte';
|
||||
@@ -58,7 +73,6 @@
|
||||
onDestroy(() => {
|
||||
$application = JSON.parse(JSON.stringify(initialApplication));
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{#await loadConfiguration()}
|
||||
|
@@ -1,8 +1,28 @@
|
||||
<script context="module" lang="ts">
|
||||
import { request } from '$lib/request';
|
||||
/**
|
||||
* @type {import('@sveltejs/kit').Load}
|
||||
*/
|
||||
export async function load(session) {
|
||||
if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) {
|
||||
return {
|
||||
status: 301,
|
||||
redirect: '/dashboard/services'
|
||||
};
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
initDashboard: await request('/api/v1/dashboard', session)
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { dashboard, dateOptions } from '$store';
|
||||
import { dashboard, dateOptions, settings } from '$store';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
import { browser } from '$app/env';
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
@@ -1,3 +1,18 @@
|
||||
<script context="module" lang="ts">
|
||||
/**
|
||||
* @type {import('@sveltejs/kit').Load}
|
||||
*/
|
||||
export async function load(session) {
|
||||
if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) {
|
||||
return {
|
||||
status: 301,
|
||||
redirect: '/dashboard/services'
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { goto } from '$app/navigation';
|
||||
import MongoDb from '$components/Database/SVGs/MongoDb.svelte';
|
||||
@@ -8,7 +23,7 @@
|
||||
import { dashboard } from '$store';
|
||||
import { fade } from 'svelte/transition';
|
||||
import Redis from '$components/Database/SVGs/Redis.svelte';
|
||||
|
||||
import { browser } from '$app/env';
|
||||
</script>
|
||||
|
||||
<div class="py-5 text-left px-6 text-3xl tracking-tight font-bold flex items-center">
|
||||
@@ -59,9 +74,7 @@
|
||||
customClass="w-10 h-10 fill-current text-red-600 absolute top-0 left-0 -m-4"
|
||||
/>
|
||||
{:else if database.configuration.general.type == 'redis'}
|
||||
<Redis
|
||||
customClass="w-10 h-10 absolute top-0 left-0 -m-4"
|
||||
/>
|
||||
<Redis customClass="w-10 h-10 absolute top-0 left-0 -m-4" />
|
||||
{:else if database.configuration.general.type == 'clickhouse'}
|
||||
<Clickhouse
|
||||
customClass="w-10 h-10 fill-current text-red-600 absolute top-0 left-0 -m-4"
|
||||
|
@@ -1,10 +1,15 @@
|
||||
<script>
|
||||
import { browser } from '$app/env';
|
||||
|
||||
import { goto } from '$app/navigation';
|
||||
import { session } from '$app/stores';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import PasswordField from '$components/PasswordField.svelte';
|
||||
import { request } from '$lib/request';
|
||||
|
||||
import { settings } from '$store';
|
||||
import Loading from '$components/Loading.svelte';
|
||||
let loading = false;
|
||||
let email = null;
|
||||
let password = null;
|
||||
async function login() {
|
||||
const left = screen.width / 2 - 1020 / 2;
|
||||
const top = screen.height / 2 - 618 / 2;
|
||||
@@ -22,11 +27,26 @@
|
||||
const timer = setInterval(() => {
|
||||
if (newWindow?.closed) {
|
||||
clearInterval(timer);
|
||||
browser && location.reload()
|
||||
browser && location.reload();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
async function loginWithEmail() {
|
||||
try {
|
||||
loading = true;
|
||||
await request('/api/v1/login/email', $session, {
|
||||
body: {
|
||||
email,
|
||||
password
|
||||
}
|
||||
});
|
||||
browser && location.reload();
|
||||
} catch (error) {
|
||||
browser && toast.push(error.error || error || 'Ooops something went wrong.');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center items-center h-screen w-full bg-warmGray-900">
|
||||
@@ -37,24 +57,54 @@
|
||||
>
|
||||
<span class="border-gradient">Coolify</span>
|
||||
</p>
|
||||
<h2 class="text-2xl md:text-3xl font-extrabold text-white">
|
||||
<h2 class="text-2xl md:text-3xl font-extrabold text-white py-10">
|
||||
An open-source, hassle-free, self-hostable<br />
|
||||
<span class="text-indigo-400">Heroku</span>
|
||||
& <span class="text-green-400">Netlify</span> alternative
|
||||
</h2>
|
||||
<div class="text-center py-10">
|
||||
{#if !$session.isLoggedIn}
|
||||
<button
|
||||
class="text-white bg-warmGray-800 hover:bg-warmGray-700 rounded p-2 px-10 font-bold"
|
||||
on:click={login}>Login with Github</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="text-white bg-warmGray-800 hover:bg-warmGray-700 rounded p-2 px-10 font-bold"
|
||||
on:click={() => goto('/dashboard/applications')}>Get Started</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{#if loading}
|
||||
<Loading fullscreen={false}/>
|
||||
{:else}
|
||||
<div class="text-center py-10 max-w-7xl">
|
||||
{#if !$session.isLoggedIn}
|
||||
{#if $settings.clientId}
|
||||
<button
|
||||
class="text-white bg-warmGray-800 hover:bg-warmGray-700 rounded p-2 px-10 font-bold"
|
||||
on:click={login}>Login with GitHub</button
|
||||
>
|
||||
{:else}
|
||||
<div>
|
||||
<div class="grid grid-flow-row gap-2 items-center pb-6">
|
||||
<div class="grid grid-flow-row">
|
||||
<label for="Email" class="">Email address</label>
|
||||
<input
|
||||
class="border-2"
|
||||
id="Email"
|
||||
bind:value={email}
|
||||
placeholder="hi@coollabs.io"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-flow-row">
|
||||
<label for="Password" class="">Password</label>
|
||||
<PasswordField bind:value={password} isEditable />
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-x-4 pt-10">
|
||||
<button
|
||||
class="text-white bg-warmGray-800 hover:bg-warmGray-700 rounded p-2 px-10 font-bold"
|
||||
on:click={loginWithEmail}>Login with Email</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<button
|
||||
class="text-white bg-warmGray-800 hover:bg-warmGray-700 rounded p-2 px-10 font-bold"
|
||||
on:click={() => goto('/dashboard/applications')}>Get Started</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -6,7 +6,9 @@ import type {
|
||||
GithubInstallations
|
||||
} from 'src/global';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const settings = writable({
|
||||
clientId: null
|
||||
})
|
||||
export const dashboard = writable<Dashboard>({
|
||||
databases: {
|
||||
deployed: []
|
||||
|
Reference in New Issue
Block a user