Features: 
- Build packs for popular frontend frameworks. It will help to understand which build packs should be chosen.

Fixes:
- Github queries optimized.
- Save repositories to store (faster navigation).
- Remove unnecessary data on dashboard requests.
- Speed up static site builds with a lot.

UI:
- Redesign of the application deployment page.
- Redesign of database deployments page.
This commit is contained in:
Andras Bacsai
2021-04-30 22:43:21 +02:00
committed by GitHub
parent b416e3ab3e
commit cccb9a5fec
49 changed files with 1309 additions and 797 deletions

View File

@@ -1,24 +0,0 @@
<script>
import { application } from "@store";
import Tooltip from "../../../Tooltip/TooltipInfo.svelte";
</script>
<div class="grid grid-cols-1 max-w-2xl md:mx-auto mx-6 text-center">
<label for="installCommand"
>Install Command <Tooltip label="Command to run for installing dependencies. eg: yarn install." />
</label>
<input
class="mb-6"
id="installCommand"
bind:value="{$application.build.command.installation}"
placeholder="eg: yarn install"
/>
<label for="buildCommand">Build Command <Tooltip label="Command to run for building your application. If empty, no build phase initiated in the deploy process." /></label>
<input
class="mb-6"
id="buildCommand"
bind:value="{$application.build.command.build}"
placeholder="eg: yarn build"
/>
</div>

View File

