- Search in repositories (thanks to @SaraVieira).
- Custom Dockerfile - you be able to deploy ANY applications! 🎉 
- Basic repository scanner for Nextjs and React. It will setup the default commands and buildpack if it detects some defined parameters.
- UI/UX fixes:
  - Github loading screen instead of standard loading screen. 
  - Info tooltips which provide some explanations of the input fields.
This commit is contained in:
Andras Bacsai
2021-04-04 14:57:42 +02:00
committed by GitHub
parent 3af1fd4d1b
commit 69f050b864
27 changed files with 669 additions and 363 deletions

View File

@@ -1,29 +1,24 @@
<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="buildCommand">Build Command</label>
<input
class="mb-6"
id="buildCommand"
bind:value="{$application.build.command.build}"
placeholder="eg: yarn build"
/>
<label for="installCommand"
>Install Command <Tooltip label="Command to run for installing dependencies. eg: yarn install." />
</label>
<label for="installCommand">Install Command</label>
<input
class="mb-6"
id="installCommand"
bind:value="{$application.build.command.installation}"
placeholder="eg: yarn install"
/>
<label for="baseDir">Base Directory</label>
<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
id="baseDir"
class="mb-6"
bind:value="{$application.build.directory}"
placeholder="/"
id="buildCommand"
bind:value="{$application.build.command.build}"
placeholder="eg: yarn build"
/>
</div>

View File

