Merge branch 'restray_i18n' of https://github.com/restray/coolify into restray-restray_i18n
This commit is contained in:
commit
fe3702847a
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"i18n-ally.localesPaths": ["src/lib/locales"],
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.extract.ignoredByFiles": {
|
||||
"src\\routes\\__layout.svelte": ["Coolify", "coolLabs logo"]
|
||||
},
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.enabledFrameworks": ["svelte"],
|
||||
"i18n-ally.enabledParsers": ["js", "ts", "json"],
|
||||
"i18n-ally.extract.autoDetect": true
|
||||
}
|
@ -1,14 +1,26 @@
|
||||
# Welcome
|
||||
# 👋 Welcome
|
||||
|
||||
First of all, thank you for considering contributing to my project! It means a lot 💜.
|
||||
|
||||
# Technical skills required
|
||||
## 🙋 Want to help?
|
||||
|
||||
- Node.js / Javascript
|
||||
- Svelte / SvelteKit
|
||||
- Prisma.io / SQL
|
||||
If you begin in GitHub contribution, you can find the [first contribution](https://github.com/firstcontributions/first-contributions) and follow this guide.
|
||||
|
||||
# Recommended Pull Request Guideline
|
||||
Follow the [introduction](#introduction) to get started then start contributing!
|
||||
|
||||
This is a little list of what you can do to help the project:
|
||||
|
||||
- [🧑💻 Develop your own ideas](#developer-contribution)
|
||||
- [🌐 Translate the project](#translation)
|
||||
- [📄 Help sorting out the issues](#help-sorting-out-the-issues)
|
||||
- [🎯 Test Pull Requests](#test-pull-requests)
|
||||
- [✒️ Help with the documentation](#help-with-the-documentation)
|
||||
|
||||
## 👋 Introduction
|
||||
|
||||
🔴 At the moment, Coolify **doesn't support Windows**. You must use Linux or MacOS.
|
||||
|
||||
#### Recommended Pull Request Guideline
|
||||
|
||||
- Fork the project
|
||||
- Clone your fork repo to local
|
||||
@ -26,7 +38,7 @@ Due to the lock file, this repository is best with [pnpm](https://pnpm.io). I re
|
||||
|
||||
You need to have [Docker Engine](https://docs.docker.com/engine/install/) installed locally.
|
||||
|
||||
## Setup development environment
|
||||
#### Setup a local development environment
|
||||
|
||||
- Copy `.env.template` to `.env` and set the `COOLIFY_APP_ID` environment variable to something cool.
|
||||
- Install dependencies with `pnpm install`.
|
||||
@ -35,13 +47,27 @@ You need to have [Docker Engine](https://docs.docker.com/engine/install/) instal
|
||||
- Seed the database with base entities with `pnpm db:seed`
|
||||
- You can start coding after starting `pnpm dev`.
|
||||
|
||||
## Database migrations
|
||||
#### How to start after you set up your local fork?
|
||||
|
||||
This repository works better with [pnpm](https://pnpm.io) due to the lock file. I recommend you to give it a try and use `pnpm` as well because it is cool and efficient!
|
||||
|
||||
You need to have [Docker Engine](https://docs.docker.com/engine/install/) installed locally.
|
||||
|
||||
## 🧑💻 Developer contribution
|
||||
|
||||
### Technical skills required
|
||||
|
||||
- **Languages**: Node.js / Javascript / Typescript
|
||||
- **Framework JS/TS**: Svelte / SvelteKit
|
||||
- **Database ORM**: Prisma.io
|
||||
|
||||
### Database migrations
|
||||
|
||||
During development, if you change the database layout, you need to run `pnpm db:push` to migrate the database and create types for Prisma. You also need to restart the development process.
|
||||
|
||||
If the schema is finalized, you need to create a migration file with `pnpm db:migrate <nameOfMigration>` where `nameOfMigration` is given by you. Make it sense. :)
|
||||
|
||||
## Tricky parts
|
||||
### Tricky parts
|
||||
|
||||
- BullMQ, the queue system Coolify uses, cannot be hot reloaded. So if you change anything in the files related to it, you need to restart the development process. I'm actively looking for a different queue/scheduler library. I'm open to discussion!
|
||||
|
||||
@ -115,3 +141,42 @@ You need to add a new folder to [src/routes/services/[id]](src/routes/services/[
|
||||
If you need to show more details on the frontend, such as users/passwords, you need to add Svelte component to [src/routes/services/[id]/\_Services](src/routes/services/[id]/_Services) with an underscore. For example, see other files in that folder.
|
||||
|
||||
You also need to add the new inputs to the `index.json.ts` file of the specific service, like for MinIO here: [src/routes/services/[id]/minio/index.json.ts](src/routes/services/[id]/minio/index.json.ts)
|
||||
|
||||
## 🌐 Translate the project
|
||||
|
||||
The project use [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) to translate the project.
|
||||
It follows the [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to name languages.
|
||||
|
||||
### Installation
|
||||
|
||||
You must have gone throw all the [intro](#introduction) steps before you can start translating.
|
||||
|
||||
It's only an advice, but I recommend you to use:
|
||||
|
||||
- Visual Studio Code
|
||||
- [i18n Ally for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally): ideal to see the progress of the translation.
|
||||
- [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode): to get the syntax color for the project
|
||||
|
||||
### Adding a language
|
||||
|
||||
If your language doesn't appear in the [locales folder list](src/lib/locales/), follow the step below:
|
||||
|
||||
1. In `src/lib/locales/`, Copy paste `en.json` and rename it with your language (eg: `cz.json`).
|
||||
2. In the [lang.json](src/lib/lang.json) file, add a line after the first bracket (`{`) with `"ISO of your language": "Language",` (eg: `"cz": "Czech",`).
|
||||
3. Have fun translating!
|
||||
|
||||
### Additionnal pull requests steps
|
||||
|
||||
Please add the emoji 🌐 to your pull request title to indicate that it is a translation.
|
||||
|
||||
## 📄 Help sorting out the issues
|
||||
|
||||
ToDo
|
||||
|
||||
## 🎯 Test Pull Requests
|
||||
|
||||
ToDo
|
||||
|
||||
## ✒️ Help with the documentation
|
||||
|
||||
ToDo
|
||||
|
@ -56,6 +56,7 @@
|
||||
"svelte-preprocess": "4.10.6",
|
||||
"svelte-select": "4.4.7",
|
||||
"tailwindcss": "3.0.24",
|
||||
"sveltekit-i18n": "2.1.2",
|
||||
"ts-node": "10.7.0",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.6.3"
|
||||
|
35
pnpm-lock.yaml
generated
35
pnpm-lock.yaml
generated
@ -49,6 +49,7 @@ specifiers:
|
||||
svelte-preprocess: 4.10.6
|
||||
svelte-select: 4.4.7
|
||||
tailwindcss: 3.0.24
|
||||
sveltekit-i18n: 2.1.2
|
||||
tailwindcss-scrollbar: 0.1.0
|
||||
ts-node: 10.7.0
|
||||
tslib: 2.3.1
|
||||
@ -109,6 +110,7 @@ devDependencies:
|
||||
svelte-select: 4.4.7
|
||||
tailwindcss: 3.0.24_ts-node@10.7.0
|
||||
ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3
|
||||
sveltekit-i18n: 2.1.2_svelte@3.46.4
|
||||
tslib: 2.3.1
|
||||
typescript: 4.6.3
|
||||
|
||||
@ -422,6 +424,26 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@sveltekit-i18n/base/1.1.1_svelte@3.46.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-J/sMU0OwS3dCLOuilHMBqu8vZHuuXiNV9vFJx8Nb4/b5BlR/KCZ4bCXI8wZR02GHeCOYKZxWus07CM1scxa/jw==
|
||||
}
|
||||
peerDependencies:
|
||||
svelte: ^3.x
|
||||
dependencies:
|
||||
svelte: 3.46.4
|
||||
optionalDependencies:
|
||||
'@sveltekit-i18n/parser-default': 1.0.3
|
||||
dev: true
|
||||
|
||||
/@sveltekit-i18n/parser-default/1.0.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-HheveklTjp3hxpYQhoHfyA6B4bQaUeSV5MQf2usIv/58UF2jY/YqhCAWj9bDBjufbuZc5pSz4BXvdX3WVT+viA==
|
||||
}
|
||||
dev: true
|
||||
|
||||
/@szmarczak/http-timer/5.0.1:
|
||||
resolution:
|
||||
{
|
||||
@ -4955,6 +4977,19 @@ packages:
|
||||
engines: { node: '>= 8' }
|
||||
dev: true
|
||||
|
||||
/sveltekit-i18n/2.1.2_svelte@3.46.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-s5YxcbNd2EWNZaZR1A4Drt8s53E4fpUkN4XIWd3VRpw1pihZVWssqmBW1qkjQ6AB0kiu1Qwule+vt1HkbQOjrg==
|
||||
}
|
||||
peerDependencies:
|
||||
svelte: ^3.x
|
||||
dependencies:
|
||||
'@sveltekit-i18n/base': 1.1.1_svelte@3.46.4
|
||||
'@sveltekit-i18n/parser-default': 1.0.3
|
||||
svelte: 3.46.4
|
||||
dev: true
|
||||
|
||||
/table/6.7.2:
|
||||
resolution:
|
||||
{
|
||||
|
1
src/app.d.ts
vendored
1
src/app.d.ts
vendored
@ -31,6 +31,7 @@ interface SessionData {
|
||||
userId?: string | null;
|
||||
teamId?: string | null;
|
||||
permission?: string;
|
||||
lang?: string;
|
||||
isAdmin?: boolean;
|
||||
expires?: string | null;
|
||||
}
|
||||
|
52
src/hooks.ts
52
src/hooks.ts
@ -6,6 +6,7 @@ import { getUserDetails, sentry } from '$lib/common';
|
||||
import { version } from '$lib/common';
|
||||
import cookie from 'cookie';
|
||||
import { dev } from '$app/env';
|
||||
import { locales } from '$lib/translations';
|
||||
|
||||
const whiteLabeled = process.env['COOLIFY_WHITE_LABELED'] === 'true';
|
||||
const whiteLabelDetails = {
|
||||
@ -20,6 +21,24 @@ export const handle = handleSession(
|
||||
},
|
||||
async function ({ event, resolve }) {
|
||||
let response;
|
||||
|
||||
const { url, request } = event;
|
||||
|
||||
// Get defined locales
|
||||
const supportedLocales = locales.get();
|
||||
let locale;
|
||||
|
||||
if (event.locals.cookies['lang']) {
|
||||
locale = event.locals.cookies['lang'];
|
||||
} else if (!locale) {
|
||||
locale = `${`${request.headers.get('accept-language')}`.match(
|
||||
/[a-zA-Z]+?(?=-|_|,|;)/
|
||||
)}`.toLowerCase();
|
||||
}
|
||||
|
||||
// Set default locale if user preferred locale does not match
|
||||
if (!supportedLocales.includes(locale)) locale = 'en';
|
||||
|
||||
try {
|
||||
if (event.locals.cookies) {
|
||||
if (event.locals.cookies['kit.session']) {
|
||||
@ -29,7 +48,8 @@ export const handle = handleSession(
|
||||
teamId,
|
||||
permission,
|
||||
isAdmin: permission === 'admin' || permission === 'owner',
|
||||
expires: event.locals.session.data.expires
|
||||
expires: event.locals.session.data.expires,
|
||||
lang: locale
|
||||
};
|
||||
|
||||
if (JSON.stringify(event.locals.session.data) !== JSON.stringify(newSession)) {
|
||||
@ -39,12 +59,14 @@ export const handle = handleSession(
|
||||
}
|
||||
|
||||
response = await resolve(event, {
|
||||
ssr: !event.url.pathname.startsWith('/webhooks/success')
|
||||
ssr: !event.url.pathname.startsWith('/webhooks/success'),
|
||||
transformPage: ({ html }) => html.replace(/<html.*>/, `<html lang="${locale}">`)
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
response = await resolve(event, {
|
||||
ssr: !event.url.pathname.startsWith('/webhooks/success')
|
||||
ssr: !event.url.pathname.startsWith('/webhooks/success'),
|
||||
transformPage: ({ html }) => html.replace(/<html.*>/, `<html lang="${locale}">`)
|
||||
});
|
||||
response.headers.append(
|
||||
'Set-Cookie',
|
||||
@ -67,14 +89,34 @@ export const handle = handleSession(
|
||||
expires: new Date('Thu, 01 Jan 1970 00:00:01 GMT')
|
||||
})
|
||||
);
|
||||
} finally {
|
||||
return response;
|
||||
}
|
||||
|
||||
response.headers.append(
|
||||
'Set-Cookie',
|
||||
cookie.serialize('lang', locale, {
|
||||
path: '/',
|
||||
sameSite: 'strict',
|
||||
maxAge: 30 * 24 * 60 * 60
|
||||
})
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
);
|
||||
|
||||
export const getSession: GetSession = function ({ locals }) {
|
||||
// Get defined locales
|
||||
const supportedLocales = locales.get();
|
||||
let locale;
|
||||
|
||||
if (locals.cookies) {
|
||||
locale = supportedLocales.find(
|
||||
(l) => `${l}`.toLowerCase() === `${locals.cookies['lang']}`.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
lang: locale,
|
||||
version,
|
||||
whiteLabeled,
|
||||
whiteLabelDetails,
|
||||
|
4
src/lib/lang.json
Normal file
4
src/lib/lang.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fr": "Français",
|
||||
"en": "English"
|
||||
}
|
326
src/lib/locales/en.json
Normal file
326
src/lib/locales/en.json
Normal file
@ -0,0 +1,326 @@
|
||||
{
|
||||
"layout": {
|
||||
"update_done": "Update completed.",
|
||||
"wait_new_version_startup": "Waiting for the new version to start...",
|
||||
"new_version": "New version reachable. Reloading...",
|
||||
"switch_to_a_different_team": "Switch to a different team...",
|
||||
"update_available": "Update available"
|
||||
},
|
||||
"error": {
|
||||
"you_can_find_your_way_back": "You can find your way back",
|
||||
"here": "here",
|
||||
"you_are_lost": "Ooops you are lost! But don't be afraid!"
|
||||
},
|
||||
"index": {
|
||||
"dashboard": "Dashboard",
|
||||
"applications": "Applications",
|
||||
"destinations": "Destinations",
|
||||
"git_sources": "Git Sources",
|
||||
"databases": "Databases",
|
||||
"services": "Services",
|
||||
"teams": "Teams",
|
||||
"not_implemented_yet": "Not implemented yet",
|
||||
"database": "Database",
|
||||
"settings": "Settings",
|
||||
"global_settings": "Global Settings",
|
||||
"secret": "Secret",
|
||||
"team": "Team",
|
||||
"logout": "Logout"
|
||||
},
|
||||
"login": {
|
||||
"already_logged_in": "Already logged in...",
|
||||
"authenticating": "Authenticating...",
|
||||
"login": "Login"
|
||||
},
|
||||
"forms": {
|
||||
"password": "Password",
|
||||
"email": "Email address",
|
||||
"passwords_not_match": "Passwords do not match.",
|
||||
"password_again": "Password again",
|
||||
"save": "Save",
|
||||
"saving": "Saving...",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"action": "Action",
|
||||
"is_required": "is required.",
|
||||
"add": "Add",
|
||||
"set": "Set",
|
||||
"remove": "Remove",
|
||||
"path": "Path",
|
||||
"confirm_continue": "Are you sure to continue?",
|
||||
"must_be_stopped_to_modify": "Must be stopped to modify.",
|
||||
"port": "Port",
|
||||
"default": "default",
|
||||
"base_directory": "Base Directory",
|
||||
"publish_directory": "Publish Directory",
|
||||
"generated_automatically_after_start": "Generated automatically after start",
|
||||
"roots_password": "Root's Password",
|
||||
"root_user": "Root User",
|
||||
"eg": "eg",
|
||||
"user": "User",
|
||||
"loading": "Loading...",
|
||||
"version": "Version",
|
||||
"host": "Host",
|
||||
"already_used_for": "<span class=\"text-red-500\">{{type}}</span> already used for",
|
||||
"configuration": "Configuration",
|
||||
"engine": "Engine",
|
||||
"network": "Network",
|
||||
"ip_address": "IP Address",
|
||||
"ssh_private_key": "SSH Private Key",
|
||||
"type": "Type",
|
||||
"html_url": "HTML URL",
|
||||
"api_url": "API URL",
|
||||
"organization": "Organization",
|
||||
"new_password": "New password",
|
||||
"super_secure_new_password": "Super secure new password",
|
||||
"submit": "Submit",
|
||||
"default_email_address": "Default Email Address",
|
||||
"default_password": "Default Password",
|
||||
"username": "Username",
|
||||
"root_db_user": "Root DB User",
|
||||
"root_db_password": "Root DB Password",
|
||||
"api_port": "API Port",
|
||||
"verifying": "Verifying",
|
||||
"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",
|
||||
"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",
|
||||
"admin_api_key": "Admin API key"
|
||||
},
|
||||
"register": {
|
||||
"register": "Register",
|
||||
"registering": "Registering...",
|
||||
"first_user": "You are registering the first user. It will be the administrator of your Coolify instance."
|
||||
},
|
||||
"reset": {
|
||||
"reset_password": "Reset",
|
||||
"invalid_secret_key": "Invalid secret key.",
|
||||
"secret_key": "Secret Key",
|
||||
"find_path_secret_key": "You can find it in ~/coolify/.env (COOLIFY_SECRET_KEY)"
|
||||
},
|
||||
"application": {
|
||||
"configuration": {
|
||||
"buildpack": {
|
||||
"choose_this_one": "Choose this one..."
|
||||
},
|
||||
"branch_already_in_use": "This branch is already used by another application. Webhooks won't work in this case for both applications. Are you sure you want to use it?",
|
||||
"no_repositories_configured": "No repositories configured for your Git Application.",
|
||||
"configure_it_now": "Configure it now",
|
||||
"loading_repositories": "Loading repositories ...",
|
||||
"select_a_repository": "Please select a repository",
|
||||
"loading_branches": "Loading branches ...",
|
||||
"select_a_repository_first": "Please select a repository first",
|
||||
"select_a_branch": "Please select a branch",
|
||||
"loading_groups": "Loading groups...",
|
||||
"select_a_group": "Please select a group",
|
||||
"loading_projects": "Loading projects...",
|
||||
"select_a_project": "Please select a project",
|
||||
"no_projects_found": "No projects found",
|
||||
"no_branches_found": "No branches found",
|
||||
"configure_build_pack": "Configure Build Pack",
|
||||
"scanning_repository_suggest_build_pack": "Scanning repository to suggest a build pack for you...",
|
||||
"found_lock_file": "Found lock file for <span class=\"font-bold text-orange-500 pl-1\">{{packageManager}}</span>. Using it for predefined commands commands.",
|
||||
"configure_destination": "Configure Destination",
|
||||
"no_configurable_destination": "No configurable Destination found",
|
||||
"select_a_repository_project": "Select a Repository / Project",
|
||||
"select_a_git_source": "Select a Git Source",
|
||||
"no_configurable_git": "No configurable Git Source found",
|
||||
"configuration_missing": "Configuration missing"
|
||||
},
|
||||
"build": {
|
||||
"queued_waiting_exec": "Queued and waiting for execution.",
|
||||
"build_logs_of": "Build logs of",
|
||||
"running": "Running",
|
||||
"queued": "Queued",
|
||||
"finished_in": "Finished in",
|
||||
"load_more": "Load More",
|
||||
"no_logs": "No logs found",
|
||||
"waiting_logs": "Waiting for the logs..."
|
||||
},
|
||||
"preview": {
|
||||
"need_during_buildtime": "Need during buildtime?",
|
||||
"setup_secret_app_first": "You can add secrets to PR/MR deployments. Please add secrets to the application first. <br>Useful for creating <span class='text-green-500 font-bold'>staging</span> environments.",
|
||||
"values_overwriting_app_secrets": "These values overwrite application secrets in PR/MR deployments. Useful for creating <span class='text-green-500 font-bold'>staging</span> environments.",
|
||||
"redeploy": "Redeploy",
|
||||
"no_previews_available": "No previews available"
|
||||
},
|
||||
"secrets": {
|
||||
"secret_saved": "Secret saved.",
|
||||
"use_isbuildsecret": "Use isBuildSecret",
|
||||
"secrets_for": "Secrets for"
|
||||
},
|
||||
"storage": {
|
||||
"path_is_required": "Path is required.",
|
||||
"storage_saved": "Storage saved.",
|
||||
"storage_updated": "Storage updated.",
|
||||
"storage_deleted": "Storage deleted.",
|
||||
"persistent_storage_explainer": "You can specify any folder that you want to be persistent across deployments. <br>This is useful for storing data such as a database (SQLite) or a cache."
|
||||
},
|
||||
"deployment_queued": "Deployment queued.",
|
||||
"confirm_to_delete": "Are you sure you would like to delete '{{name}}'?",
|
||||
"stop_application": "Stop application",
|
||||
"permission_denied_stop_application": "You do not have permission to stop the application.",
|
||||
"rebuild_application": "Rebuild application",
|
||||
"permission_denied_rebuild_application": "You do not have permission to rebuild application.",
|
||||
"build_and_start_application": "Build and start application",
|
||||
"permission_denied_build_and_start_application": "You do not have permission to Build and start application.",
|
||||
"configurations": "Configurations",
|
||||
"secret": "Secrets",
|
||||
"persistent_storage": "Persistent Storage",
|
||||
"previews": "Previews",
|
||||
"logs": "Application Logs",
|
||||
"build_logs": "Build Logs",
|
||||
"delete_application": "Delete application",
|
||||
"permission_denied_delete_application": "You do not have permission to delete this application",
|
||||
"domain_already_in_use": "Domain {{domain}} is already used.",
|
||||
"dns_not_set_error": "DNS not set or propogated for {{domain}}.<br><br>Please check your DNS settings.",
|
||||
"settings_saved": "Settings saved.",
|
||||
"dns_not_set_partial_error": "DNS not set",
|
||||
"git_source": "Git Source",
|
||||
"git_repository": "Git Repository",
|
||||
"build_pack": "Build Pack",
|
||||
"destination": "Destination",
|
||||
"application": "Application",
|
||||
"url_fqdn": "URL (FQDN)",
|
||||
"domain_fqdn": "Domain (FQDN)",
|
||||
"https_explainer": "If you specify <span class='text-green-500 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-green-500 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-white font-bold'>You must set your DNS to point to the server IP in advance.</span>",
|
||||
"ssl_www_and_non_www": "Generate SSL for www and non-www?",
|
||||
"ssl_explainer": "It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-green-500'>both DNS entries</span> set in advance.<br><br>Useful if you expect to have visitors on both.",
|
||||
"install_command": "Install Command",
|
||||
"build_command": "Build Command",
|
||||
"start_command": "Start Command",
|
||||
"directory_to_use_explainer": "Directory to use as the base for all commands.<br>Could be useful with <span class='text-green-500 font-bold'>monorepos</span>.",
|
||||
"publish_directory_explainer": "Directory containing all the assets for deployment. <br> For example: <span class='text-green-500 font-bold'>dist</span>,<span class='text-green-500 font-bold'>_site</span> or <span class='text-green-500 font-bold'>public</span>.",
|
||||
"features": "Features",
|
||||
"enable_automatic_deployment": "Enable Automatic Deployment",
|
||||
"enable_auto_deploy_webhooks": "Enable automatic deployment through webhooks.",
|
||||
"enable_mr_pr_previews": "Enable MR/PR Previews",
|
||||
"enable_preview_deploy_mr_pr_requests": "Enable preview deployments from pull or merge requests.",
|
||||
"debug_logs": "Debug Logs",
|
||||
"enable_debug_log_during_build": "Enable debug logs during build phase.<br><span class='text-red-500 font-bold'>Sensitive information</span> could be visible and saved in logs.",
|
||||
"cant_activate_auto_deploy_without_repo": "Cannot activate automatic deployments until only one application is defined for this repository / branch.",
|
||||
"no_applications_found": "No applications found",
|
||||
"secret__batch_dot_env": "Paste .env file",
|
||||
"batch_secrets": "Batch add secrets"
|
||||
},
|
||||
"general": "General",
|
||||
"database": {
|
||||
"default_database": "Default Database",
|
||||
"generated_automatically_after_set_to_public": "Generated automatically after set to public",
|
||||
"connection_string": "Connection String",
|
||||
"set_public": "Set it public",
|
||||
"warning_database_public": "Your database will be reachable over the internet. <br>Take security seriously in this case!",
|
||||
"change_append_only_mode": "Change append only mode",
|
||||
"warning_append_only": "Useful if you would like to restore redis data from a backup.<br><span class='font-bold text-white'>Database restart is required.</span>",
|
||||
"select_database_type": "Select a Database type",
|
||||
"select_database_version": "Select a Database version",
|
||||
"confirm_stop": "Are you sure you would like to stop {{name}}?",
|
||||
"stop_database": "Stop database",
|
||||
"permission_denied_stop_database": "You do not have permission to stop the database.",
|
||||
"start_database": "Start database",
|
||||
"permission_denied_start_database": "You do not have permission to start the database.",
|
||||
"delete_database": "Delete Database",
|
||||
"permission_denied_delete_database": "You do not have permission to delete a Database",
|
||||
"no_databases_found": "No databases found"
|
||||
},
|
||||
"destination": {
|
||||
"delete_destination": "Delete Destination",
|
||||
"permission_denied_delete_destination": "You do not have permission to delete this destination",
|
||||
"add_to_coolify": "Add to Coolify",
|
||||
"coolify_proxy_stopped": "Coolify Proxy stopped!",
|
||||
"coolify_proxy_started": "Coolify Proxy started!",
|
||||
"confirm_restart_proxy": "Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.",
|
||||
"coolify_proxy_restarting": "Coolify Proxy restarting...",
|
||||
"restarting_please_wait": "Restarting... please wait...",
|
||||
"force_restart_proxy": "Force restart proxy",
|
||||
"use_coolify_proxy": "Use Coolify Proxy?",
|
||||
"no_destination_found": "No destination found",
|
||||
"new_error_network_already_exists": "Network {{network}} already configured for another team!",
|
||||
"new": {
|
||||
"saving_and_configuring_proxy": "Saving and configuring proxy...",
|
||||
"install_proxy": "This will install a proxy on the destination to allow you to access your applications and services without any manual configuration (recommended for Docker).<br><br>Databases will have their own proxy.",
|
||||
"add_new_destination": "Add New Destination",
|
||||
"predefined_destinations": "Predefined destinations"
|
||||
}
|
||||
},
|
||||
"sources": {
|
||||
"local_docker": "Local Docker",
|
||||
"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."
|
||||
},
|
||||
"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": {
|
||||
"all_email_verified": "All email verified. You can login now.",
|
||||
"generate_www_non_www_ssl": "It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-pink-600'>both DNS entries</span> set in advance.<br><br>Service needs to be restarted."
|
||||
},
|
||||
"service": {
|
||||
"stop_service": "Stop Service",
|
||||
"permission_denied_stop_service": "You do not have permission to stop the service.",
|
||||
"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.",
|
||||
"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",
|
||||
"credential_stat_explainer": "Credentials for <a class=\"text-white font-bold\" href=\"{{link}}\" target=\"_blank\">stats</a> page."
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
322
src/lib/locales/fr.json
Normal file
322
src/lib/locales/fr.json
Normal file
@ -0,0 +1,322 @@
|
||||
{
|
||||
"application": {
|
||||
"application": "Application",
|
||||
"build": {
|
||||
"build_logs_of": "Créer des journaux de",
|
||||
"finished_in": "Fini en",
|
||||
"load_more": "Charger plus",
|
||||
"no_logs": "Aucun journal trouvé",
|
||||
"queued": "En file d'attente",
|
||||
"queued_waiting_exec": "En file d'attente et en attente d'exécution.",
|
||||
"running": "Fonctionnement",
|
||||
"waiting_logs": "En attente des logs..."
|
||||
},
|
||||
"build_and_start_application": "Build et démarrer l'application",
|
||||
"build_command": "Commande Build",
|
||||
"build_logs": "Créer des journaux",
|
||||
"build_pack": "Pack de Build",
|
||||
"cant_activate_auto_deploy_without_repo": "Impossible d'activer les déploiements automatiques tant qu'une seule application n'est pas définie pour ce dépôt/branche.",
|
||||
"configuration": {
|
||||
"branch_already_in_use": "Cette branche est déjà utilisée par une autre application. \nLes webhooks ne fonctionneront pas dans ce cas pour les deux applications. \nÊtes-vous sûr de vouloir l'utiliser ?",
|
||||
"buildpack": {
|
||||
"choose_this_one": "Choisir celui-ci..."
|
||||
},
|
||||
"configuration_missing": "Configuration manquante",
|
||||
"configure_build_pack": "Configurer le pack de build",
|
||||
"configure_destination": "Configurer la destination",
|
||||
"configure_it_now": "Configurez-le maintenant",
|
||||
"found_lock_file": "Fichier .lock trouvé pour <span class=\"font-bold text-orange-500 pl-1\">{{packageManager}}</span>. \nL'utiliser pour les commandes prédéfinies.",
|
||||
"loading_branches": "Chargement des branches...",
|
||||
"loading_groups": "Chargement des groupes...",
|
||||
"loading_projects": "Chargement des projets...",
|
||||
"loading_repositories": "Chargement des dépôts Git...",
|
||||
"no_branches_found": "Aucune branche trouvée",
|
||||
"no_configurable_destination": "Aucune destination configurable trouvée",
|
||||
"no_configurable_git": "Aucune source Git configurable trouvée",
|
||||
"no_projects_found": "Aucun projet trouvé",
|
||||
"no_repositories_configured": "Aucun dépôt Git configuré pour votre application.",
|
||||
"scanning_repository_suggest_build_pack": "Analyse du dépôt pour vous suggérer un pack de Build...",
|
||||
"select_a_branch": "Veuillez sélectionner une branche",
|
||||
"select_a_git_source": "Sélectionnez une source Git",
|
||||
"select_a_group": "Veuillez sélectionner un groupe",
|
||||
"select_a_project": "Veuillez sélectionner un projet",
|
||||
"select_a_repository": "Veuillez sélectionner un dépôt",
|
||||
"select_a_repository_first": "Veuillez d'abord sélectionner un dépôt",
|
||||
"select_a_repository_project": "Sélectionnez un dépôt / projet"
|
||||
},
|
||||
"configurations": "Configurations",
|
||||
"confirm_to_delete": "Voulez-vous vraiment supprimer '{{name}}'?",
|
||||
"debug_logs": "Journaux de débogage",
|
||||
"delete_application": "Supprimer l'application",
|
||||
"deployment_queued": "Déploiement en file d'attente.",
|
||||
"destination": "Destination",
|
||||
"directory_to_use_explainer": "Répertoire à utiliser comme base pour toutes les commandes.<br>Pourrait être utile avec <span class='text-green-500 font-bold'>monorepos</span>.",
|
||||
"dns_not_set_error": "DNS non défini ou propagé pour {{domain}}.<br><br>Veuillez vérifier vos paramètres DNS.",
|
||||
"dns_not_set_partial_error": "DNS non défini",
|
||||
"domain_already_in_use": "Le domaine {{domain}} est déjà utilisé.",
|
||||
"domain_fqdn": "Domaine (FQDN)",
|
||||
"url_fqdn": "URL (FQDN)",
|
||||
"enable_auto_deploy_webhooks": "Activez le déploiement automatique via des webhooks.",
|
||||
"enable_automatic_deployment": "Activer le déploiement automatique",
|
||||
"enable_debug_log_during_build": "Activez les journaux de débogage pendant la phase de build.<br><span class='text-red-500 font-bold'>Les informations sensibles</span> peuvent être visibles et enregistrées dans les journaux.",
|
||||
"enable_mr_pr_previews": "Activer les aperçus MR/PR",
|
||||
"enable_preview_deploy_mr_pr_requests": "Activez les déploiements de prévisualisation à partir de demandes d'extraction ou de fusion.",
|
||||
"features": "Caractéristiques",
|
||||
"git_repository": "Dépôt Git",
|
||||
"git_source": "Source Git",
|
||||
"https_explainer": "Si vous spécifiez <span class='text-green-500 font-bold'>https</span>, l'application sera accessible uniquement via https. \nUn certificat SSL sera généré pour vous.<br>Si vous spécifiez <span class='text-green-500 font-bold'>www</span>, l'application sera redirigée (302) à partir de non-www et vice versa \n.<br><br>Pour modifier le domaine, vous devez d'abord arrêter l'application.<br><br><span class='text-white font-bold'>Vous devez configurer, en avance, votre DNS pour pointer vers l'IP du serveur.</span>",
|
||||
"install_command": "Commande d'installation",
|
||||
"logs": "Journaux des applications",
|
||||
"no_applications_found": "Aucune application trouvée",
|
||||
"permission_denied_build_and_start_application": "Vous n'êtes pas autorisé à créer et à démarrer l'application.",
|
||||
"permission_denied_delete_application": "Vous n'êtes pas autorisé à supprimer cette application",
|
||||
"permission_denied_rebuild_application": "Vous n'êtes pas autorisé à re-build l'application.",
|
||||
"permission_denied_stop_application": "Vous n'êtes pas autorisé à arrêter l'application.",
|
||||
"persistent_storage": "Stockage persistant",
|
||||
"preview": {
|
||||
"need_during_buildtime": "Besoin pendant la build ?",
|
||||
"no_previews_available": "Aucun aperçu disponible",
|
||||
"redeploy": "Redéployer",
|
||||
"setup_secret_app_first": "Vous pouvez ajouter des secrets aux déploiements PR/MR. \nVeuillez d'abord ajouter des secrets à l'application. \n<br>Utile pour créer des environnements <span class='text-green-500 font-bold'>de mise en scène</span>.",
|
||||
"values_overwriting_app_secrets": "Ces valeurs remplacent les secrets d'application dans les déploiements PR/MR. \nUtile pour créer des environnements <span class='text-green-500 font-bold'>de mise en scène</span>."
|
||||
},
|
||||
"previews": "Aperçus",
|
||||
"publish_directory_explainer": "Répertoire contenant tous les actifs à déployer. \n<br> Par exemple : <span class='text-green-500 font-bold'>dist</span>,<span class='text-green-500 font-bold'>_site</span> ou <span \nclass='text-green-500 font-bold'>public</span>.",
|
||||
"rebuild_application": "Re-build l'application",
|
||||
"secret": "secrets",
|
||||
"secrets": {
|
||||
"secret_saved": "Secret enregistré.",
|
||||
"secrets_for": "secrets pour",
|
||||
"use_isbuildsecret": "Utiliser isBuildSecret"
|
||||
},
|
||||
"settings_saved": "Paramètres sauvegardés.",
|
||||
"ssl_explainer": "Il générera des certificats pour www et non-www. \n<br>Vous devez avoir <span class='font-bold text-green-500'>les deux entrées DNS</span> définies à l'avance.<br><br>Utile si vous prévoyez d'avoir des visiteurs sur les deux.",
|
||||
"ssl_www_and_non_www": "Générer SSL pour www et non-www ?",
|
||||
"start_command": "Démarrer la commande",
|
||||
"stop_application": "Arrêter l'application",
|
||||
"storage": {
|
||||
"path_is_required": "Le chemin est requis.",
|
||||
"persistent_storage_explainer": "Vous pouvez spécifier n'importe quel dossier que vous souhaitez conserver dans les déploiements. \n<br>Ceci est utile pour stocker des données telles qu'une base de données (SQLite) ou un cache.",
|
||||
"storage_deleted": "Stockage supprimé.",
|
||||
"storage_saved": "Stockage enregistré.",
|
||||
"storage_updated": "Stockage mis à jour."
|
||||
}
|
||||
},
|
||||
"database": {
|
||||
"change_append_only_mode": "Changer le mode d'ajout uniquement",
|
||||
"confirm_stop": "Êtes-vous sûr de vouloir arrêter {{name}} ?",
|
||||
"connection_string": "Connexion string",
|
||||
"default_database": "Base de données par défaut",
|
||||
"delete_database": "Supprimer la base de données",
|
||||
"generated_automatically_after_set_to_public": "Généré automatiquement après avoir été défini sur public",
|
||||
"no_databases_found": "Aucune base de données trouvée",
|
||||
"permission_denied_delete_database": "Vous n'êtes pas autorisé à supprimer une base de données",
|
||||
"permission_denied_start_database": "Vous n'êtes pas autorisé à démarrer la base de données.",
|
||||
"permission_denied_stop_database": "Vous n'êtes pas autorisé à arrêter la base de données.",
|
||||
"select_database_type": "Sélectionnez un type de base de données",
|
||||
"select_database_version": "Sélectionnez une version de la base de données",
|
||||
"set_public": "Rendre public",
|
||||
"start_database": "Démarrer la base de données",
|
||||
"stop_database": "Arrêter la base de données",
|
||||
"warning_append_only": "Utile si vous souhaitez restaurer des données Redis à partir d'une sauvegarde.<br><span class='font-bold text-white'>Le redémarrage de la base de données est nécessaire.</span>",
|
||||
"warning_database_public": "Votre base de données sera accessible depuis Internet. \n<br>Prenez la sécurité au sérieux dans ce cas!"
|
||||
},
|
||||
"destination": {
|
||||
"add_to_coolify": "Ajouter à Coolify",
|
||||
"confirm_restart_proxy": "Voulez-vous vraiment redémarrer le proxy? \nTout sera reconfiguré en ~10 secondes.",
|
||||
"coolify_proxy_restarting": "Redémarrage du Proxy Coolify...",
|
||||
"coolify_proxy_started": "Proxy Coolify démarré!",
|
||||
"coolify_proxy_stopped": "Proxy Coolify arrêté!",
|
||||
"delete_destination": "Supprimer le destinataire",
|
||||
"force_restart_proxy": "Forcer le redémarrage du proxy",
|
||||
"new": {
|
||||
"add_new_destination": "Ajouter une nouvelle destination",
|
||||
"install_proxy": "Cela installera un proxy sur la destination pour vous permettre d'accéder à vos applications et services sans aucune configuration manuelle (recommandé pour Docker).<br><br>Les bases de données auront leur propre proxy.",
|
||||
"predefined_destinations": "Destinations prédéfinies",
|
||||
"saving_and_configuring_proxy": "Enregistrement et configuration du proxy..."
|
||||
},
|
||||
"new_error_network_already_exists": "Réseau {{network}} déjà configuré pour une autre équipe !",
|
||||
"no_destination_found": "Aucune destination trouvée",
|
||||
"permission_denied_delete_destination": "Vous n'êtes pas autorisé à supprimer cette destination",
|
||||
"restarting_please_wait": "Redémarrage... veuillez patienter...",
|
||||
"use_coolify_proxy": "Utiliser le Proxy Coolify ?"
|
||||
},
|
||||
"error": {
|
||||
"here": "ici",
|
||||
"you_are_lost": "Oups vous êtes perdu ! \nMais n'ayez pas peur !",
|
||||
"you_can_find_your_way_back": "Tu peux retrouver ton chemin"
|
||||
},
|
||||
"forms": {
|
||||
"action": "action",
|
||||
"add": "Ajouter",
|
||||
"already_used_for": "<span class=\"text-red-500\">{{type}}</span> déjà utilisé pour",
|
||||
"api_port": "Port API",
|
||||
"api_url": "URL de l'API",
|
||||
"base_directory": "Répertoire de base",
|
||||
"configuration": "Configuration",
|
||||
"confirm_continue": "Êtes-vous sûr de continuer ?",
|
||||
"default": "défaut",
|
||||
"default_email_address": "Adresse e-mail par défaut",
|
||||
"default_password": "Mot de passe par défaut",
|
||||
"eg": "ex",
|
||||
"email": "Adresse e-mail",
|
||||
"engine": "Moteur",
|
||||
"extra_config": "Configuration supplémentaire",
|
||||
"generated_automatically_after_start": "Généré automatiquement après le démarrage",
|
||||
"host": "Hôte",
|
||||
"html_url": "URL HTML",
|
||||
"ip_address": "Adresse IP",
|
||||
"is_required": "est requis.",
|
||||
"loading": "Chargement...",
|
||||
"must_be_stopped_to_modify": "Doit être arrêté pour être modifié.",
|
||||
"name": "Nom",
|
||||
"network": "Réseau",
|
||||
"new_password": "Nouveau mot de passe",
|
||||
"no_actions_available": "Aucune action disponible",
|
||||
"organization": "Organisation",
|
||||
"password": "Mot de passe",
|
||||
"password_again": "Mot de passe à nouveau",
|
||||
"passwords_not_match": "Les mots de passe ne correspondent pas.",
|
||||
"path": "Chemin",
|
||||
"port": "Port",
|
||||
"public_port_range": "Gamme de ports publics",
|
||||
"public_port_range_explainer": "Ports utilisés pour exposer les bases de données/services/services internes.<br> Ajoutez-les à votre pare-feu (le cas échéant).<br><br>Vous pouvez spécifier une plage de ports, par exemple : <span class='text-yellow-500 \nfont-bold'>9000-9100</span>",
|
||||
"publish_directory": "Publier le répertoire",
|
||||
"remove": "Retirer",
|
||||
"remove_domain": "Supprimer le domaine",
|
||||
"removing": "Suppression...",
|
||||
"root_db_password": "Mot de passe root de la base de données",
|
||||
"root_db_user": "Utilisateur root de la base de données",
|
||||
"root_user": "Utilisateur root",
|
||||
"roots_password": "Mot de passe de l'utilisateur root",
|
||||
"save": "sauvegarder",
|
||||
"saving": "Sauvegarde...",
|
||||
"select_a_service": "Sélectionnez un service",
|
||||
"select_a_service_version": "Sélectionnez une version de service",
|
||||
"set": "Régler",
|
||||
"ssh_private_key": "Clé privée SSH",
|
||||
"submit": "Nous faire parvenir",
|
||||
"super_secure_new_password": "Nouveau mot de passe super sécurisé",
|
||||
"type": "Taper",
|
||||
"user": "Utilisateur",
|
||||
"username": "Nom d'utilisateur",
|
||||
"value": "Valeur",
|
||||
"verify_emails_without_smtp": "Vérifier les e-mails sans SMTP",
|
||||
"verifying": "Vérification",
|
||||
"version": "Version"
|
||||
},
|
||||
"general": "Général",
|
||||
"index": {
|
||||
"applications": "Applications",
|
||||
"dashboard": "Tableau de bord",
|
||||
"database": "Base de données",
|
||||
"databases": "Bases de données",
|
||||
"destinations": "Destinations",
|
||||
"git_sources": "Sources Git",
|
||||
"global_settings": "Paramètres globaux",
|
||||
"logout": "Se déconnecter",
|
||||
"not_implemented_yet": "Pas encore implémenté",
|
||||
"secret": "Secret",
|
||||
"services": "Services",
|
||||
"settings": "Réglages",
|
||||
"team": "Équipe",
|
||||
"teams": "Équipes"
|
||||
},
|
||||
"layout": {
|
||||
"new_version": "Nouvelle version accessible. \nRechargement...",
|
||||
"switch_to_a_different_team": "Changer d'équipe...",
|
||||
"update_available": "Mise à jour disponible",
|
||||
"update_done": "Mise à jour terminée.",
|
||||
"wait_new_version_startup": "En attendant le lancement de la nouvelle version..."
|
||||
},
|
||||
"login": {
|
||||
"already_logged_in": "Déjà connecté...",
|
||||
"authenticating": "Authentification...",
|
||||
"login": "Connexion"
|
||||
},
|
||||
"register": {
|
||||
"first_user": "Vous enregistrez le premier utilisateur. \nCe sera l'administrateur de votre instance Coolify.",
|
||||
"register": "S'inscrire"
|
||||
},
|
||||
"reset": {
|
||||
"find_path_secret_key": "Vous pouvez le trouver dans ~/coolify/.env (COOLIFY_SECRET_KEY)",
|
||||
"invalid_secret_key": "Clé secrète invalide.",
|
||||
"reset_password": "Réinitialiser",
|
||||
"secret_key": "Clef secrète"
|
||||
},
|
||||
"service": {
|
||||
"delete_service": "Supprimer le service",
|
||||
"no_service": "Aucun service trouvé",
|
||||
"permission_denied_delete_service": "Vous n'êtes pas autorisé à supprimer un service.",
|
||||
"permission_denied_start_service": "Vous n'êtes pas autorisé à démarrer le service.",
|
||||
"permission_denied_stop_service": "Vous n'êtes pas autorisé à arrêter le service.",
|
||||
"start_service": "Démarrer le service",
|
||||
"stop_service": "Stopper le service"
|
||||
},
|
||||
"services": {
|
||||
"all_email_verified": "Tous les e-mails sont vérifiés. \nVous pouvez vous connecter maintenant.",
|
||||
"generate_www_non_www_ssl": "Il générera des certificats pour www et non-www. \n<br>Vous devez avoir <span class='font-bold text-pink-600'>les deux entrées DNS</span> définies à l'avance.<br><br>Le service devra être redémarré."
|
||||
},
|
||||
"setting": {
|
||||
"coolify_proxy_settings": "Paramètres du proxy Coolify",
|
||||
"credential_stat_explainer": "Identifiants pour la page <a class=\"text-white font-bold\" href=\"{{link}}\" target=\"_blank\">statistiques</a>.",
|
||||
"domain_removed": "Domaine supprimé",
|
||||
"must_remove_domain_before_changing": "Vous devez supprimer le domaine avant de pouvoir modifier ce paramètre.",
|
||||
"permission_denied": "Vous n'avez pas la permission de faire cela. \n\\nDemandez à un administrateur de modifier vos autorisations.",
|
||||
"registration_allowed": "Inscription autorisée ?",
|
||||
"registration_allowed_explainer": "Autoriser d'autres inscriptions à l'application. \n<br>Il est désactivé après la première inscription.",
|
||||
"ssl_explainer": "Si vous spécifiez <span class='text-yellow-500 font-bold'>https</span>, Coolify sera accessible uniquement via https. \nUn certificat SSL sera généré pour vous.<br>Si vous spécifiez <span class='text-yellow-500 font-bold'>www</span>, Coolify sera redirigé (302) à partir de non-www et vice versa."
|
||||
},
|
||||
"source": {
|
||||
"application_id": "ID d'application",
|
||||
"change_app_settings": "Modifier les paramètres de l'application {{name}}",
|
||||
"create_new_app": "Créer une nouvelle application {{name}}",
|
||||
"delete_git_source": "Supprimer la source Git",
|
||||
"github": {
|
||||
"redirecting": "Redirection vers Github..."
|
||||
},
|
||||
"gitlab": {
|
||||
"already_configured": "L'application GitLab est déjà configurée.",
|
||||
"gitlab_application_type": "Type d'application GitLab",
|
||||
"group_owned": "Application détenue par le groupe",
|
||||
"self_hosted": "Application à l'échelle de l'instance (auto-hébergée)",
|
||||
"user_owned": "Application appartenant à l'utilisateur"
|
||||
},
|
||||
"group_name": "Nom de groupe",
|
||||
"install_repositories": "Installer les dépôts",
|
||||
"new": {
|
||||
"git_source": "Ajouter une nouvelle source Git",
|
||||
"official_providers": "Fournisseurs officiels"
|
||||
},
|
||||
"no_git_sources_found": "Aucune source git trouvée",
|
||||
"oauth_id": "ID OAuth",
|
||||
"oauth_id_explainer": "L'identifiant OAuth est l'identifiant unique de l'application GitLab. \n<br>Vous pouvez le trouver <span class='font-bold text-orange-600' >dans l'URL</span> de votre application GitLab OAuth.",
|
||||
"permission_denied": "Vous n'êtes pas autorisé à supprimer une source Git",
|
||||
"register_oauth_gitlab": "Enregistrer une nouvelle application OAuth sur GitLab"
|
||||
},
|
||||
"sources": {
|
||||
"local_docker": "Docker local",
|
||||
"organization_explainer": "Remplissez-le si vous souhaitez utiliser une organisation comme source Git. \nSinon, votre utilisateur sera utilisé.",
|
||||
"remote_docker": "Station d'accueil à distance"
|
||||
},
|
||||
"team": {
|
||||
"accept": "J'accepte",
|
||||
"admin": "Administrateur",
|
||||
"delete": "Supprimer",
|
||||
"invite_new_member": "Inviter un nouveau membre",
|
||||
"invite_only_register_explainer": "Vous ne pouvez inviter que des utilisateurs enregistrés pour le moment - sera bientôt prolongé.",
|
||||
"invited_with_permissions": "Invité à <span class=\"font-bold text-pink-600\">{{teamName}}</span> avec <span class=\"font-bold text-rose-600\">{{permission}}</span \n> autorisation.",
|
||||
"member": "membre(s)",
|
||||
"members": "Membres",
|
||||
"pending_invitation": "Invitation en attente",
|
||||
"pending_invitations": "Invitations en attente",
|
||||
"permission": "Autorisation",
|
||||
"promote_to": "Promouvoir à {{grade}}",
|
||||
"read": "Lire",
|
||||
"revoke_invitation": "Révoquer l'invitation",
|
||||
"root": "(suprême)",
|
||||
"root_team_explainer": "Il s'agit de l'équipe <span class='text-red-500 font-bold'>suprême</span>. \nCela signifie que les membres de ce groupe peuvent gérer les paramètres à l'échelle de l'instance et avoir tous les privilèges dans Coolify (imaginez comme un utilisateur root sous Linux).",
|
||||
"send_invitation": "Envoyer une invitation",
|
||||
"you": "(Toi)"
|
||||
}
|
||||
}
|
26
src/lib/translations.ts
Normal file
26
src/lib/translations.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import i18n from 'sveltekit-i18n';
|
||||
import lang from './lang.json';
|
||||
|
||||
/** @type {import('sveltekit-i18n').Config} */
|
||||
export const config = {
|
||||
fallbackLocale: 'en',
|
||||
translations: {
|
||||
en: { lang },
|
||||
fr: { lang }
|
||||
},
|
||||
loaders: [
|
||||
{
|
||||
locale: 'en',
|
||||
key: '',
|
||||
loader: async () => (await import('./locales/en.json')).default
|
||||
},
|
||||
{
|
||||
locale: 'fr',
|
||||
key: '',
|
||||
loader: async () => (await import('./locales/fr.json')).default
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const { t, loading, locales, locale, loadTranslations } = new i18n(config);
|
||||
loading.subscribe(($loading) => $loading && console.log('Loading translations...'));
|
@ -12,15 +12,18 @@
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let status;
|
||||
export let error;
|
||||
</script>
|
||||
|
||||
<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">
|
||||
You can find your way back <a href="/" class="font-bold uppercase text-sky-400">here</a>
|
||||
{$t('error.you_can_find_your_way_back')}
|
||||
<a href="/" class="font-bold uppercase text-sky-400">{$t('error.here')}</a>
|
||||
</div>
|
||||
<div class="py-10 text-xs font-bold">
|
||||
<pre
|
||||
|
@ -81,6 +81,7 @@
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { disabledButton } from '$lib/store';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
if (githubToken) $gitTokens.githubToken = githubToken;
|
||||
if (gitlabToken) $gitTokens.gitlabToken = gitlabToken;
|
||||
@ -99,7 +100,7 @@
|
||||
async function handleDeploySubmit() {
|
||||
try {
|
||||
const { buildId } = await post(`/applications/${id}/deploy.json`, { ...application });
|
||||
toast.push('Deployment queued.');
|
||||
toast.push($t('application.deployment_queued'));
|
||||
if ($page.url.pathname.startsWith(`/applications/${id}/logs/build`)) {
|
||||
return window.location.assign(`/applications/${id}/logs/build?buildId=${buildId}`);
|
||||
} else {
|
||||
@ -113,7 +114,7 @@
|
||||
}
|
||||
|
||||
async function deleteApplication(name) {
|
||||
const sure = confirm(`Are you sure you would like to delete '${name}'?`);
|
||||
const sure = confirm($t('application.confirm_to_delete', { name }));
|
||||
if (sure) {
|
||||
loading = true;
|
||||
try {
|
||||
@ -186,8 +187,8 @@
|
||||
disabled={$disabledButton}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Stop application'
|
||||
: 'You do not have permission to stop the application.'}
|
||||
? $t('application.stop_application')
|
||||
: $t('application.permission_denied_stop_application')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -400,10 +401,10 @@
|
||||
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/logs`}
|
||||
>
|
||||
<button
|
||||
title="Application Logs"
|
||||
title={$t('application.build_logs')}
|
||||
disabled={$disabledButton}
|
||||
class="icons bg-transparent tooltip-bottom text-sm"
|
||||
data-tooltip="Application Logs"
|
||||
data-tooltip={$t('application.build_logs')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -463,14 +464,14 @@
|
||||
|
||||
<button
|
||||
on:click={() => deleteApplication(application.name)}
|
||||
title="Delete application"
|
||||
title={$t('application.delete_application')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class:hover:text-red-500={$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Delete application'
|
||||
: 'You do not have permission to delete this application'}
|
||||
? $t('application.delete_application')
|
||||
: $t('application.permission_denied_delete_application')}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</button>
|
||||
|
@ -4,6 +4,7 @@ import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { promises as dns } from 'dns';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { status, body } = await getUserDetails(event);
|
||||
@ -18,7 +19,9 @@ export const post: RequestHandler = async (event) => {
|
||||
const found = await db.isDomainConfigured({ id, fqdn });
|
||||
if (found) {
|
||||
throw {
|
||||
message: `Domain ${getDomain(fqdn).replace('www.', '')} is already used.`
|
||||
message: t.get('application.domain_already_in_use', {
|
||||
domain: getDomain(fqdn).replace('www.', '')
|
||||
})
|
||||
};
|
||||
}
|
||||
if (!dev && !forceSave) {
|
||||
@ -36,7 +39,7 @@ export const post: RequestHandler = async (event) => {
|
||||
if (localIp?.length > 0) {
|
||||
if (ip?.length === 0 || !ip.includes(localIp[0])) {
|
||||
throw {
|
||||
message: `DNS not set or propogated for ${domain}.<br><br>Please check your DNS settings.`
|
||||
message: t.get('application.dns_not_set_error', { domain: domain })
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
import { post } from '$lib/api';
|
||||
import { findBuildPack } from '$lib/components/templates';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -43,7 +44,9 @@
|
||||
buildPack.name && buildPack.color}"
|
||||
><span>{buildPack.fancyName}</span>
|
||||
{#if !scanning && foundConfig?.name === buildPack.name}
|
||||
<span class="absolute bottom-0 pb-2 text-xs">Choose this one...</span>
|
||||
<span class="absolute bottom-0 pb-2 text-xs"
|
||||
>{$t('application.configuration.buildpack.choose_this_one')}</span
|
||||
>
|
||||
{/if}
|
||||
</button>
|
||||
</form>
|
||||
|
@ -7,6 +7,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { onMount } from 'svelte';
|
||||
import { gitTokens } from '$lib/store';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -95,9 +96,7 @@
|
||||
`/applications/${id}/configuration/repository.json?repository=${selected.repository}&branch=${selected.branch}`
|
||||
);
|
||||
if (data.used) {
|
||||
const sure = confirm(
|
||||
`This branch is already used by another application. Webhooks won't work in this case for both applications. Are you sure you want to use it?`
|
||||
);
|
||||
const sure = confirm($t('application.configuration.branch_already_in_use'));
|
||||
if (sure) {
|
||||
selected.autodeploy = false;
|
||||
showSave = true;
|
||||
@ -171,8 +170,10 @@
|
||||
|
||||
{#if repositories.length === 0 && loading.repositories === false}
|
||||
<div class="flex-col text-center">
|
||||
<div class="pb-4">No repositories configured for your Git Application.</div>
|
||||
<a href={`/sources/${application.gitSource.id}`}><button>Configure it now</button></a>
|
||||
<div class="pb-4">{$t('application.configuration.no_repositories_configured')}</div>
|
||||
<a href={`/sources/${application.gitSource.id}`}
|
||||
><button>{$t('application.configuration.configure_it_now')}</button></a
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<form on:submit|preventDefault={handleSubmit} class="flex flex-col justify-center text-center">
|
||||
@ -181,8 +182,8 @@
|
||||
<div class="custom-select-wrapper">
|
||||
<Select
|
||||
placeholder={loading.repositories
|
||||
? 'Loading repositories...'
|
||||
: 'Please select a repository'}
|
||||
? $t('application.configuration.loading_repositories')
|
||||
: $t('application.configuration.select_a_repository')}
|
||||
id="repository"
|
||||
showIndicator={true}
|
||||
isWaiting={loading.repositories}
|
||||
@ -196,10 +197,10 @@
|
||||
<div class="custom-select-wrapper">
|
||||
<Select
|
||||
placeholder={loading.branches
|
||||
? 'Loading branches...'
|
||||
? $t('application.configuration.loading_branches')
|
||||
: !selected.repository
|
||||
? 'Please select a repository first'
|
||||
: 'Please select a branch'}
|
||||
? $t('application.configuration.select_a_repository_first')
|
||||
: $t('application.configuration.select_a_branch')}
|
||||
isWaiting={loading.branches}
|
||||
showIndicator={selected.repository}
|
||||
id="branches"
|
||||
@ -217,7 +218,7 @@
|
||||
type="submit"
|
||||
disabled={!showSave}
|
||||
class:bg-orange-600={showSave}
|
||||
class:hover:bg-orange-500={showSave}>Save</button
|
||||
class:hover:bg-orange-500={showSave}>{$t('forms.save')}</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -9,6 +9,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { del, get, post, put } from '$lib/api';
|
||||
import { gitTokens } from '$lib/store';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -139,9 +140,7 @@
|
||||
`/applications/${id}/configuration/repository.json?repository=${selected.project.path_with_namespace}&branch=${selected.branch.name}`
|
||||
);
|
||||
if (data.used) {
|
||||
const sure = confirm(
|
||||
`This branch is already used by another application. Webhooks won't work in this case for both applications. Are you sure you want to use it?`
|
||||
);
|
||||
const sure = confirm($t('application.configuration.branch_already_in_use'));
|
||||
if (sure) {
|
||||
autodeploy = false;
|
||||
showSave = true;
|
||||
@ -270,11 +269,11 @@
|
||||
<div class="flex flex-col space-y-2 px-4 xl:flex-row xl:space-y-0 xl:space-x-2 ">
|
||||
{#if loading.base}
|
||||
<select name="group" disabled class="w-96">
|
||||
<option selected value="">Loading groups...</option>
|
||||
<option selected value="">{$t('application.configuration.loading_groups')}</option>
|
||||
</select>
|
||||
{:else}
|
||||
<select name="group" class="w-96" bind:value={selected.group} on:change={loadProjects}>
|
||||
<option value="" disabled selected>Please select a group</option>
|
||||
<option value="" disabled selected>{$t('application.configuration.select_a_group')}</option>
|
||||
{#each groups as group}
|
||||
<option value={group}>{group.full_name}</option>
|
||||
{/each}
|
||||
@ -282,7 +281,7 @@
|
||||
{/if}
|
||||
{#if loading.projects}
|
||||
<select name="project" disabled class="w-96">
|
||||
<option selected value="">Loading projects...</option>
|
||||
<option selected value="">{$t('application.configuration.loading_projects')}</option>
|
||||
</select>
|
||||
{:else if !loading.projects && projects.length > 0}
|
||||
<select
|
||||
@ -292,20 +291,24 @@
|
||||
on:change={loadBranches}
|
||||
disabled={!selected.group}
|
||||
>
|
||||
<option value="" disabled selected>Please select a project</option>
|
||||
<option value="" disabled selected
|
||||
>{$t('application.configuration.select_a_project')}</option
|
||||
>
|
||||
{#each projects as project}
|
||||
<option value={project}>{project.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<select name="project" disabled class="w-96">
|
||||
<option disabled selected value="">No projects found</option>
|
||||
<option disabled selected value=""
|
||||
>{$t('application.configuration.no_projects_found')}</option
|
||||
>
|
||||
</select>
|
||||
{/if}
|
||||
|
||||
{#if loading.branches}
|
||||
<select name="branch" disabled class="w-96">
|
||||
<option selected value="">Loading branches...</option>
|
||||
<option selected value="">{$t('application.configuration.loading_branches')}</option>
|
||||
</select>
|
||||
{:else if !loading.branches && branches.length > 0}
|
||||
<select
|
||||
@ -315,14 +318,17 @@
|
||||
on:change={isBranchAlreadyUsed}
|
||||
disabled={!selected.project}
|
||||
>
|
||||
<option value="" disabled selected>Please select a branch</option>
|
||||
<option value="" disabled selected>{$t('application.configuration.select_a_branch')}</option
|
||||
>
|
||||
{#each branches as branch}
|
||||
<option value={branch}>{branch.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<select name="project" disabled class="w-96">
|
||||
<option disabled selected value="">No branches found</option>
|
||||
<option disabled selected value=""
|
||||
>{$t('application.configuration.no_branches_found')}</option
|
||||
>
|
||||
</select>
|
||||
{/if}
|
||||
</div>
|
||||
@ -334,7 +340,7 @@
|
||||
disabled={!showSave || loading.save}
|
||||
class:bg-orange-600={showSave && !loading.save}
|
||||
class:hover:bg-orange-500={showSave && !loading.save}
|
||||
>{loading.save ? 'Saving...' : 'Save'}</button
|
||||
>{loading.save ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -36,6 +36,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { gitTokens } from '$lib/store';
|
||||
import { browser } from '$app/env';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
|
||||
@ -204,18 +205,21 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Configure Build Pack</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">
|
||||
{$t('application.configuration.configure_build_pack')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if scanning}
|
||||
<div class="flex justify-center space-x-1 p-6 font-bold">
|
||||
<div class="text-xl tracking-tight">Scanning repository to suggest a build pack for you...</div>
|
||||
<div class="text-xl tracking-tight">
|
||||
{$t('application.configuration.scanning_repository_suggest_build_pack')}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
{#if packageManager === 'yarn' || packageManager === 'pnpm'}
|
||||
<div class="flex justify-center p-6">
|
||||
Found lock file for <span class="font-bold text-orange-500 pl-1">{packageManager}</span>.
|
||||
Using it for predefined commands commands.
|
||||
{@html $t('application.configuration.found_lock_file', { packageManager })}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="max-w-7xl mx-auto flex flex-wrap justify-center">
|
||||
|
@ -33,6 +33,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -60,12 +61,14 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Configure Destination</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">
|
||||
{$t('application.configuration.configure_destination')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
{#if !destinations || ownDestinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2">No configurable Destination found</div>
|
||||
<div class="pb-2">{$t('application.configuration.no_configurable_destination')}</div>
|
||||
<div class="flex justify-center">
|
||||
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
|
@ -18,6 +18,8 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let application;
|
||||
export let appId;
|
||||
|
||||
@ -26,7 +28,9 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Repository / Project</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">
|
||||
{$t('application.configuration.select_a_repository_project')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-center">
|
||||
{#if application.gitSource.type === 'github'}
|
||||
|
@ -33,6 +33,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -72,12 +73,14 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Git Source</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">
|
||||
{$t('application.configuration.select_a_git_source')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
{#if !filteredSources || ownSources.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2 text-center">No configurable Git Source found</div>
|
||||
<div class="pb-2">{$t('application.configuration.no_configurable_git')}</div>
|
||||
<div class="flex justify-center">
|
||||
<button on:click={newSource} class="add-icon bg-orange-600 hover:bg-orange-500">
|
||||
<svg
|
||||
@ -139,7 +142,7 @@
|
||||
<div class="font-bold text-xl text-center truncate">{source.name}</div>
|
||||
{#if source.gitlabApp && !source.gitlabAppId}
|
||||
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
|
@ -49,6 +49,7 @@
|
||||
import cuid from 'cuid';
|
||||
import { browser } from '$app/env';
|
||||
import { disabledButton } from '$lib/store';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
let domainEl: HTMLInputElement;
|
||||
@ -101,7 +102,7 @@
|
||||
branch: application.branch,
|
||||
projectId: application.projectId
|
||||
});
|
||||
return toast.push('Settings saved.');
|
||||
return toast.push($t('application.settings_saved'));
|
||||
} catch ({ error }) {
|
||||
if (name === 'debug') {
|
||||
debug = !debug;
|
||||
@ -126,7 +127,7 @@
|
||||
$disabledButton = false;
|
||||
return toast.push('Configurations saved.');
|
||||
} catch ({ error }) {
|
||||
if (error?.startsWith('DNS not set')) {
|
||||
if (error?.startsWith($t('application.dns_not_set_partial_error'))) {
|
||||
forceSave = true;
|
||||
}
|
||||
return errorNotification(error);
|
||||
@ -216,7 +217,7 @@
|
||||
<!-- svelte-ignore missing-declaration -->
|
||||
<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"
|
||||
@ -225,13 +226,17 @@
|
||||
class:hover:bg-green-500={!loading}
|
||||
class:hover:bg-orange-400={forceSave}
|
||||
disabled={loading}
|
||||
>{loading ? 'Saving...' : forceSave ? 'Are you sure to continue?' : 'Save'}</button
|
||||
>{loading
|
||||
? $t('forms.saving')
|
||||
: forceSave
|
||||
? $t('forms.confirm_continue')
|
||||
: $t('forms.save')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="mt-2 grid grid-cols-2 items-center">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="name"
|
||||
@ -241,7 +246,9 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="gitSource" class="text-base font-bold text-stone-100">Git Source</label>
|
||||
<label for="gitSource" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.git_source')}</label
|
||||
>
|
||||
<a
|
||||
href={$session.isAdmin
|
||||
? `/applications/${id}/configuration/source?from=/applications/${id}`
|
||||
@ -256,7 +263,9 @@
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository" class="text-base font-bold text-stone-100">Git Repository</label>
|
||||
<label for="repository" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.git_repository')}</label
|
||||
>
|
||||
<a
|
||||
href={$session.isAdmin
|
||||
? `/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`
|
||||
@ -271,7 +280,9 @@
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="buildPack" class="text-base font-bold text-stone-100">Build Pack</label>
|
||||
<label for="buildPack" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.build_pack')}</label
|
||||
>
|
||||
<a
|
||||
href={$session.isAdmin
|
||||
? `/applications/${id}/configuration/buildpack?from=/applications/${id}`
|
||||
@ -287,7 +298,9 @@
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<label for="destination" class="text-base font-bold text-stone-100">Destination</label>
|
||||
<label for="destination" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.destination')}</label
|
||||
>
|
||||
<div class="no-underline">
|
||||
<input
|
||||
value={application.destinationDocker.name}
|
||||
@ -299,20 +312,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">Application</div>
|
||||
<div class="title">{$t('application.application')}</div>
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="flex-col">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100">URL (FQDN)</label>
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100"
|
||||
>{$t('application.url_fqdn')}</label
|
||||
>
|
||||
{#if browser && window.location.hostname === 'demo.coolify.io'}
|
||||
<Explainer
|
||||
text="<span class='text-white font-bold'>You can use the predefined random url name or enter your own domain name.</span>"
|
||||
/>
|
||||
{/if}
|
||||
<Explainer
|
||||
text="If you specify <span class='text-green-500 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-green-500 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the url, you must first stop the application.<br><br><span class='text-white font-bold'>You must set your DNS to point to the server IP in advance.</span>"
|
||||
/>
|
||||
<Explainer text={$t('application.https_explainer')} />
|
||||
</div>
|
||||
<input
|
||||
readonly={!$session.isAdmin || isRunning}
|
||||
@ -328,12 +341,12 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<Setting
|
||||
dataTooltip="Must be stopped to modify."
|
||||
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||
disabled={isRunning}
|
||||
isCenter={false}
|
||||
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-green-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('application.ssl_explainer')}
|
||||
on:click={() => !isRunning && changeSettings('dualCerts')}
|
||||
/>
|
||||
</div>
|
||||
@ -372,13 +385,13 @@
|
||||
{/if}
|
||||
{#if !staticDeployments.includes(application.buildPack)}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="port" class="text-base font-bold text-stone-100">Port</label>
|
||||
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="port"
|
||||
id="port"
|
||||
bind:value={application.port}
|
||||
placeholder={application.buildPack === 'python' ? '8000' : '3000'}
|
||||
placeholder="{$t('forms.default')}: 'python' ? '8000' : '3000'"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@ -386,34 +399,38 @@
|
||||
{#if !notNodeDeployments.includes(application.buildPack)}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="installCommand" class="text-base font-bold text-stone-100"
|
||||
>Install Command</label
|
||||
>{$t('application.install_command')}</label
|
||||
>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="installCommand"
|
||||
id="installCommand"
|
||||
bind:value={application.installCommand}
|
||||
placeholder="default: yarn install"
|
||||
placeholder="{$t('forms.default')}: yarn install"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="buildCommand" class="text-base font-bold text-stone-100">Build Command</label>
|
||||
<label for="buildCommand" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.build_command')}</label
|
||||
>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="buildCommand"
|
||||
id="buildCommand"
|
||||
bind:value={application.buildCommand}
|
||||
placeholder="default: yarn build"
|
||||
placeholder="{$t('forms.default')}: yarn build"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="startCommand" class="text-base font-bold text-stone-100">Start Command</label>
|
||||
<label for="startCommand" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.start_command')}</label
|
||||
>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="startCommand"
|
||||
id="startCommand"
|
||||
bind:value={application.startCommand}
|
||||
placeholder="default: yarn start"
|
||||
placeholder="{$t('forms.default')}: yarn start"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@ -462,29 +479,25 @@
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="flex-col">
|
||||
<label for="baseDirectory" class="pt-2 text-base font-bold text-stone-100"
|
||||
>Base Directory</label
|
||||
>{$t('forms.base_directory')}</label
|
||||
>
|
||||
<Explainer
|
||||
text="Directory to use as the base for all commands.<br>Could be useful with <span class='text-green-500 font-bold'>monorepos</span>."
|
||||
/>
|
||||
<Explainer text={$t('application.directory_to_use_explainer')} />
|
||||
</div>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="baseDirectory"
|
||||
id="baseDirectory"
|
||||
bind:value={application.baseDirectory}
|
||||
placeholder="default: /"
|
||||
placeholder="{$t('forms.default')}: /"
|
||||
/>
|
||||
</div>
|
||||
{#if !notNodeDeployments.includes(application.buildPack)}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="flex-col">
|
||||
<label for="publishDirectory" class="pt-2 text-base font-bold text-stone-100"
|
||||
>Publish Directory</label
|
||||
>{$t('forms.publish_directory')}</label
|
||||
>
|
||||
<Explainer
|
||||
text="Directory containing all the assets for deployment. <br> For example: <span class='text-green-500 font-bold'>dist</span>,<span class='text-green-500 font-bold'>_site</span> or <span class='text-green-500 font-bold'>public</span>."
|
||||
/>
|
||||
<Explainer text={$t('application.publish_directory_explainer')} />
|
||||
</div>
|
||||
|
||||
<input
|
||||
@ -492,14 +505,14 @@
|
||||
name="publishDirectory"
|
||||
id="publishDirectory"
|
||||
bind:value={application.publishDirectory}
|
||||
placeholder=" default: /"
|
||||
placeholder=" {$t('forms.default')}: /"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex space-x-1 pb-5 font-bold">
|
||||
<div class="title">Features</div>
|
||||
<div class="title">{$t('application.features')}</div>
|
||||
</div>
|
||||
<div class="px-10 pb-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
@ -507,8 +520,8 @@
|
||||
isCenter={false}
|
||||
bind:setting={autodeploy}
|
||||
on:click={() => changeSettings('autodeploy')}
|
||||
title="Enable Automatic Deployment"
|
||||
description="Enable automatic deployment through webhooks."
|
||||
title={$t('application.enable_automatic_deployment')}
|
||||
description={$t('application.enable_auto_deploy_webhooks')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
@ -516,8 +529,8 @@
|
||||
isCenter={false}
|
||||
bind:setting={previews}
|
||||
on:click={() => changeSettings('previews')}
|
||||
title="Enable MR/PR Previews"
|
||||
description="Enable preview deployments from pull or merge requests."
|
||||
title={$t('application.enable_mr_pr_previews')}
|
||||
description={$t('application.enable_preview_deploy_mr_pr_requests')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
@ -525,8 +538,8 @@
|
||||
isCenter={false}
|
||||
bind:setting={debug}
|
||||
on:click={() => changeSettings('debug')}
|
||||
title="Debug Logs"
|
||||
description="Enable debug logs during build phase.<br><span class='text-red-500 font-bold'>Sensitive information</span> could be visible and saved in logs."
|
||||
title={$t('application.debug_logs')}
|
||||
description={$t('application.enable_debug_log_during_build')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@
|
||||
import LoadingLogs from '../_Loading.svelte';
|
||||
import { get } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
let logs = [];
|
||||
let loading = true;
|
||||
@ -84,7 +85,7 @@
|
||||
<LoadingLogs />
|
||||
{/if}
|
||||
{#if currentStatus === 'queued'}
|
||||
<div class="text-center font-bold text-xl">Queued and waiting for execution.</div>
|
||||
<div class="text-center font-bold text-xl">{$t('application.build.queued_waiting_exec')}</div>
|
||||
{:else}
|
||||
<div class="flex justify-end sticky top-0 p-2">
|
||||
<button
|
||||
|
@ -26,6 +26,7 @@
|
||||
import BuildLog from './_BuildLog.svelte';
|
||||
import { get } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let builds;
|
||||
export let application;
|
||||
@ -86,7 +87,9 @@
|
||||
|
||||
<div class="flex items-center space-x-2 p-5 px-6 font-bold">
|
||||
<div class="-mb-5 flex-col">
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">Build Logs</div>
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||
$t('application.build_logs')}
|
||||
</div>
|
||||
<span class="text-xs">{application.name} </span>
|
||||
</div>
|
||||
|
||||
@ -183,12 +186,14 @@
|
||||
|
||||
<div class="w-48 text-center text-xs">
|
||||
{#if build.status === 'running'}
|
||||
<div class="font-bold">Running</div>
|
||||
<div class="font-bold">{$t('application.build.running')}</div>
|
||||
{:else if build.status === 'queued'}
|
||||
<div class="font-bold">Queued</div>
|
||||
<div class="font-bold">{$t('application.build.queued')}</div>
|
||||
{:else}
|
||||
<div>{build.since}</div>
|
||||
<div>Finished in <span class="font-bold">{build.took}s</span></div>
|
||||
<div>
|
||||
{$t('application.build.finished_in')} <span class="font-bold">{build.took}s</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@ -197,7 +202,8 @@
|
||||
{#if !noMoreBuilds}
|
||||
{#if buildCount > 5}
|
||||
<div class="flex space-x-2">
|
||||
<button disabled={noMoreBuilds} class="w-full" on:click={loadMoreBuilds}>Load More</button
|
||||
<button disabled={noMoreBuilds} class="w-full" on:click={loadMoreBuilds}
|
||||
>{$t('application.build.load_more')}</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
@ -212,5 +218,5 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if buildCount === 0}
|
||||
<div class="text-center text-xl font-bold">No logs found</div>
|
||||
<div class="text-center text-xl font-bold">{$t('application.build.no_logs')}</div>
|
||||
{/if}
|
||||
|
@ -26,6 +26,7 @@
|
||||
import LoadingLogs from './_Loading.svelte';
|
||||
import { get } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
let loadLogsInterval = null;
|
||||
let allLogs = {
|
||||
@ -176,7 +177,7 @@
|
||||
</div>
|
||||
<div class="flex flex-row justify-center space-x-2 px-10 pt-6">
|
||||
{#if logs.length === 0}
|
||||
<div class="text-xl font-bold tracking-tighter">Waiting for the logs...</div>
|
||||
<div class="text-xl font-bold tracking-tighter">{$t('application.build.waiting_logs')}</div>
|
||||
{:else}
|
||||
<div class="relative w-full">
|
||||
<div class="text-right " />
|
||||
|
@ -30,6 +30,7 @@
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
async function refreshSecrets() {
|
||||
@ -134,10 +135,12 @@
|
||||
<table class="mx-auto border-separate text-left">
|
||||
<thead>
|
||||
<tr class="h-12">
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Value</th>
|
||||
<th scope="col" class="w-64 text-center">Need during buildtime?</th>
|
||||
<th scope="col" class="w-96 text-center">Action</th>
|
||||
<th scope="col">{$t('forms.name')}</th>
|
||||
<th scope="col">{$t('forms.value')}</th>
|
||||
<th scope="col" class="w-64 text-center"
|
||||
>{$t('application.preview.need_during_buildtime')}</th
|
||||
>
|
||||
<th scope="col" class="w-96 text-center">{$t('forms.action')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -171,13 +174,15 @@
|
||||
</a>
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="bg-coollabs hover:bg-coollabs-100" on:click={() => redeploy(container)}
|
||||
>Redeploy</button
|
||||
>{$t('application.preview.redeploy')}</button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
{:else}
|
||||
<div class="flex-col">
|
||||
<div class="text-center font-bold text-xl">No previews available</div>
|
||||
<div class="text-center font-bold text-xl">
|
||||
{$t('application.preview.no_previews_available')}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { saveSecret } from './utils';
|
||||
import pLimit from 'p-limit';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { t } from '$lib/translations';
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let batchSecrets = '';
|
||||
@ -38,11 +39,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<h2 class="title my-6 font-bold">Paste .env file</h2>
|
||||
<h2 class="title my-6 font-bold">{$t('application.secret__batch_dot_env')}</h2>
|
||||
<form on:submit|preventDefault={getValues} class="mb-12 w-full">
|
||||
<textarea bind:value={batchSecrets} class="mb-2 min-h-[200px] w-full" />
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500 disabled:text-white disabled:opacity-40"
|
||||
type="submit">Batch add secrets</button
|
||||
type="submit">{$t('application.batch_secrets')}</button
|
||||
>
|
||||
</form>
|
||||
|
@ -12,6 +12,7 @@
|
||||
import { del } from '$lib/api';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { saveSecret } from './utils';
|
||||
@ -104,7 +105,7 @@
|
||||
class:cursor-not-allowed={isPRMRSecret}
|
||||
class:cursor-pointer={!isPRMRSecret}
|
||||
>
|
||||
<span class="sr-only">Use isBuildSecret</span>
|
||||
<span class="sr-only">{$t('application.secrets.use_isbuildsecret')}</span>
|
||||
<span
|
||||
class="pointer-events-none relative inline-block h-5 w-5 transform rounded-full bg-white shadow transition duration-200 ease-in-out"
|
||||
class:translate-x-5={isBuildSecret}
|
||||
@ -145,17 +146,19 @@
|
||||
{#if isNewSecret}
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="bg-green-600 hover:bg-green-500" on:click={() => createSecret(true)}
|
||||
>Add</button
|
||||
>{$t('forms.add')}</button
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row justify-center space-x-2">
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="" on:click={() => createSecret(false)}>Set</button>
|
||||
<button class="" on:click={() => createSecret(false)}>{$t('forms.set')}</button>
|
||||
</div>
|
||||
{#if !isPRMRSecret}
|
||||
<div class="flex justify-center items-end">
|
||||
<button class="bg-red-600 hover:bg-red-500" on:click={removeSecret}>Remove</button>
|
||||
<button class="bg-red-600 hover:bg-red-500" on:click={removeSecret}
|
||||
>{$t('forms.remove')}</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -25,6 +25,7 @@
|
||||
import pLimit from 'p-limit';
|
||||
import Secret from './_Secret.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { t } from '$lib/translations';
|
||||
import { get } from '$lib/api';
|
||||
import { saveSecret } from './utils';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
@ -65,7 +66,9 @@
|
||||
|
||||
<div class="flex items-center space-x-2 p-5 px-6 font-bold">
|
||||
<div class="-mb-5 flex-col">
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">Secrets</div>
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||
{$t('application.secret')}
|
||||
</div>
|
||||
<span class="text-xs">{application.name} </span>
|
||||
</div>
|
||||
|
||||
@ -137,10 +140,12 @@
|
||||
<table class="mx-auto border-separate text-left">
|
||||
<thead>
|
||||
<tr class="h-12">
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Value</th>
|
||||
<th scope="col" class="w-64 text-center">Need during buildtime?</th>
|
||||
<th scope="col" class="w-96 text-center">Action</th>
|
||||
<th scope="col">{$t('forms.name')}</th>
|
||||
<th scope="col">{$t('forms.value')}</th>
|
||||
<th scope="col" class="w-64 text-center"
|
||||
>{$t('application.preview.need_during_buildtime')}</th
|
||||
>
|
||||
<th scope="col" class="w-96 text-center">{$t('forms.action')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
type Props = {
|
||||
isNew: boolean;
|
||||
@ -21,8 +22,8 @@ export async function saveSecret({
|
||||
isNewSecret,
|
||||
applicationId
|
||||
}: Props): Promise<void> {
|
||||
if (!name) return errorNotification('Name is required.');
|
||||
if (!value) return errorNotification('Value is required.');
|
||||
if (!name) return errorNotification(`${t.get('forms.name')} ${t.get('forms.is_required')}`);
|
||||
if (!value) return errorNotification(`${t.get('forms.value')} ${t.get('forms.is_required')}`);
|
||||
try {
|
||||
await post(`/applications/${applicationId}/secrets.json`, {
|
||||
name,
|
||||
|
@ -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) => {
|
||||
@ -14,8 +15,7 @@ export const post: RequestHandler = async (event) => {
|
||||
const isDouble = await db.checkDoubleBranch(branch, projectId);
|
||||
if (isDouble && autodeploy) {
|
||||
throw {
|
||||
message:
|
||||
'Cannot activate automatic deployments until only one application is defined for this repository / branch.'
|
||||
message: t.get('application.cant_activate_auto_deploy_without_repo')
|
||||
};
|
||||
}
|
||||
await db.setApplicationSettings({ id, debug, previews, dualCerts, autodeploy });
|
||||
|
@ -10,12 +10,13 @@
|
||||
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
async function saveStorage(newStorage = false) {
|
||||
try {
|
||||
if (!storage.path) return errorNotification('Path is required.');
|
||||
if (!storage.path) return errorNotification($t('application.storage.path_is_required'));
|
||||
storage.path = storage.path.startsWith('/') ? storage.path : `/${storage.path}`;
|
||||
storage.path = storage.path.endsWith('/') ? storage.path.slice(0, -1) : storage.path;
|
||||
storage.path.replace(/\/\//g, '/');
|
||||
@ -29,8 +30,8 @@
|
||||
storage.path = null;
|
||||
storage.id = null;
|
||||
}
|
||||
if (newStorage) toast.push('Storage saved.');
|
||||
else toast.push('Storage updated.');
|
||||
if (newStorage) toast.push($t('application.storage.storage_saved'));
|
||||
else toast.push($t('application.storage.storage_updated'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@ -39,7 +40,7 @@
|
||||
try {
|
||||
await del(`/applications/${id}/storage.json`, { path: storage.path });
|
||||
dispatch('refresh');
|
||||
toast.push('Storage deleted.');
|
||||
toast.push($t('application.storage.storage_deleted'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@ -57,16 +58,19 @@
|
||||
<td>
|
||||
{#if isNew}
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="bg-green-600 hover:bg-green-500" on:click={() => saveStorage(true)}>Add</button
|
||||
<button class="bg-green-600 hover:bg-green-500" on:click={() => saveStorage(true)}
|
||||
>{$t('forms.add')}</button
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row justify-center space-x-2">
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="" on:click={() => saveStorage(false)}>Set</button>
|
||||
<button class="" on:click={() => saveStorage(false)}>{$t('forms.set')}</button>
|
||||
</div>
|
||||
<div class="flex justify-center items-end">
|
||||
<button class="bg-red-600 hover:bg-red-500" on:click={removeStorage}>Remove</button>
|
||||
<button class="bg-red-600 hover:bg-red-500" on:click={removeStorage}
|
||||
>{$t('forms.remove')}</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -28,6 +28,7 @@
|
||||
import Storage from './_Storage.svelte';
|
||||
import { get } from '$lib/api';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
async function refreshStorage() {
|
||||
@ -111,15 +112,12 @@
|
||||
|
||||
<div class="mx-auto max-w-6xl rounded-xl px-6 pt-4">
|
||||
<div class="flex justify-center py-4 text-center">
|
||||
<Explainer
|
||||
customClass="w-full"
|
||||
text={'You can specify any folder that you want to be persistent across deployments. <br>This is useful for storing data such as a database (SQLite) or a cache.'}
|
||||
/>
|
||||
<Explainer customClass="w-full" text={$t('application.storage.persistent_storage_explainer')} />
|
||||
</div>
|
||||
<table class="mx-auto border-separate text-left">
|
||||
<thead>
|
||||
<tr class="h-12">
|
||||
<th scope="col">Path</th>
|
||||
<th scope="col">{$t('forms.path')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -3,6 +3,8 @@
|
||||
import { session } from '$app/stores';
|
||||
import { post } from '$lib/api';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from '$lib/translations';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
|
||||
import Rust from '$lib/components/svg/applications/Rust.svelte';
|
||||
import Nodejs from '$lib/components/svg/applications/Nodejs.svelte';
|
||||
@ -20,7 +22,6 @@
|
||||
import Astro from '$lib/components/svg/applications/Astro.svelte';
|
||||
import Eleventy from '$lib/components/svg/applications/Eleventy.svelte';
|
||||
import Deno from '$lib/components/svg/applications/Deno.svelte';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
|
||||
async function newApplication() {
|
||||
const { id } = await post('/applications/new', {});
|
||||
@ -39,7 +40,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl ">Applications</div>
|
||||
<div class="mr-4 text-2xl ">{$t('index.applications')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<div on:click={newApplication} class="add-icon cursor-pointer bg-green-600 hover:bg-green-500">
|
||||
<svg
|
||||
@ -61,7 +62,7 @@
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
{#if !applications || ownApplications.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">No applications found</div>
|
||||
<div class="text-center text-xl font-bold">{$t('application.no_applications_found')}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if ownApplications.length > 0 || otherApplications.length > 0}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script>
|
||||
export let database;
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
@ -8,34 +9,38 @@
|
||||
</div>
|
||||
<div class="space-y-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100">Default Database</label>
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100"
|
||||
>{$t('database.default_database')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
required
|
||||
readonly={database.defaultDatabase}
|
||||
disabled={database.defaultDatabase}
|
||||
placeholder="eg: mydb"
|
||||
placeholder="{$t('forms.eg')}: mydb"
|
||||
id="defaultDatabase"
|
||||
name="defaultDatabase"
|
||||
bind:value={database.defaultDatabase}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">User</label>
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">{$t('forms.user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="dbUser"
|
||||
name="dbUser"
|
||||
value={database.dbUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100">Password</label>
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="dbUserPassword"
|
||||
name="dbUserPassword"
|
||||
@ -43,22 +48,24 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">Root User</label>
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">{$t('forms.root_user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="rootUser"
|
||||
name="rootUser"
|
||||
value={database.rootUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100">Root's Password</label>
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.roots_password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="rootUserPassword"
|
||||
name="rootUserPassword"
|
||||
|
@ -18,6 +18,7 @@
|
||||
import { post } from '$lib/api';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
|
||||
@ -59,7 +60,7 @@
|
||||
: window.location.hostname
|
||||
: database.id
|
||||
}:${isPublic ? database.publicPort : privatePort}/${databaseDefault}`
|
||||
: 'Loading...');
|
||||
: $t('forms.loading');
|
||||
}
|
||||
|
||||
async function changeSettings(name) {
|
||||
@ -110,20 +111,20 @@
|
||||
<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 font-bold">
|
||||
<div class="title">General</div>
|
||||
<div class="title">{$t('general')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-purple-600={!loading}
|
||||
class:hover:bg-purple-500={!loading}
|
||||
disabled={loading}>{loading ? 'Saving...' : 'Save'}</button
|
||||
disabled={loading}>{loading ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
name="name"
|
||||
@ -133,7 +134,9 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="destination" class="text-base font-bold text-stone-100">Destination</label>
|
||||
<label for="destination" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.destination')}</label
|
||||
>
|
||||
{#if database.destinationDockerId}
|
||||
<div class="no-underline">
|
||||
<input
|
||||
@ -148,16 +151,17 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="version" class="text-base font-bold text-stone-100">Version</label>
|
||||
<label for="version" class="text-base font-bold text-stone-100">{$t('forms.version')}</label
|
||||
>
|
||||
<input value={database.version} readonly disabled class="bg-transparent " />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row gap-2 px-10 pt-2">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="host" class="text-base font-bold text-stone-100">Host</label>
|
||||
<label for="host" class="text-base font-bold text-stone-100">{$t('forms.host')}</label>
|
||||
<CopyPasswordField
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField={false}
|
||||
readonly
|
||||
disabled
|
||||
@ -167,9 +171,10 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="publicPort" class="text-base font-bold text-stone-100">Port</label>
|
||||
<label for="publicPort" class="text-base font-bold text-stone-100">{$t('forms.port')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
placeholder="Generated automatically after set to public"
|
||||
placeholder={$t('database.generated_automatically_after_set_to_public')}
|
||||
id="publicPort"
|
||||
readonly
|
||||
disabled
|
||||
@ -191,10 +196,12 @@
|
||||
<CouchDb {database} />
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center px-10 pb-8">
|
||||
<label for="url" class="text-base font-bold text-stone-100">Connection String</label>
|
||||
<label for="url" class="text-base font-bold text-stone-100"
|
||||
>{$t('database.connection_string')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
textarea={true}
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField={false}
|
||||
id="url"
|
||||
name="url"
|
||||
@ -206,7 +213,7 @@
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex space-x-1 pb-5 font-bold">
|
||||
<div class="title">Features</div>
|
||||
<div class="title">{$t('application.features')}</div>
|
||||
</div>
|
||||
<div class="px-10 pb-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
@ -214,8 +221,8 @@
|
||||
loading={publicLoading}
|
||||
bind:setting={isPublic}
|
||||
on:click={() => changeSettings('isPublic')}
|
||||
title="Set it public"
|
||||
description="Your database will be reachable over the internet. <br>Take security seriously in this case!"
|
||||
title={$t('database.set_public')}
|
||||
description={$t('database.warning_database_public')}
|
||||
disabled={!isRunning}
|
||||
/>
|
||||
</div>
|
||||
@ -224,8 +231,8 @@
|
||||
<Setting
|
||||
bind:setting={appendOnly}
|
||||
on:click={() => changeSettings('appendOnly')}
|
||||
title="Change append only mode"
|
||||
description="Useful if you would like to restore redis data from a backup.<br><span class='font-bold text-white'>Database restart is required.</span>"
|
||||
title={$t('database.change_append_only_mode')}
|
||||
description={$t('database.warning_append_only')}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -3,6 +3,7 @@
|
||||
export let isRunning;
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
@ -10,9 +11,9 @@
|
||||
</div>
|
||||
<div class="space-y-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">Root User</label>
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">{$t('forms.root_user')}</label>
|
||||
<CopyPasswordField
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="rootUser"
|
||||
readonly
|
||||
disabled
|
||||
@ -21,11 +22,13 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100">Root's Password</label>
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.roots_password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField={true}
|
||||
id="rootUserPassword"
|
||||
name="rootUserPassword"
|
||||
|
@ -3,6 +3,7 @@
|
||||
export let isRunning;
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
@ -10,34 +11,38 @@
|
||||
</div>
|
||||
<div class="space-y-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100">Default Database</label>
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100"
|
||||
>{$t('database.default_database')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
required
|
||||
readonly={database.defaultDatabase}
|
||||
disabled={database.defaultDatabase}
|
||||
placeholder="eg: mydb"
|
||||
placeholder="{$t('forms.eg')}: mydb"
|
||||
id="defaultDatabase"
|
||||
name="defaultDatabase"
|
||||
bind:value={database.defaultDatabase}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">User</label>
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">{$t('forms.user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="dbUser"
|
||||
name="dbUser"
|
||||
value={database.dbUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100">Password</label>
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="dbUserPassword"
|
||||
name="dbUserPassword"
|
||||
@ -46,22 +51,24 @@
|
||||
<Explainer text="Could be changed while the database is running." />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">Root User</label>
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">{$t('forms.root_user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="rootUser"
|
||||
name="rootUser"
|
||||
value={database.rootUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100">Root's Password</label>
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.roots_password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="rootUserPassword"
|
||||
name="rootUserPassword"
|
||||
|
@ -3,6 +3,7 @@
|
||||
export let isRunning;
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
@ -10,12 +11,14 @@
|
||||
</div>
|
||||
<div class="space-y-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100">Default Database</label>
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100"
|
||||
>{$t('database.default_database')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
required
|
||||
readonly={database.defaultDatabase}
|
||||
disabled={database.defaultDatabase}
|
||||
placeholder="eg: mydb"
|
||||
placeholder="{$t('forms.eg')}: mydb"
|
||||
id="defaultDatabase"
|
||||
name="defaultDatabase"
|
||||
bind:value={database.defaultDatabase}
|
||||
@ -37,22 +40,24 @@
|
||||
<Explainer text="Could be changed while the database is running." />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">User</label>
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">{$t('forms.user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="dbUser"
|
||||
name="dbUser"
|
||||
value={database.dbUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100">Password</label>
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="dbUserPassword"
|
||||
name="dbUserPassword"
|
||||
|
@ -3,6 +3,7 @@
|
||||
export let isRunning;
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
@ -10,11 +11,13 @@
|
||||
</div>
|
||||
<div class="space-y-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100">Password</label>
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="dbUserPassword"
|
||||
name="dbUserPassword"
|
||||
|
@ -63,6 +63,7 @@
|
||||
import Loading from '$lib/components/Loading.svelte';
|
||||
import { del, post } from '$lib/api';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let database;
|
||||
export let isRunning;
|
||||
@ -83,7 +84,7 @@
|
||||
}
|
||||
}
|
||||
async function stopDatabase() {
|
||||
const sure = confirm(`Are you sure you would like to stop '${database.name}'?`);
|
||||
const sure = confirm($t('database.confirm_stop', { name: database.name }));
|
||||
if (sure) {
|
||||
loading = true;
|
||||
try {
|
||||
@ -113,13 +114,13 @@
|
||||
{#if isRunning}
|
||||
<button
|
||||
on:click={stopDatabase}
|
||||
title="Stop database"
|
||||
title={$t('database.stop_database')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Stop database'
|
||||
: 'You do not have permission to stop the database.'}
|
||||
? $t('database.stop_database')
|
||||
: $t('database.permission_denied_stop_database')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -139,13 +140,13 @@
|
||||
{:else}
|
||||
<button
|
||||
on:click={startDatabase}
|
||||
title="Start database"
|
||||
title={$t('database.start_database')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Start database'
|
||||
: 'You do not have permission to start the database.'}
|
||||
? $t('database.start_database')
|
||||
: $t('database.permission_denied_start_database')}
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
@ -164,14 +165,14 @@
|
||||
{/if}
|
||||
<button
|
||||
on:click={deleteDatabase}
|
||||
title="Delete Database"
|
||||
title={$t('database.delete_database')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class:hover:text-red-500={$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Delete Database'
|
||||
: 'You do not have permission to delete a Database'}><DeleteIcon /></button
|
||||
? $t('database.delete_database')
|
||||
: $t('database.permission_denied_delete_database')}><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</nav>
|
||||
|
@ -34,6 +34,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -52,12 +53,14 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Configure Destination</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">
|
||||
{$t('application.configuration.configure_destination')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
{#if !destinations || destinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2">No configurable Destination found</div>
|
||||
<div class="pb-2">{$t('application.configuration.no_configurable_destination')}</div>
|
||||
<div class="flex justify-center">
|
||||
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
|
@ -42,6 +42,7 @@
|
||||
import Redis from '$lib/components/svg/databases/Redis.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
async function handleSubmit(type) {
|
||||
try {
|
||||
await post(`/databases/${id}/configuration/type.json`, { type });
|
||||
@ -53,7 +54,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Database type</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('database.select_database_type')}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center">
|
||||
|
@ -31,6 +31,7 @@
|
||||
import { enhance, errorNotification } from '$lib/form';
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -47,7 +48,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Database version</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('database.select_database_version')}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center">
|
||||
|
@ -9,6 +9,7 @@
|
||||
import { post } from '$lib/api';
|
||||
import { goto } from '$app/navigation';
|
||||
import { session } from '$app/stores';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
async function newDatabase() {
|
||||
const { id } = await post('/databases/new', {});
|
||||
@ -27,7 +28,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Databases</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.databases')}</div>
|
||||
<div on:click={newDatabase} class="add-icon cursor-pointer bg-purple-600 hover:bg-purple-500">
|
||||
<svg
|
||||
class="w-6"
|
||||
@ -48,7 +49,7 @@
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
{#if !databases || ownDatabases.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">No databases found</div>
|
||||
<div class="text-center text-xl font-bold">{$t('database.no_databases_found')}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if ownDatabases.length > 0 || otherDatabases.length > 0}
|
||||
@ -78,7 +79,7 @@
|
||||
{/if}
|
||||
{#if !database.type}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@
|
||||
export let app;
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
let loading = true;
|
||||
async function checkApp() {
|
||||
@ -58,20 +59,20 @@
|
||||
<div class="box-selection hover:border-transparent hover:bg-coolgray-200">
|
||||
<div class="truncate pb-2 text-center text-xl font-bold">{app.domain}</div>
|
||||
{#if loading}
|
||||
<div class="w-full text-center font-bold">Loading...</div>
|
||||
<div class="w-full text-center font-bold">{$t('forms.loading')}</div>
|
||||
{:else if app.foundByDomain}
|
||||
<div class="w-full bg-coolgray-200 text-xs">
|
||||
<span class="text-red-500">Domain</span> already used for
|
||||
{@html $t('forms.already_used_for', { type: 'Domains' })}
|
||||
<span class="text-red-500">{app.foundName}</span>
|
||||
</div>
|
||||
{:else if app.foundByRepository}
|
||||
<div class="w-full bg-coolgray-200 text-xs">
|
||||
<span class="text-red-500">Repository</span> already used for
|
||||
{@html $t('forms.already_used_for', { type: 'Repository' })}
|
||||
<span class="text-red-500">{app.foundName}</span>
|
||||
</div>
|
||||
{:else}
|
||||
<button class="bg-green-600 hover:bg-green-500 w-full" on:click={addToCoolify}
|
||||
>Add to Coolify</button
|
||||
>{$t('destination.add_to_coolify')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@
|
||||
import { post } from '$lib/api';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
|
||||
let loading = false;
|
||||
@ -85,7 +86,7 @@
|
||||
async function stopProxy() {
|
||||
try {
|
||||
await post(`/destinations/${id}/stop.json`, { engine: destination.engine });
|
||||
return toast.push('Coolify Proxy stopped!');
|
||||
return toast.push($t('destination.coolify_proxy_stopped'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@ -93,19 +94,17 @@
|
||||
async function startProxy() {
|
||||
try {
|
||||
await post(`/destinations/${id}/start.json`, { engine: destination.engine });
|
||||
return toast.push('Coolify Proxy started!');
|
||||
return toast.push($t('destination.coolify_proxy_started'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function forceRestartProxy() {
|
||||
const sure = confirm(
|
||||
'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.'
|
||||
);
|
||||
const sure = confirm($t('destination.confirm_restart_proxy'));
|
||||
if (sure) {
|
||||
try {
|
||||
restarting = true;
|
||||
toast.push('Coolify Proxy restarting...');
|
||||
toast.push($t('destination.coolify_proxy_restarting'));
|
||||
await post(`/destinations/${id}/restart.json`, {
|
||||
engine: destination.engine,
|
||||
fqdn: settings.fqdn
|
||||
@ -123,7 +122,7 @@
|
||||
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex space-x-1 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
<div class="title font-bold">{$t('forms.configuration')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<button
|
||||
type="submit"
|
||||
@ -131,13 +130,15 @@
|
||||
class:bg-sky-600={!loading}
|
||||
class:hover:bg-sky-500={!loading}
|
||||
disabled={loading}
|
||||
>{loading ? 'Saving...' : 'Save'}
|
||||
>{loading ? $t('forms.saving') : $t('forms.save')}
|
||||
</button>
|
||||
<button
|
||||
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
||||
disabled={restarting}
|
||||
on:click|preventDefault={forceRestartProxy}
|
||||
>{restarting ? 'Restarting... please wait...' : 'Force restart proxy'}</button
|
||||
>{restarting
|
||||
? $t('destination.restarting_please_wait')
|
||||
: $t('destination.force_restart_proxy')}</button
|
||||
>
|
||||
{/if}
|
||||
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
|
||||
@ -145,10 +146,10 @@
|
||||
> -->
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10 ">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input
|
||||
name="name"
|
||||
placeholder="name"
|
||||
placeholder={$t('forms.name')}
|
||||
disabled={!$session.isAdmin}
|
||||
readonly={!$session.isAdmin}
|
||||
bind:value={destination.name}
|
||||
@ -156,13 +157,13 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="engine" class="text-base font-bold text-stone-100">Engine</label>
|
||||
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
|
||||
<CopyPasswordField
|
||||
id="engine"
|
||||
readonly
|
||||
disabled
|
||||
name="engine"
|
||||
placeholder="eg: /var/run/docker.sock"
|
||||
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
|
||||
value={destination.engine}
|
||||
/>
|
||||
</div>
|
||||
@ -171,13 +172,13 @@
|
||||
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
|
||||
</div> -->
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||
<CopyPasswordField
|
||||
id="network"
|
||||
readonly
|
||||
disabled
|
||||
name="network"
|
||||
placeholder="default: coolify"
|
||||
placeholder="{$t('forms.default')}: coolify"
|
||||
value={destination.network}
|
||||
/>
|
||||
</div>
|
||||
@ -188,7 +189,7 @@
|
||||
disabled={cannotDisable}
|
||||
bind:setting={destination.isCoolifyProxyUsed}
|
||||
on:click={changeProxySetting}
|
||||
title="Use Coolify Proxy?"
|
||||
title={$t('destination.use_coolify_proxy')}
|
||||
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration. Databases will have their own proxy. <br><br>${
|
||||
cannotDisable
|
||||
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
|
||||
|
@ -11,6 +11,7 @@
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { generateRemoteEngine } from '$lib/components/common';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
|
||||
// let scannedApps = [];
|
||||
@ -90,7 +91,7 @@
|
||||
try {
|
||||
const engine = generateRemoteEngine(destination);
|
||||
await post(`/destinations/${id}/stop.json`, { engine });
|
||||
return toast.push('Coolify Proxy stopped!');
|
||||
return toast.push($t('destination.coolify_proxy_stopped'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@ -99,19 +100,17 @@
|
||||
try {
|
||||
const engine = generateRemoteEngine(destination);
|
||||
await post(`/destinations/${id}/start.json`, { engine });
|
||||
return toast.push('Coolify Proxy started!');
|
||||
return toast.push($t('destination.coolify_proxy_started'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function forceRestartProxy() {
|
||||
const sure = confirm(
|
||||
'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.'
|
||||
);
|
||||
const sure = confirm($t('destination.confirm_restart_proxy'));
|
||||
if (sure) {
|
||||
try {
|
||||
restarting = true;
|
||||
toast.push('Coolify Proxy restarting...');
|
||||
toast.push($t('destination.coolify_proxy_restarting'));
|
||||
await post(`/destinations/${id}/restart.json`, {
|
||||
engine: destination.engine,
|
||||
fqdn: settings.fqdn
|
||||
@ -127,7 +126,7 @@
|
||||
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex space-x-1 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
<div class="title font-bold">{$t('forms.configuration')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<button
|
||||
type="submit"
|
||||
@ -135,13 +134,15 @@
|
||||
class:bg-sky-600={!loading}
|
||||
class:hover:bg-sky-500={!loading}
|
||||
disabled={loading}
|
||||
>{loading ? 'Saving...' : 'Save'}
|
||||
>{loading ? $t('forms.saving') : $t('forms.save')}
|
||||
</button>
|
||||
<button
|
||||
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
||||
disabled={restarting}
|
||||
on:click|preventDefault={forceRestartProxy}
|
||||
>{restarting ? 'Restarting... please wait...' : 'Force restart proxy'}</button
|
||||
>{restarting
|
||||
? $t('destination.restarting_please_wait')
|
||||
: $t('destination.force_restart_proxy')}</button
|
||||
>
|
||||
{/if}
|
||||
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
|
||||
@ -149,10 +150,10 @@
|
||||
> -->
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10 ">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input
|
||||
name="name"
|
||||
placeholder="name"
|
||||
placeholder={$t('forms.name')}
|
||||
disabled={!$session.isAdmin}
|
||||
readonly={!$session.isAdmin}
|
||||
bind:value={destination.name}
|
||||
@ -160,13 +161,13 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="engine" class="text-base font-bold text-stone-100">Engine</label>
|
||||
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
|
||||
<CopyPasswordField
|
||||
id="engine"
|
||||
readonly
|
||||
disabled
|
||||
name="engine"
|
||||
placeholder="eg: /var/run/docker.sock"
|
||||
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
|
||||
value={destination.engine}
|
||||
/>
|
||||
</div>
|
||||
@ -175,13 +176,13 @@
|
||||
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
|
||||
</div> -->
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||
<CopyPasswordField
|
||||
id="network"
|
||||
readonly
|
||||
disabled
|
||||
name="network"
|
||||
placeholder="default: coolify"
|
||||
placeholder="{$t('forms.default')}: coolify"
|
||||
value={destination.network}
|
||||
/>
|
||||
</div>
|
||||
@ -190,7 +191,7 @@
|
||||
disabled={cannotDisable}
|
||||
bind:setting={destination.isCoolifyProxyUsed}
|
||||
on:click={changeProxySetting}
|
||||
title="Use Coolify Proxy?"
|
||||
title={$t('destination.use_coolify_proxy')}
|
||||
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration. Databases will have their own proxy. <br><br>${
|
||||
cannotDisable
|
||||
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
|
||||
|
@ -37,10 +37,11 @@
|
||||
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
|
||||
import { del } from '$lib/api';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let destination;
|
||||
async function deleteDestination(destination) {
|
||||
const sure = confirm(`Are you sure you would like to delete '${destination.name}'?`);
|
||||
const sure = confirm($t('application.confirm_to_delete', { name: destination.name }));
|
||||
if (sure) {
|
||||
try {
|
||||
await del(`/destinations/${destination.id}.json`, { id: destination.id });
|
||||
@ -55,14 +56,14 @@
|
||||
<nav class="nav-side">
|
||||
<button
|
||||
on:click={() => deleteDestination(destination)}
|
||||
title="Delete Destination"
|
||||
title={$t('destination.delete_destination')}
|
||||
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 Destination'
|
||||
: 'You do not have permission to delete this destination'}><DeleteIcon /></button
|
||||
? $t('destination.delete_destination')
|
||||
: $t('destination.permission_denied_delete_destination')}><DeleteIcon /></button
|
||||
>
|
||||
</nav>
|
||||
<slot />
|
||||
|
@ -36,10 +36,11 @@
|
||||
import type Prisma from '@prisma/client';
|
||||
import LocalDocker from './_LocalDocker.svelte';
|
||||
import RemoteDocker from './_RemoteDocker.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 text-2xl font-bold">
|
||||
<div class="tracking-tight">Destination</div>
|
||||
<div class="tracking-tight">{$t('application.destination')}</div>
|
||||
<span class="arrow-right-applications px-1">></span>
|
||||
<span class="pr-2">{destination.name}</span>
|
||||
</div>
|
||||
|
@ -23,6 +23,8 @@
|
||||
import type Prisma from '@prisma/client';
|
||||
|
||||
import { session } from '$app/stores';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let destinations: Prisma.DestinationDocker[];
|
||||
const ownDestinations = destinations.filter((destination) => {
|
||||
if (destination.teams[0].id === $session.teamId) {
|
||||
@ -37,7 +39,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Destinations</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.destinations')}</div>
|
||||
{#if $session.isAdmin}
|
||||
<a href="/new/destination" class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
@ -59,7 +61,7 @@
|
||||
<div class="flex justify-center">
|
||||
{#if !destinations || ownDestinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">No destination found</div>
|
||||
<div class="text-center text-xl font-bold">{$t('destination.no_destination_found')}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if ownDestinations.length > 0 || otherDestinations.length > 0}
|
||||
|
@ -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">Name</label>
|
||||
<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>
|
||||
|
@ -20,6 +20,8 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let applicationsCount: number;
|
||||
export let sourcesCount: number;
|
||||
export let destinationsCount: number;
|
||||
@ -29,7 +31,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Dashboard</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.dashboard')}</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 pb-12 tracking-tight sm:pb-16">
|
||||
@ -44,7 +46,7 @@
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-green-500 no-underline transition duration-150 hover:bg-green-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
Applications
|
||||
{$t('index.applications')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{applicationsCount}
|
||||
@ -56,7 +58,7 @@
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-sky-500 no-underline transition duration-150 hover:bg-sky-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
Destinations
|
||||
{$t('index.destinations')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{destinationsCount}
|
||||
@ -68,7 +70,7 @@
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-orange-500 no-underline transition duration-150 hover:bg-orange-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
Git Sources
|
||||
{$t('index.git_sources')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{sourcesCount}
|
||||
@ -79,7 +81,9 @@
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-purple-500 no-underline transition duration-150 hover:bg-purple-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">Databases</dt>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.databases')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">{databasesCount}</dd>
|
||||
</a>
|
||||
<a
|
||||
@ -87,7 +91,9 @@
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-pink-500 no-underline transition duration-150 hover:bg-pink-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">Services</dt>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.services')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">{servicesCount}</dd>
|
||||
</a>
|
||||
|
||||
@ -96,7 +102,9 @@
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-cyan-500 no-underline transition duration-150 hover:bg-cyan-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">Teams</dt>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.teams')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{teamsCount}
|
||||
</dd>
|
||||
|
@ -4,6 +4,7 @@
|
||||
import { session } from '$app/stores';
|
||||
import { post } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
import { onMount } from 'svelte';
|
||||
let loading = false;
|
||||
let emailEl;
|
||||
@ -37,9 +38,13 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelt:head>
|
||||
<title>{$t('login.login')}</title>
|
||||
</svelt:head>
|
||||
|
||||
<div class="flex h-screen flex-col items-center justify-center">
|
||||
{#if $session.userId}
|
||||
<div class="flex justify-center px-4 text-xl font-bold">Already logged in...</div>
|
||||
<div class="flex justify-center px-4 text-xl font-bold">{$t('login.already_logged_in')}</div>
|
||||
{:else}
|
||||
<div class="flex justify-center px-4">
|
||||
<form on:submit|preventDefault={handleSubmit} class="flex flex-col py-4 space-y-2">
|
||||
@ -55,7 +60,7 @@
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
placeholder={$t('forms.email')}
|
||||
autocomplete="off"
|
||||
required
|
||||
bind:this={emailEl}
|
||||
@ -64,7 +69,7 @@
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
placeholder={$t('forms.password')}
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
@ -76,12 +81,14 @@
|
||||
class="hover:opacity-90 text-white"
|
||||
class:bg-transparent={loading}
|
||||
class:text-stone-600={loading}
|
||||
class:bg-coollabs={!loading}>{loading ? 'Authenticating...' : 'Login'}</button
|
||||
class:bg-coollabs={!loading}
|
||||
>{loading ? $t('login.authenticating') : $t('login.login')}</button
|
||||
>
|
||||
|
||||
<button
|
||||
on:click|preventDefault={() => goto('/register')}
|
||||
class="bg-transparent hover:bg-coolgray-300 text-white ">Register</button
|
||||
class="bg-transparent hover:bg-coolgray-300 text-white "
|
||||
>{$t('register.register')}</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -7,6 +7,7 @@
|
||||
import { post } from '$lib/api';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
let loading = false;
|
||||
|
||||
@ -28,7 +29,7 @@
|
||||
<div class="flex justify-center px-6 pb-8">
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex items-center space-x-2 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
<div class="title font-bold">{$t('forms.configuration')}</div>
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-sky-600={!loading}
|
||||
@ -36,36 +37,41 @@
|
||||
disabled={loading}
|
||||
>{loading
|
||||
? payload.isCoolifyProxyUsed
|
||||
? 'Saving and configuring proxy...'
|
||||
: 'Saving...'
|
||||
: 'Save'}</button
|
||||
? $t('destination.new.saving_and_configuring_proxy')
|
||||
: $t('forms.saving')
|
||||
: $t('forms.save')}</button
|
||||
>
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-10">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<input required name="name" placeholder="name" bind:value={payload.name} />
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input required name="name" placeholder={$t('forms.name')} bind:value={payload.name} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="engine" class="text-base font-bold text-stone-100">Engine</label>
|
||||
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
|
||||
<input
|
||||
required
|
||||
name="engine"
|
||||
placeholder="eg: /var/run/docker.sock"
|
||||
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
|
||||
bind:value={payload.engine}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<input required name="network" placeholder="default: coolify" bind:value={payload.network} />
|
||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||
<input
|
||||
required
|
||||
name="network"
|
||||
placeholder="{$t('forms.default')}: coolify"
|
||||
bind:value={payload.network}
|
||||
/>
|
||||
</div>
|
||||
{#if $session.teamId === '0'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
bind:setting={payload.isCoolifyProxyUsed}
|
||||
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
|
||||
title="Use Coolify Proxy?"
|
||||
description="This will install a proxy on the destination to allow you to access your applications and services without any manual configuration (recommended for Docker).<br><br>Databases will have their own proxy."
|
||||
title={$t('destination.use_coolify_proxy')}
|
||||
description={$t('destination.new.install_proxy')}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -7,6 +7,7 @@
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
let loading = false;
|
||||
|
||||
@ -25,7 +26,7 @@
|
||||
<div class="flex justify-center px-6 pb-8">
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex items-center space-x-2 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
<div class="title font-bold">{$t('forms.configuration')}</div>
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-sky-600={!loading}
|
||||
@ -33,57 +34,66 @@
|
||||
disabled={loading}
|
||||
>{loading
|
||||
? payload.isCoolifyProxyUsed
|
||||
? 'Saving and configuring proxy...'
|
||||
: 'Saving...'
|
||||
: 'Save'}</button
|
||||
? $t('destination.new.saving_and_configuring_proxy')
|
||||
: $t('forms.saving')
|
||||
: $t('forms.save')}</button
|
||||
>
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-10">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<input required name="name" placeholder="name" bind:value={payload.name} />
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input required name="name" placeholder={$t('forms.name')} bind:value={payload.name} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="ipAddress" class="text-base font-bold text-stone-100">IP Address</label>
|
||||
<label for="ipAddress" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.ip_address')}</label
|
||||
>
|
||||
<input
|
||||
required
|
||||
name="ipAddress"
|
||||
placeholder="eg: 192.168..."
|
||||
placeholder="{$t('forms.eg')}: 192.168..."
|
||||
bind:value={payload.ipAddress}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="user" class="text-base font-bold text-stone-100">User</label>
|
||||
<input required name="user" placeholder="eg: root" bind:value={payload.user} />
|
||||
<label for="user" class="text-base font-bold text-stone-100">{$t('forms.user')}</label>
|
||||
<input required name="user" placeholder="{$t('forms.eg')}: root" bind:value={payload.user} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="port" class="text-base font-bold text-stone-100">Port</label>
|
||||
<input required name="port" placeholder="eg: 22" bind:value={payload.port} />
|
||||
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
||||
<input required name="port" placeholder="{$t('forms.eg')}: 22" bind:value={payload.port} />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="sshPrivateKey" class="text-base font-bold text-stone-100">SSH Private Key</label>
|
||||
<label for="sshPrivateKey" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.ssh_private_key')}</label
|
||||
>
|
||||
<textarea
|
||||
rows="10"
|
||||
class="resize-none"
|
||||
required
|
||||
name="sshPrivateKey"
|
||||
placeholder="eg: -----BEGIN...."
|
||||
placeholder="{$t('forms.eg')}: -----BEGIN...."
|
||||
bind:value={payload.sshPrivateKey}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<input required name="network" placeholder="default: coolify" bind:value={payload.network} />
|
||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||
<input
|
||||
required
|
||||
name="network"
|
||||
placeholder="{$t('forms.default')}: coolify"
|
||||
bind:value={payload.network}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
bind:setting={payload.isCoolifyProxyUsed}
|
||||
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
|
||||
title="Use Coolify Proxy?"
|
||||
description="This will install a proxy on the destination to allow you to access your applications and services without any manual configuration (recommended for Docker).<br><br>Databases will have their own proxy."
|
||||
title={$t('destination.use_coolify_proxy')}
|
||||
description={$t('destination.new.install_proxy')}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import { isDockerNetworkExists, ErrorHandler } from '$lib/database';
|
||||
import { t } from '$lib/translations';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -9,9 +10,10 @@ export const post: RequestHandler = async (event) => {
|
||||
const { network } = await event.request.json();
|
||||
try {
|
||||
const found = await isDockerNetworkExists({ network });
|
||||
|
||||
if (found) {
|
||||
throw {
|
||||
error: `Network ${network} already configured for another team!`
|
||||
error: t.get('destination.new_error_network_already_exists', { network: network })
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
@ -2,6 +2,7 @@
|
||||
import LocalDocker from './_LocalDocker.svelte';
|
||||
import cuid from 'cuid';
|
||||
import RemoteDocker from './_RemoteDocker.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
let payload = {};
|
||||
let selected = 'localDocker';
|
||||
|
||||
@ -10,7 +11,7 @@
|
||||
switch (type) {
|
||||
case 'localDocker':
|
||||
payload = {
|
||||
name: 'Local Docker',
|
||||
name: t.get('sources.local_docker'),
|
||||
engine: '/var/run/docker.sock',
|
||||
remoteEngine: false,
|
||||
network: cuid(),
|
||||
@ -19,7 +20,7 @@
|
||||
break;
|
||||
case 'remoteDocker':
|
||||
payload = {
|
||||
name: 'Remote Docker',
|
||||
name: $t('sources.remote_docker'),
|
||||
remoteEngine: true,
|
||||
ipAddress: null,
|
||||
user: 'root',
|
||||
@ -36,12 +37,14 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Add New Destination</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('destination.new.add_new_destination')}</div>
|
||||
</div>
|
||||
<div class="flex-col space-y-2 pb-10 text-center">
|
||||
<div class="text-xl font-bold text-white">Predefined destinations</div>
|
||||
<div class="text-xl font-bold text-white">{$t('destination.new.predefined_destinations')}</div>
|
||||
<div class="flex justify-center space-x-2">
|
||||
<button class="w-32" on:click={() => setPredefined('localDocker')}>Local Docker</button>
|
||||
<button class="w-32" on:click={() => setPredefined('localDocker')}
|
||||
>{$t('sources.local_docker')}</button
|
||||
>
|
||||
<!-- <button class="w-32" on:click={() => setPredefined('remoteDocker')}>Remote Docker</button> -->
|
||||
<button class="w-32" on:click={() => setPredefined('kubernetes')}>Kubernetes</button>
|
||||
</div>
|
||||
@ -51,5 +54,5 @@
|
||||
{:else if selected === 'remoteDocker'}
|
||||
<RemoteDocker {payload} />
|
||||
{:else}
|
||||
<div class="text-center font-bold text-4xl py-10">Not implemented yet</div>
|
||||
<div class="text-center font-bold text-4xl py-10">{$t('index.not_implemented_yet')}</div>
|
||||
{/if}
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { session } from '$app/stores';
|
||||
import { post } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let loading = false;
|
||||
@ -23,7 +24,7 @@
|
||||
if (loading) return;
|
||||
|
||||
if (password !== passwordCheck) {
|
||||
return errorNotification('Passwords do not match.');
|
||||
return errorNotification($t('forms.passwords_not_match'));
|
||||
}
|
||||
loading = true;
|
||||
try {
|
||||
@ -60,7 +61,7 @@
|
||||
</div>
|
||||
<div class="flex h-screen flex-col items-center justify-center">
|
||||
{#if $session.userId}
|
||||
<div class="flex justify-center px-4 text-xl font-bold">Already logged in...</div>
|
||||
<div class="flex justify-center px-4 text-xl font-bold">{$t('login.already_logged_in')}</div>
|
||||
{:else}
|
||||
<div class="flex justify-center px-4">
|
||||
<form on:submit|preventDefault={handleSubmit} class="flex flex-col py-4 space-y-2">
|
||||
@ -76,7 +77,7 @@
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
placeholder={$t('forms.email')}
|
||||
autocomplete="off"
|
||||
required
|
||||
bind:this={emailEl}
|
||||
@ -85,14 +86,14 @@
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
placeholder={$t('forms.password')}
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
name="passwordCheck"
|
||||
placeholder="Password again"
|
||||
placeholder={$t('forms.password_again')}
|
||||
bind:value={passwordCheck}
|
||||
required
|
||||
/>
|
||||
@ -104,17 +105,15 @@
|
||||
disabled={loading}
|
||||
class:bg-transparent={loading}
|
||||
class:text-stone-600={loading}
|
||||
class:bg-coollabs={!loading}>{loading ? 'Registering...' : 'Register'}</button
|
||||
class:bg-coollabs={!loading}
|
||||
>{loading ? $t('register.registering') : $t('register.register')}</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{#if userCount === 0}
|
||||
<div class="pt-5">
|
||||
You are registering the first user. It will be the administrator of your Coolify instance.
|
||||
<br />
|
||||
It will take a while, because Coolify will configure itself, the proxy and other docker related
|
||||
stuff.
|
||||
{$t('register.first_user')}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
export let readOnly;
|
||||
export let service;
|
||||
</script>
|
||||
@ -8,19 +9,19 @@
|
||||
<div class="title">Ghost</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="email">Default Email Address</label>
|
||||
<label for="email">{$t('forms.default_email_address')}</label>
|
||||
<input
|
||||
name="email"
|
||||
id="email"
|
||||
disabled
|
||||
readonly
|
||||
placeholder="Email address"
|
||||
placeholder={$t('forms.email')}
|
||||
value={service.ghost.defaultEmail}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="defaultPassword">Default Password</label>
|
||||
<label for="defaultPassword">{$t('forms.default_password')}</label>
|
||||
<CopyPasswordField
|
||||
id="defaultPassword"
|
||||
isPasswordField
|
||||
@ -34,7 +35,7 @@
|
||||
<div class="title">MariaDB</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbUser">Username</label>
|
||||
<label for="mariadbUser">{$t('forms.username')}</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbUser"
|
||||
id="mariadbUser"
|
||||
@ -44,7 +45,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbPassword">Password</label>
|
||||
<label for="mariadbPassword">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbPassword"
|
||||
isPasswordField
|
||||
@ -55,7 +56,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbDatabase">Database</label>
|
||||
<label for="mariadbDatabase">{$t('index.database')}</label>
|
||||
<input
|
||||
name="mariadbDatabase"
|
||||
id="mariadbDatabase"
|
||||
@ -63,11 +64,11 @@
|
||||
readonly={readOnly}
|
||||
disabled={readOnly}
|
||||
bind:value={service.ghost.mariadbDatabase}
|
||||
placeholder="eg: ghost_db"
|
||||
placeholder="{$t('forms.eg')}: ghost_db"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbRootUser">Root DB User</label>
|
||||
<label for="mariadbRootUser">{$t('forms.root_db_user')}</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbRootUser"
|
||||
isPasswordField
|
||||
@ -78,7 +79,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbRootUserPassword">Root DB Password</label>
|
||||
<label for="mariadbRootUserPassword">{$t('forms.root_db_password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbRootUserPassword"
|
||||
isPasswordField
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
export let service;
|
||||
</script>
|
||||
|
||||
@ -7,7 +8,7 @@
|
||||
<div class="title">MeiliSearch</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="masterKey">Admin API key</label>
|
||||
<label for="masterKey">{$t('forms.admin_api_key')}</label>
|
||||
<CopyPasswordField
|
||||
id="masterKey"
|
||||
isPasswordField
|
||||
|
@ -1,25 +1,26 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let service;
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">MinIO Server</div>
|
||||
<div class="title">MinIO</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="rootUser">Root User</label>
|
||||
<label for="rootUser">{$t('forms.root_user')}</label>
|
||||
<input
|
||||
name="rootUser"
|
||||
id="rootUser"
|
||||
placeholder="User to login"
|
||||
placeholder={$t('forms.username')}
|
||||
value={service.minio.rootUser}
|
||||
disabled
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="rootUserPassword">Root's Password</label>
|
||||
<label for="rootUserPassword">{$t('forms.roots_password')}</label>
|
||||
<CopyPasswordField
|
||||
id="rootUserPassword"
|
||||
isPasswordField
|
||||
@ -30,13 +31,13 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="publicPort">API Port</label>
|
||||
<label for="publicPort">{$t('forms.api_port')}</label>
|
||||
<input
|
||||
name="publicPort"
|
||||
id="publicPort"
|
||||
value={service.minio.publicPort}
|
||||
disabled
|
||||
readonly
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
export let service;
|
||||
export let readOnly;
|
||||
</script>
|
||||
@ -8,31 +9,31 @@
|
||||
<div class="title">Plausible Analytics</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="email">Email Address</label>
|
||||
<label for="email">{$t('forms.email')}</label>
|
||||
<input
|
||||
name="email"
|
||||
id="email"
|
||||
disabled={readOnly}
|
||||
readonly={readOnly}
|
||||
placeholder="Email address"
|
||||
placeholder={$t('forms.email')}
|
||||
bind:value={service.plausibleAnalytics.email}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="username">Username</label>
|
||||
<label for="username">{$t('forms.username')}</label>
|
||||
<CopyPasswordField
|
||||
name="username"
|
||||
id="username"
|
||||
disabled={readOnly}
|
||||
readonly={readOnly}
|
||||
placeholder="User to login"
|
||||
placeholder={$t('forms.username')}
|
||||
bind:value={service.plausibleAnalytics.username}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="password">Password</label>
|
||||
<label for="password">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="password"
|
||||
isPasswordField
|
||||
@ -46,7 +47,7 @@
|
||||
<div class="title">PostgreSQL</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="postgresqlUser">Username</label>
|
||||
<label for="postgresqlUser">{$t('forms.username')}</label>
|
||||
<CopyPasswordField
|
||||
name="postgresqlUser"
|
||||
id="postgresqlUser"
|
||||
@ -56,7 +57,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="postgresqlPassword">Password</label>
|
||||
<label for="postgresqlPassword">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="postgresqlPassword"
|
||||
isPasswordField
|
||||
@ -67,7 +68,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="postgresqlDatabase">Database</label>
|
||||
<label for="postgresqlDatabase">{$t('index.database')}</label>
|
||||
<CopyPasswordField
|
||||
name="postgresqlDatabase"
|
||||
id="postgresqlDatabase"
|
||||
@ -80,7 +81,7 @@
|
||||
<label for="postgresqlPublicPort">Public Port</label>
|
||||
<div class="col-span-2 ">
|
||||
<CopyPasswordField
|
||||
placeholder="Generated automatically after start"
|
||||
placeholder="{ $t('forms.generated_automatically_after_start') }"
|
||||
readonly
|
||||
disabled
|
||||
id="postgresqlPublicPort"
|
||||
|
@ -10,6 +10,7 @@
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { t } from '$lib/translations';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import Ghost from './_Ghost.svelte';
|
||||
import MeiliSearch from './_MeiliSearch.svelte';
|
||||
@ -40,7 +41,7 @@
|
||||
loadingVerification = true;
|
||||
try {
|
||||
await post(`/services/${id}/${service.type}/activate.json`, { id: service.id });
|
||||
toast.push('All email verified. You can login now.');
|
||||
toast.push(t.get('services.all_email_verified'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
@ -53,7 +54,7 @@
|
||||
dualCerts = !dualCerts;
|
||||
}
|
||||
await post(`/services/${id}/settings.json`, { dualCerts });
|
||||
return toast.push('Settings saved.');
|
||||
return toast.push(t.get('application.settings_saved'));
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@ -63,25 +64,27 @@
|
||||
<div class="mx-auto max-w-4xl px-6 pb-12">
|
||||
<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-pink-600={!loading}
|
||||
class:hover:bg-pink-500={!loading}
|
||||
disabled={loading}>{loading ? 'Saving...' : 'Save'}</button
|
||||
disabled={loading}>{loading ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>
|
||||
{/if}
|
||||
{#if service.type === 'plausibleanalytics' && isRunning}
|
||||
<button on:click|preventDefault={setEmailsToVerified} disabled={loadingVerification}
|
||||
>{loadingVerification ? 'Verifying' : 'Verify emails without SMTP'}</button
|
||||
>{loadingVerification
|
||||
? $t('forms.verifying')
|
||||
: $t('forms.verify_emails_without_smtp')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row gap-2">
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-10">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<div>
|
||||
<input
|
||||
readonly={!$session.isAdmin}
|
||||
@ -109,7 +112,9 @@
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="destination" class="text-base font-bold text-stone-100">Destination</label>
|
||||
<label for="destination" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.destination')}</label
|
||||
>
|
||||
<div>
|
||||
{#if service.destinationDockerId}
|
||||
<div class="no-underline">
|
||||
@ -125,10 +130,10 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 px-10">
|
||||
<div class="flex-col ">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100">URL (FQDN)</label>
|
||||
<Explainer
|
||||
text="If you specify <span class='text-pink-600 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-pink-600 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the url, you must first stop the application."
|
||||
/>
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100"
|
||||
>{$t('application.url_fqdn')}</label
|
||||
>
|
||||
<Explainer text={$t('application.https_explainer')} />
|
||||
</div>
|
||||
|
||||
<CopyPasswordField
|
||||
@ -145,10 +150,10 @@
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<Setting
|
||||
disabled={isRunning}
|
||||
dataTooltip="Must be stopped to modify."
|
||||
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||
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-pink-600'>both DNS entries</span> set in advance.<br><br>Service needs to be restarted."
|
||||
title={$t('application.ssl_www_and_non_www')}
|
||||
description={$t('services.generate_www_non_www_ssl')}
|
||||
on:click={() => !isRunning && changeSettings('dualCerts')}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let service;
|
||||
</script>
|
||||
@ -8,7 +9,7 @@
|
||||
<div class="title">VSCode Server</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="password">Password</label>
|
||||
<label for="password">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="password"
|
||||
isPasswordField
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { browser } from '$app/env';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let service;
|
||||
export let isRunning;
|
||||
@ -60,7 +61,7 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="extraConfig">Extra Config</label>
|
||||
<label for="extraConfig">{$t('forms.extra_config')}</label>
|
||||
<textarea
|
||||
bind:value={service.wordpress.extraConfig}
|
||||
disabled={isRunning}
|
||||
@ -70,7 +71,7 @@
|
||||
name="extraConfig"
|
||||
id="extraConfig"
|
||||
placeholder={!isRunning
|
||||
? `eg:
|
||||
? `${$t('forms.eg')}:
|
||||
|
||||
define('WP_ALLOW_MULTISITE', true);
|
||||
define('MULTISITE', true);
|
||||
@ -106,7 +107,7 @@ define('SUBDOMAIN_INSTALL', false);`
|
||||
<div class="title">MySQL</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlDatabase">Database</label>
|
||||
<label for="mysqlDatabase">{$t('index.database')}</label>
|
||||
<input
|
||||
name="mysqlDatabase"
|
||||
id="mysqlDatabase"
|
||||
@ -114,22 +115,22 @@ define('SUBDOMAIN_INSTALL', false);`
|
||||
readonly={readOnly}
|
||||
disabled={readOnly}
|
||||
bind:value={service.wordpress.mysqlDatabase}
|
||||
placeholder="eg: wordpress_db"
|
||||
placeholder="{$t('forms.eg')}: wordpress_db"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlRootUser">Root User</label>
|
||||
<label for="mysqlRootUser">{$t('forms.root_user')}</label>
|
||||
<input
|
||||
name="mysqlRootUser"
|
||||
id="mysqlRootUser"
|
||||
placeholder="MySQL Root User"
|
||||
placeholder="MySQL {$t('forms.root_user')}"
|
||||
value={service.wordpress.mysqlRootUser}
|
||||
disabled
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlRootUserPassword">Root's Password</label>
|
||||
<label for="mysqlRootUserPassword">{$t('forms.roots_password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mysqlRootUserPassword"
|
||||
isPasswordField
|
||||
@ -140,11 +141,11 @@ define('SUBDOMAIN_INSTALL', false);`
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlUser">User</label>
|
||||
<label for="mysqlUser">{$t('forms.user')}</label>
|
||||
<input name="mysqlUser" id="mysqlUser" value={service.wordpress.mysqlUser} disabled readonly />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlPassword">Password</label>
|
||||
<label for="mysqlPassword">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mysqlPassword"
|
||||
isPasswordField
|
||||
|
@ -65,6 +65,7 @@
|
||||
import Loading from '$lib/components/Loading.svelte';
|
||||
import { del, post } from '$lib/api';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
export let service;
|
||||
@ -73,7 +74,7 @@
|
||||
let loading = false;
|
||||
|
||||
async function deleteService() {
|
||||
const sure = confirm(`Are you sure you would like to delete '${service.name}'?`);
|
||||
const sure = confirm($t('application.confirm_to_delete', { name: service.name }));
|
||||
if (sure) {
|
||||
loading = true;
|
||||
try {
|
||||
@ -88,7 +89,7 @@
|
||||
}
|
||||
}
|
||||
async function stopService() {
|
||||
const sure = confirm(`Are you sure you would like to stop '${service.name}'?`);
|
||||
const sure = confirm($t('database.confirm_stop', { name: service.name }));
|
||||
if (sure) {
|
||||
loading = true;
|
||||
try {
|
||||
@ -122,13 +123,13 @@
|
||||
{#if isRunning}
|
||||
<button
|
||||
on:click={stopService}
|
||||
title="Stop Service"
|
||||
title={$t('service.stop_service')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Stop Service'
|
||||
: 'You do not have permission to stop the service.'}
|
||||
? $t('service.stop_service')
|
||||
: $t('service.permission_denied_stop_service')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -148,13 +149,13 @@
|
||||
{:else}
|
||||
<button
|
||||
on:click={startService}
|
||||
title="Start Service"
|
||||
title={$t('service.start_service')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Start Service'
|
||||
: 'You do not have permission to start the service.'}
|
||||
? $t('service.start_service')
|
||||
: $t('service.permission_denied_start_service')}
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
@ -181,9 +182,9 @@
|
||||
class:bg-coolgray-500={$page.url.pathname === `/services/${id}`}
|
||||
>
|
||||
<button
|
||||
title="Configurations"
|
||||
title={$t('application.configurations')}
|
||||
class="icons bg-transparent tooltip-bottom text-sm disabled:text-red-500"
|
||||
data-tooltip="Configurations"
|
||||
data-tooltip={$t('application.configurations')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -216,9 +217,9 @@
|
||||
class:bg-coolgray-500={$page.url.pathname === `/services/${id}/secrets`}
|
||||
>
|
||||
<button
|
||||
title="Secrets"
|
||||
title={$t('application.secret')}
|
||||
class="icons bg-transparent tooltip-bottom text-sm disabled:text-red-500"
|
||||
data-tooltip="Secrets"
|
||||
data-tooltip={$t('application.secret')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -272,14 +273,14 @@
|
||||
{/if}
|
||||
<button
|
||||
on:click={deleteService}
|
||||
title="Delete Service"
|
||||
title={$t('service.delete_service')}
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class:hover:text-red-500={$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Delete Service'
|
||||
: 'You do not have permission to delete a service.'}><DeleteIcon /></button
|
||||
? $t('service.delete_service')
|
||||
: $t('service.permission_denied_delete_service')}><DeleteIcon /></button
|
||||
>
|
||||
{/if}
|
||||
</nav>
|
||||
|
@ -34,6 +34,7 @@
|
||||
import { enhance, errorNotification } from '$lib/form';
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -50,12 +51,14 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Configure Destination</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">
|
||||
{$t('application.configuration.configure_destination')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
{#if !destinations || destinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2">No configurable Destination found</div>
|
||||
<div class="pb-2">{$t('application.configuration.no_configurable_destination')}</div>
|
||||
<div class="flex justify-center">
|
||||
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
|
@ -41,6 +41,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';
|
||||
import MeiliSearch from '$lib/components/svg/services/MeiliSearch.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
@ -59,7 +60,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Service</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('forms.select_a_service')}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center">
|
||||
|
@ -32,6 +32,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import { supportedServiceTypesAndVersions } from '$lib/components/common';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -52,7 +53,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Service version</div>
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('forms.select_a_service_version')}</div>
|
||||
</div>
|
||||
{#if from}
|
||||
<div class="pb-10 text-center">
|
||||
|
@ -26,6 +26,7 @@
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { page } from '$app/stores';
|
||||
import { get } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import ServiceLinks from '$lib/components/ServiceLinks.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
@ -42,7 +43,9 @@
|
||||
class:p-6={!service.fqdn}
|
||||
>
|
||||
<div class="-mb-5 flex-col">
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">Secrets</div>
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||
{$t('application.secret')}
|
||||
</div>
|
||||
<span class="text-xs">{service.name}</span>
|
||||
</div>
|
||||
{#if service.fqdn}
|
||||
@ -74,9 +77,9 @@
|
||||
<table class="mx-auto border-separate text-left">
|
||||
<thead>
|
||||
<tr class="h-12">
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Value</th>
|
||||
<th scope="col" class="w-96 text-center">Action</th>
|
||||
<th scope="col">{$t('forms.name')}</th>
|
||||
<th scope="col">{$t('forms.value')}</th>
|
||||
<th scope="col" class="w-96 text-center">{$t('forms.action')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -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';
|
||||
import MeiliSearch from '$lib/components/svg/services/MeiliSearch.svelte';
|
||||
import { session } from '$app/stores';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
@ -33,7 +34,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"
|
||||
@ -54,7 +55,7 @@
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
{#if !services || ownServices.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>
|
||||
{/if}
|
||||
{#if ownServices.length > 0 || otherServices.length > 0}
|
||||
@ -97,7 +98,7 @@
|
||||
{/if}
|
||||
{#if !service.type || !service.fqdn}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{/if}
|
||||
</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 };
|
||||
|
@ -36,6 +36,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;
|
||||
@ -72,7 +73,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);
|
||||
}
|
||||
@ -99,19 +100,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
|
||||
@ -119,17 +120,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">URL (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.url_fqdn')}
|
||||
</div>
|
||||
<Explainer text={$t('setting.ssl_explainer')} />
|
||||
</div>
|
||||
<div class="justify-start text-left">
|
||||
<input
|
||||
@ -139,16 +140,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
|
||||
@ -170,40 +171,40 @@
|
||||
</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=${
|
||||
fqdn
|
||||
text={$t('setting.credential_stat_explainer', {
|
||||
link: fqdn
|
||||
? `http://${settings.proxyUser}:${settings.proxyPassword}@` + getDomain(fqdn) + ':8404'
|
||||
: browser &&
|
||||
`http://${settings.proxyUser}:${settings.proxyPassword}@` +
|
||||
window.location.hostname +
|
||||
':8404'
|
||||
} target="_blank">stats</a> page.`}
|
||||
})}
|
||||
/>
|
||||
<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
|
||||
@ -213,7 +214,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
|
||||
|
@ -5,6 +5,7 @@
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
|
||||
let loading = false;
|
||||
@ -125,7 +126,7 @@
|
||||
{: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"
|
||||
@ -134,14 +135,14 @@
|
||||
disabled={loading}>{loading ? 'Saving...' : 'Save'}</button
|
||||
>
|
||||
<button on:click|preventDefault={() => installRepositories(source)}
|
||||
>Change GitHub App Settings</button
|
||||
>{$t('source.change_app_settings', { name: 'GitHub' })}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="grid grid-flow-row gap-2">
|
||||
<div class="mt-2 grid grid-cols-2 items-center">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input name="name" id="name" required bind:value={source.name} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
|
||||
import { t } from '$lib/translations';
|
||||
const { id } = $page.params;
|
||||
let url = browser ? (settings.fqdn ? settings.fqdn : window.location.origin) : '';
|
||||
|
||||
@ -130,10 +131,12 @@
|
||||
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
|
||||
>
|
||||
{#if source.gitlabAppId}
|
||||
<button on:click|preventDefault={changeSettings}>Change GitLab App Settings</button>
|
||||
<button on:click|preventDefault={changeSettings}
|
||||
>{$t('source.change_app_settings', { name: 'GitLab' })}</button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
@ -144,10 +147,10 @@
|
||||
>GitLab Application Type</label
|
||||
>
|
||||
<select name="type" id="type" class="w-96" bind:value={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>
|
||||
@ -167,13 +170,15 @@
|
||||
|
||||
<div class="grid grid-flow-row gap-2">
|
||||
<div class="mt-2 grid grid-cols-2 items-center">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<input name="name" id="name" required bind:value={source.name} />
|
||||
</div>
|
||||
</div>
|
||||
{#if source.gitlabApp.groupName}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="groupName" class="text-base font-bold text-stone-100">Group Name</label>
|
||||
<label for="groupName" class="text-base font-bold text-stone-100"
|
||||
>{$t('source.group_name')}</label
|
||||
>
|
||||
<input
|
||||
name="groupName"
|
||||
id="groupName"
|
||||
@ -194,11 +199,11 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-start">
|
||||
<div class="flex-col">
|
||||
<label for="oauthId" class="pt-2 text-base font-bold text-stone-100">OAuth ID</label>
|
||||
<label for="oauthId" class="pt-2 text-base font-bold text-stone-100"
|
||||
>{$t('source.oauth_id')}</label
|
||||
>
|
||||
{#if !source.gitlabAppId}
|
||||
<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."
|
||||
/>
|
||||
<Explainer text={$t('source.oauth_id_explainer')} />
|
||||
{/if}
|
||||
</div>
|
||||
<input
|
||||
@ -215,7 +220,9 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="appId" class="text-base font-bold text-stone-100">Application ID</label>
|
||||
<label for="appId" class="text-base font-bold text-stone-100"
|
||||
>{$t('source.application_id')}</label
|
||||
>
|
||||
<input
|
||||
name="appId"
|
||||
id="appId"
|
||||
@ -226,7 +233,9 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="appSecret" class="text-base font-bold text-stone-100">Secret</label>
|
||||
<label for="appSecret" class="text-base font-bold text-stone-100"
|
||||
>{$t('index.secret')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={source.gitlabAppId}
|
||||
readonly={source.gitlabAppId}
|
||||
|
@ -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 };
|
||||
|
@ -30,6 +30,8 @@
|
||||
<script lang="ts">
|
||||
export let source: Prisma.GitSource;
|
||||
export let settings;
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
import type Prisma from '@prisma/client';
|
||||
import Github from './_Github.svelte';
|
||||
import Gitlab from './_Gitlab.svelte';
|
||||
@ -67,7 +69,7 @@
|
||||
</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>
|
||||
|
@ -39,10 +39,11 @@
|
||||
const { id } = await post('/sources/new', {});
|
||||
return await goto(`/sources/${id}`, { replaceState: true });
|
||||
}
|
||||
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}
|
||||
<button on:click={newSource} class="add-icon bg-orange-600 hover:bg-orange-500">
|
||||
<svg
|
||||
@ -64,7 +65,7 @@
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
{#if !sources || ownSources.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>
|
||||
{/if}
|
||||
{#if ownSources.length > 0 || otherSources.length > 0}
|
||||
@ -85,7 +86,7 @@
|
||||
|
||||
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && source.githubApp?.installationId === null)}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="truncate text-center">{getDomain(source.htmlUrl) || ''}</div>
|
||||
@ -112,7 +113,7 @@
|
||||
{/if}
|
||||
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && source.githubApp?.installationId === null)}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="truncate text-center">{source.htmlUrl}</div>
|
||||
|
@ -12,6 +12,11 @@ const config = {
|
||||
vite: {
|
||||
optimizeDeps: {
|
||||
exclude: ['svelte-kit-cookie-session']
|
||||
},
|
||||
server: {
|
||||
fs: {
|
||||
allow: ['./src/lib/locales/']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user