@@ -1,56 +1,213 @@
<style lang="postcss">
.buildpack {
@apply px-6 py-2 mx-2 my-2 bg-warmGray-800 w-48 ease-in-out transform hover:scale-105 text-center rounded border-2 border-transparent border-dashed cursor-pointer transition duration-100;
}
</style>
<script>
import { application} from "@store";
import { application } from "@store";
import { onMount } from "svelte";
import TooltipInfo from "../../../Tooltip/TooltipInfo.svelte";
const showPorts = ['nodejs','custom','rust']
let domainInput;
const buildpacks = {
static: {
port: {
active: false,
number: 80,
},
build: true,
},
nodejs: {
port: {
active: true,
number: 3000,
},
build: true,
},
vuejs: {
port: {
active: false,
number: 80,
},
build: true,
},
nuxtjs: {
port: {
active: true,
number: 3000,
},
build: true,
},
react: {
port: {
active: false,
number: 80,
},
build: true,
},
nextjs: {
port: {
active: true,
number: 3000,
},
build: true,
},
gatsby: {
port: {
active: true,
number: 3000,
},
build: true,
},
svelte: {
port: {
active: false,
number: 80,
},
build: true,
},
php: {
port: {
active: false,
number: 80,
},
build: false,
},
rust: {
port: {
active: true,
number: 3000,
},
build: false,
},
docker: {
port: {
active: true,
number: 3000,
},
build: false,
},
};
function selectBuildPack(event) {
if (event.target.innerText === "React/Preact") {
$application.build.pack = "react";
} else {
$application.build.pack = event.target.innerText
.replace(/\./g, "")
.toLowerCase();
}
}
onMount(()=> {
domainInput.focus();
})
</script>
<div>
<div
class="grid grid-cols-1 text-sm max-w-2xl md:mx-auto mx-6 pb-6 auto-cols-max "
class="grid grid-cols-1 text-sm max-w-4xl md:mx-auto mx-6 pb-16 auto-cols-max "
>
<label for="buildPack"
>Build Pack
{#if $application.build.pack === 'custom'}
<TooltipInfo
label="Your custom Dockerfile will be used from the root directory (or from 'Base Directory' specified below) of your repository. "
/>
{:else if $application.build.pack === 'static'}
<TooltipInfo
label="Published as a static site (for build phase see 'Build Step' tab)."
/>
{:else if $application.build.pack === 'nodejs'}
<TooltipInfo
label="Published as a Node.js application (for build phase see 'Build Step' tab)."
/>
{:else if $application.build.pack === 'php'}
<TooltipInfo
size="large"
label="Published as a PHP application."
/>
{:else if $application.build.pack === 'rust'}
<TooltipInfo
size="large"
label="Published as a Rust application."
/>
{/if}
</label
>
<select id="buildPack" bind:value="{$application.build.pack}">
<option selected class="font-bold">static</option>
<option class="font-bold">nodejs</option>
<option class="font-bold">php</option>
<option class="font-bold">custom</option>
<option class="font-bold">rust</option>
</select>
<div class="text-2xl font-bold border-gradient w-40">Build Packs</div>
<div class="flex font-bold flex-wrap justify-center pt-10">
<div
class="{$application.build.pack === 'static'
? 'buildpack bg-red-500'
: 'buildpack hover:border-red-500'}"
on:click="{selectBuildPack}"
>
Static
</div>
<div
class="{$application.build.pack === 'nodejs'
? 'buildpack bg-emerald-600'
: 'buildpack hover:border-emerald-600'}"
on:click="{selectBuildPack}"
>
NodeJS
</div>
<div
class="{$application.build.pack === 'vuejs'
? 'buildpack bg-green-500'
: 'buildpack hover:border-green-500'}"
on:click="{selectBuildPack}"
>
VueJS
</div>
<div
class="{$application.build.pack === 'nuxtjs'
? 'buildpack bg-green-500'
: 'buildpack hover:border-green-500'}"
on:click="{selectBuildPack}"
>
NuxtJS
</div>
<div
class="{$application.build.pack === 'react'
? 'buildpack bg-gradient-to-r from-blue-500 to-purple-500'
: 'buildpack hover:border-blue-500'}"
on:click="{selectBuildPack}"
>
React/Preact
</div>
<div
class="{$application.build.pack === 'nextjs'
? 'buildpack bg-blue-500'
: 'buildpack hover:border-blue-500'}"
on:click="{selectBuildPack}"
>
NextJS
</div>
<div
class="{$application.build.pack === 'gatsby'
? 'buildpack bg-blue-500'
: 'buildpack hover:border-blue-500'}"
on:click="{selectBuildPack}"
>
Gatsby
</div>
<div
class="{$application.build.pack === 'svelte'
? 'buildpack bg-orange-600'
: 'buildpack hover:border-orange-600'}"
on:click="{selectBuildPack}"
>
Svelte
</div>
<div
class="{$application.build.pack === 'php'
? 'buildpack bg-indigo-500'
: 'buildpack hover:border-indigo-500'}"
on:click="{selectBuildPack}"
>
PHP
</div>
<div
class="{$application.build.pack === 'rust'
? 'buildpack bg-pink-500'
: 'buildpack hover:border-pink-500'}"
on:click="{selectBuildPack}"
>
Rust
</div>
<div
class="{$application.build.pack === 'docker'
? 'buildpack bg-purple-500'
: 'buildpack hover:border-purple-500'}"
on:click="{selectBuildPack}"
>
Docker
</div>
</div>
</div>
<div class="text-2xl font-bold border-gradient w-52">General settings</div>
<div
class="grid grid-cols-1 max-w-2xl md:mx-auto mx-6 justify-center items-center"
class="grid grid-cols-1 max-w-2xl md:mx-auto mx-6 justify-center items-center pt-10"
>
<div class="grid grid-flow-col gap-2 items-center pb-6">
<div class="grid grid-flow-row">
<label for="Domain" class="">Domain</label>
<input
bind:this={domainInput}
class="border-2"
class:placeholder-red-500="{$application.publish.domain == null ||
$application.publish.domain == ''}"
class:border-red-500="{$application.publish.domain == null ||
@@ -63,7 +220,9 @@
<div class="grid grid-flow-row">
<label for="Path"
>Path <TooltipInfo
label="{`Path to deploy your application on your domain. eg: /api means it will be deployed to -> https://${$application.publish.domain || '<yourdomain>'}/api`}"
label="{`Path to deploy your application on your domain. eg: /api means it will be deployed to -> https://${
$application.publish.domain || '<yourdomain>'
}/api`}"
/></label
>
<input
@@ -73,16 +232,27 @@
/>
</div>
</div>
{#if showPorts.includes($application.build.pack)}
<label for="Port" >Port</label>
<label
for="Port"
class:text-warmGray-800="{!buildpacks[$application.build.pack].port
.active}">Port</label
>
<input
disabled="{!buildpacks[$application.build.pack].port.active}"
id="Port"
class="mb-6"
class:bg-warmGray-900="{!buildpacks[$application.build.pack].port.active}"
class:text-warmGray-900="{!buildpacks[$application.build.pack].port
.active}"
class:placeholder-warmGray-800="{!buildpacks[$application.build.pack].port
.active}"
class:hover:bg-warmGray-900="{!buildpacks[$application.build.pack].port
.active}"
class:cursor-not-allowed="{!buildpacks[$application.build.pack].port
.active}"
bind:value="{$application.publish.port}"
placeholder="{$application.build.pack === 'static' ? '80' : '3000'}"
placeholder="{buildpacks[$application.build.pack].port.number}"
/>
{/if}
<div class="grid grid-flow-col gap-2 items-center pt-12">
<div class="grid grid-flow-col gap-2 items-center pt-6 pb-12">
<div class="grid grid-flow-row">
<label for="baseDir"
>Base Directory <TooltipInfo
@@ -109,4 +279,62 @@
</div>
</div>
</div>
<div
class="text-2xl font-bold w-40"
class:border-gradient="{buildpacks[$application.build.pack].build}"
class:text-warmGray-800="{!buildpacks[$application.build.pack].build}"
>
Commands
</div>
<div
class=" max-w-2xl md:mx-auto mx-6 justify-center items-center pt-10 pb-32"
>
<div class="grid grid-flow-col gap-2 items-center">
<div class="grid grid-flow-row">
<label
for="installCommand"
class:text-warmGray-800="{!buildpacks[$application.build.pack].build}"
>Install Command <TooltipInfo
label="Command to run for installing dependencies. eg: yarn install."
/>
</label>
<input
class="mb-6"
class:bg-warmGray-900="{!buildpacks[$application.build.pack].build}"
class:text-warmGray-900="{!buildpacks[$application.build.pack].build}"
class:placeholder-warmGray-800="{!buildpacks[$application.build.pack]
.build}"
class:hover:bg-warmGray-900="{!buildpacks[$application.build.pack]
.build}"
class:cursor-not-allowed="{!buildpacks[$application.build.pack]
.build}"
id="installCommand"
bind:value="{$application.build.command.installation}"
placeholder="eg: yarn install"
/>
<label
for="buildCommand"
class:text-warmGray-800="{!buildpacks[$application.build.pack].build}"
>Build Command <TooltipInfo
label="Command to run for building your application. If empty, no build phase initiated in the deploy process."
/></label
>
<input
class="mb-6"
class:bg-warmGray-900="{!buildpacks[$application.build.pack].build}"
class:text-warmGray-900="{!buildpacks[$application.build.pack].build}"
class:placeholder-warmGray-800="{!buildpacks[$application.build.pack]
.build}"
class:hover:bg-warmGray-900="{!buildpacks[$application.build.pack]
.build}"
class:cursor-not-allowed="{!buildpacks[$application.build.pack]
.build}"
id="buildCommand"
bind:value="{$application.build.command.build}"
placeholder="eg: yarn build"
/>
</div>
</div>
</div>
</div>

View File

@@ -36,40 +36,43 @@
];
}
</script>
<div class="max-w-2xl md:mx-auto mx-6 text-center">
<div class="text-2xl font-bold border-gradient w-24">Secrets</div>
<div class="max-w-xl mx-auto text-center pt-4">
<div class="text-left text-base font-bold tracking-tight text-warmGray-400">
New Secret
</div>
<div class="grid md:grid-flow-col grid-flow-row gap-2">
<input id="secretName" bind:value="{secret.name}" placeholder="Name" />
<input id="secretValue" bind:value="{secret.value}" placeholder="Value" />
<button
class="button p-1 w-20 bg-green-600 hover:bg-green-500 text-white"
on:click="{saveSecret}">Save</button
>
<div class="flex space-x-4">
<input id="secretName" bind:value="{secret.name}" placeholder="Name" class="w-64 border-2 border-transparent" />
<input id="secretValue" bind:value="{secret.value}" placeholder="Value" class="w-64 border-2 border-transparent" />
<button class="icon hover:text-green-500" on:click="{saveSecret}">
<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="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</button>
</div>
{#if $application.publish.secrets.length > 0}
<div class="py-4">
{#each $application.publish.secrets as s}
<div class="grid md:grid-flow-col grid-flow-row gap-2">
<div class="flex space-x-4">
<input
id="{s.name}"
value="{s.name}"
disabled
class="border-2 bg-transparent border-transparent"
class="border-2 bg-transparent border-transparent w-64"
class:border-red-600="{foundSecret && foundSecret.name === s.name}"
/>
<input
id="{s.createdAt}"
value="SAVED"
disabled
class="bg-transparent border-transparent"
class="border-2 bg-transparent border-transparent w-64"
/>
<button
class="button w-20 bg-red-600 hover:bg-red-500 text-white"
on:click="{() => removeSecret(s.name)}">Delete</button
>
<button class="icon hover:text-red-500" on:click="{() => removeSecret(s.name)}">
<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="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</button>
</div>
{/each}
</div>

View File

@@ -1,11 +1,10 @@
<script>
export let loading, branches;
import { isActive } from "@roxi/routify";
import { application } from "@store";
import { application, activePage } from "@store";
import Select from "svelte-select";
const selectedValue =
!$isActive("/application/new") && $application.repository.branch
$activePage.application !== "new" && $application.repository.branch;
function handleSelect(event) {
$application.repository.branch = null;
@@ -36,10 +35,10 @@
selectedValue="{selectedValue}"
isClearable="{false}"
items="{branches.map(b => ({ label: b.name, value: b.name }))}"
showIndicator="{$isActive('/application/new')}"
showIndicator="{$activePage.new}"
noOptionsMessage="No branches found"
placeholder="Select a branch"
isDisabled="{!$isActive('/application/new')}"
isDisabled="{!$activePage.new}"
/>
</div>
</div>

View File

@@ -1,7 +1,15 @@
<script>
import { redirect, isActive } from "@roxi/routify";
import { fade } from "svelte/transition";
import { session, application, fetch, initialApplication } from "@store";
import {
session,
application,
fetch,
initialApplication,
githubRepositories,
githubInstallations,
activePage,
} from "@store";
import Login from "./Login.svelte";
import Loading from "../../Loading.svelte";
@@ -15,8 +23,6 @@
};
let branches = [];
let repositories = [];
function dashify(str, options) {
if (typeof str !== "string") return str;
return str
@@ -29,8 +35,8 @@
async function loadBranches() {
loading.branches = true;
if ($isActive("/application/new")) $application.repository.branch = null;
const selectedRepository = repositories.find(
if ($activePage.new) $application.repository.branch = null;
const selectedRepository = $githubRepositories.find(
r => r.id === $application.repository.id,
);
@@ -54,6 +60,23 @@
}
async function loadGithub() {
if ($githubRepositories.length > 0) {
$application.github.installation.id = $githubInstallations.id;
$application.github.app.id = $githubInstallations.app_id;
const foundRepositoryOnGithub = $githubRepositories.find(
r =>
r.full_name ===
`${$application.repository.organization}/${$application.repository.name}`,
);
if (foundRepositoryOnGithub) {
$application.repository.id = foundRepositoryOnGithub.id;
$application.repository.organization = foundRepositoryOnGithub.owner.login;
$application.repository.name = foundRepositoryOnGithub.name;
// await loadBranches();
}
return;
}
loading.github = true;
try {
const { installations } = await $fetch(
@@ -64,6 +87,7 @@
}
$application.github.installation.id = installations[0].id;
$application.github.app.id = installations[0].app_id;
$githubInstallations = installations[0];
let page = 1;
let userRepos = 0;
@@ -72,21 +96,20 @@
page,
);
repositories = repositories.concat(data.repositories);
$githubRepositories = $githubRepositories.concat(data.repositories);
userRepos = data.total_count;
if (userRepos > repositories.length) {
while (userRepos > repositories.length) {
if (userRepos > $githubRepositories.length) {
while (userRepos > $githubRepositories.length) {
page = page + 1;
const repos = await getGithubRepos(
$application.github.installation.id,
page,
);
repositories = repositories.concat(repos.repositories);
$githubRepositories = $githubRepositories.concat(repos.repositories);
}
}
const foundRepositoryOnGithub = repositories.find(
const foundRepositoryOnGithub = $githubRepositories.find(
r =>
r.full_name ===
`${$application.repository.organization}/${$application.repository.name}`,
@@ -120,7 +143,7 @@
if (newWindow.closed) {
clearInterval(timer);
loading.github = true;
if (!$isActive("/application/new")) {
if (!$activePage.new) {
try {
const config = await $fetch(`/api/v1/config`, {
body: {
@@ -137,28 +160,46 @@
$application = JSON.parse(JSON.stringify(initialApplication));
}
branches = [];
repositories = [];
$githubRepositories = [];
await loadGithub();
}
}, 100);
}
</script>
{#if !$isActive("/application/new")}
{#if !$activePage.new}
<div class="min-h-full text-white">
<div
class="py-5 text-left px-6 text-3xl tracking-tight font-bold flex items-center"
>
{$application.publish.domain
? `${$application.publish.domain}${
$application.publish.path !== "/" ? $application.publish.path : ""
}`
: "example.com"}
<a
target="_blank"
class="text-green-500 hover:underline cursor-pointer px-2"
class="icon mx-2"
href="{'https://' +
$application.publish.domain +
$application.publish.path}"
>{$application.publish.domain
? `${$application.publish.domain}${$application.publish.path !== '/' ? $application.publish.path : ''}`
: "<yourdomain>"}</a
>
<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="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
></path>
</svg></a
>
<a
target="_blank"
class="icon"
@@ -180,7 +221,7 @@
>
</div>
</div>
{:else if $isActive("/application/new")}
{:else if $activePage.new}
<div class="min-h-full text-white">
<div
class="py-5 text-left px-6 text-3xl tracking-tight font-bold flex items-center"
@@ -205,11 +246,10 @@
in:fade="{{ duration: 100 }}"
>
<Repositories
bind:repositories
on:loadBranches="{loadBranches}"
on:modifyGithubAppConfig="{modifyGithubAppConfig}"
/>
{#if $application.repository.organization !== "new"}
{#if $application.repository.organization}
<Branches loading="{loading.branches}" branches="{branches}" />
{/if}

View File

@@ -1,43 +1,42 @@
<script>
import { createEventDispatcher } from "svelte";
import { isActive } from "@roxi/routify";
import { application } from "@store";
import { application, githubRepositories, activePage } from "@store";
import Select from "svelte-select";
function handleSelect(event) {
$application.build.pack = 'static'
$application.repository.id = parseInt(event.detail.value, 10);
dispatch("loadBranches");
}
export let repositories;
let items = repositories.map(repo => ({
let items = $githubRepositories.map(repo => ({
label: `${repo.owner.login}/${repo.name}`,
value: repo.id.toString(),
}));
const selectedValue =
!$isActive("/application/new") &&
!$activePage.new &&
`${$application.repository.organization}/${$application.repository.name}`;
const dispatch = createEventDispatcher();
const modifyGithubAppConfig = () => dispatch("modifyGithubAppConfig");
</script>
<div class="grid grid-cols-1">
{#if repositories.length !== 0}
<div class="grid grid-cols-1 pt-4">
{#if $githubRepositories.length !== 0}
<label for="repository">Organization / Repository</label>
<div class="grid grid-cols-3 ">
<div class="repository-select-search col-span-2">
<Select
isFocused="true"
containerClasses="w-full border-none bg-transparent"
on:select="{handleSelect}"
selectedValue="{selectedValue}"
isClearable="{false}"
items="{items}"
showIndicator="{$isActive('/application/new')}"
showIndicator="{$activePage.new}"
noOptionsMessage="No Repositories found"
placeholder="Select a Repository"
isDisabled="{!$isActive('/application/new')}"
isDisabled="{!$activePage.new}"
/>
</div>
<button

View File

@@ -1,17 +1,57 @@
<script>
import { redirect, isActive } from "@roxi/routify";
import { redirect } from "@roxi/routify";
import { onMount } from "svelte";
import { toast } from "@zerodevx/svelte-toast";
import templates from "../../../utils/templates";
import { application, fetch, deployments } from "@store";
import { application, fetch, deployments, activePage } from "@store";
import General from "./ActiveTab/General.svelte";
import BuildStep from "./ActiveTab/BuildStep.svelte";
import Secrets from "./ActiveTab/Secrets.svelte";
import Loading from "../../Loading.svelte";
const buildPhaseActive = ["nodejs", "static"];
let loading = false;
onMount(async () => {
if (!$isActive("/application/new")) {
let activeTab = {
general: true,
buildStep: false,
secrets: false,
};
function activateTab(tab) {
if (activeTab.hasOwnProperty(tab)) {
activeTab = {
general: false,
buildStep: false,
secrets: false,
};
activeTab[tab] = true;
}
}
async function load() {
const found = $deployments?.applications?.deployed.find(deployment => {
if (
deployment.configuration.repository.organization ===
$application.repository.organization &&
deployment.configuration.repository.name ===
$application.repository.name &&
deployment.configuration.repository.branch ===
$application.repository.branch
) {
return deployment;
}
});
if (found) {
$application = { ...found.configuration };
if ($activePage.new) {
$activePage.new = false;
toast.push(
"This repository & branch is already defined. Redirecting...",
);
$redirect(`/application/:organization/:name/:branch/configuration`, {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
});
}
return;
}
if (!$activePage.new) {
const config = await $fetch(`/api/v1/config`, {
body: {
name: $application.repository.name,
@@ -20,29 +60,7 @@
},
});
$application = { ...config };
$redirect(`/application/:organization/:name/:branch/configuration`, {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
});
} else {
loading = true;
$deployments?.applications?.deployed.find(d => {
const conf = d?.Spec?.Labels.configuration;
if (
conf?.repository?.organization ===
$application.repository.organization &&
conf?.repository?.name === $application.repository.name &&
conf?.repository?.branch === $application.repository.branch
) {
$redirect(`/application/:organization/:name/:branch/configuration`, {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
});
toast.push("This repository & branch is already defined. Redirecting...");
}
});
try {
const dir = await $fetch(
`https://api.github.com/repos/${$application.repository.organization}/${$application.repository.name}/contents/?ref=${$application.repository.branch}`,
@@ -70,9 +88,11 @@
if (checkPackageJSONContents(dep)) {
const config = templates[dep];
$application.build.pack = config.pack;
if (config.installation) $application.build.command.installation = config.installation;
if (config.installation)
$application.build.command.installation = config.installation;
if (config.port) $application.publish.port = config.port;
if (config.directory) $application.publish.directory = config.directory;
if (config.directory)
$application.publish.directory = config.directory;
if (
packageJsonContent.scripts.hasOwnProperty("build") &&
@@ -80,43 +100,27 @@
) {
$application.build.command.build = config.build;
}
toast.push(`${config.name} App detected. Default values set.`);
toast.push(`${config.name} detected. Default values set.`);
}
});
} else if (CargoToml) {
$application.build.pack = "rust";
toast.push(`Rust language detected. Default values set.`);
} else if (Dockerfile) {
$application.build.pack = "custom";
toast.push("Custom Dockerfile found. Build pack set to custom.");
$application.build.pack = "docker";
toast.push("Custom Dockerfile found. Build pack set to docker.");
}
} catch (error) {
// Nothing detected
}
}
loading = false;
});
let activeTab = {
general: true,
buildStep: false,
secrets: false,
};
function activateTab(tab) {
if (activeTab.hasOwnProperty(tab)) {
activeTab = {
general: false,
buildStep: false,
secrets: false,
};
activeTab[tab] = true;
}
}
</script>
{#if loading}
{#await load()}
<Loading github githubLoadingText="Scanning repository..." />
{:else}
<div class="block text-center py-4">
{:then}
<div class="block text-center py-8">
<nav
class="flex space-x-4 justify-center font-bold text-md text-white"
aria-label="Tabs"
@@ -124,47 +128,26 @@
<div
on:click="{() => activateTab('general')}"
class:text-green-500="{activeTab.general}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
class="px-3 py-2 cursor-pointer hover:bg-warmGray-700 rounded-lg transition duration-100"
>
General
</div>
{#if !buildPhaseActive.includes($application.build.pack)}
<div disabled class="px-3 py-2 text-warmGray-700 cursor-not-allowed">
Build Step
</div>
{:else}
<div
on:click="{() => activateTab('buildStep')}"
class:text-green-500="{activeTab.buildStep}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
Build Step
</div>
{/if}
{#if $application.build.pack === "custom"}
<div disabled class="px-3 py-2 text-warmGray-700 cursor-not-allowed">
Secrets
</div>
{:else}
<div
on:click="{() => activateTab('secrets')}"
class:text-green-500="{activeTab.secrets}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
Secrets
</div>
{/if}
<div
on:click="{() => activateTab('secrets')}"
class:text-green-500="{activeTab.secrets}"
class="px-3 py-2 cursor-pointer hover:bg-warmGray-700 rounded-lg transition duration-100"
>
Secrets
</div>
</nav>
</div>
<div class="max-w-4xl mx-auto">
<div class="h-full">
{#if activeTab.general}
<General />
{:else if activeTab.buildStep}
<BuildStep />
{:else if activeTab.secrets}
<Secrets />
{/if}
</div>
</div>
{/if}
{/await}

View File

@@ -0,0 +1,195 @@
<script>
import { params, goto, redirect } from "@roxi/routify";
import {
application,
fetch,
initialApplication,
initConf,
activePage,
} from "@store";
import { onDestroy } from "svelte";
import { toast } from "@zerodevx/svelte-toast";
import Tooltip from "../../components/Tooltip/Tooltip.svelte";
$application.repository.organization = $params.organization;
$application.repository.name = $params.name;
$application.repository.branch = $params.branch;
async function removeApplication() {
await $fetch(`/api/v1/application/remove`, {
body: {
organization: $params.organization,
name: $params.name,
branch: $params.branch,
},
});
toast.push("Application removed.");
$application = JSON.parse(JSON.stringify(initialApplication));
$redirect(`/dashboard/applications`);
}
onDestroy(() => {
$application = JSON.parse(JSON.stringify(initialApplication));
});
async function deploy() {
try {
toast.push("Checking configuration.");
await $fetch(`/api/v1/application/check`, {
body: $application,
});
const { nickname, name, deployId } = await $fetch(
`/api/v1/application/deploy`,
{
body: $application,
},
);
$application.general.nickname = nickname;
$application.build.container.name = name;
$application.general.deployId = deployId;
$initConf = JSON.parse(JSON.stringify($application));
toast.push("Application deployment queued.");
$redirect(
`/application/${$application.repository.organization}/${$application.repository.name}/${$application.repository.branch}/logs/${$application.general.deployId}`,
);
} catch (error) {
console.log(error);
toast.push(error.error || error || "Ooops something went wrong.");
}
}
</script>
<nav
class="flex text-white justify-end items-center m-4 fixed right-0 top-0 space-x-4 z-50"
>
<Tooltip position="bottom" label="Deploy">
<button
disabled="{$application.publish.domain === '' ||
$application.publish.domain === null}"
class:cursor-not-allowed="{$application.publish.domain === '' ||
$application.publish.domain === null}"
class:hover:bg-green-500="{$application.publish.domain}"
class:bg-green-600="{$application.publish.domain}"
class:hover:bg-transparent="{$activePage.new}"
class:text-warmGray-700="{$application.publish.domain === '' ||
$application.publish.domain === null}"
class="icon"
on:click="{deploy}"
>
<svg
class="w-6"
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"
><polyline points="16 16 12 12 8 16"></polyline><line
x1="12"
y1="12"
x2="12"
y2="21"></line><path
d="M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3"
></path><polyline points="16 16 12 12 8 16"></polyline></svg
>
</button>
</Tooltip>
<Tooltip position="bottom" label="Delete">
<button
disabled="{$application.publish.domain === '' ||
$application.publish.domain === null ||
$activePage.new}"
class:cursor-not-allowed="{$application.publish.domain === '' ||
$application.publish.domain === null ||
$activePage.new}"
class:hover:text-red-500="{$application.publish.domain &&
!$activePage.new}"
class:hover:bg-warmGray-700="{$application.publish.domain &&
!$activePage.new}"
class:hover:bg-transparent="{$activePage.new}"
class:text-warmGray-700="{$application.publish.domain === '' ||
$application.publish.domain === null ||
$activePage.new}"
class="icon"
on:click="{removeApplication}"
>
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
></path>
</svg>
</button>
</Tooltip>
<div class="border border-warmGray-700 h-8"></div>
<Tooltip position="bottom" label="Logs">
<button
class="icon"
class:text-warmGray-700="{$activePage.new}"
disabled="{$activePage.new}"
class:hover:text-blue-400="{!$activePage.new}"
class:hover:bg-transparent="{$activePage.new}"
class:cursor-not-allowed="{$activePage.new}"
class:text-blue-400="{$activePage.application === 'logs'}"
class:bg-warmGray-700="{$activePage.application === 'logs'}"
on:click="{() =>
$goto(
`/application/${$application.repository.organization}/${$application.repository.name}/${$application.repository.branch}/logs`,
)}"
>
<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 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
></path>
</svg>
</button>
</Tooltip>
<Tooltip position="bottom-left" label="Configuration">
<button
class="icon hover:text-yellow-400"
disabled="{$activePage.new}"
class:text-yellow-400="{$activePage.application === 'configuration' ||
$activePage.new}"
class:bg-warmGray-700="{$activePage.application === 'configuration' ||
$activePage.new}"
on:click="{() =>
$goto(
`/application/${$application.repository.organization}/${$application.repository.name}/${$application.repository.branch}/configuration`,
)}"
>
<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 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"
></path>
</svg>
</button>
</Tooltip>
</nav>