@@ -1,16 +1,40 @@
<script>
import { application } from "@store";
import { application} from "@store";
import TooltipInfo from "../../../Tooltip/TooltipInfo.svelte";
</script>
<div>
<div
class="grid grid-cols-1 text-sm max-w-2xl md:mx-auto mx-6 pb-6 auto-cols-max "
>
<label for="buildPack">Build Pack</label>
<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."
/>
{/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>
</select>
</div>
<div
@@ -30,7 +54,11 @@
/>
</div>
<div class="grid grid-flow-row">
<label for="Path">Path</label>
<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}/api`}"
/></label
>
<input
id="Path"
bind:value="{$application.publish.path}"
@@ -38,19 +66,40 @@
/>
</div>
</div>
<label for="publishDir">Publish Directory</label>
{#if $application.build.pack === "nodejs" || $application.build.pack === "custom"}
<label for="Port" >Port</label>
<input
id="publishDir"
bind:value="{$application.publish.directory}"
placeholder="/"
id="Port"
class="mb-6"
bind:value="{$application.publish.port}"
placeholder="{$application.build.pack === 'static' ? '80' : '3000'}"
/>
{#if $application.build.pack === "nodejs"}
<label for="Port" class="pt-6">Port</label>
<input
id="Port"
bind:value="{$application.publish.port}"
placeholder="{$application.build.pack === 'static' ? '80' : '3000'}"
/>
{/if}
{/if}
<div class="grid grid-flow-col gap-2 items-center pt-12">
<div class="grid grid-flow-row">
<label for="baseDir"
>Base Directory <TooltipInfo
label="The directory to use as base for every command (could be useful if you have a monorepo)."
/></label
>
<input
id="baseDir"
bind:value="{$application.build.directory}"
placeholder="/"
/>
</div>
<div class="grid grid-flow-row">
<label for="publishDir"
>Publish Directory <TooltipInfo
label="The directory to deploy after running the build command. eg: dist, _site, public."
/></label
>
<input
id="publishDir"
bind:value="{$application.publish.directory}"
placeholder="/"
/>
</div>
</div>
</div>
</div>
</div>

View File

@@ -147,13 +147,13 @@
<Login />
{:else}
{#await loadGithub()}
<Loading />
<Loading github githubLoadingText="Loading repositories..." />
{:then}
{#if loading.github}
<Loading />
<Loading github githubLoadingText="Loading repositories..." />
{:else}
<div
class="text-center space-y-2 max-w-4xl mx-auto px-6"
class="space-y-2 max-w-4xl mx-auto px-6"
in:fade="{{ duration: 100 }}"
>
<Repositories

View File

@@ -1,36 +1,63 @@
<style lang="postcss">
:global(.repository-select-search .listItem .item),
:global(.repository-select-search .empty) {
@apply text-sm py-3 font-bold bg-warmGray-800 text-white cursor-pointer border-none hover:bg-warmGray-700 !important;
}
:global(.repository-select-search .listContainer) {
@apply bg-transparent !important;
}
:global(.repository-select-search .clearSelect) {
@apply text-white cursor-pointer !important;
}
:global(.repository-select-search .selectedItem) {
@apply text-white relative cursor-pointer font-bold text-sm flex items-center !important;
}
</style>
<script>
import { createEventDispatcher } from "svelte";
import { isActive } from "@roxi/routify";
import { application } from "@store";
import Select from "svelte-select";
function handleSelect(event) {
$application.repository.id = parseInt(event.detail.value, 10);
dispatch("loadBranches");
}
export let repositories;
let items = repositories.map(repo => ({
label: `${repo.owner.login}/${repo.name}`,
value: repo.id.toString(),
}));
const selectedValue =
!$isActive("/application/new") &&
`${$application.repository.organization}/${$application.repository.name}`;
const dispatch = createEventDispatcher();
const loadBranches = () => dispatch("loadBranches");
const modifyGithubAppConfig = () => dispatch("modifyGithubAppConfig");
</script>
<div class="grid grid-cols-1">
{#if repositories.length !== 0}
<label for="repository">Organization / Repository</label>
<div class="grid grid-cols-3">
<!-- svelte-ignore a11y-no-onchange -->
<select
id="repository"
class:cursor-not-allowed="{!$isActive('/application/new')}"
class="col-span-2"
bind:value="{$application.repository.id}"
on:change="{loadBranches}"
disabled="{!$isActive('/application/new')}"
>
<option selected disabled>Select a repository</option>
{#each repositories as repo}
<option value="{repo.id}" class="font-bold">
{repo.owner.login}
/
{repo.name}
</option>
{/each}
</select>
<div class="grid grid-cols-3 ">
<div class="repository-select-search col-span-2">
<Select
containerClasses="w-full border-none bg-transparent"
on:select="{handleSelect}"
selectedValue="{selectedValue}"
isClearable="{false}"
items="{items}"
noOptionsMessage="No Repositories found"
placeholder="Select a Repository"
isDisabled="{!$isActive('/application/new')}"
/>
</div>
<button
class="button col-span-1 ml-2 bg-warmGray-800 hover:bg-warmGray-700 text-white"
on:click="{modifyGithubAppConfig}">Configure on Github</button

View File

@@ -1,11 +1,15 @@
<script>
import { redirect, isActive } from "@roxi/routify";
import { onMount } from "svelte";
import { toast } from "@zerodevx/svelte-toast";
import { application, fetch, deployments } from "@store";
import General from "./ActiveTab/General.svelte";
import BuildStep from "./ActiveTab/BuildStep.svelte";
import Secrets from "./ActiveTab/Secrets.svelte";
import { onMount } from "svelte";
import Loading from "../../Loading.svelte";
let loading = false;
onMount(async () => {
if (!$isActive("/application/new")) {
const config = await $fetch(`/api/v1/config`, {
@@ -22,13 +26,14 @@
branch: $application.repository.branch,
});
} else {
$deployments.applications.deployed.filter(d => {
loading = true;
$deployments?.applications?.deployed.filter(d => {
const conf = d?.Spec?.Labels.application;
if (
conf.repository.organization ===
conf?.repository?.organization ===
$application.repository.organization &&
conf.repository.name === $application.repository.name &&
conf.repository.branch === $application.repository.branch
conf?.repository?.name === $application.repository.name &&
conf?.repository?.branch === $application.repository.branch
) {
$redirect(`/application/:organization/:name/:branch/configuration`, {
name: $application.repository.name,
@@ -37,7 +42,51 @@
});
}
});
try {
const dir = await $fetch(
`https://api.github.com/repos/${$application.repository.organization}/${$application.repository.name}/contents/?ref=${$application.repository.branch}`,
);
const packageJson = dir.find(
f => f.type === "file" && f.name === "package.json",
);
const Dockerfile = dir.find(
f => f.type === "file" && f.name === "Dockerfile",
);
if (Dockerfile) {
$application.build.pack = "custom";
toast.push("Custom Dockerfile found. Build pack set to custom.");
} else if (packageJson) {
// Check here for things like nextjs,react,vue,blablabla
const { content } = await $fetch(packageJson.git_url);
const packageJsonContent = JSON.parse(atob(content));
if (packageJsonContent.dependencies.hasOwnProperty("next")) {
// Next.js
$application.build.pack = "nodejs";
$application.build.command.installation = "yarn install";
if (packageJsonContent.scripts.hasOwnProperty("build")) {
$application.build.command.build = `yarn build`;
}
toast.push("Next.js App detected. Build pack set to Node.js.");
} else if (packageJsonContent.dependencies.hasOwnProperty("react")) {
// CRA
$application.build.pack = "static";
$application.publish.directory = "build";
$application.build.command.installation = "yarn install";
if (packageJsonContent.scripts.hasOwnProperty("build")) {
$application.build.command.build = `yarn build`;
}
toast.push(
"React App detected. Build pack set to static with build phase.",
);
}
}
} catch (error) {
// Nothing detected
}
}
loading = false;
});
let activeTab = {
general: true,
@@ -56,42 +105,53 @@
}
</script>
<div class="block text-center py-4">
<nav
class="flex space-x-4 justify-center font-bold text-md text-white"
aria-label="Tabs"
>
<div
on:click="{() => activateTab('general')}"
class:text-green-500="{activeTab.general}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
{#if loading}
<Loading github githubLoadingText="Scanning repository 🤖" />
{:else}
<div class="block text-center py-4">
<nav
class="flex space-x-4 justify-center font-bold text-md text-white"
aria-label="Tabs"
>
General
</div>
<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>
<div
on:click="{() => activateTab('secrets')}"
class:text-green-500="{activeTab.secrets}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
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
on:click="{() => activateTab('general')}"
class:text-green-500="{activeTab.general}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
General
</div>
{#if $application.build.pack === "php"}
<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}
<div
on:click="{() => activateTab('secrets')}"
class:text-green-500="{activeTab.secrets}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
Secrets
</div>
</nav>
</div>
</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}