fix: read-only permission
This commit is contained in:
parent
395df36d57
commit
30cd2149ea
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
export let application: any;
|
||||
import { status } from '$lib/store';
|
||||
import { appSession, status } from '$lib/store';
|
||||
import { page } from '$app/stores';
|
||||
</script>
|
||||
|
||||
@ -220,7 +220,7 @@
|
||||
<li class="menu-title">
|
||||
<span>Advanced</span>
|
||||
</li>
|
||||
{#if application.gitSourceId}
|
||||
{#if application.gitSourceId && $appSession.isAdmin}
|
||||
<li
|
||||
class="rounded"
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/revert`}
|
||||
@ -295,6 +295,7 @@
|
||||
>
|
||||
</li>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<li
|
||||
class="rounded"
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/danger`}
|
||||
@ -318,4 +319,5 @@
|
||||
</svg>Danger Zone</a
|
||||
>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
|
@ -9,7 +9,7 @@
|
||||
import { del, post, put } from '$lib/api';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { addToast } from '$lib/store';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
import { t } from '$lib/translations';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
@ -120,6 +120,7 @@
|
||||
<label for="name" class="pb-5 uppercase lg:block hidden font-bold" />
|
||||
{/if}
|
||||
|
||||
{#if $appSession.isAdmin}
|
||||
<div class="flex justify-center h-full items-center pt-3">
|
||||
<div class="flex flex-row justify-center space-x-2">
|
||||
<div class="flex items-center justify-center">
|
||||
@ -127,5 +128,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
import { del, post, put } from '$lib/api';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { addToast } from '$lib/store';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
import { t } from '$lib/translations';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
@ -124,8 +124,9 @@
|
||||
<div class="flex justify-center h-full items-center pt-0 lg:pt-0 pl-4 lg:pl-0">
|
||||
<button
|
||||
on:click={() => updateSecret({ changeIsBuildSecret: true })}
|
||||
disabled={!$appSession.isAdmin}
|
||||
aria-pressed="false"
|
||||
class="relative inline-flex h-6 w-11 flex-shrink-0 rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out "
|
||||
class="relative inline-flex h-6 w-11 flex-shrink-0 rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out"
|
||||
class:bg-green-600={isBuildSecret}
|
||||
class:bg-stone-700={!isBuildSecret}
|
||||
>
|
||||
@ -177,7 +178,7 @@
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="btn btn-sm btn-primary" on:click={addNewSecret}>Add</button>
|
||||
</div>
|
||||
{:else}
|
||||
{:else if $appSession.isAdmin}
|
||||
<div class="flex flex-row justify-center space-x-2">
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="btn btn-sm btn-primary" on:click={() => updateSecret()}>Set</button>
|
||||
|
@ -51,6 +51,7 @@
|
||||
let isDBBranching = application.settings.isDBBranching;
|
||||
|
||||
async function changeSettings(name: any) {
|
||||
if (!$appSession.isAdmin) return
|
||||
if (name === 'previews') {
|
||||
previews = !previews;
|
||||
}
|
||||
@ -119,6 +120,7 @@
|
||||
id="autodeploy"
|
||||
isCenter={false}
|
||||
bind:setting={autodeploy}
|
||||
disabled={!$appSession.isAdmin}
|
||||
on:click={() => changeSettings('autodeploy')}
|
||||
title={$t('application.enable_automatic_deployment')}
|
||||
description={$t('application.enable_auto_deploy_webhooks')}
|
||||
@ -130,6 +132,7 @@
|
||||
id="previews"
|
||||
isCenter={false}
|
||||
bind:setting={previews}
|
||||
disabled={!$appSession.isAdmin}
|
||||
on:click={() => changeSettings('previews')}
|
||||
title={$t('application.enable_mr_pr_previews')}
|
||||
description={$t('application.enable_preview_deploy_mr_pr_requests')}
|
||||
|
@ -490,7 +490,7 @@
|
||||
<div class="grid grid-flow-row gap-2 px-4">
|
||||
<div class="mt-2 grid grid-cols-2 items-center">
|
||||
<label for="name">{$t('forms.name')}</label>
|
||||
<input name="name" id="name" class="w-full" bind:value={application.name} required />
|
||||
<input name="name" id="name" class="w-full" bind:value={application.name} disabled={!$appSession.isAdmin} required />
|
||||
</div>
|
||||
{#if !isSimpleDockerfile}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
|
@ -23,7 +23,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { asyncSleep, errorNotification, getRndInteger } from '$lib/common';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { addToast } from '$lib/store';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
|
||||
|
||||
@ -264,6 +264,7 @@
|
||||
{:else}
|
||||
<button
|
||||
id="restart"
|
||||
disabled={!$appSession.isAdmin}
|
||||
on:click={() => restartPreview(preview)}
|
||||
type="submit"
|
||||
class="icons bg-transparent text-sm flex items-center space-x-2"
|
||||
@ -286,7 +287,12 @@
|
||||
{/if}
|
||||
|
||||
<Tooltip triggeredBy="#restart">Restart (useful to change secrets)</Tooltip>
|
||||
<button id="forceredeploypreview" class="icons" on:click={() => redeploy(preview)}>
|
||||
<button
|
||||
id="forceredeploypreview"
|
||||
class="icons"
|
||||
disabled={!$appSession.isAdmin}
|
||||
on:click={() => redeploy(preview)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
@ -310,7 +316,7 @@
|
||||
id="deletepreview"
|
||||
class="icons"
|
||||
class:hover:text-error={!loading.removing}
|
||||
disabled={loading.removing}
|
||||
disabled={loading.removing || !$appSession.isAdmin}
|
||||
on:click={() => removeApplication(preview)}
|
||||
><DeleteIcon />
|
||||
</button>
|
||||
|
@ -25,7 +25,7 @@
|
||||
import pLimit from 'p-limit';
|
||||
import { page } from '$app/stores';
|
||||
import { get, post, put } from '$lib/api';
|
||||
import { addToast } from '$lib/store';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
import Secret from './_Secret.svelte';
|
||||
import PreviewSecret from './_PreviewSecret.svelte';
|
||||
import { errorNotification } from '$lib/common';
|
||||
@ -106,46 +106,50 @@
|
||||
/>
|
||||
{/key}
|
||||
{/each}
|
||||
<div class="lg:pt-0 pt-10">
|
||||
<Secret on:refresh={refreshSecrets} length={secrets.length} isNewSecret />
|
||||
</div>
|
||||
{#if !application.settings.isBot && !application.simpleDockerfile}
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
|
||||
<div class="title font-bold pb-3 pt-8">
|
||||
Preview Secrets <Explainer
|
||||
explanation="These values overwrite application secrets in PR/MR deployments. <br>Useful for creating <span class='text-green-500 font-bold'>staging</span> environments."
|
||||
/>
|
||||
{#if $appSession.isAdmin}
|
||||
<div class="lg:pt-0 pt-10">
|
||||
<Secret on:refresh={refreshSecrets} length={secrets.length} isNewSecret />
|
||||
</div>
|
||||
</div>
|
||||
{#if previewSecrets.length !== 0}
|
||||
{#each previewSecrets as secret, index}
|
||||
{#key index}
|
||||
<PreviewSecret
|
||||
{index}
|
||||
length={secrets.length}
|
||||
name={secret.name}
|
||||
value={secret.value}
|
||||
isBuildSecret={secret.isBuildSecret}
|
||||
on:refresh={refreshSecrets}
|
||||
/>
|
||||
{/key}
|
||||
{/each}
|
||||
{:else}
|
||||
Add secrets first to see Preview Secrets.
|
||||
{/if}
|
||||
{#if !application.settings.isBot && !application.simpleDockerfile}
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
|
||||
<div class="title font-bold pb-3 pt-8">
|
||||
Preview Secrets <Explainer
|
||||
explanation="These values overwrite application secrets in PR/MR deployments. <br>Useful for creating <span class='text-green-500 font-bold'>staging</span> environments."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{#if previewSecrets.length !== 0}
|
||||
{#each previewSecrets as secret, index}
|
||||
{#key index}
|
||||
<PreviewSecret
|
||||
{index}
|
||||
length={secrets.length}
|
||||
name={secret.name}
|
||||
value={secret.value}
|
||||
isBuildSecret={secret.isBuildSecret}
|
||||
on:refresh={refreshSecrets}
|
||||
/>
|
||||
{/key}
|
||||
{/each}
|
||||
{:else}
|
||||
Add secrets first to see Preview Secrets.
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<form on:submit|preventDefault={getValues} class="mb-12 w-full">
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2 pt-10">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<div class="title font-bold pb-3 ">Paste <code>.env</code> file</div>
|
||||
<button type="submit" class="btn btn-sm bg-primary">Add Secrets in Batch</button>
|
||||
{#if $appSession.isAdmin}
|
||||
<form on:submit|preventDefault={getValues} class="mb-12 w-full">
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2 pt-10">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<div class="title font-bold pb-3 ">Paste <code>.env</code> file</div>
|
||||
<button type="submit" class="btn btn-sm bg-primary">Add Secrets in Batch</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
placeholder={`PORT=1337\nPASSWORD=supersecret`}
|
||||
bind:value={batchSecrets}
|
||||
class="mb-2 min-h-[200px] w-full"
|
||||
/>
|
||||
</form>
|
||||
<textarea
|
||||
placeholder={`PORT=1337\nPASSWORD=supersecret`}
|
||||
bind:value={batchSecrets}
|
||||
class="mb-2 min-h-[200px] w-full"
|
||||
/>
|
||||
</form>
|
||||
{/if}
|
||||
|
@ -27,6 +27,7 @@
|
||||
import { get } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { appSession } from '$lib/store';
|
||||
|
||||
let composeJson = JSON.parse(application?.dockerComposeFile || '{}');
|
||||
let predefinedVolumes: any[] = [];
|
||||
@ -86,12 +87,16 @@
|
||||
<Storage on:refresh={refreshStorage} {storage} />
|
||||
{/key}
|
||||
{/each}
|
||||
<div class="Preview Secrets" class:pt-10={predefinedVolumes.length > 0}>
|
||||
{#if $appSession.isAdmin}
|
||||
<div class:pt-10={predefinedVolumes.length > 0}>
|
||||
Add New Volume <Explainer
|
||||
position="dropdown-bottom"
|
||||
explanation={$t('application.storage.persistent_storage_explainer')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Storage on:refresh={refreshStorage} isNew />
|
||||
{}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -669,7 +669,7 @@
|
||||
<button class="btn btn-sm btn-primary" on:click={refreshStatusApplications}
|
||||
>{noInitialStatus.applications ? 'Load Status' : 'Refresh Status'}</button
|
||||
>
|
||||
{#if foundUnconfiguredApplication}
|
||||
{#if foundUnconfiguredApplication && $appSession.isAdmin}
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
class:loading={loading.applications}
|
||||
@ -783,11 +783,13 @@
|
||||
</svg>
|
||||
</a>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<button
|
||||
class="icons hover:bg-green-500"
|
||||
on:click|stopPropagation|preventDefault={() =>
|
||||
deleteApplication(application.id)}><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -896,11 +898,13 @@
|
||||
</svg>
|
||||
</a>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<button
|
||||
class="icons hover:bg-green-500"
|
||||
on:click|stopPropagation|preventDefault={() =>
|
||||
deleteApplication(application.id)}><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -991,11 +995,13 @@
|
||||
</svg>
|
||||
</a>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<button
|
||||
class="icons hover:bg-pink-500"
|
||||
on:click|stopPropagation|preventDefault={() => deleteService(service.id)}
|
||||
><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1077,11 +1083,13 @@
|
||||
</svg>
|
||||
</a>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<button
|
||||
class="icons hover:bg-pink-500"
|
||||
on:click|stopPropagation|preventDefault={() => deleteService(service.id)}
|
||||
><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1173,11 +1181,13 @@
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<button
|
||||
class="icons hover:bg-databases-100"
|
||||
on:click|stopPropagation|preventDefault={() => deleteDatabase(database.id)}
|
||||
><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1259,11 +1269,13 @@
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $appSession.isAdmin}
|
||||
<button
|
||||
class="icons hover:bg-databases"
|
||||
on:click|stopPropagation|preventDefault={() => deleteDatabase(database.id)}
|
||||
><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@
|
||||
export let service: any;
|
||||
export let template: any;
|
||||
import { page } from '$app/stores';
|
||||
import { appSession } from '$lib/store';
|
||||
import ServiceLinks from './_ServiceLinks.svelte';
|
||||
</script>
|
||||
|
||||
@ -106,6 +107,7 @@
|
||||
</svg>Service</a
|
||||
>
|
||||
</li>
|
||||
{#if $appSession.isAdmin}
|
||||
<li class="menu-title">
|
||||
<span>Advanced</span>
|
||||
</li>
|
||||
@ -132,4 +134,5 @@
|
||||
</svg>Danger Zone</a
|
||||
>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
|
@ -8,7 +8,7 @@
|
||||
import { del, post } from '$lib/api';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { addToast } from '$lib/store';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
@ -77,6 +77,7 @@
|
||||
/>
|
||||
</td>
|
||||
|
||||
{#if $appSession.isAdmin}
|
||||
<td>
|
||||
{#if isNewSecret}
|
||||
<div class="flex items-center justify-center">
|
||||
@ -93,3 +94,4 @@
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
|
@ -165,6 +165,7 @@
|
||||
}
|
||||
}
|
||||
async function changeSettings(name: any) {
|
||||
if (!$appSession.isAdmin) return
|
||||
try {
|
||||
if (name === 'dualCerts') {
|
||||
dualCerts = !dualCerts;
|
||||
@ -277,7 +278,7 @@
|
||||
<div class="grid grid-flow-row gap-2 px-4">
|
||||
<div class="mt-2 grid grid-cols-2 items-center">
|
||||
<label for="name">{$t('forms.name')}</label>
|
||||
<input name="name" id="name" class="w-full" bind:value={service.name} required />
|
||||
<input name="name" id="name" class="w-full" disabled={!$appSession.isAdmin} bind:value={service.name} required />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="version">Version / Tag</label>
|
||||
@ -386,7 +387,7 @@
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
id="dualCerts"
|
||||
disabled={$status.service.isRunning}
|
||||
disabled={$status.service.isRunning || !$appSession.isAdmin}
|
||||
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||
bind:setting={dualCerts}
|
||||
title={$t('application.ssl_www_and_non_www')}
|
||||
|
@ -25,7 +25,7 @@
|
||||
import { get } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import pLimit from 'p-limit';
|
||||
import { addToast } from '$lib/store';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
import { saveSecret } from './utils';
|
||||
const limit = pLimit(1);
|
||||
|
||||
@ -83,7 +83,12 @@
|
||||
{#each secrets as secret}
|
||||
{#key secret.id}
|
||||
<tr>
|
||||
<Secret name={secret.name} value={secret.value} readonly={secret.readOnly} on:refresh={refreshSecrets} />
|
||||
<Secret
|
||||
name={secret.name}
|
||||
value={secret.value}
|
||||
readonly={secret.readOnly}
|
||||
on:refresh={refreshSecrets}
|
||||
/>
|
||||
</tr>
|
||||
{/key}
|
||||
{/each}
|
||||
@ -93,18 +98,20 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<form on:submit|preventDefault={getValues} class="mb-12 w-full">
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2 pt-10">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<div class="title font-bold pb-3 ">Paste <code>.env</code> file</div>
|
||||
<button type="submit" class="btn btn-sm bg-primary">Add Secrets in Batch</button>
|
||||
{#if $appSession.isAdmin}
|
||||
<form on:submit|preventDefault={getValues} class="mb-12 w-full">
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2 pt-10">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<div class="title font-bold pb-3 ">Paste <code>.env</code> file</div>
|
||||
<button type="submit" class="btn btn-sm bg-primary">Add Secrets in Batch</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
placeholder={`PORT=1337\nPASSWORD=supersecret`}
|
||||
bind:value={batchSecrets}
|
||||
class="mb-2 min-h-[200px] w-full"
|
||||
/>
|
||||
</form>
|
||||
<textarea
|
||||
placeholder={`PORT=1337\nPASSWORD=supersecret`}
|
||||
bind:value={batchSecrets}
|
||||
class="mb-2 min-h-[200px] w-full"
|
||||
/>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -26,6 +26,7 @@
|
||||
import { get } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { appSession } from '$lib/store';
|
||||
|
||||
const { id } = $page.params;
|
||||
async function refreshStorage() {
|
||||
@ -81,10 +82,11 @@
|
||||
{/key}
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<div class="title" class:pt-10={persistentStorages.filter((s) => s.predefined).length > 0}>
|
||||
Add New Volume
|
||||
</div>
|
||||
<Storage on:refresh={refreshStorage} isNew {services} />
|
||||
{#if $appSession.isAdmin}
|
||||
<div class="title" class:pt-10={persistentStorages.filter((s) => s.predefined).length > 0}>
|
||||
Add New Volume
|
||||
</div>
|
||||
<Storage on:refresh={refreshStorage} isNew {services} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -190,7 +190,7 @@
|
||||
id="name"
|
||||
required
|
||||
bind:value={source.name}
|
||||
disabled={$appSession.teamId !== '0'}
|
||||
disabled={!$appSession.isAdmin}
|
||||
/>
|
||||
<label for="htmlUrl">HTML URL</label>
|
||||
<input
|
||||
@ -236,16 +236,18 @@
|
||||
placeholder="eg: coollabsio"
|
||||
bind:value={source.organization}
|
||||
/>
|
||||
<Setting
|
||||
customClass="pt-4"
|
||||
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>"
|
||||
/>
|
||||
{#if $appSession.isAdmin}
|
||||
<Setting
|
||||
customClass="pt-4"
|
||||
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>"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
{:else}
|
||||
|
Loading…
x
Reference in New Issue
Block a user