View File

@@ -3,6 +3,10 @@
import { isActive, redirect } from "@roxi/routify/runtime";
import { fade } from "svelte/transition";
import { toast } from "@zerodevx/svelte-toast";
import MongoDb from "../SVGs/MongoDb.svelte";
import Postgresql from "../SVGs/Postgresql.svelte";
import Mysql from "../SVGs/Mysql.svelte";
import CouchDb from "../SVGs/CouchDb.svelte";
let type;
let defaultDatabaseName;
@@ -15,7 +19,7 @@
defaultDatabaseName,
},
});
$dbInprogress = true
$dbInprogress = true;
toast.push("Database deployment queued.");
$redirect(`/dashboard/databases`);
} catch (error) {
@@ -30,34 +34,47 @@
>
{#if $isActive("/database/new")}
<div class="flex justify-center space-x-4 font-bold pb-6">
<button
class="button bg-gray-500 p-2 text-white hover:bg-green-600 cursor-pointer w-32"
<div
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-green-600 p-2 rounded bg-warmGray-800 w-32"
class:border-green-600="{type === 'mongodb'}"
on:click="{() => (type = 'mongodb')}"
class:bg-green-600="{type === 'mongodb'}"
>
MongoDB
</button>
<button
class="button bg-gray-500 p-2 text-white hover:bg-blue-600 cursor-pointer w-32"
<div class="flex items-center justify-center my-2">
<MongoDb customClass="w-6" />
</div>
<div class="text-white">MongoDB</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-red-600 p-2 rounded bg-warmGray-800 w-32"
class:border-red-600="{type === 'couchdb'}"
on:click="{() => (type = 'couchdb')}"
>
<div class="flex items-center justify-center my-2">
<CouchDb customClass="w-12 text-red-600 fill-current" />
</div>
<div class="text-white">Couchdb</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-600 p-2 rounded bg-warmGray-800 w-32"
class:border-blue-600="{type === 'postgresql'}"
on:click="{() => (type = 'postgresql')}"
class:bg-blue-600="{type === 'postgresql'}"
>
PostgreSQL
</button>
<button
class="button bg-gray-500 p-2 text-white hover:bg-orange-600 cursor-pointer w-32"
<div class="flex items-center justify-center my-2">
<Postgresql customClass="w-12" />
</div>
<div class="text-white">PostgreSQL</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-orange-600 p-2 rounded bg-warmGray-800 w-32"
class:border-orange-600="{type === 'mysql'}"
on:click="{() => (type = 'mysql')}"
class:bg-orange-600="{type === 'mysql'}"
>
MySQL
</button>
<button
class="button bg-gray-500 p-2 text-white hover:bg-red-600 cursor-pointer w-32"
on:click="{() => (type = 'couchdb')}"
class:bg-red-600="{type === 'couchdb'}"
>
Couchdb
</button>
<div class="flex items-center justify-center">
<Mysql customClass="w-10" />
</div>
<div class="text-white">MySQL</div>
</div>
<!-- <button
class="button bg-gray-500 p-2 text-white hover:bg-yellow-500 cursor-pointer w-32"
on:click="{() => (type = 'clickhouse')}"
@@ -67,18 +84,15 @@
</button> -->
</div>
{#if type}
<div>
<div
class="grid grid-rows-1 justify-center items-center text-center pb-5"
>
<label for="defaultDB">Default database</label>
<input
id="defaultDB"
class="w-64"
placeholder="random"
bind:value="{defaultDatabaseName}"
/>
</div>
<div class="flex justify-center space-x-4 items-center">
<label for="defaultDB">Default database</label>
<input
id="defaultDB"
class="w-64"
placeholder="random"
bind:value="{defaultDatabaseName}"
/>
<button
class:bg-green-600="{type === 'mongodb'}"
class:hover:bg-green-500="{type === 'mongodb'}"

View File

@@ -34,7 +34,7 @@
<div class="text-left max-w-5xl mx-auto px-6" in:fade="{{ duration: 100 }}">
<div class="pb-2 pt-5 space-y-4">
<div class="flex space-x-5 items-center">
<div class="text-2xl font-bold py-4 border-gradient">General</div>
<div class="text-2xl font-bold border-gradient">General</div>
<div class="flex-1"></div>
<Tooltip
position="bottom"
@@ -48,7 +48,7 @@
</Tooltip>
</div>
<div class="flex items-center">
<div class="flex items-center pt-4">
<div class="font-bold w-64 text-warmGray-400">Domain</div>
<input class="w-full" value="{service.config.baseURL}" disabled />
</div>
@@ -64,8 +64,8 @@
<div class="font-bold w-64 text-warmGray-400">Password</div>
<PasswordField value="{service.config.userPassword}" />
</div>
<div class="text-2xl font-bold py-4 border-gradient w-32">PostgreSQL</div>
<div class="flex items-center">
<div class="text-2xl font-bold pt-4 border-gradient w-32">PostgreSQL</div>
<div class="flex items-center pt-4">
<div class="font-bold w-64 text-warmGray-400">Username</div>
<input class="w-full" value="{service.config.generateEnvsPostgres.POSTGRESQL_USERNAME}" disabled />
</div>