Compare commits

...

17 Commits

Author SHA1 Message Date
Andras Bacsai
5e02c386ec Merge pull request #641 from coollabsio/next
v3.10.10
2022-09-28 10:49:19 +02:00
Andras Bacsai
b4501fe52d ui: beta flag 2022-09-28 10:41:32 +02:00
Andras Bacsai
3c29eaa1b1 ui: small fix 2022-09-28 10:35:47 +02:00
Andras Bacsai
ee67e163b1 feat: system-wide github apps 2022-09-28 10:34:27 +02:00
Andras Bacsai
9662bc29fb ui: fix gitlab importer view 2022-09-28 09:56:27 +02:00
Andras Bacsai
96f2660b98 ui: loading button 2022-09-28 09:47:05 +02:00
Andras Bacsai
20f594c66c chore: version++ 2022-09-28 09:30:57 +02:00
Andras Bacsai
2b8d59dca3 Merge pull request #637 from coollabsio/next
v3.10.9
2022-09-28 09:29:31 +02:00
Andras Bacsai
d44047d109 ui: dev logs 2022-09-28 09:19:51 +02:00
Andras Bacsai
57c4d33bd3 ui: main resource search 2022-09-28 09:07:59 +02:00
Andras Bacsai
7a5377efe0 ui: resource button fix 2022-09-28 09:07:46 +02:00
Andras Bacsai
91e7cffccc fix: only log things to console in dev mode 2022-09-28 08:39:59 +02:00
Andras Bacsai
df31e47313 fix: disable development low disk space 2022-09-28 08:39:33 +02:00
Andras Bacsai
cb9586270c fix: able to delete apps in unconfigured state 2022-09-27 09:27:28 +00:00
Andras Bacsai
21dfa5227c fix: logs in docker bp 2022-09-26 20:37:58 +00:00
Andras Bacsai
9d15d2be77 chore: version++ 2022-09-26 20:22:08 +00:00
Andras Bacsai
929c02d31f ui: fix basedirectory meaning 2022-09-26 20:21:41 +00:00
27 changed files with 667 additions and 327 deletions

View File

@@ -0,0 +1,26 @@
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_GitSource" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"forPublic" BOOLEAN NOT NULL DEFAULT false,
"type" TEXT,
"apiUrl" TEXT,
"htmlUrl" TEXT,
"customPort" INTEGER NOT NULL DEFAULT 22,
"organization" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"githubAppId" TEXT,
"gitlabAppId" TEXT,
"isSystemWide" BOOLEAN NOT NULL DEFAULT false,
CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_GitSource" ("apiUrl", "createdAt", "customPort", "forPublic", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt") SELECT "apiUrl", "createdAt", "customPort", "forPublic", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt" FROM "GitSource";
DROP TABLE "GitSource";
ALTER TABLE "new_GitSource" RENAME TO "GitSource";
CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

View File

