Finish routes translations
This commit is contained in:
parent
360fb5ea37
commit
fe787538e3
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -4,5 +4,8 @@
|
||||
"i18n-ally.extract.ignoredByFiles": {
|
||||
"src\\routes\\__layout.svelte": ["Coolify", "coolLabs logo"]
|
||||
},
|
||||
"i18n-ally.sourceLanguage": "en"
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.enabledFrameworks": ["svelte"],
|
||||
"i18n-ally.enabledParsers": ["js", "ts", "json"],
|
||||
"i18n-ally.extract.autoDetect": true
|
||||
}
|
||||
|
@ -8,7 +8,8 @@
|
||||
},
|
||||
"error": {
|
||||
"you_can_find_your_way_back": "You can find your way back",
|
||||
"here": "here"
|
||||
"here": "here",
|
||||
"you_are_lost": "Ooops you are lost! But don't be afraid!"
|
||||
},
|
||||
"index": {
|
||||
"dashboard": "Dashboard",
|
||||
@ -19,7 +20,12 @@
|
||||
"services": "Services",
|
||||
"teams": "Teams",
|
||||
"not_implemented_yet": "Not implemented yet",
|
||||
"database": "Database"
|
||||
"database": "Database",
|
||||
"settings": "Settings",
|
||||
"global_settings": "Global Settings",
|
||||
"secret": "Secret",
|
||||
"team": "Team",
|
||||
"logout": "Logout"
|
||||
},
|
||||
"login": {
|
||||
"already_logged_in": "Already logged in...",
|
||||
@ -78,7 +84,12 @@
|
||||
"verify_emails_without_smtp": "Verify emails without SMTP",
|
||||
"extra_config": "Extra Config",
|
||||
"select_a_service": "Select a Service",
|
||||
"select_a_service_version": "Select a Service version"
|
||||
"select_a_service_version": "Select a Service version",
|
||||
"removing": "Removing...",
|
||||
"remove_domain": "Remove domain",
|
||||
"public_port_range": "Public Port Range",
|
||||
"public_port_range_explainer": "Ports used to expose databases/services/internal services.<br> Add them to your firewall (if applicable).<br><br>You can specify a range of ports, eg: <span class='text-yellow-500 font-bold'>9000-9100</span>",
|
||||
"no_actions_available": "No actions available"
|
||||
},
|
||||
"register": {
|
||||
"register": "Register",
|
||||
@ -237,12 +248,31 @@
|
||||
"remote_docker": "Remote Docker",
|
||||
"organization_explainer": "Fill it if you would like to use an organization's as your Git Source. Otherwise your user will be used."
|
||||
},
|
||||
"eg_https_api_github_com": "eg: https://api.github.com",
|
||||
"eg_https_github_com": "eg: https://github.com",
|
||||
"source": {
|
||||
"new": {
|
||||
"git_source": "Add New Git Source",
|
||||
"official_providers": "Official providers"
|
||||
},
|
||||
"no_git_sources_found": "No git sources found",
|
||||
"delete_git_source": "Delete Git Source",
|
||||
"permission_denied": "You do not have permission to delete a Git Source",
|
||||
"create_new_app": "Create new {name} App",
|
||||
"change_app_settings": "Change {name} App Settings",
|
||||
"install_repositories": "Install Repositories",
|
||||
"application_id": "Application ID",
|
||||
"group_name": "Group Name",
|
||||
"oauth_id": "OAuth ID",
|
||||
"oauth_id_explainer": "The OAuth ID is the unique identifier of the GitLab application. <br>You can find it <span class='font-bold text-orange-600' >in the URL</span> of your GitLab OAuth Application.",
|
||||
"register_oauth_gitlab": "Register new OAuth application on GitLab",
|
||||
"gitlab": {
|
||||
"self_hosted": "Instance-wide application (self-hosted)",
|
||||
"user_owned": "User owned application",
|
||||
"group_owned": "Group owned application",
|
||||
"gitlab_application_type": "GitLab Application Type",
|
||||
"already_configured": "GitLab App is already configured."
|
||||
},
|
||||
"github": {
|
||||
"redirecting": "Redirecting to Github..."
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
@ -255,6 +285,36 @@
|
||||
"start_service": "Start Service",
|
||||
"permission_denied_start_service": "You do not have permission to start the service.",
|
||||
"delete_service": "Delete Service",
|
||||
"permission_denied_delete_service": "You do not have permission to delete a service."
|
||||
"permission_denied_delete_service": "You do not have permission to delete a service.",
|
||||
"no_service": "No services found"
|
||||
},
|
||||
"setting": {
|
||||
"permission_denied": "You do not have permission to do this. \\nAsk an admin to modify your permissions.",
|
||||
"domain_removed": "Domain removed",
|
||||
"ssl_explainer": "If you specify <span class='text-yellow-500 font-bold'>https</span>, Coolify will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-yellow-500 font-bold'>www</span>, Coolify will be redirected (302) from non-www and vice versa.",
|
||||
"must_remove_domain_before_changing": "Must remove the domain before you can change this setting.",
|
||||
"registration_allowed": "Registration allowed?",
|
||||
"registration_allowed_explainer": "Allow further registrations to the application. <br>It's turned off after the first registration.",
|
||||
"coolify_proxy_settings": "Coolify Proxy Settings"
|
||||
},
|
||||
"team": {
|
||||
"pending_invitations": "Pending invitations",
|
||||
"accept": "Accept",
|
||||
"delete": "Delete",
|
||||
"member": "member(s)",
|
||||
"root": "(root)",
|
||||
"invited_with_permissions": "Invited to <span class=\"font-bold text-pink-600\">{teamName}</span> with <span class=\"font-bold text-rose-600\">{permission}</span> permission.",
|
||||
"members": "Members",
|
||||
"root_team_explainer": "This is the <span class='text-red-500 font-bold'>root</span> team. That means members of this group can manage instance wide settings and have all the priviliges in Coolify (imagine like root user on Linux).",
|
||||
"permission": "Permission",
|
||||
"you": "(You)",
|
||||
"promote_to": "Promote to {grade}",
|
||||
"revoke_invitation": "Revoke invitation",
|
||||
"pending_invitation": "Pending invitation",
|
||||
"invite_new_member": "Invite new member",
|
||||
"send_invitation": "Send invitation",
|
||||
"invite_only_register_explainer": "You can only invite registered users at the moment - will be extended soon.",
|
||||
"admin": "Admin",
|
||||
"read": "Read"
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
<div class="mx-auto flex h-screen flex-col items-center justify-center px-4">
|
||||
<div class="pb-10 text-7xl font-bold">{status}</div>
|
||||
<div class="text-3xl font-bold">Ooops you are lost! But don't be afraid!</div>
|
||||
<div class="text-3xl font-bold">{$t('error.you_are_lost')}</div>
|
||||
<div class="text-xl">
|
||||
{$t('error.you_can_find_your_way_back')}
|
||||
<a href="/" class="font-bold uppercase text-sky-400">{$t('error.here')}</a>
|
||||
|
@ -159,7 +159,7 @@
|
||||
class="icons tooltip-right bg-coolgray-200 hover:text-white"
|
||||
class:text-white={$page.url.pathname === '/'}
|
||||
class:bg-coolgray-500={$page.url.pathname === '/'}
|
||||
data-tooltip="Dashboard"
|
||||
data-tooltip={$t('index.dashboard')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -188,7 +188,7 @@
|
||||
$page.url.pathname.startsWith('/new/application')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/applications') ||
|
||||
$page.url.pathname.startsWith('/new/application')}
|
||||
data-tooltip="Applications"
|
||||
data-tooltip={$t('index.applications')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -216,7 +216,7 @@
|
||||
$page.url.pathname.startsWith('/new/source')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/sources') ||
|
||||
$page.url.pathname.startsWith('/new/source')}
|
||||
data-tooltip="Git Sources"
|
||||
data-tooltip={$t('index.git_sources')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -246,7 +246,7 @@
|
||||
$page.url.pathname.startsWith('/new/destination')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/destinations') ||
|
||||
$page.url.pathname.startsWith('/new/destination')}
|
||||
data-tooltip="Destinations"
|
||||
data-tooltip={$t('index.destinations')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -281,7 +281,7 @@
|
||||
$page.url.pathname.startsWith('/new/database')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/databases') ||
|
||||
$page.url.pathname.startsWith('/new/database')}
|
||||
data-tooltip="Databases"
|
||||
data-tooltip={$t('index.databases')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -308,7 +308,7 @@
|
||||
$page.url.pathname.startsWith('/new/service')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/services') ||
|
||||
$page.url.pathname.startsWith('/new/service')}
|
||||
data-tooltip="Services"
|
||||
data-tooltip={$t('index.services')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -446,7 +446,7 @@
|
||||
class="icons tooltip-right bg-coolgray-200 hover:text-cyan-500"
|
||||
class:text-cyan-500={$page.url.pathname.startsWith('/teams')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/teams')}
|
||||
data-tooltip="Teams"
|
||||
data-tooltip={$t('index.teams')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -472,7 +472,7 @@
|
||||
class="icons tooltip-right bg-coolgray-200 hover:text-yellow-500"
|
||||
class:text-yellow-500={$page.url.pathname.startsWith('/settings')}
|
||||
class:bg-coolgray-500={$page.url.pathname.startsWith('/settings')}
|
||||
data-tooltip="Settings"
|
||||
data-tooltip={$t('index.settings')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -494,7 +494,7 @@
|
||||
{/if}
|
||||
<div
|
||||
class="icons tooltip-right bg-coolgray-200 hover:text-red-500"
|
||||
data-tooltip="Logout"
|
||||
data-tooltip={$t('index.logout')}
|
||||
on:click={logout}
|
||||
>
|
||||
<svg
|
||||
|
@ -11,6 +11,7 @@
|
||||
import N8n from '$lib/components/svg/services/N8n.svelte';
|
||||
import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte';
|
||||
import Ghost from '$lib/components/svg/services/Ghost.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let services;
|
||||
async function newService() {
|
||||
@ -20,7 +21,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Services</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.services')}</div>
|
||||
<div on:click={newService} class="add-icon cursor-pointer bg-pink-600 hover:bg-pink-500">
|
||||
<svg
|
||||
class="w-6"
|
||||
@ -41,7 +42,7 @@
|
||||
<div class="flex flex-wrap justify-center">
|
||||
{#if !services || services.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">No services found</div>
|
||||
<div class="text-center text-xl font-bold">{$t('service.no_service')}</div>
|
||||
</div>
|
||||
{:else}
|
||||
{#each services as service}
|
||||
@ -73,7 +74,7 @@
|
||||
</div>
|
||||
{#if !service.type || !service.fqdn}
|
||||
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center truncate">{service.type}</div>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { asyncExecShell, getEngine, getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { t } from '$lib/translations';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -16,7 +17,8 @@ export const post: RequestHandler = async (event) => {
|
||||
return {
|
||||
status: found ? 500 : 200,
|
||||
body: {
|
||||
error: found && `Domain ${fqdn.replace('www.', '')} is already used.`
|
||||
error:
|
||||
found && t.get('application.domain_already_in_use', { domain: fqdn.replace('www.', '') })
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { listSettings, ErrorHandler } from '$lib/database';
|
||||
import { t } from '$lib/translations';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { promises as dns } from 'dns';
|
||||
|
||||
@ -27,7 +28,7 @@ export const del: RequestHandler = async (event) => {
|
||||
return {
|
||||
status: 401,
|
||||
body: {
|
||||
message: 'You do not have permission to do this. \nAsk an admin to modify your permissions.'
|
||||
message: t.get('setting.permission_denied')
|
||||
}
|
||||
};
|
||||
if (status === 401) return { status, body };
|
||||
@ -44,7 +45,7 @@ export const del: RequestHandler = async (event) => {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
message: 'Domain removed',
|
||||
message: t.get('setting.domain_removed'),
|
||||
redirect: ip ? `http://${ip[0]}:3000/settings` : undefined
|
||||
}
|
||||
};
|
||||
@ -58,7 +59,7 @@ export const post: RequestHandler = async (event) => {
|
||||
return {
|
||||
status: 401,
|
||||
body: {
|
||||
message: 'You do not have permission to do this. \nAsk an admin to modify your permissions.'
|
||||
message: t.get('setting.permission_denied')
|
||||
}
|
||||
};
|
||||
if (status === 401) return { status, body };
|
||||
|
@ -31,6 +31,7 @@
|
||||
import { browser } from '$app/env';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
let isRegistrationEnabled = settings.isRegistrationEnabled;
|
||||
let dualCerts = settings.dualCerts;
|
||||
@ -67,7 +68,7 @@
|
||||
dualCerts = !dualCerts;
|
||||
}
|
||||
await post(`/settings.json`, { isRegistrationEnabled, dualCerts });
|
||||
return toast.push('Settings saved.');
|
||||
return toast.push(t.get('application.settings_saved'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@ -94,19 +95,19 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Settings</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.settings')}</div>
|
||||
</div>
|
||||
{#if $session.teamId === '0'}
|
||||
<div class="mx-auto max-w-4xl px-6">
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex space-x-1 pb-6">
|
||||
<div class="title font-bold">Global Settings</div>
|
||||
<div class="title font-bold">{$t('index.global_settings')}</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading.save}
|
||||
class:bg-yellow-500={!loading.save}
|
||||
class:hover:bg-yellow-400={!loading.save}
|
||||
class="mx-2 ">{loading.save ? 'Saving...' : 'Save'}</button
|
||||
class="mx-2 ">{loading.save ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
{#if isFqdnSet}
|
||||
<button
|
||||
@ -114,17 +115,17 @@
|
||||
disabled={loading.remove}
|
||||
class:bg-red-600={!loading.remove}
|
||||
class:hover:bg-red-500={!loading.remove}
|
||||
>{loading.remove ? 'Removing...' : 'Remove domain'}</button
|
||||
>{loading.remove ? $t('forms.removing') : $t('forms.remove_domain')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="grid grid-cols-2 items-start">
|
||||
<div class="flex-col">
|
||||
<div class="pt-2 text-base font-bold text-stone-100">Domain (FQDN)</div>
|
||||
<Explainer
|
||||
text="If you specify <span class='text-yellow-500 font-bold'>https</span>, Coolify will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-yellow-500 font-bold'>www</span>, Coolify will be redirected (302) from non-www and vice versa."
|
||||
/>
|
||||
<div class="pt-2 text-base font-bold text-stone-100">
|
||||
{$t('application.domain_fqdn')}
|
||||
</div>
|
||||
<Explainer text={$t('setting.ssl_explainer')} />
|
||||
</div>
|
||||
<div class="justify-start text-left">
|
||||
<input
|
||||
@ -134,16 +135,16 @@
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
placeholder="eg: https://coolify.io"
|
||||
placeholder="{$t('forms.eg')}: https://coolify.io"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-start py-6">
|
||||
<div class="flex-col">
|
||||
<div class="pt-2 text-base font-bold text-stone-100">Public Port Range</div>
|
||||
<Explainer
|
||||
text="Ports used to expose databases/services/internal services.<br> Add them to your firewall (if applicable).<br><br>You can specify a range of ports, eg: <span class='text-yellow-500 font-bold'>9000-9100</span>"
|
||||
/>
|
||||
<div class="pt-2 text-base font-bold text-stone-100">
|
||||
{$t('forms.public_port_range')}
|
||||
</div>
|
||||
<Explainer text={$t('forms.public_port_range_explainer')} />
|
||||
</div>
|
||||
<div class="mx-auto flex-row items-center justify-center space-y-2">
|
||||
<input
|
||||
@ -165,26 +166,26 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
dataTooltip="Must remove the domain before you can change this setting."
|
||||
dataTooltip={$t('setting.must_remove_domain_before_changing')}
|
||||
disabled={isFqdnSet}
|
||||
bind:setting={dualCerts}
|
||||
title="Generate SSL for www and non-www?"
|
||||
description="It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-yellow-500'>both DNS entries</span> set in advance.<br><br>Useful if you expect to have visitors on both."
|
||||
title={$t('application.ssl_www_and_non_www')}
|
||||
description={$t('services.generate_www_non_www_ssl')}
|
||||
on:click={() => !isFqdnSet && changeSettings('dualCerts')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
bind:setting={isRegistrationEnabled}
|
||||
title="Registration allowed?"
|
||||
description="Allow further registrations to the application. <br>It's turned off after the first registration. "
|
||||
title={$t('setting.registration_allowed')}
|
||||
description={$t('setting.registration_allowed_explainer')}
|
||||
on:click={() => changeSettings('isRegistrationEnabled')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex space-x-1 pt-6 font-bold">
|
||||
<div class="title">Coolify Proxy Settings</div>
|
||||
<div class="title">{$t('setting.coolify_proxy_settings')}</div>
|
||||
</div>
|
||||
<Explainer
|
||||
text={`Credentials for <a class="text-white font-bold" href=${
|
||||
@ -198,7 +199,7 @@
|
||||
/>
|
||||
<div class="space-y-2 px-10 py-5">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="proxyUser">User</label>
|
||||
<label for="proxyUser">{$t('forms.user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
@ -208,7 +209,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="proxyPassword">Password</label>
|
||||
<label for="proxyPassword">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { page, session } from '$app/stores';
|
||||
import { post } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
let loading = false;
|
||||
@ -60,20 +61,20 @@
|
||||
</script>
|
||||
|
||||
{#if !source.githubAppId}
|
||||
<button on:click={newGithubApp}>Create new GitHub App</button>
|
||||
<button on:click={newGithubApp}>{$t('source.create_new_app', { name: 'GitHub' })}</button>
|
||||
{:else if source.githubApp?.installationId}
|
||||
<form on:submit|preventDefault={handleSubmit} class="py-4">
|
||||
<div class="flex space-x-1 pb-5 font-bold">
|
||||
<div class="title">General</div>
|
||||
<div class="title">{$t('general')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-orange-600={!loading}
|
||||
class:hover:bg-orange-500={!loading}
|
||||
disabled={loading}>{loading ? 'Saving...' : 'Save'}</button
|
||||
disabled={loading}>{loading ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
<button on:click|preventDefault={() => installRepositories(source)}
|
||||
>Change GitHub App Settings</button
|
||||
>{$t('source.change_app_settings', { name: 'GitHub' })}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
@ -85,5 +86,5 @@
|
||||
</div>
|
||||
</form>
|
||||
{:else}
|
||||
<button on:click={() => installRepositories(source)}>Install Repositories</button>
|
||||
<button on:click={() => installRepositories(source)}>{$t('source.install_repositories')}</button>
|
||||
{/if}
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { onMount } from 'svelte';
|
||||
import { post } from '$lib/api';
|
||||
import { browser } from '$app/env';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
let loading = false;
|
||||
@ -93,25 +94,25 @@
|
||||
{#if !source.gitlabApp?.appId}
|
||||
<form class="grid grid-flow-row gap-2 py-4" on:submit|preventDefault={newApp}>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="type">GitLab Application Type</label>
|
||||
<label for="type">{$t('source.gitlab.gitlab_application_type')}</label>
|
||||
<select name="type" id="type" class="w-96" bind:value={payload.applicationType}>
|
||||
<option value="user">User owned application</option>
|
||||
<option value="group">Group owned application</option>
|
||||
<option value="user">{$t('source.gitlab.user_owned')}</option>
|
||||
<option value="group">{$t('source.gitlab.group_owned')}</option>
|
||||
{#if source.htmlUrl !== 'https://gitlab.com'}
|
||||
<option value="instance">Instance-wide application (self-hosted)</option>
|
||||
<option value="instance">{$t('source.gitlab.self_hosted')}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
{#if payload.applicationType === 'group'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="groupName">Group Name</label>
|
||||
<label for="groupName">{$t('source.group_name')}</label>
|
||||
<input name="groupName" id="groupName" required bind:value={payload.groupName} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="w-full pt-10 text-center">
|
||||
<button class="w-96 bg-orange-600 hover:bg-orange-500" type="submit"
|
||||
>Register new OAuth application on GitLab</button
|
||||
>{$t('source.register_oauth_gitlab')}</button
|
||||
>
|
||||
</div>
|
||||
|
||||
@ -131,21 +132,19 @@
|
||||
</form>
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4 pt-10">
|
||||
<div class="flex h-8 items-center space-x-2">
|
||||
<div class="text-xl font-bold text-white">Configuration</div>
|
||||
<div class="text-xl font-bold text-white">{$t('forms.configuration')}</div>
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-orange-600={!loading}
|
||||
class:hover:bg-orange-500={!loading}
|
||||
disabled={loading}>{loading ? 'Saving...' : 'Save'}</button
|
||||
disabled={loading}>{loading ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-start">
|
||||
<div class="flex-col">
|
||||
<label for="oauthId" class="pt-2">OAuth ID</label>
|
||||
<Explainer
|
||||
text="The OAuth ID is the unique identifier of the GitLab application. <br>You can find it <span class='font-bold text-orange-600' >in the URL</span> of your GitLab OAuth Application."
|
||||
/>
|
||||
<label for="oauthId" class="pt-2">{$t('source.oauth_id')}</label>
|
||||
<Explainer text={$t('source.oauth_id_explainer')} />
|
||||
</div>
|
||||
<input
|
||||
on:change={checkOauthId}
|
||||
@ -159,16 +158,16 @@
|
||||
</div>
|
||||
{#if payload.applicationType === 'group'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="groupName">Group Name</label>
|
||||
<label for="groupName">{$t('source.group_name')}</label>
|
||||
<input name="groupName" id="groupName" required bind:value={payload.groupName} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="appId">Application ID</label>
|
||||
<label for="appId">{$t('source.application_id')}</label>
|
||||
<input name="appId" id="appId" required bind:value={payload.appId} />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="appSecret">Secret</label>
|
||||
<label for="appSecret">{$t('index.secret')}</label>
|
||||
<input
|
||||
name="appSecret"
|
||||
id="appSecret"
|
||||
@ -188,9 +187,11 @@
|
||||
type="submit"
|
||||
class:bg-orange-600={!loading}
|
||||
class:hover:bg-orange-500={!loading}
|
||||
disabled={loading}>{loading ? 'Saving...' : 'Save'}</button
|
||||
disabled={loading}>{loading ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
<button on:click|preventDefault={changeSettings}
|
||||
>{$t('source.change_app_settings', { name: 'GitLab' })}</button
|
||||
>
|
||||
<button on:click|preventDefault={changeSettings}>Change GitLab App Settings</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
|
@ -34,10 +34,11 @@
|
||||
import { page, session } from '$app/stores';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
async function deleteSource(name) {
|
||||
const sure = confirm(`Are you sure you would like to delete '${name}'?`);
|
||||
const sure = confirm($t('application.confirm_to_delete', { name: name }));
|
||||
if (sure) {
|
||||
const response = await fetch(`/sources/${id}.json`, {
|
||||
method: 'delete'
|
||||
@ -55,14 +56,14 @@
|
||||
<nav class="nav-side">
|
||||
<button
|
||||
on:click={() => deleteSource(source.name)}
|
||||
title="Delete Git Source"
|
||||
title={$t('source.delete_git_source')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class:hover:text-red-500={$session.isAdmin}
|
||||
class="icons tooltip-bottom bg-transparent text-sm"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Delete Git Source'
|
||||
: 'You do not have permission to delete a Git Source'}><DeleteIcon /></button
|
||||
? $t('source.delete_git_source')
|
||||
: $t('source.permission_denied')}><DeleteIcon /></button
|
||||
>
|
||||
</nav>
|
||||
<slot />
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { t } from '$lib/translations';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -11,7 +12,7 @@ export const post: RequestHandler = async (event) => {
|
||||
const found = await db.prisma.gitlabApp.findFirst({ where: { oauthId: Number(oauthId) } });
|
||||
if (found) {
|
||||
throw {
|
||||
message: `GitLab App is already configured.`
|
||||
message: t.get('source.gitlab.already_configured')
|
||||
};
|
||||
}
|
||||
return { status: 200 };
|
||||
|
@ -32,10 +32,11 @@
|
||||
import type Prisma from '@prisma/client';
|
||||
import Github from './_Github.svelte';
|
||||
import Gitlab from './_Gitlab.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 px-6 text-2xl font-bold">
|
||||
<div class="tracking-tight">Git Source</div>
|
||||
<div class="tracking-tight">{$t('application.git_source')}</div>
|
||||
<span class="arrow-right-applications px-1 text-orange-500">></span>
|
||||
<span class="pr-2">{source.name}</span>
|
||||
</div>
|
||||
|
@ -31,6 +31,7 @@
|
||||
<script>
|
||||
import { dev } from '$app/env';
|
||||
import { getDomain, dashify } from '$lib/components/common';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let source;
|
||||
export let settings;
|
||||
@ -84,5 +85,5 @@
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen items-center justify-center text-3xl font-bold">
|
||||
Redirecting to Github...
|
||||
{$t('source.github.redirecting')}
|
||||
</div>
|
||||
|
@ -22,10 +22,11 @@
|
||||
<script lang="ts">
|
||||
export let sources;
|
||||
import { session } from '$app/stores';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Git Sources</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.git_sources')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<a href="/new/source" sveltekit:prefetch class="add-icon bg-orange-600 hover:bg-orange-500">
|
||||
<svg
|
||||
@ -47,7 +48,7 @@
|
||||
<div class="flex justify-center">
|
||||
{#if !sources || sources.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">No git sources found</div>
|
||||
<div class="text-center text-xl font-bold">{$t('source.no_git_sources_found')}</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-wrap justify-center">
|
||||
@ -62,7 +63,7 @@
|
||||
<div class="font-bold text-xl text-center truncate">{source.name}</div>
|
||||
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
|
||||
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="truncate text-center">{source.htmlUrl}</div>
|
||||
|
@ -27,6 +27,7 @@
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
let invitation = {
|
||||
teamName: team.name,
|
||||
@ -94,25 +95,22 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 px-6 text-2xl font-bold">
|
||||
<div class="tracking-tight">Team</div>
|
||||
<div class="tracking-tight">{$t('index.team')}</div>
|
||||
<span class="arrow-right-applications px-1 text-cyan-500">></span>
|
||||
<span class="pr-2">{team.name}</span>
|
||||
</div>
|
||||
<div class="mx-auto max-w-4xl px-6">
|
||||
<form on:submit|preventDefault={handleSubmit} class=" py-4">
|
||||
<div class="flex space-x-1 pb-5">
|
||||
<div class="title font-bold">Settings</div>
|
||||
<button class="bg-cyan-600 hover:bg-cyan-500" type="submit">Save</button>
|
||||
<div class="title font-bold">{$t('index.settings')}</div>
|
||||
<button class="bg-cyan-600 hover:bg-cyan-500" type="submit">{$t('forms.save')}</button>
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="mt-2 grid grid-cols-2">
|
||||
<div class="flex-col">
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
{#if team.id === '0'}
|
||||
<Explainer
|
||||
customClass="w-full"
|
||||
text="This is the <span class='text-red-500 font-bold'>root</span> team. That means members of this group can manage instance wide settings and have all the priviliges in Coolify (imagine like root user on Linux)."
|
||||
/>
|
||||
<Explainer customClass="w-full" text={$t('team.root_team_explainer')} />
|
||||
{/if}
|
||||
</div>
|
||||
<input id="name" name="name" placeholder="name" bind:value={team.name} />
|
||||
@ -121,22 +119,23 @@
|
||||
</form>
|
||||
|
||||
<div class="flex space-x-1 py-5 pt-10 font-bold">
|
||||
<div class="title">Members</div>
|
||||
<div class="title">{$t('team.members')}</div>
|
||||
</div>
|
||||
<div class="px-4 sm:px-6">
|
||||
<table class="w-full border-separate text-left">
|
||||
<thead>
|
||||
<tr class="h-8 border-b border-coolgray-400">
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Permission</th>
|
||||
<th scope="col" class="text-center">Actions</th>
|
||||
<th scope="col">{$t('forms.email')}</th>
|
||||
<th scope="col">{$t('team.permission')}</th>
|
||||
<th scope="col" class="text-center">{$t('forms.action')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{#each permissions as permission}
|
||||
<tr class="text-xs">
|
||||
<td class="py-4"
|
||||
>{permission.user.email}
|
||||
<span class="font-bold">{permission.user.id === $session.userId ? '(You)' : ''}</span
|
||||
<span class="font-bold"
|
||||
>{permission.user.id === $session.userId ? $t('team.you') : ''}</span
|
||||
></td
|
||||
>
|
||||
<td class="py-4">{permission.permission}</td>
|
||||
@ -144,17 +143,21 @@
|
||||
<td class="flex flex-col items-center justify-center space-y-2 py-4 text-center">
|
||||
<button
|
||||
class="w-52 bg-red-600 hover:bg-red-500"
|
||||
on:click={() => removeFromTeam(permission.user.id)}>Remove</button
|
||||
on:click={() => removeFromTeam(permission.user.id)}>{$t('forms.remove')}</button
|
||||
>
|
||||
<button
|
||||
class="w-52"
|
||||
on:click={() =>
|
||||
changePermission(permission.user.id, permission.id, permission.permission)}
|
||||
>Promote to {permission.permission === 'admin' ? 'read' : 'admin'}</button
|
||||
>{$t('team.promote_to', {
|
||||
grade: permission.permission === 'admin' ? 'read' : 'admin'
|
||||
})}</button
|
||||
>
|
||||
</td>
|
||||
{:else}
|
||||
<td class="text-center py-4 flex-col space-y-2"> No actions available </td>
|
||||
<td class="text-center py-4 flex-col space-y-2">
|
||||
{$t('forms.no_actions_available')}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
@ -167,11 +170,12 @@
|
||||
<td class="flex-col space-y-2 py-4 text-center">
|
||||
<button
|
||||
class="w-52 bg-red-600 hover:bg-red-500"
|
||||
on:click={() => revokeInvitation(invitation.id)}>Revoke invitation</button
|
||||
on:click={() => revokeInvitation(invitation.id)}
|
||||
>{$t('team.revoke_invitation')}</button
|
||||
>
|
||||
</td>
|
||||
{:else}
|
||||
<td class="text-center py-4 flex-col space-y-2">Pending invitation</td>
|
||||
<td class="text-center py-4 flex-col space-y-2">{$t('team.pending_invitation')}</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
@ -181,18 +185,18 @@
|
||||
<form on:submit|preventDefault={sendInvitation} class="py-5 pt-10">
|
||||
<div class="flex space-x-1">
|
||||
<div class="flex space-x-1">
|
||||
<div class="title font-bold">Invite new member</div>
|
||||
<button class="bg-cyan-600 hover:bg-cyan-500" type="submit">Send invitation</button>
|
||||
<div class="title font-bold">{$t('team.invite_new_member')}</div>
|
||||
<button class="bg-cyan-600 hover:bg-cyan-500" type="submit"
|
||||
>{$t('team.send_invitation')}</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<Explainer
|
||||
text="You can only invite registered users at the moment - will be extended soon."
|
||||
/>
|
||||
<Explainer text={$t('team.invite_only_register_explainer')} />
|
||||
<div class="flex-col space-y-2 px-4 pt-5 sm:px-6">
|
||||
<div class="flex space-x-0">
|
||||
<input
|
||||
bind:value={invitation.email}
|
||||
placeholder="Email address"
|
||||
placeholder={$t('forms.email')}
|
||||
class="mr-2 w-full"
|
||||
required
|
||||
/>
|
||||
@ -202,14 +206,14 @@
|
||||
class="rounded-none rounded-l border border-dashed border-transparent"
|
||||
type="button"
|
||||
class:border-coolgray-300={invitation.permission !== 'read'}
|
||||
class:bg-pink-500={invitation.permission === 'read'}>Read</button
|
||||
class:bg-pink-500={invitation.permission === 'read'}>{$t('team.read')}</button
|
||||
>
|
||||
<button
|
||||
on:click={() => (invitation.permission = 'admin')}
|
||||
class="rounded-none rounded-r border border-dashed border-transparent"
|
||||
type="button"
|
||||
class:border-coolgray-300={invitation.permission !== 'admin'}
|
||||
class:bg-red-500={invitation.permission === 'admin'}>Admin</button
|
||||
class:bg-red-500={invitation.permission === 'admin'}>{$t('team.admin')}</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,6 +23,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { session } from '$app/stores';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let teams;
|
||||
export let invitations;
|
||||
@ -46,7 +47,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Teams</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.teams')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<a href="/new/team" class="add-icon bg-cyan-600 hover:bg-cyan-500">
|
||||
<svg
|
||||
@ -69,22 +70,26 @@
|
||||
{#if invitations.length > 0}
|
||||
<div class="mx-auto max-w-2xl pb-10">
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="title">Pending invitations</div>
|
||||
<div class="title">{$t('team.pending_invitations')}</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
{#each invitations as invitation}
|
||||
<div class="flex justify-center space-x-2">
|
||||
<div>
|
||||
Invited to <span class="font-bold text-pink-600">{invitation.teamName}</span> with
|
||||
<span class="font-bold text-rose-600">{invitation.permission}</span> permission.
|
||||
{@html $t('team.invited_with_permissions', {
|
||||
teamName: invitation.teamName,
|
||||
permission: invitation.permission
|
||||
})}
|
||||
</div>
|
||||
<button
|
||||
class="hover:bg-green-500"
|
||||
on:click={() => acceptInvitation(invitation.id, invitation.teamId)}>Accept</button
|
||||
on:click={() => acceptInvitation(invitation.id, invitation.teamId)}
|
||||
>{$t('team.accept')}</button
|
||||
>
|
||||
<button
|
||||
class="hover:bg-red-600"
|
||||
on:click={() => revokeInvitation(invitation.id, invitation.teamId)}>Delete</button
|
||||
on:click={() => revokeInvitation(invitation.id, invitation.teamId)}
|
||||
>{$t('team.delete')}</button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
@ -101,10 +106,10 @@
|
||||
>
|
||||
<div class="truncate text-center text-xl font-bold">
|
||||
{team.team.name}
|
||||
{team.team?.id === '0' ? '(root)' : ''}
|
||||
{team.team?.id === '0' ? $t('team.root') : ''}
|
||||
</div>
|
||||
|
||||
<div class="mt-1 text-center">{team.team._count.users} member(s)</div>
|
||||
<div class="mt-1 text-center">{team.team._count.users} {$t('team.member')}</div>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
|
Loading…
Reference in New Issue
Block a user