@@ -299,6 +299,7 @@ model GitSource {
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
githubAppId String? @unique githubAppId String? @unique
gitlabAppId String? @unique gitlabAppId String? @unique
isSystemWide Boolean @default(false)
gitlabApp GitlabApp? @relation(fields: [gitlabAppId], references: [id]) gitlabApp GitlabApp? @relation(fields: [gitlabAppId], references: [id])
githubApp GithubApp? @relation(fields: [githubAppId], references: [id]) githubApp GithubApp? @relation(fields: [githubAppId], references: [id])
application Application[] application Application[]

View File

@@ -211,7 +211,6 @@ import * as buildpacks from '../lib/buildPacks';
// //
} }
await copyBaseConfigurationFiles(buildPack, workdir, buildId, applicationId, baseImage); await copyBaseConfigurationFiles(buildPack, workdir, buildId, applicationId, baseImage);
if (forceRebuild) deployNeeded = true if (forceRebuild) deployNeeded = true
if (!imageFound || deployNeeded) { if (!imageFound || deployNeeded) {
// if (true) { // if (true) {

View File

@@ -472,7 +472,8 @@ export const saveBuildLog = async ({
if (isDev) { if (isDev) {
console.debug(`[${applicationId}] ${addTimestamp}`); console.debug(`[${applicationId}] ${addTimestamp}`);
} return
}
try { try {
return await got.post(`${fluentBitUrl}/${applicationId}_buildlog_${buildId}.csv`, { return await got.post(`${fluentBitUrl}/${applicationId}_buildlog_${buildId}.csv`, {
json: { json: {
@@ -586,9 +587,9 @@ export async function buildImage({
} else { } else {
await saveBuildLog({ line: `Building image started.`, buildId, applicationId }); await saveBuildLog({ line: `Building image started.`, buildId, applicationId });
} }
if (!debug && isCache) { if (!debug) {
await saveBuildLog({ await saveBuildLog({
line: `Debug turned off. To see more details, allow it in the configuration.`, line: `Debug turned off. To see more details, allow it in the features tab.`,
buildId, buildId,
applicationId applicationId
}); });
@@ -607,30 +608,6 @@ export async function buildImage({
} }
} }
export async function streamEvents({ stream, docker, buildId, applicationId, debug }) {
await new Promise((resolve, reject) => {
docker.engine.modem.followProgress(stream, onFinished, onProgress);
function onFinished(err, res) {
if (err) reject(err);
resolve(res);
}
async function onProgress(event) {
if (event.error) {
reject(event.error);
} else if (event.stream) {
if (event.stream !== '\n') {
if (debug)
await saveBuildLog({
line: `${event.stream.replace('\n', '')}`,
buildId,
applicationId
});
}
}
}
});
}
export function makeLabelForStandaloneApplication({ export function makeLabelForStandaloneApplication({
applicationId, applicationId,
fqdn, fqdn,
@@ -721,6 +698,7 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
if (installCommand) { if (installCommand) {
Dockerfile.push(`RUN ${installCommand}`); Dockerfile.push(`RUN ${installCommand}`);
} }
// Dockerfile.push(`ARG CACHEBUST=1`);
Dockerfile.push(`RUN ${buildCommand}`); Dockerfile.push(`RUN ${buildCommand}`);
await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n'));
await buildImage({ ...data, isCache: true }); await buildImage({ ...data, isCache: true });

View File

@@ -13,36 +13,33 @@ export default async function (data) {
pullmergeRequestId, pullmergeRequestId,
dockerFileLocation dockerFileLocation
} = data } = data
try { const file = `${workdir}${baseDirectory}${dockerFileLocation}`;
const file = `${workdir}${baseDirectory}${dockerFileLocation}`; data.workdir = `${workdir}${baseDirectory}`;
data.workdir = `${workdir}${baseDirectory}`; const DockerfileRaw = await fs.readFile(`${file}`, 'utf8')
const Dockerfile: Array<string> = (await fs.readFile(`${file}`, 'utf8')) const Dockerfile: Array<string> = DockerfileRaw
.toString() .toString()
.trim() .trim()
.split('\n'); .split('\n');
Dockerfile.push(`LABEL coolify.buildId=${buildId}`); Dockerfile.push(`LABEL coolify.buildId=${buildId}`);
if (secrets.length > 0) { if (secrets.length > 0) {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if ( if (
(pullmergeRequestId && secret.isPRMRSecret) || (pullmergeRequestId && secret.isPRMRSecret) ||
(!pullmergeRequestId && !secret.isPRMRSecret) (!pullmergeRequestId && !secret.isPRMRSecret)
) { ) {
Dockerfile.unshift(`ARG ${secret.name}=${secret.value}`); Dockerfile.unshift(`ARG ${secret.name}=${secret.value}`);
Dockerfile.forEach((line, index) => { Dockerfile.forEach((line, index) => {
if (line.startsWith('FROM')) { if (line.startsWith('FROM')) {
Dockerfile.splice(index + 1, 0, `ARG ${secret.name}`); Dockerfile.splice(index + 1, 0, `ARG ${secret.name}`);
} }
}); });
}
} }
}); }
} });
await fs.writeFile(`${workdir}${dockerFileLocation}`, Dockerfile.join('\n'));
await buildImage(data);
} catch (error) {
throw error;
} }
await fs.writeFile(`${workdir}${dockerFileLocation}`, Dockerfile.join('\n'));
await buildImage(data);
} }

View File

@@ -21,7 +21,7 @@ import { scheduler } from './scheduler';
import { supportedServiceTypesAndVersions } from './services/supportedVersions'; import { supportedServiceTypesAndVersions } from './services/supportedVersions';
import { includeServices } from './services/common'; import { includeServices } from './services/common';
export const version = '3.10.8'; export const version = '3.10.10';
export const isDev = process.env.NODE_ENV === 'development'; export const isDev = process.env.NODE_ENV === 'development';
const algorithm = 'aes-256-ctr'; const algorithm = 'aes-256-ctr';
@@ -1651,10 +1651,10 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) {
} }
} catch (error) { } } catch (error) { }
if (lowDiskSpace || force) { if (lowDiskSpace || force) {
if (isDev) { // if (isDev) {
if (!force) console.log(`[DEV MODE] Low disk space: ${lowDiskSpace}`); // if (!force) console.log(`[DEV MODE] Low disk space: ${lowDiskSpace}`);
return; // return;
} // }
try { try {
await executeDockerCmd({ await executeDockerCmd({
dockerId, dockerId,

View File

@@ -135,7 +135,7 @@ export async function showDashboard(request: FastifyRequest) {
include: { destinationDocker: true, teams: true }, include: { destinationDocker: true, teams: true },
}); });
const gitSources = await prisma.gitSource.findMany({ const gitSources = await prisma.gitSource.findMany({
where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, where: { OR: [{ teams: { some: { id: teamId === "0" ? undefined : teamId } } }, { isSystemWide: true }] },
include: { teams: true }, include: { teams: true },
}); });
const destinations = await prisma.destinationDocker.findMany({ const destinations = await prisma.destinationDocker.findMany({

View File

@@ -9,7 +9,7 @@ export async function listSources(request: FastifyRequest) {
try { try {
const teamId = request.user?.teamId; const teamId = request.user?.teamId;
const sources = await prisma.gitSource.findMany({ const sources = await prisma.gitSource.findMany({
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }, where: { OR: [{ teams: { some: { id: teamId === "0" ? undefined : teamId } } }, { isSystemWide: true }] },
include: { teams: true, githubApp: true, gitlabApp: true } include: { teams: true, githubApp: true, gitlabApp: true }
}); });
return { return {
@@ -22,11 +22,11 @@ export async function listSources(request: FastifyRequest) {
export async function saveSource(request, reply) { export async function saveSource(request, reply) {
try { try {
const { id } = request.params const { id } = request.params
let { name, htmlUrl, apiUrl, customPort } = request.body let { name, htmlUrl, apiUrl, customPort, isSystemWide } = request.body
if (customPort) customPort = Number(customPort) if (customPort) customPort = Number(customPort)
await prisma.gitSource.update({ await prisma.gitSource.update({
where: { id }, where: { id },
data: { name, htmlUrl, apiUrl, customPort } data: { name, htmlUrl, apiUrl, customPort, isSystemWide }
}); });
return reply.code(201).send() return reply.code(201).send()
} catch ({ status, message }) { } catch ({ status, message }) {
@@ -56,7 +56,7 @@ export async function getSource(request: FastifyRequest<OnlyId>) {
} }
const source = await prisma.gitSource.findFirst({ const source = await prisma.gitSource.findFirst({
where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } }, where: { id, OR: [{ teams: { some: { id: teamId === "0" ? undefined : teamId } } }, { isSystemWide: true }] },
include: { githubApp: true, gitlabApp: true } include: { githubApp: true, gitlabApp: true }
}); });
if (!source) { if (!source) {
@@ -104,7 +104,7 @@ export async function saveGitHubSource(request: FastifyRequest<SaveGitHubSource>
const { teamId } = request.user const { teamId } = request.user
const { id } = request.params const { id } = request.params
let { name, htmlUrl, apiUrl, organization, customPort } = request.body let { name, htmlUrl, apiUrl, organization, customPort, isSystemWide } = request.body
if (customPort) customPort = Number(customPort) if (customPort) customPort = Number(customPort)
if (id === 'new') { if (id === 'new') {
@@ -117,6 +117,7 @@ export async function saveGitHubSource(request: FastifyRequest<SaveGitHubSource>
apiUrl, apiUrl,
organization, organization,
customPort, customPort,
isSystemWide,
type: 'github', type: 'github',
teams: { connect: { id: teamId } } teams: { connect: { id: teamId } }
} }

View File

@@ -7,6 +7,7 @@ export interface SaveGitHubSource extends OnlyId {
apiUrl: string, apiUrl: string,
organization: string, organization: string,
customPort: number, customPort: number,
isSystemWide: boolean
} }
} }
export interface SaveGitLabSource extends OnlyId { export interface SaveGitLabSource extends OnlyId {

View File

@@ -0,0 +1 @@
<span class="badge bg-coollabs-gradient rounded text-white font-normal"> BETA </span>

View File

@@ -1,10 +1,13 @@
<script lang="ts"> <script lang="ts">
import Beta from './Beta.svelte';
import Explaner from './Explainer.svelte'; import Explaner from './Explainer.svelte';
import Tooltip from './Tooltip.svelte'; import Tooltip from './Tooltip.svelte';
export let id: any; export let id: any;
export let customClass: any = null;
export let setting: any; export let setting: any;
export let title: any; export let title: any;
export let isBeta: any = false;
export let description: any; export let description: any;
export let isCenter = true; export let isCenter = true;
export let disabled = false; export let disabled = false;
@@ -18,13 +21,16 @@
<!-- svelte-ignore a11y-label-has-associated-control --> <!-- svelte-ignore a11y-label-has-associated-control -->
<label> <label>
{title} {title}
{#if isBeta}
<Beta />
{/if}
{#if description && description !== ''} {#if description && description !== ''}
<Explaner explanation={description} /> <Explaner explanation={description} />
{/if} {/if}
</label> </label>
</div> </div>
</div> </div>
<div class:text-center={isCenter} class="flex justify-center"> <div class:text-center={isCenter} class={`flex justify-center ${customClass}`}>
<div <div
on:click on:click
aria-pressed="false" aria-pressed="false"

View File

@@ -86,7 +86,7 @@
id="update" id="update"
disabled={updateStatus.success === false} disabled={updateStatus.success === false}
on:click={update} on:click={update}
class="icons bg-coollabs-gradient text-white duration-75 hover:scale-105 w-full" class="icons bg-coollabs-gradient text-white duration-75 hover:scale-105 w-full"
> >
{#if updateStatus.loading} {#if updateStatus.loading}
<svg <svg

View File

@@ -27,6 +27,7 @@
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { get, post } from '$lib/api'; import { get, post } from '$lib/api';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import Beta from './Beta.svelte';
async function getStatus() { async function getStatus() {
if (loading.usage) return; if (loading.usage) return;
loading.usage = true; loading.usage = true;
@@ -78,7 +79,7 @@
<h1 class="font-bold text-lg lg:text-xl truncate"> <h1 class="font-bold text-lg lg:text-xl truncate">
{server.name} {server.name}
{#if server.remoteEngine} {#if server.remoteEngine}
<span class="badge bg-coollabs-gradient rounded text-white"> BETA </span> <Beta />
{/if} {/if}
</h1> </h1>
<div class="text-xs"> <div class="text-xs">

View File

@@ -18,8 +18,8 @@
<div class="dropdown dropdown-bottom"> <div class="dropdown dropdown-bottom">
<slot> <slot>
<label for="new" tabindex="0" class="btn btn-square btn-sm bg-coollabs"> <label for="new" tabindex="0" class="btn btn-sm text-sm bg-coollabs hover:bg-coollabs-100">
<svg Create New Resource <svg
class="h-6 w-6" class="h-6 w-6"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
fill="none" fill="none"
@@ -35,11 +35,7 @@
> >
</slot> </slot>
<ul <ul id="new" tabindex="0" class="dropdown-content menu p-2 shadow bg-coolgray-300 rounded w-52">
id="new"
tabindex="0"
class="dropdown-content menu p-2 shadow bg-coolgray-300 rounded w-52"
>
<li> <li>
<button on:click={newApplication} class="no-underline hover:bg-applications rounded-none "> <button on:click={newApplication} class="no-underline hover:bg-applications rounded-none ">
<svg <svg

View File

@@ -59,6 +59,7 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
import { import {
appSession, appSession,
status, status,
@@ -75,10 +76,25 @@
let statusInterval: any; let statusInterval: any;
let forceDelete = false; let forceDelete = false;
const { id } = $page.params;
const { id } = $page.params;
$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application); $isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
async function deleteApplication(name: string, force: boolean) {
const sure = confirm($t('application.confirm_to_delete', { name }));
if (sure) {
try {
await del(`/applications/${id}`, { id, force });
return await goto('/');
} catch (error) {
if (error.message.startsWith(`Command failed: SSH_AUTH_SOCK=/tmp/coolify-ssh-agent.pid`)) {
forceDelete = true;
}
return errorNotification(error);
}
}
}
async function handleDeploySubmit(forceRebuild = false) { async function handleDeploySubmit(forceRebuild = false) {
if (!$isDeploymentEnabled) return; if (!$isDeploymentEnabled) return;
try { try {
@@ -172,13 +188,13 @@
</script> </script>
<div class="mx-auto max-w-screen-2xl px-6 grid grid-cols-1 lg:grid-cols-2"> <div class="mx-auto max-w-screen-2xl px-6 grid grid-cols-1 lg:grid-cols-2">
<nav class="header flex flex-row order-2 lg:order-1 px-0 lg:px-4"> <nav class="header flex flex-row order-2 lg:order-1 px-0 lg:px-4 items-start">
<div class="title lg:pb-10"> <div class="title lg:pb-10">
{#if $page.url.pathname === `/applications/${id}/configuration/source`} {#if $page.url.pathname === `/applications/${id}/configuration/source`}
Select a Source Select a Source
{:else if $page.url.pathname === `/applications/${id}/configuration/destination`} {:else if $page.url.pathname === `/applications/${id}/configuration/destination`}
Select a Destination Select a Destination
{:else if $page.url.pathname === `/applications/${id}/configuration/repository`} {:else if $page.url.pathname === `/applications/${id}/configuration/repository`}
Select a Repository Select a Repository
{:else if $page.url.pathname === `/applications/${id}/configuration/buildpack`} {:else if $page.url.pathname === `/applications/${id}/configuration/buildpack`}
Select a Build Pack Select a Build Pack
@@ -195,6 +211,32 @@
</div> </div>
{/if} {/if}
</div> </div>
{#if $page.url.pathname.startsWith(`/applications/${id}/configuration/`)}
<div class="px-2">
{#if forceDelete}
<button
on:click={() => deleteApplication(application.name, true)}
disabled={!$appSession.isAdmin}
class:bg-red-600={$appSession.isAdmin}
class:hover:bg-red-500={$appSession.isAdmin}
class="btn btn-sm btn-error text-sm"
>
Force Delete Application
</button>
{:else}
<button
on:click={() => deleteApplication(application.name, false)}
disabled={!$appSession.isAdmin}
class:bg-red-600={$appSession.isAdmin}
class:hover:bg-red-500={$appSession.isAdmin}
class="btn btn-sm btn-error text-sm"
>
Delete Application
</button>
{/if}
</div>
{/if}
</nav> </nav>
<div <div
class="pt-4 flex flex-row items-start justify-center lg:justify-end space-x-2 order-1 lg:order-2" class="pt-4 flex flex-row items-start justify-center lg:justify-end space-x-2 order-1 lg:order-2"
@@ -320,8 +362,7 @@
</svg> </svg>
</button> </button>
<Tooltip triggeredBy="#forceredeploy">Force Redeploy (without cache)</Tooltip> <Tooltip triggeredBy="#forceredeploy">Force Redeploy (without cache)</Tooltip>
{:else} {:else if $isDeploymentEnabled && !$page.url.pathname.startsWith(`/applications/${id}/configuration/`)}
{#if $isDeploymentEnabled}
<button <button
class="icons flex items-center font-bold" class="icons flex items-center font-bold"
disabled={!$isDeploymentEnabled} disabled={!$isDeploymentEnabled}
@@ -342,7 +383,6 @@
</svg> </svg>
Deploy Deploy
</button> </button>
{/if}
{/if} {/if}
{#if $location && $status.application.isRunning} {#if $location && $status.application.isRunning}

View File

@@ -152,8 +152,8 @@
</div> </div>
{:else} {:else}
<form on:submit|preventDefault={handleSubmit} class="px-10"> <form on:submit|preventDefault={handleSubmit} class="px-10">
<div class="flex lg:flex-row flex-col lg:space-y-0 space-y-2 space-x-0 lg:space-x-2 items-center"> <div class="flex lg:flex-row flex-col lg:space-y-0 space-y-2 space-x-0 lg:space-x-2 items-center lg:justify-center">
<div class="custom-select-wrapper w-1/2"><label for="repository" class="pb-1">Repository</label> <div class="custom-select-wrapper"><label for="repository" class="pb-1">Repository</label>
<Select <Select
placeholder={loading.repositories placeholder={loading.repositories
? $t('application.configuration.loading_repositories') ? $t('application.configuration.loading_repositories')
@@ -168,7 +168,7 @@
/> />
</div> </div>
<input class="hidden" bind:value={selected.projectId} name="projectId" /> <input class="hidden" bind:value={selected.projectId} name="projectId" />
<div class="custom-select-wrapper w-1/2"><label for="repository" class="pb-1">Branch</label> <div class="custom-select-wrapper"><label for="repository" class="pb-1">Branch</label>
<Select <Select
placeholder={loading.branches placeholder={loading.branches
? $t('application.configuration.loading_branches') ? $t('application.configuration.loading_branches')

View File

@@ -328,8 +328,9 @@
</script> </script>
<form on:submit={handleSubmit}> <form on:submit={handleSubmit}>
<div class="flex flex-col space-y-2 px-4 xl:flex-row xl:space-y-0 xl:space-x-2 "> <div class="flex lg:flex-row flex-col lg:space-y-0 space-y-2 space-x-0 lg:space-x-2 items-center lg:justify-center">
<div class="custom-select-wrapper"> <div class="custom-select-wrapper">
<label for="groups" class="pb-1">Groups</label>
<Select <Select
placeholder={loading.base placeholder={loading.base
? $t('application.configuration.loading_groups') ? $t('application.configuration.loading_groups')
@@ -355,6 +356,7 @@
/> />
</div> </div>
<div class="custom-select-wrapper"> <div class="custom-select-wrapper">
<label for="projects" class="pb-1">Projects</label>
<Select <Select
placeholder={loading.projects placeholder={loading.projects
? $t('application.configuration.loading_projects') ? $t('application.configuration.loading_projects')
@@ -380,6 +382,7 @@
/> />
</div> </div>
<div class="custom-select-wrapper"> <div class="custom-select-wrapper">
<label for="branches" class="pb-1">Branches</label>
<Select <Select
placeholder={loading.branches placeholder={loading.branches
? $t('application.configuration.loading_branches') ? $t('application.configuration.loading_branches')

View File

@@ -53,7 +53,6 @@
return source; return source;
} }
}); });
async function handleSubmit(gitSourceId: string) { async function handleSubmit(gitSourceId: string) {
try { try {
await post(`/applications/${id}/configuration/source`, { gitSourceId }); await post(`/applications/${id}/configuration/source`, { gitSourceId });
@@ -71,7 +70,7 @@
<div class="max-w-screen-2xl mx-auto px-9"> <div class="max-w-screen-2xl mx-auto px-9">
<div class="title pb-8">Git App</div> <div class="title pb-8">Git App</div>
<div class="flex flex-wrap justify-center"> <div class="flex flex-wrap justify-center">
{#if !filteredSources || ownSources.length === 0} {#if !filteredSources}
<div class="flex-col"> <div class="flex-col">
<div class="pb-2 text-center font-bold"> <div class="pb-2 text-center font-bold">
{$t('application.configuration.no_configurable_git')} {$t('application.configuration.no_configurable_git')}
@@ -169,11 +168,68 @@
<button <button
disabled={source.gitlabApp && !source.gitlabAppId} disabled={source.gitlabApp && !source.gitlabAppId}
type="submit" type="submit"
class="disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group" class="relative disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group"
class:border-red-500={source.gitlabApp && !source.gitlabAppId} class:border-red-500={source.gitlabApp && !source.gitlabAppId}
class:border-0={source.gitlabApp && !source.gitlabAppId} class:border-0={source.gitlabApp && !source.gitlabAppId}
class:border-l-4={source.gitlabApp && !source.gitlabAppId} class:border-l-4={source.gitlabApp && !source.gitlabAppId}
> >
<div class="absolute top-0 left-0 -m-5 flex">
{#if source?.type === 'gitlab'}
<svg viewBox="0 0 128 128" class="h-10 w-10">
<path
fill="#FC6D26"
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
fill="#FC6D26"
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
/><path
fill="#FCA326"
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
/><path
fill="#E24329"
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
fill="#FCA326"
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
/><path
fill="#E24329"
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
/>
</svg>
{:else if source?.type === 'github'}
<svg viewBox="0 0 128 128" class="h-10 w-10">
<g fill="#ffffff"
><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
/><path
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
/></g
>
</svg>
{/if}
{#if source.isSystemWide}
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-10 w-10"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="12" cy="12" r="9" />
<line x1="3.6" y1="9" x2="20.4" y2="9" />
<line x1="3.6" y1="15" x2="20.4" y2="15" />
<path d="M11.5 3a17 17 0 0 0 0 18" />
<path d="M12.5 3a17 17 0 0 1 0 18" />
</svg>
{/if}
</div>
<div class="font-bold text-xl text-center truncate">{source.name}</div> <div class="font-bold text-xl text-center truncate">{source.name}</div>
{#if source.gitlabApp && !source.gitlabAppId} {#if source.gitlabApp && !source.gitlabAppId}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white"> <div class="font-bold text-center truncate text-red-500 group-hover:text-white">

View File

@@ -266,7 +266,6 @@
await getBaseBuildImages(); await getBaseBuildImages();
await handleSubmit(); await handleSubmit();
} }
async function isDNSValid(domain: any, isWWW: any) { async function isDNSValid(domain: any, isWWW: any) {
try { try {
await get(`/applications/${id}/check?domain=${domain}`); await get(`/applications/${id}/check?domain=${domain}`);
@@ -707,24 +706,6 @@
/> />
</div> </div>
{/if} {/if}
{#if application.buildPack === 'docker'}
<div class="grid grid-cols-2 items-center pt-4">
<label for="dockerFileLocation"
>Dockerfile Location <Explainer
explanation={"Should be absolute path, like <span class='text-settings font-bold'>/data/Dockerfile</span> or <span class='text-settings font-bold'>/Dockerfile.</span>"}
/></label
>
<input
class="w-full"
disabled={isDisabled}
readonly={!$appSession.isAdmin}
name="dockerFileLocation"
id="dockerFileLocation"
bind:value={application.dockerFileLocation}
placeholder="default: /Dockerfile"
/>
</div>
{/if}
{#if application.buildPack === 'deno'} {#if application.buildPack === 'deno'}
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="denoMainFile">Main File</label> <label for="denoMainFile">Main File</label>
@@ -776,6 +757,31 @@
/> />
</div> </div>
{/if} {/if}
{#if application.buildPack === 'docker'}
<div class="grid grid-cols-2 items-center pb-4">
<label for="dockerFileLocation"
class="mb-10"
>Dockerfile Location <Explainer
explanation={"Should be absolute path, like <span class='text-settings font-bold'>/data/Dockerfile</span> or <span class='text-settings font-bold'>/Dockerfile.</span>"}
/></label
>
<div class="form-control w-full">
<input
class="w-full input"
disabled={isDisabled}
readonly={!$appSession.isAdmin}
name="dockerFileLocation"
id="dockerFileLocation"
bind:value={application.dockerFileLocation}
placeholder="default: /Dockerfile"
/>
<label class="label">
<span class="label-text-alt text-xs">Path: {application.baseDirectory.replace(/^\/$/,'')}{application.dockerFileLocation}</span>
</label>
</div>
</div>
{/if}
{#if !notNodeDeployments.includes(application.buildPack)} {#if !notNodeDeployments.includes(application.buildPack)}
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<div class="flex-col"> <div class="flex-col">

View File

@@ -7,6 +7,7 @@
import Tooltip from '$lib/components/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip.svelte';
import { day } from '$lib/dayjs'; import { day } from '$lib/dayjs';
import { selectedBuildId } from '$lib/store'; import { selectedBuildId } from '$lib/store';
import { dev } from '$app/env';
let logs: any = []; let logs: any = [];
let currentStatus: any; let currentStatus: any;
@@ -104,86 +105,86 @@
}); });
</script> </script>
<div class="flex justify-start top-0 pb-2 space-x-2"> <div class="flex justify-start top-0 pb-2 space-x-2">
<button <button
on:click={followBuild} on:click={followBuild}
class="btn btn-sm bg-coollabs" class="btn btn-sm bg-coollabs"
disabled={currentStatus !== 'running'} disabled={currentStatus !== 'running'}
class:bg-coolgray-300={followingLogs || currentStatus !== 'running'} class:bg-coolgray-300={followingLogs || currentStatus !== 'running'}
class:text-applications={followingLogs} class:text-applications={followingLogs}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6 mr-2"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
> >
<svg <path stroke="none" d="M0 0h24v24H0z" fill="none" />
xmlns="http://www.w3.org/2000/svg" <circle cx="12" cy="12" r="9" />
class="w-6 h-6 mr-2" <line x1="8" y1="12" x2="12" y2="16" />
viewBox="0 0 24 24" <line x1="12" y1="8" x2="12" y2="16" />
stroke-width="1.5" <line x1="16" y1="12" x2="12" y2="16" />
stroke="currentColor" </svg>
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="12" cy="12" r="9" />
<line x1="8" y1="12" x2="12" y2="16" />
<line x1="12" y1="8" x2="12" y2="16" />
<line x1="16" y1="12" x2="12" y2="16" />
</svg>
{followingLogs ? 'Following Logs...' : 'Follow Logs'} {followingLogs ? 'Following Logs...' : 'Follow Logs'}
</button> </button>
<button <button
on:click={cancelBuild} on:click={cancelBuild}
class:animation-spin={cancelInprogress} class:animation-spin={cancelInprogress}
class="btn btn-sm" class="btn btn-sm"
disabled={currentStatus !== 'running'} disabled={currentStatus !== 'running'}
class:bg-coolgray-300={cancelInprogress || currentStatus !== 'running'} class:bg-coolgray-300={cancelInprogress || currentStatus !== 'running'}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6 mr-2"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
> >
<svg <path stroke="none" d="M0 0h24v24H0z" fill="none" />
xmlns="http://www.w3.org/2000/svg" <circle cx="12" cy="12" r="9" />
class="w-6 h-6 mr-2" <path d="M10 10l4 4m0 -4l-4 4" />
viewBox="0 0 24 24" </svg>
stroke-width="1.5" {cancelInprogress ? 'Cancelling...' : 'Cancel Build'}
stroke="currentColor" </button>
fill="none" {#if currentStatus === 'running'}
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="12" cy="12" r="9" />
<path d="M10 10l4 4m0 -4l-4 4" />
</svg>
{cancelInprogress ? 'Cancelling...' : 'Cancel Build'}
</button>
{#if currentStatus === 'running'}
<button id="streaming" class="btn btn-sm bg-transparent border-none loading" /> <button id="streaming" class="btn btn-sm bg-transparent border-none loading" />
<Tooltip triggeredBy="#streaming">Streaming logs</Tooltip> <Tooltip triggeredBy="#streaming">Streaming logs</Tooltip>
{/if}
</div>
{#if currentStatus === 'queued'}
<div
class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col whitespace-nowrap scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
{$t('application.build.queued_waiting_exec')}
</div>
{:else if logs.length > 0}
<div
bind:this={logsEl}
on:scroll={detect}
class="font-mono w-full bg-coolgray-100 border border-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
{#each logs as log}
{#if fromDb}
<div>{log.line + '\n'}</div>
{:else}
<div>[{day.unix(log.time).format('HH:mm:ss.SSS')}] {log.line + '\n'}</div>
{/if}
{/each}
</div>
{:else}
<div
class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col whitespace-nowrap scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
No logs found yet.
</div>
{/if} {/if}
</div>
{#if currentStatus === 'queued'}
<div
class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col whitespace-nowrap scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
{$t('application.build.queued_waiting_exec')}
</div>
{:else if logs.length > 0}
<div
bind:this={logsEl}
on:scroll={detect}
class="font-mono w-full bg-coolgray-100 border border-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
{#each logs as log}
{#if fromDb}
<div>{log.line + '\n'}</div>
{:else}
<div>[{day.unix(log.time).format('HH:mm:ss.SSS')}] {log.line + '\n'}</div>
{/if}
{/each}
</div>
{:else}
<div
class="font-mono w-full bg-coolgray-200 p-5 overflow-x-auto overflox-y-auto max-h-[80vh] rounded mb-20 flex flex-col whitespace-nowrap scrollbar-thumb-coollabs scrollbar-track-coolgray-200 scrollbar-w-1"
>
{dev ? 'In development, logs are shown in the console.' : 'No logs found yet.'}
</div>
{/if}

View File

@@ -148,7 +148,7 @@
class="flex cursor-pointer items-center justify-center py-4 no-underline transition-all duration-150 hover:bg-coolgray-300 hover:shadow-xl" class="flex cursor-pointer items-center justify-center py-4 no-underline transition-all duration-150 hover:bg-coolgray-300 hover:shadow-xl"
class:bg-coolgray-200={$selectedBuildId === build.id} class:bg-coolgray-200={$selectedBuildId === build.id}
> >
<div class="flex-col px-2 text-center min-w-[10rem]"> <div class="flex-col px-2 text-center">
<div class="text-sm font-bold truncate"> <div class="text-sm font-bold truncate">
{build.branch || application.branch} {build.branch || application.branch}
</div> </div>

View File

@@ -41,25 +41,44 @@
let numberOfGetStatus = 0; let numberOfGetStatus = 0;
let status: any = {}; let status: any = {};
let noInitialStatus: any = {
applications: false,
services: false,
databases: false
};
let loading = {
applications: false,
services: false,
databases: false
};
doSearch(); doSearch();
async function refreshStatusApplications() { async function refreshStatusApplications() {
loading.applications = true;
noInitialStatus.applications = false;
numberOfGetStatus = 0; numberOfGetStatus = 0;
for (const application of applications) { for (const application of applications) {
getStatus(application, true); await getStatus(application, true);
} }
loading.applications = false;
} }
async function refreshStatusServices() { async function refreshStatusServices() {
loading.services = true;
noInitialStatus.services = false;
numberOfGetStatus = 0; numberOfGetStatus = 0;
for (const service of services) { for (const service of services) {
getStatus(service, true); await getStatus(service, true);
} }
loading.services = false;
} }
async function refreshStatusDatabases() { async function refreshStatusDatabases() {
loading.databases = true;
noInitialStatus.databases = false;
numberOfGetStatus = 0; numberOfGetStatus = 0;
for (const database of databases) { for (const database of databases) {
getStatus(database, true); await getStatus(database, true);
} }
loading.databases = false;
} }
function setInitials(onlyOthers: boolean = false) { function setInitials(onlyOthers: boolean = false) {
return { return {
@@ -109,9 +128,15 @@
async function getStatus(resources: any, force: boolean = false) { async function getStatus(resources: any, force: boolean = false) {
const { id, buildPack, dualCerts, type } = resources; const { id, buildPack, dualCerts, type } = resources;
if (buildPack && applications.length > 10 && !force) { if (buildPack && applications.length > 10 && !force) {
noInitialStatus.applications = true;
return; return;
} }
if (type && services.length > 10 && !force) { if (type && services.length > 10 && !force) {
noInitialStatus.services = true;
return;
}
if (databases.length > 10 && !force) {
noInitialStatus.databases = true;
return; return;
} }
if (status[id] && !force) return status[id]; if (status[id] && !force) return status[id];
@@ -309,6 +334,128 @@
{/if} {/if}
</nav> </nav>
<div class="container lg:mx-auto lg:p-0 px-8 pt-5"> <div class="container lg:mx-auto lg:p-0 px-8 pt-5">
<div class="space-x-2 lg:flex lg:justify-center text-center mb-4 ">
<button
class="btn btn-sm btn-ghost"
class:bg-applications={$search === '!app'}
class:hover:bg-coollabs={$search !== '!app'}
on:click={() => doSearch('!app')}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 hidden lg:block "
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentcolor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<rect x="4" y="4" width="6" height="6" rx="1" />
<rect x="4" y="14" width="6" height="6" rx="1" />
<rect x="14" y="14" width="6" height="6" rx="1" />
<line x1="14" y1="7" x2="20" y2="7" />
<line x1="17" y1="4" x2="17" y2="10" />
</svg> Applications</button
>
<button
class="btn btn-sm btn-ghost"
class:bg-services={$search === '!service'}
class:hover:bg-coollabs={$search !== '!service'}
on:click={() => doSearch('!service')}
><svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 hidden lg:block"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M7 18a4.6 4.4 0 0 1 0 -9a5 4.5 0 0 1 11 2h1a3.5 3.5 0 0 1 0 7h-12" />
</svg> Services</button
>
<button
class="btn btn-sm btn-ghost "
class:bg-databases={$search === '!db'}
class:hover:bg-coollabs={$search !== '!db'}
on:click={() => doSearch('!db')}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 hidden lg:block"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<ellipse cx="12" cy="6" rx="8" ry="3" />
<path d="M4 6v6a8 3 0 0 0 16 0v-6" />
<path d="M4 12v6a8 3 0 0 0 16 0v-6" />
</svg> Databases</button
>
<button
class="btn btn-sm btn-ghost"
class:bg-sources={$search === '!git'}
class:hover:bg-coollabs={$search !== '!git'}
on:click={() => doSearch('!git')}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 hidden lg:block"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="6" cy="6" r="2" />
<circle cx="18" cy="18" r="2" />
<path d="M11 6h5a2 2 0 0 1 2 2v8" />
<polyline points="14 9 11 6 14 3" />
<path d="M13 18h-5a2 2 0 0 1 -2 -2v-8" />
<polyline points="10 15 13 18 10 21" />
</svg> Git Sources</button
>
<button
class="btn btn-sm btn-ghost"
class:bg-destinations={$search === '!destination'}
class:hover:bg-coollabs={$search !== '!destination'}
on:click={() => doSearch('!destination')}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 hidden lg:block"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1.002 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z"
/>
<path d="M5 10h3v3h-3z" />
<path d="M8 10h3v3h-3z" />
<path d="M11 10h3v3h-3z" />
<path d="M8 7h3v3h-3z" />
<path d="M11 7h3v3h-3z" />
<path d="M11 4h3v3h-3z" />
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
<line x1="10" y1="16" x2="10" y2="16.01" />
</svg>Destinations</button
>
</div>
{#if applications.length !== 0 || destinations.length !== 0 || databases.length !== 0 || services.length !== 0 || gitSources.length !== 0 || destinations.length !== 0} {#if applications.length !== 0 || destinations.length !== 0 || databases.length !== 0 || services.length !== 0 || gitSources.length !== 0 || destinations.length !== 0}
<div class="form-control"> <div class="form-control">
<div class="input-group flex w-full"> <div class="input-group flex w-full">
@@ -343,40 +490,16 @@
</div> </div>
<label for="search" class="label w-full mt-3"> <label for="search" class="label w-full mt-3">
<span class="label-text text-xs flex flex-wrap gap-2 items-center"> <span class="label-text text-xs flex flex-wrap gap-2 items-center">
<button
class:bg-coollabs={$search === '!notmine'}
class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!notmine')}>Other Teams</button
>
<button
class:bg-coollabs={$search === '!app'}
class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!app')}>Applications</button
>
<button <button
class:bg-coollabs={$search === '!bot'} class:bg-coollabs={$search === '!bot'}
class="badge badge-lg text-white text-xs rounded" class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!bot')}>Bots</button on:click={() => doSearch('!bot')}>Bots</button
> >
<button <button
class:bg-coollabs={$search === '!service'} class:bg-coollabs={$search === '!notmine'}
class="badge badge-lg text-white text-xs rounded" class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!service')}>Services</button on:click={() => doSearch('!notmine')}>Other Teams</button
>
<button
class:bg-coollabs={$search === '!db'}
class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!db')}>Databases</button
>
<button
class:bg-coollabs={$search === '!git'}
class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!git')}>Git Sources</button
>
<button
class:bg-coollabs={$search === '!destination'}
class="badge badge-lg text-white text-xs rounded"
on:click={() => doSearch('!destination')}>Destinations</button
> >
<button <button
class:bg-coollabs={$search === '!running'} class:bg-coollabs={$search === '!running'}
@@ -400,15 +523,19 @@
{#if (filtered.applications.length > 0 && applications.length > 0) || filtered.otherApplications.length > 0} {#if (filtered.applications.length > 0 && applications.length > 0) || filtered.otherApplications.length > 0}
<div class="flex items-center mt-10"> <div class="flex items-center mt-10">
<h1 class="title lg:text-3xl pr-4">Applications</h1> <h1 class="title lg:text-3xl pr-4">Applications</h1>
<button class="btn btn-sm btn-primary" on:click={refreshStatusApplications} <button
>Refresh Status</button class="btn btn-sm btn-primary"
class:loading={loading.applications}
disabled={loading.applications}
on:click={refreshStatusApplications}
>{noInitialStatus.applications ? 'Load Status' : 'Refresh Status'}</button
> >
</div> </div>
{/if} {/if}
{#if filtered.applications.length > 0 && applications.length > 0} {#if filtered.applications.length > 0 && applications.length > 0}
<div class="divider" /> <div class="divider" />
<div <div
class="grid grid-col gap-8 auto-cols-max grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 p-4" class="grid grid-col gap-2 lg:gap-8 auto-cols-max grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 p-4"
> >
{#if filtered.applications.length > 0} {#if filtered.applications.length > 0}
{#each filtered.applications as application} {#each filtered.applications as application}
@@ -417,12 +544,16 @@
class="w-full rounded p-5 bg-coolgray-200 hover:bg-green-600 indicator duration-150" class="w-full rounded p-5 bg-coolgray-200 hover:bg-green-600 indicator duration-150"
> >
{#await getStatus(application)} {#await getStatus(application)}
<span class="indicator-item badge bg-yellow-500 badge-sm" /> <span class="indicator-item badge bg-yellow-300 badge-sm" />
{:then} {:then}
{#if status[application.id] === 'running'} {#if !noInitialStatus.applications}
<span class="indicator-item badge bg-success badge-sm" /> {#if loading.applications}
{:else} <span class="indicator-item badge bg-yellow-300 badge-sm" />
<span class="indicator-item badge bg-error badge-sm" /> {:else if status[application.id] === 'running'}
<span class="indicator-item badge bg-success badge-sm" />
{:else}
<span class="indicator-item badge bg-error badge-sm" />
{/if}
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
@@ -511,9 +642,6 @@
{#if filtered.applications.length > 0} {#if filtered.applications.length > 0}
<div class="divider w-32 mx-auto" /> <div class="divider w-32 mx-auto" />
{/if} {/if}
<div class="flex items-center mt-10">
<h1 class="text-lg font-bold">Other Teams</h1>
</div>
{/if} {/if}
{#if filtered.otherApplications.length > 0} {#if filtered.otherApplications.length > 0}
<div <div
@@ -523,12 +651,16 @@
<a class="no-underline mb-5" href={`/applications/${application.id}`}> <a class="no-underline mb-5" href={`/applications/${application.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-green-600 indicator duration-150"> <div class="w-full rounded p-5 bg-coolgray-200 hover:bg-green-600 indicator duration-150">
{#await getStatus(application)} {#await getStatus(application)}
<span class="indicator-item badge bg-yellow-500 badge-sm" /> <span class="indicator-item badge bg-yellow-300 badge-sm" />
{:then} {:then}
{#if status[application.id] === 'running'} {#if !noInitialStatus.applications}
<span class="indicator-item badge bg-success badge-sm" /> {#if loading.applications}
{:else} <span class="indicator-item badge bg-yellow-300 badge-sm" />
<span class="indicator-item badge bg-error badge-sm" /> {:else if status[application.id] === 'running'}
<span class="indicator-item badge bg-success badge-sm" />
{:else}
<span class="indicator-item badge bg-error badge-sm" />
{/if}
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
@@ -610,7 +742,12 @@
{#if (filtered.services.length > 0 && services.length > 0) || filtered.otherServices.length > 0} {#if (filtered.services.length > 0 && services.length > 0) || filtered.otherServices.length > 0}
<div class="flex items-center mt-10"> <div class="flex items-center mt-10">
<h1 class="title lg:text-3xl pr-4">Services</h1> <h1 class="title lg:text-3xl pr-4">Services</h1>
<button class="btn btn-sm btn-primary" on:click={refreshStatusServices}>Refresh Status</button <button
class="btn btn-sm btn-primary"
class:loading={loading.services}
disabled={loading.services}
on:click={refreshStatusServices}
>{noInitialStatus.services ? 'Load Status' : 'Refresh Status'}</button
> >
</div> </div>
{/if} {/if}
@@ -626,12 +763,16 @@
class="w-full rounded p-5 bg-coolgray-200 hover:bg-pink-600 indicator duration-150" class="w-full rounded p-5 bg-coolgray-200 hover:bg-pink-600 indicator duration-150"
> >
{#await getStatus(service)} {#await getStatus(service)}
<span class="indicator-item badge bg-yellow-500 badge-sm" /> <span class="indicator-item badge bg-yellow-300 badge-sm" />
{:then} {:then}
{#if status[service.id] === 'running'} {#if !noInitialStatus.services}
<span class="indicator-item badge bg-success badge-sm" /> {#if loading.services}
{:else} <span class="indicator-item badge bg-yellow-300 badge-sm" />
<span class="indicator-item badge bg-error badge-sm" /> {:else if status[service.id] === 'running'}
<span class="indicator-item badge bg-success badge-sm" />
{:else}
<span class="indicator-item badge bg-error badge-sm" />
{/if}
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
@@ -686,9 +827,6 @@
{#if filtered.services.length > 0} {#if filtered.services.length > 0}
<div class="divider w-32 mx-auto" /> <div class="divider w-32 mx-auto" />
{/if} {/if}
<div class="flex items-center mt-10">
<h1 class="text-lg font-bold">Other Teams</h1>
</div>
{/if} {/if}
{#if filtered.otherServices.length > 0} {#if filtered.otherServices.length > 0}
<div <div
@@ -698,12 +836,16 @@
<a class="no-underline mb-5" href={`/services/${service.id}`}> <a class="no-underline mb-5" href={`/services/${service.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-pink-600 indicator duration-150"> <div class="w-full rounded p-5 bg-coolgray-200 hover:bg-pink-600 indicator duration-150">
{#await getStatus(service)} {#await getStatus(service)}
<span class="indicator-item badge bg-yellow-500 badge-sm" /> <span class="indicator-item badge bg-yellow-300 badge-sm" />
{:then} {:then}
{#if status[service.id] === 'running'} {#if !noInitialStatus.services}
<span class="indicator-item badge bg-success badge-sm" /> {#if loading.services}
{:else} <span class="indicator-item badge bg-yellow-300 badge-sm" />
<span class="indicator-item badge bg-error badge-sm" /> {:else if status[service.id] === 'running'}
<span class="indicator-item badge bg-success badge-sm" />
{:else}
<span class="indicator-item badge bg-error badge-sm" />
{/if}
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
@@ -754,8 +896,12 @@
{#if (filtered.databases.length > 0 && databases.length > 0) || filtered.otherDatabases.length > 0} {#if (filtered.databases.length > 0 && databases.length > 0) || filtered.otherDatabases.length > 0}
<div class="flex items-center mt-10"> <div class="flex items-center mt-10">
<h1 class="title lg:text-3xl pr-4">Databases</h1> <h1 class="title lg:text-3xl pr-4">Databases</h1>
<button class="btn btn-sm btn-primary" on:click={refreshStatusDatabases} <button
>Refresh Status</button class="btn btn-sm btn-primary"
on:click={refreshStatusDatabases}
class:loading={loading.databases}
disabled={loading.databases}
>{noInitialStatus.databases ? 'Load Status' : 'Refresh Status'}</button
> >
</div> </div>
{/if} {/if}
@@ -771,12 +917,16 @@
class="w-full rounded p-5 bg-coolgray-200 hover:bg-databases indicator duration-150" class="w-full rounded p-5 bg-coolgray-200 hover:bg-databases indicator duration-150"
> >
{#await getStatus(database)} {#await getStatus(database)}
<span class="indicator-item badge bg-yellow-500 badge-sm" /> <span class="indicator-item badge bg-yellow-300 badge-sm" />
{:then} {:then}
{#if status[database.id] === 'running'} {#if !noInitialStatus.databases}
<span class="indicator-item badge bg-success badge-sm" /> {#if loading.databases}
{:else} <span class="indicator-item badge bg-yellow-300 badge-sm" />
<span class="indicator-item badge bg-error badge-sm" /> {:else if status[databases.id] === 'running'}
<span class="indicator-item badge bg-success badge-sm" />
{:else}
<span class="indicator-item badge bg-error badge-sm" />
{/if}
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
@@ -835,9 +985,6 @@
{#if filtered.databases.length > 0} {#if filtered.databases.length > 0}
<div class="divider w-32 mx-auto" /> <div class="divider w-32 mx-auto" />
{/if} {/if}
<div class="flex items-center mt-10">
<h1 class="text-lg font-bold">Other Teams</h1>
</div>
{/if} {/if}
{#if filtered.otherDatabases.length > 0} {#if filtered.otherDatabases.length > 0}
<div <div
@@ -847,12 +994,16 @@
<a class="no-underline mb-5" href={`/databases/${database.id}`}> <a class="no-underline mb-5" href={`/databases/${database.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-databases indicator duration-150"> <div class="w-full rounded p-5 bg-coolgray-200 hover:bg-databases indicator duration-150">
{#await getStatus(database)} {#await getStatus(database)}
<span class="indicator-item badge bg-yellow-500 badge-sm" /> <span class="indicator-item badge bg-yellow-300 badge-sm" />
{:then} {:then}
{#if status[database.id] === 'running'} {#if !noInitialStatus.databases}
<span class="indicator-item badge bg-success badge-sm" /> {#if loading.databases}
{:else} <span class="indicator-item badge bg-yellow-300 badge-sm" />
<span class="indicator-item badge bg-error badge-sm" /> {:else if status[databases.id] === 'running'}
<span class="indicator-item badge bg-success badge-sm" />
{:else}
<span class="indicator-item badge bg-error badge-sm" />
{/if}
{/if} {/if}
{/await} {/await}
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
@@ -919,9 +1070,9 @@
<a class="no-underline mb-5" href={`/sources/${source.id}`}> <a class="no-underline mb-5" href={`/sources/${source.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-sources indicator duration-150"> <div class="w-full rounded p-5 bg-coolgray-200 hover:bg-sources indicator duration-150">
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
<div class="absolute top-0 left-0 -m-5 h-10 w-10"> <div class="absolute top-0 left-0 -m-5 flex">
{#if source?.type === 'gitlab'} {#if source?.type === 'gitlab'}
<svg viewBox="0 0 128 128"> <svg viewBox="0 0 128 128" class="h-10 w-10">
<path <path
fill="#FC6D26" fill="#FC6D26"
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357" d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
@@ -943,7 +1094,7 @@
/> />
</svg> </svg>
{:else if source?.type === 'github'} {:else if source?.type === 'github'}
<svg viewBox="0 0 128 128"> <svg viewBox="0 0 128 128" class="h-10 w-10">
<g fill="#ffffff" <g fill="#ffffff"
><path ><path
fill-rule="evenodd" fill-rule="evenodd"
@@ -955,6 +1106,26 @@
> >
</svg> </svg>
{/if} {/if}
{#if source.isSystemWide}
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-10 w-10"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="12" cy="12" r="9" />
<line x1="3.6" y1="9" x2="20.4" y2="9" />
<line x1="3.6" y1="15" x2="20.4" y2="15" />
<path d="M11.5 3a17 17 0 0 0 0 18" />
<path d="M12.5 3a17 17 0 0 1 0 18" />
</svg>
{/if}
</div> </div>
<div class="w-full flex flex-col"> <div class="w-full flex flex-col">
<div class="h-10"> <div class="h-10">
@@ -979,9 +1150,6 @@
{#if filtered.gitSources.length > 0} {#if filtered.gitSources.length > 0}
<div class="divider w-32 mx-auto" /> <div class="divider w-32 mx-auto" />
{/if} {/if}
<div class="flex items-center mt-10">
<h1 class="text-lg font-bold">Other Teams</h1>
</div>
{/if} {/if}
{#if filtered.otherGitSources.length > 0} {#if filtered.otherGitSources.length > 0}
<div <div
@@ -991,9 +1159,9 @@
<a class="no-underline mb-5" href={`/sources/${source.id}`}> <a class="no-underline mb-5" href={`/sources/${source.id}`}>
<div class="w-full rounded p-5 bg-coolgray-200 hover:bg-sources indicator duration-150"> <div class="w-full rounded p-5 bg-coolgray-200 hover:bg-sources indicator duration-150">
<div class="w-full flex flex-row"> <div class="w-full flex flex-row">
<div class="absolute top-0 left-0 -m-5 h-10 w-10"> <div class="absolute top-0 left-0 -m-5 flex">
{#if source?.type === 'gitlab'} {#if source?.type === 'gitlab'}
<svg viewBox="0 0 128 128"> <svg viewBox="0 0 128 128" class="h-10 w-10">
<path <path
fill="#FC6D26" fill="#FC6D26"
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357" d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
@@ -1015,7 +1183,7 @@
/> />
</svg> </svg>
{:else if source?.type === 'github'} {:else if source?.type === 'github'}
<svg viewBox="0 0 128 128"> <svg viewBox="0 0 128 128" class="h-10 w-10">
<g fill="#ffffff" <g fill="#ffffff"
><path ><path
fill-rule="evenodd" fill-rule="evenodd"
@@ -1027,6 +1195,26 @@
> >
</svg> </svg>
{/if} {/if}
{#if source.isSystemWide}
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-10 w-10"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="12" cy="12" r="9" />
<line x1="3.6" y1="9" x2="20.4" y2="9" />
<line x1="3.6" y1="15" x2="20.4" y2="15" />
<path d="M11.5 3a17 17 0 0 0 0 18" />
<path d="M12.5 3a17 17 0 0 1 0 18" />
</svg>
{/if}
</div> </div>
<div class="w-full flex flex-col"> <div class="w-full flex flex-col">
<div class="h-10"> <div class="h-10">
@@ -1130,9 +1318,6 @@
{#if filtered.destinations.length > 0} {#if filtered.destinations.length > 0}
<div class="divider w-32 mx-auto" /> <div class="divider w-32 mx-auto" />
{/if} {/if}
<div class="flex items-center mt-10">
<h1 class="text-lg font-bold">Other Teams</h1>
</div>
{/if} {/if}
{#if filtered.otherDestinations.length > 0} {#if filtered.otherDestinations.length > 0}
<div <div

View File

@@ -20,6 +20,7 @@
export let certificates: any; export let certificates: any;
import { del, post } from '$lib/api'; import { del, post } from '$lib/api';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import Beta from '$lib/components/Beta.svelte';
let loading = { let loading = {
save: false save: false
@@ -55,40 +56,40 @@
} }
</script> </script>
<div class="mx-auto w-full"> <div class="mx-auto w-full">
<div class="flex border-b border-coolgray-500 mb-6"> <div class="flex border-b border-coolgray-500 mb-6">
<div class="title font-bold pb-3 pr-4">SSL Certificates <span class="badge rounded bg-coollabs-gradient text-white">BETA</span></div> <div class="title font-bold pb-3 pr-4">SSL Certificates <Beta /></div>
<label for="my-modal" class="btn btn-sm btn-primary" on:click={() => (isModalActive = true)} <label for="my-modal" class="btn btn-sm btn-primary" on:click={() => (isModalActive = true)}
>Add SSL Certificate</label >Add SSL Certificate</label
> >
</div>
{#if certificates.length > 0}
<table class="table w-full">
<thead>
<tr>
<th>Common Name</th>
<th>CreatedAt</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{#each certificates as cert}
<tr>
<td>{cert.commonName}</td>
<td>{cert.createdAt}</td>
<td
><button on:click={() => deleteCertificate(cert.id)} class="btn btn-sm btn-error"
>Delete</button
></td
>
</tr>
{/each}
</tbody>
</table>
{:else}
<div class="text-sm">No SSL Certificate found</div>
{/if}
</div> </div>
{#if certificates.length > 0}
<table class="table w-full">
<thead>
<tr>
<th>Common Name</th>
<th>CreatedAt</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{#each certificates as cert}
<tr>
<td>{cert.commonName}</td>
<td>{cert.createdAt}</td>
<td
><button on:click={() => deleteCertificate(cert.id)} class="btn btn-sm btn-error"
>Delete</button
></td
>
</tr>
{/each}
</tbody>
</table>
{:else}
<div class="text-sm">No SSL Certificate found</div>
{/if}
</div>
{#if isModalActive} {#if isModalActive}
<input type="checkbox" id="my-modal" class="modal-toggle" /> <input type="checkbox" id="my-modal" class="modal-toggle" />

View File

@@ -8,6 +8,7 @@
import { addToast, appSession } from '$lib/store'; import { addToast, appSession } from '$lib/store';
import { dev } from '$app/env'; import { dev } from '$app/env';
import Explainer from '$lib/components/Explainer.svelte'; import Explainer from '$lib/components/Explainer.svelte';
import Setting from '$lib/components/Setting.svelte';
const { id } = $page.params; const { id } = $page.params;
@@ -21,7 +22,8 @@
await post(`/sources/${id}`, { await post(`/sources/${id}`, {
name: source.name, name: source.name,
htmlUrl: source.htmlUrl.replace(/\/$/, ''), htmlUrl: source.htmlUrl.replace(/\/$/, ''),
apiUrl: source.apiUrl.replace(/\/$/, '') apiUrl: source.apiUrl.replace(/\/$/, ''),
isSystemWide: source.isSystemWide
}); });
return addToast({ return addToast({
message: 'Configuration saved.', message: 'Configuration saved.',
@@ -43,7 +45,8 @@
htmlUrl: source.htmlUrl.replace(/\/$/, ''), htmlUrl: source.htmlUrl.replace(/\/$/, ''),
apiUrl: source.apiUrl.replace(/\/$/, ''), apiUrl: source.apiUrl.replace(/\/$/, ''),
organization: source.organization, organization: source.organization,
customPort: source.customPort customPort: source.customPort,
isSystemWide: source.isSystemWide
}); });
const { organization, htmlUrl } = source; const { organization, htmlUrl } = source;
const { fqdn, ipv4, ipv6 } = settings; const { fqdn, ipv4, ipv6 } = settings;
@@ -88,6 +91,16 @@
return errorNotification(error); return errorNotification(error);
} }
} }
async function changeSettings(name: any, save: boolean) {
if ($appSession.teamId === '0') {
if (name === 'isSystemWide') {
source.isSystemWide = !source.isSystemWide;
}
if (save) {
await handleSubmit();
}
}
}
</script> </script>
<div class="mx-auto max-w-6xl lg:px-6 px-3"> <div class="mx-auto max-w-6xl lg:px-6 px-3">
@@ -104,13 +117,13 @@
{/if} {/if}
</div> </div>
<div class="grid gap-2 grid-cols-2 auto-rows-max"> <div class="grid gap-2 grid-cols-2 auto-rows-max">
<label for="name" class="text-base font-bold text-stone-100">Name</label> <label for="name">Name</label>
<input class="w-full" name="name" id="name" required bind:value={source.name} /> <input class="w-full" name="name" id="name" required bind:value={source.name} />
<label for="htmlUrl" class="text-base font-bold text-stone-100">HTML URL</label> <label for="htmlUrl">HTML URL</label>
<input class="w-full" name="htmlUrl" id="htmlUrl" required bind:value={source.htmlUrl} /> <input class="w-full" name="htmlUrl" id="htmlUrl" required bind:value={source.htmlUrl} />
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label> <label for="apiUrl">API URL</label>
<input class="w-full" name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} /> <input class="w-full" name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
<label for="customPort" class="text-base font-bold text-stone-100" <label for="customPort"
>Custom SSH Port <Explainer >Custom SSH Port <Explainer
explanation={'If you use a self-hosted version of Git, you can provide custom port for all the Git related actions.'} explanation={'If you use a self-hosted version of Git, you can provide custom port for all the Git related actions.'}
/></label /></label
@@ -124,7 +137,7 @@
required required
value={source.customPort} value={source.customPort}
/> />
<label for="organization" class="pt-2 text-base font-bold text-stone-100" <label for="organization" class="pt-2"
>Organization >Organization
<Explainer <Explainer
explanation={"Fill it if you would like to use an organization's as your Git Source. Otherwise your user will be used."} explanation={"Fill it if you would like to use an organization's as your Git Source. Otherwise your user will be used."}
@@ -137,14 +150,26 @@
placeholder="eg: coollabsio" placeholder="eg: coollabsio"
bind:value={source.organization} bind:value={source.organization}
/> />
<Setting
customClass="pt-4"
isBeta={true}
id="autodeploy"
isCenter={false}
bind:setting={source.isSystemWide}
on:click={() => changeSettings('isSystemWide', false)}
title="System Wide Git Source"
description="System Wide Git Sources are available to all the users in your Coolify instance. <br><br> <span class='font-bold text-warning'>Use with caution, as it can be a security risk.</span>"
/>
</div> </div>
</form> </form>
{:else if source.githubApp?.installationId} {:else if source.githubApp?.installationId}
<form on:submit|preventDefault={handleSubmit} class="py-4"> <form on:submit|preventDefault={handleSubmit} class="py-4">
<div class="flex lg:flex-row lg:justify-between flex-col space-y-3 w-full lg:items-center"> <div class="flex lg:flex-row lg:justify-between flex-col space-y-3 w-full lg:items-center">
<h1 class="title">{$t('general')}</h1> <h1 class="title">{$t('general')}</h1>
{#if $appSession.isAdmin} {#if $appSession.isAdmin && $appSession.teamId === '0'}
<div class="flex flex-col lg:flex-row lg:space-x-4 lg:w-fit space-y-2 lg:space-y-0 w-full"> <div
class="flex flex-col lg:flex-row lg:space-x-4 lg:w-fit space-y-2 lg:space-y-0 w-full"
>
<button class="btn btn-sm bg-sources" type="submit" disabled={loading} <button class="btn btn-sm bg-sources" type="submit" disabled={loading}
>{loading ? 'Saving...' : 'Save'}</button >{loading ? 'Saving...' : 'Save'}</button
> >
@@ -159,9 +184,16 @@
{/if} {/if}
</div> </div>
<div class="grid gap-2 grid-cols-2 auto-rows-max mt-4"> <div class="grid gap-2 grid-cols-2 auto-rows-max mt-4">
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label> <label for="name">{$t('forms.name')}</label>
<input class="w-full" name="name" id="name" required bind:value={source.name} /> <input
<label for="htmlUrl" class="text-base font-bold text-stone-100">HTML URL</label> class="w-full"
name="name"
id="name"
required
bind:value={source.name}
disabled={$appSession.teamId !== '0'}
/>
<label for="htmlUrl">HTML URL</label>
<input <input
class="w-full" class="w-full"
name="htmlUrl" name="htmlUrl"
@@ -171,7 +203,7 @@
required required
bind:value={source.htmlUrl} bind:value={source.htmlUrl}
/> />
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label> <label for="apiUrl">API URL</label>
<input <input
class="w-full" class="w-full"
name="apiUrl" name="apiUrl"
@@ -181,7 +213,7 @@
readonly={source.githubAppId} readonly={source.githubAppId}
bind:value={source.apiUrl} bind:value={source.apiUrl}
/> />
<label for="customPort" class="text-base font-bold text-stone-100" <label for="customPort"
>Custom SSH Port <Explainer >Custom SSH Port <Explainer
explanation="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions." explanation="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."
/></label /></label
@@ -195,9 +227,7 @@
required required
value={source.customPort} value={source.customPort}
/> />
<label for="organization" class="pt-2 text-base font-bold text-stone-100" <label for="organization" class="pt-2">Organization</label>
>Organization</label
>
<input <input
class="w-full" class="w-full"
readonly readonly
@@ -207,6 +237,17 @@
placeholder="eg: coollabsio" placeholder="eg: coollabsio"
bind:value={source.organization} bind:value={source.organization}
/> />
<Setting
customClass="pt-4"
isBeta={true}
id="autodeploy"
isCenter={false}
disabled={$appSession.teamId !== '0'}
bind:setting={source.isSystemWide}
on:click={() => changeSettings('isSystemWide', true)}
title="System Wide Git Source"
description="System Wide Git Sources are available to all the users in your Coolify instance. <br><br> <span class='font-bold text-warning'>Use with caution, as it can be a security risk.</span>"
/>
</div> </div>
</form> </form>
{:else} {:else}

View File

@@ -53,7 +53,7 @@
} }
</script> </script>
{#if id !== 'new'} {#if id !== 'new' && $appSession.teamId === '0'}
<nav class="nav-side"> <nav class="nav-side">
<button <button
id="delete" id="delete"

View File

@@ -43,7 +43,7 @@ textarea {
} }
#svelte .custom-select-wrapper .selectContainer { #svelte .custom-select-wrapper .selectContainer {
@apply h-12 w-96 rounded bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm w-full ; @apply h-12 w-96 rounded bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm ;
} }
#svelte .listContainer { #svelte .listContainer {

View File

@@ -1,7 +1,7 @@
{ {
"name": "coolify", "name": "coolify",
"description": "An open-source & self-hostable Heroku / Netlify alternative.", "description": "An open-source & self-hostable Heroku / Netlify alternative.",
"version": "3.10.8", "version": "3.10.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": "github:coollabsio/coolify", "repository": "github:coollabsio/coolify",
"scripts": { "scripts": {