Merge branch 'next' into git-cliff
This commit is contained in:
@@ -13,16 +13,16 @@ jobs:
|
|||||||
id: stale
|
id: stale
|
||||||
with:
|
with:
|
||||||
stale-issue-message: 'This issue will be automatically closed in a few days if no response is received. Please provide an update with the requested information.'
|
stale-issue-message: 'This issue will be automatically closed in a few days if no response is received. Please provide an update with the requested information.'
|
||||||
stale-pr-message: 'This pull request will be automatically closed in a few days if no response is received. Please update your PR or comment if you would like to continue working on it.'
|
stale-pr-message: 'This pull request requires attention. If no changes or response is received within the next few days, it will be automatically closed. Please update your PR or leave a comment with the requested information.'
|
||||||
close-issue-message: 'This issue has been automatically closed due to inactivity.'
|
close-issue-message: 'This issue has been automatically closed due to inactivity.'
|
||||||
close-pr-message: 'This pull request has been automatically closed due to inactivity.'
|
close-pr-message: 'Thank you for your contribution. Due to inactivity, this PR was automatically closed. If you would like to continue working on this change in the future, feel free to reopen this PR or submit a new one.'
|
||||||
days-before-stale: 14
|
days-before-stale: 14
|
||||||
days-before-close: 7
|
days-before-close: 7
|
||||||
stale-issue-label: '⏱︎ Stale'
|
stale-issue-label: '⏱︎ Stale'
|
||||||
stale-pr-label: '⏱︎ Stale'
|
stale-pr-label: '⏱︎ Stale'
|
||||||
only-labels: '💤 Waiting for feedback'
|
only-labels: '💤 Waiting for feedback, 💤 Waiting for changes'
|
||||||
remove-stale-when-updated: true
|
remove-stale-when-updated: true
|
||||||
operations-per-run: 100
|
operations-per-run: 100
|
||||||
labels-to-remove-when-unstale: '⏱︎ Stale, 💤 Waiting for feedback'
|
labels-to-remove-when-unstale: '⏱︎ Stale, 💤 Waiting for feedback, 💤 Waiting for changes'
|
||||||
close-issue-reason: 'not_planned'
|
close-issue-reason: 'not_planned'
|
||||||
exempt-all-milestones: false
|
exempt-all-milestones: false
|
||||||
|
@@ -19,8 +19,12 @@ jobs:
|
|||||||
script: |
|
script: |
|
||||||
const { owner, repo } = context.repo;
|
const { owner, repo } = context.repo;
|
||||||
|
|
||||||
async function processIssue(issueNumber) {
|
async function processIssue(issueNumber, isFromPR = false, prBaseBranch = null) {
|
||||||
try {
|
try {
|
||||||
|
if (isFromPR && prBaseBranch !== 'main') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
|
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
@@ -59,19 +63,19 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.eventName === 'issues' || context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
|
if (context.eventName === 'issues') {
|
||||||
const issue = context.payload.issue || context.payload.pull_request;
|
await processIssue(context.payload.issue.number);
|
||||||
await processIssue(issue.number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
|
if (context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
|
||||||
const pr = context.payload.pull_request;
|
const pr = context.payload.pull_request;
|
||||||
if (pr.body) {
|
await processIssue(pr.number);
|
||||||
|
if (pr.merged && pr.base.ref === 'main' && pr.body) {
|
||||||
const issueReferences = pr.body.match(/#(\d+)/g);
|
const issueReferences = pr.body.match(/#(\d+)/g);
|
||||||
if (issueReferences) {
|
if (issueReferences) {
|
||||||
for (const reference of issueReferences) {
|
for (const reference of issueReferences) {
|
||||||
const issueNumber = parseInt(reference.substring(1));
|
const issueNumber = parseInt(reference.substring(1));
|
||||||
await processIssue(issueNumber);
|
await processIssue(issueNumber, true, pr.base.ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
.github/workflows/coolify-helper-next.yml
vendored
6
.github/workflows/coolify-helper-next.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -77,7 +77,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -119,7 +119,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
||||||
run: |
|
run: |
|
||||||
|
6
.github/workflows/coolify-helper.yml
vendored
6
.github/workflows/coolify-helper.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -77,7 +77,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -119,7 +119,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
||||||
run: |
|
run: |
|
||||||
|
6
.github/workflows/coolify-realtime-next.yml
vendored
6
.github/workflows/coolify-realtime-next.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -82,7 +82,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -125,7 +125,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
||||||
run: |
|
run: |
|
||||||
|
6
.github/workflows/coolify-realtime.yml
vendored
6
.github/workflows/coolify-realtime.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -82,7 +82,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and Push Image
|
- name: Build and Push Image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
@@ -125,7 +125,7 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
||||||
run: |
|
run: |
|
||||||
|
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
You can ask for guidance anytime on our [Discord server](https://coollabs.io/discord) in the `#contribute` channel.
|
You can ask for guidance anytime on our [Discord server](https://coollabs.io/discord) in the `#contribute` channel.
|
||||||
|
|
||||||
|
To understand the tech stack, please refer to the [Tech Stack](TECH_STACK.md) document.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
1. [Setup Development Environment](#1-setup-development-environment)
|
1. [Setup Development Environment](#1-setup-development-environment)
|
||||||
|
29
TECH_STACK.md
Normal file
29
TECH_STACK.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Coolify Technology Stack
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
- Livewire and Alpine.js
|
||||||
|
- Blade (PHP templating engine)
|
||||||
|
- Tailwind CSS
|
||||||
|
- Monaco Editor (Code editor component)
|
||||||
|
- XTerm.js (Terminal component)
|
||||||
|
|
||||||
|
## Backend
|
||||||
|
|
||||||
|
- Laravel 11 (PHP Framework)
|
||||||
|
- PostgreSQL 15 (Database)
|
||||||
|
- Redis 7 (Caching & Real-time features)
|
||||||
|
- Soketi (WebSocket Server)
|
||||||
|
|
||||||
|
## DevOps & Infrastructure
|
||||||
|
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- Nginx (Web Server)
|
||||||
|
- S6 Overlay (Process Supervisor)
|
||||||
|
- GitHub Actions (CI/CD)
|
||||||
|
|
||||||
|
## Languages
|
||||||
|
|
||||||
|
- PHP 8.4
|
||||||
|
- JavaScript
|
||||||
|
- Shell/Bash scripts
|
@@ -1122,7 +1122,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
||||||
$nixpacks_php_fallback_path->value = '/index.php';
|
$nixpacks_php_fallback_path->value = '/index.php';
|
||||||
$nixpacks_php_fallback_path->is_build_time = false;
|
$nixpacks_php_fallback_path->is_build_time = false;
|
||||||
$nixpacks_php_fallback_path->application_id = $this->application->id;
|
$nixpacks_php_fallback_path->resourceable_id = $this->application->id;
|
||||||
|
$nixpacks_php_fallback_path->resourceable_type = 'App\Models\Application';
|
||||||
$nixpacks_php_fallback_path->save();
|
$nixpacks_php_fallback_path->save();
|
||||||
}
|
}
|
||||||
if (! $nixpacks_php_root_dir) {
|
if (! $nixpacks_php_root_dir) {
|
||||||
@@ -1130,7 +1131,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
||||||
$nixpacks_php_root_dir->value = '/app/public';
|
$nixpacks_php_root_dir->value = '/app/public';
|
||||||
$nixpacks_php_root_dir->is_build_time = false;
|
$nixpacks_php_root_dir->is_build_time = false;
|
||||||
$nixpacks_php_root_dir->application_id = $this->application->id;
|
$nixpacks_php_root_dir->resourceable_id = $this->application->id;
|
||||||
|
$nixpacks_php_root_dir->resourceable_type = 'App\Models\Application';
|
||||||
$nixpacks_php_root_dir->save();
|
$nixpacks_php_root_dir->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2286,8 +2288,16 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
|
|
||||||
private function generate_build_env_variables()
|
private function generate_build_env_variables()
|
||||||
{
|
{
|
||||||
$variables = collect($this->nixpacks_plan_json->get('variables'));
|
if ($this->application->build_pack === 'nixpacks') {
|
||||||
|
$variables = collect($this->nixpacks_plan_json->get('variables'));
|
||||||
|
} else {
|
||||||
|
$this->generate_env_variables();
|
||||||
|
$variables = collect([])->merge($this->env_args);
|
||||||
|
}
|
||||||
|
|
||||||
$this->build_args = $variables->map(function ($value, $key) {
|
$this->build_args = $variables->map(function ($value, $key) {
|
||||||
|
$value = escapeshellarg($value);
|
||||||
|
|
||||||
return "--build-arg {$key}={$value}";
|
return "--build-arg {$key}={$value}";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (isDev() || isCloud()) {
|
if (isDev()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
||||||
|
@@ -442,6 +442,7 @@ class General extends Component
|
|||||||
{
|
{
|
||||||
$config = GenerateConfig::run($this->application, true);
|
$config = GenerateConfig::run($this->application, true);
|
||||||
$fileName = str($this->application->name)->slug()->append('_config.json');
|
$fileName = str($this->application->name)->slug()->append('_config.json');
|
||||||
|
dd($config);
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($config) {
|
return response()->streamDownload(function () use ($config) {
|
||||||
echo $config;
|
echo $config;
|
||||||
|
@@ -88,12 +88,12 @@ class General extends Component
|
|||||||
if (version_compare($this->redis_version, '6.0', '>=')) {
|
if (version_compare($this->redis_version, '6.0', '>=')) {
|
||||||
$this->database->runtime_environment_variables()->updateOrCreate(
|
$this->database->runtime_environment_variables()->updateOrCreate(
|
||||||
['key' => 'REDIS_USERNAME'],
|
['key' => 'REDIS_USERNAME'],
|
||||||
['value' => $this->redis_username, 'standalone_redis_id' => $this->database->id]
|
['value' => $this->redis_username, 'resourceable_id' => $this->database->id]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->database->runtime_environment_variables()->updateOrCreate(
|
$this->database->runtime_environment_variables()->updateOrCreate(
|
||||||
['key' => 'REDIS_PASSWORD'],
|
['key' => 'REDIS_PASSWORD'],
|
||||||
['value' => $this->redis_password, 'standalone_redis_id' => $this->database->id]
|
['value' => $this->redis_password, 'resourceable_id' => $this->database->id]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->database->save();
|
$this->database->save();
|
||||||
|
@@ -77,18 +77,28 @@ class Show extends Component
|
|||||||
public function syncData(bool $toModel = false)
|
public function syncData(bool $toModel = false)
|
||||||
{
|
{
|
||||||
if ($toModel) {
|
if ($toModel) {
|
||||||
$this->validate();
|
if ($this->isSharedVariable) {
|
||||||
|
$this->validate([
|
||||||
|
'key' => 'required|string',
|
||||||
|
'value' => 'nullable',
|
||||||
|
'is_multiline' => 'required|boolean',
|
||||||
|
'is_literal' => 'required|boolean',
|
||||||
|
'is_shown_once' => 'required|boolean',
|
||||||
|
'real_value' => 'nullable',
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$this->validate();
|
||||||
|
$this->env->is_build_time = $this->is_build_time;
|
||||||
|
$this->env->is_required = $this->is_required;
|
||||||
|
$this->env->is_shared = $this->is_shared;
|
||||||
|
}
|
||||||
$this->env->key = $this->key;
|
$this->env->key = $this->key;
|
||||||
$this->env->value = $this->value;
|
$this->env->value = $this->value;
|
||||||
$this->env->is_build_time = $this->is_build_time;
|
|
||||||
$this->env->is_multiline = $this->is_multiline;
|
$this->env->is_multiline = $this->is_multiline;
|
||||||
$this->env->is_literal = $this->is_literal;
|
$this->env->is_literal = $this->is_literal;
|
||||||
$this->env->is_shown_once = $this->is_shown_once;
|
$this->env->is_shown_once = $this->is_shown_once;
|
||||||
$this->env->is_required = $this->is_required;
|
|
||||||
$this->env->is_shared = $this->is_shared;
|
|
||||||
$this->env->save();
|
$this->env->save();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$this->key = $this->env->key;
|
$this->key = $this->env->key;
|
||||||
$this->value = $this->env->value;
|
$this->value = $this->env->value;
|
||||||
$this->is_build_time = $this->env->is_build_time ?? false;
|
$this->is_build_time = $this->env->is_build_time ?? false;
|
||||||
@@ -141,30 +151,15 @@ class Show extends Component
|
|||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($this->isSharedVariable) {
|
|
||||||
$this->validate([
|
|
||||||
'key' => 'required|string',
|
|
||||||
'value' => 'nullable',
|
|
||||||
'is_shown_once' => 'required|boolean',
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
$this->validate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $this->isSharedVariable && $this->is_required && str($this->value)->isEmpty()) {
|
if (! $this->isSharedVariable && $this->is_required && str($this->value)->isEmpty()) {
|
||||||
$oldValue = $this->env->getOriginal('value');
|
$oldValue = $this->env->getOriginal('value');
|
||||||
$this->value = $oldValue;
|
$this->value = $oldValue;
|
||||||
$this->dispatch('error', 'Required environment variable cannot be empty.');
|
$this->dispatch('error', 'Required environment variables cannot be empty.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->serialize();
|
$this->serialize();
|
||||||
|
|
||||||
if ($this->isSharedVariable) {
|
|
||||||
unset($this->is_required);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->syncData(true);
|
$this->syncData(true);
|
||||||
$this->dispatch('success', 'Environment variable updated.');
|
$this->dispatch('success', 'Environment variable updated.');
|
||||||
$this->dispatch('envsUpdated');
|
$this->dispatch('envsUpdated');
|
||||||
|
@@ -27,6 +27,8 @@ class ExecuteContainerCommand extends Component
|
|||||||
|
|
||||||
public Collection $servers;
|
public Collection $servers;
|
||||||
|
|
||||||
|
public bool $hasShell = true;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'server' => 'required',
|
'server' => 'required',
|
||||||
'container' => 'required',
|
'container' => 'required',
|
||||||
@@ -141,6 +143,16 @@ class ExecuteContainerCommand extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkShellAvailability(Server $server, string $container): bool
|
||||||
|
{
|
||||||
|
$escapedContainer = escapeshellarg($container);
|
||||||
|
$result = instant_remote_process([
|
||||||
|
"docker exec {$escapedContainer} which bash || docker exec {$escapedContainer} which sh",
|
||||||
|
], $server, false);
|
||||||
|
|
||||||
|
return ! empty($result);
|
||||||
|
}
|
||||||
|
|
||||||
#[On('connectToServer')]
|
#[On('connectToServer')]
|
||||||
public function connectToServer()
|
public function connectToServer()
|
||||||
{
|
{
|
||||||
@@ -148,6 +160,7 @@ class ExecuteContainerCommand extends Component
|
|||||||
if ($this->server->isForceDisabled()) {
|
if ($this->server->isForceDisabled()) {
|
||||||
throw new \RuntimeException('Server is disabled.');
|
throw new \RuntimeException('Server is disabled.');
|
||||||
}
|
}
|
||||||
|
$this->hasShell = true;
|
||||||
$this->dispatch(
|
$this->dispatch(
|
||||||
'send-terminal-command',
|
'send-terminal-command',
|
||||||
false,
|
false,
|
||||||
@@ -201,6 +214,11 @@ class ExecuteContainerCommand extends Component
|
|||||||
throw new \RuntimeException('Server ownership verification failed.');
|
throw new \RuntimeException('Server ownership verification failed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->hasShell = $this->checkShellAvailability($server, data_get($container, 'container.Names'));
|
||||||
|
if (! $this->hasShell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->dispatch(
|
$this->dispatch(
|
||||||
'send-terminal-command',
|
'send-terminal-command',
|
||||||
true,
|
true,
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\ApplicationDeploymentStatus;
|
use App\Enums\ApplicationDeploymentStatus;
|
||||||
|
use App\Services\ConfigurationGenerator;
|
||||||
|
use App\Traits\HasConfiguration;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@@ -105,7 +107,7 @@ use Visus\Cuid2\Cuid2;
|
|||||||
|
|
||||||
class Application extends BaseModel
|
class Application extends BaseModel
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes;
|
use HasConfiguration, HasFactory, SoftDeletes;
|
||||||
|
|
||||||
private static $parserVersion = '4';
|
private static $parserVersion = '4';
|
||||||
|
|
||||||
@@ -1640,35 +1642,28 @@ class Application extends BaseModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLimits(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'limits_memory' => $this->limits_memory,
|
||||||
|
'limits_memory_swap' => $this->limits_memory_swap,
|
||||||
|
'limits_memory_swappiness' => $this->limits_memory_swappiness,
|
||||||
|
'limits_memory_reservation' => $this->limits_memory_reservation,
|
||||||
|
'limits_cpus' => $this->limits_cpus,
|
||||||
|
'limits_cpuset' => $this->limits_cpuset,
|
||||||
|
'limits_cpu_shares' => $this->limits_cpu_shares,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function generateConfig($is_json = false)
|
public function generateConfig($is_json = false)
|
||||||
{
|
{
|
||||||
$config = collect([]);
|
$generator = new ConfigurationGenerator($this);
|
||||||
if ($this->build_pack = 'nixpacks') {
|
|
||||||
$config = collect([
|
|
||||||
'build_pack' => 'nixpacks',
|
|
||||||
'docker_registry_image_name' => $this->docker_registry_image_name,
|
|
||||||
'docker_registry_image_tag' => $this->docker_registry_image_tag,
|
|
||||||
'install_command' => $this->install_command,
|
|
||||||
'build_command' => $this->build_command,
|
|
||||||
'start_command' => $this->start_command,
|
|
||||||
'base_directory' => $this->base_directory,
|
|
||||||
'publish_directory' => $this->publish_directory,
|
|
||||||
'custom_docker_run_options' => $this->custom_docker_run_options,
|
|
||||||
'ports_exposes' => $this->ports_exposes,
|
|
||||||
'ports_mappings' => $this->ports_mapping,
|
|
||||||
'settings' => collect([
|
|
||||||
'is_static' => $this->settings->is_static,
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$config = $config->filter(function ($value) {
|
|
||||||
return str($value)->isNotEmpty();
|
|
||||||
});
|
|
||||||
if ($is_json) {
|
if ($is_json) {
|
||||||
return json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
return $generator->toJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $config;
|
return $generator->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setConfig($config)
|
public function setConfig($config)
|
||||||
|
@@ -4,9 +4,7 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
#[OA\Schema(
|
#[OA\Schema(
|
||||||
description: 'Environment Variable model',
|
description: 'Environment Variable model',
|
||||||
@@ -30,7 +28,7 @@ use Visus\Cuid2\Cuid2;
|
|||||||
'updated_at' => ['type' => 'string'],
|
'updated_at' => ['type' => 'string'],
|
||||||
]
|
]
|
||||||
)]
|
)]
|
||||||
class EnvironmentVariable extends Model
|
class EnvironmentVariable extends BaseModel
|
||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
@@ -49,12 +47,6 @@ class EnvironmentVariable extends Model
|
|||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::creating(function (Model $model) {
|
|
||||||
if (! $model->uuid) {
|
|
||||||
$model->uuid = (string) new Cuid2;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
static::created(function (EnvironmentVariable $environment_variable) {
|
static::created(function (EnvironmentVariable $environment_variable) {
|
||||||
if ($environment_variable->resourceable_type === Application::class && ! $environment_variable->is_preview) {
|
if ($environment_variable->resourceable_type === Application::class && ! $environment_variable->is_preview) {
|
||||||
$found = ModelsEnvironmentVariable::where('key', $environment_variable->key)
|
$found = ModelsEnvironmentVariable::where('key', $environment_variable->key)
|
||||||
|
@@ -53,6 +53,7 @@ class EmailChannel
|
|||||||
if (! $type) {
|
if (! $type) {
|
||||||
throw new Exception('No email settings found.');
|
throw new Exception('No email settings found.');
|
||||||
}
|
}
|
||||||
|
config()->set('mail.default', $type);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
194
app/Services/ConfigurationGenerator.php
Normal file
194
app/Services/ConfigurationGenerator.php
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
class ConfigurationGenerator
|
||||||
|
{
|
||||||
|
protected array $config = [];
|
||||||
|
|
||||||
|
public function __construct(protected Application $resource)
|
||||||
|
{
|
||||||
|
$this->generateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generateConfig(): void
|
||||||
|
{
|
||||||
|
if ($this->resource instanceof Application) {
|
||||||
|
$this->config = [
|
||||||
|
'id' => $this->resource->id,
|
||||||
|
'name' => $this->resource->name,
|
||||||
|
'uuid' => $this->resource->uuid,
|
||||||
|
'description' => $this->resource->description,
|
||||||
|
'coolify_details' => [
|
||||||
|
'project_uuid' => $this->resource->project()->uuid,
|
||||||
|
'environment_uuid' => $this->resource->environment->uuid,
|
||||||
|
|
||||||
|
'destination_type' => $this->resource->destination_type,
|
||||||
|
'destination_id' => $this->resource->destination_id,
|
||||||
|
'source_type' => $this->resource->source_type,
|
||||||
|
'source_id' => $this->resource->source_id,
|
||||||
|
'private_key_id' => $this->resource->private_key_id,
|
||||||
|
],
|
||||||
|
|
||||||
|
'post_deployment_command' => $this->resource->post_deployment_command,
|
||||||
|
'post_deployment_command_container' => $this->resource->post_deployment_command_container,
|
||||||
|
'pre_deployment_command' => $this->resource->pre_deployment_command,
|
||||||
|
'pre_deployment_command_container' => $this->resource->pre_deployment_command_container,
|
||||||
|
'build' => [
|
||||||
|
'type' => $this->resource->build_pack,
|
||||||
|
'static_image' => $this->resource->static_image,
|
||||||
|
'base_directory' => $this->resource->base_directory,
|
||||||
|
'publish_directory' => $this->resource->publish_directory,
|
||||||
|
'dockerfile' => $this->resource->dockerfile,
|
||||||
|
'dockerfile_location' => $this->resource->dockerfile_location,
|
||||||
|
'dockerfile_target_build' => $this->resource->dockerfile_target_build,
|
||||||
|
'custom_docker_run_options' => $this->resource->custom_docker_options,
|
||||||
|
'compose_parsing_version' => $this->resource->compose_parsing_version,
|
||||||
|
'docker_compose' => $this->resource->docker_compose,
|
||||||
|
'docker_compose_location' => $this->resource->docker_compose_location,
|
||||||
|
'docker_compose_raw' => $this->resource->docker_compose_raw,
|
||||||
|
'docker_compose_domains' => $this->resource->docker_compose_domains,
|
||||||
|
'docker_compose_custom_start_command' => $this->resource->docker_compose_custom_start_command,
|
||||||
|
'docker_compose_custom_build_command' => $this->resource->docker_compose_custom_build_command,
|
||||||
|
'install_command' => $this->resource->install_command,
|
||||||
|
'build_command' => $this->resource->build_command,
|
||||||
|
'start_command' => $this->resource->start_command,
|
||||||
|
'watch_paths' => $this->resource->watch_paths,
|
||||||
|
],
|
||||||
|
'source' => [
|
||||||
|
'git_repository' => $this->resource->git_repository,
|
||||||
|
'git_branch' => $this->resource->git_branch,
|
||||||
|
'git_commit_sha' => $this->resource->git_commit_sha,
|
||||||
|
'repository_project_id' => $this->resource->repository_project_id,
|
||||||
|
],
|
||||||
|
'docker_registry_image' => $this->getDockerRegistryImage(),
|
||||||
|
'domains' => [
|
||||||
|
'fqdn' => $this->resource->fqdn,
|
||||||
|
'ports_exposes' => $this->resource->ports_exposes,
|
||||||
|
'ports_mappings' => $this->resource->ports_mappings,
|
||||||
|
'redirect' => $this->resource->redirect,
|
||||||
|
'custom_nginx_configuration' => $this->resource->custom_nginx_configuration,
|
||||||
|
],
|
||||||
|
'environment_variables' => [
|
||||||
|
'production' => $this->getEnvironmentVariables(),
|
||||||
|
'preview' => $this->getPreviewEnvironmentVariables(),
|
||||||
|
],
|
||||||
|
'settings' => $this->getApplicationSettings(),
|
||||||
|
'preview' => $this->getPreview(),
|
||||||
|
'limits' => $this->resource->getLimits(),
|
||||||
|
'health_check' => [
|
||||||
|
'health_check_path' => $this->resource->health_check_path,
|
||||||
|
'health_check_port' => $this->resource->health_check_port,
|
||||||
|
'health_check_host' => $this->resource->health_check_host,
|
||||||
|
'health_check_method' => $this->resource->health_check_method,
|
||||||
|
'health_check_return_code' => $this->resource->health_check_return_code,
|
||||||
|
'health_check_scheme' => $this->resource->health_check_scheme,
|
||||||
|
'health_check_response_text' => $this->resource->health_check_response_text,
|
||||||
|
'health_check_interval' => $this->resource->health_check_interval,
|
||||||
|
'health_check_timeout' => $this->resource->health_check_timeout,
|
||||||
|
'health_check_retries' => $this->resource->health_check_retries,
|
||||||
|
'health_check_start_period' => $this->resource->health_check_start_period,
|
||||||
|
'health_check_enabled' => $this->resource->health_check_enabled,
|
||||||
|
],
|
||||||
|
'webhooks_secrets' => [
|
||||||
|
'manual_webhook_secret_github' => $this->resource->manual_webhook_secret_github,
|
||||||
|
'manual_webhook_secret_gitlab' => $this->resource->manual_webhook_secret_gitlab,
|
||||||
|
'manual_webhook_secret_bitbucket' => $this->resource->manual_webhook_secret_bitbucket,
|
||||||
|
'manual_webhook_secret_gitea' => $this->resource->manual_webhook_secret_gitea,
|
||||||
|
],
|
||||||
|
'swarm' => [
|
||||||
|
'swarm_replicas' => $this->resource->swarm_replicas,
|
||||||
|
'swarm_placement_constraints' => $this->resource->swarm_placement_constraints,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPreview(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'preview_url_template' => $this->resource->preview_url_template,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDockerRegistryImage(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'image' => $this->resource->docker_registry_image_name,
|
||||||
|
'tag' => $this->resource->docker_registry_image_tag,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getEnvironmentVariables(): array
|
||||||
|
{
|
||||||
|
$variables = collect([]);
|
||||||
|
foreach ($this->resource->environment_variables as $env) {
|
||||||
|
$variables->push([
|
||||||
|
'key' => $env->key,
|
||||||
|
'value' => $env->value,
|
||||||
|
'is_build_time' => $env->is_build_time,
|
||||||
|
'is_preview' => $env->is_preview,
|
||||||
|
'is_multiline' => $env->is_multiline,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $variables->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPreviewEnvironmentVariables(): array
|
||||||
|
{
|
||||||
|
$variables = collect([]);
|
||||||
|
foreach ($this->resource->environment_variables_preview as $env) {
|
||||||
|
$variables->push([
|
||||||
|
'key' => $env->key,
|
||||||
|
'value' => $env->value,
|
||||||
|
'is_build_time' => $env->is_build_time,
|
||||||
|
'is_preview' => $env->is_preview,
|
||||||
|
'is_multiline' => $env->is_multiline,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $variables->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getApplicationSettings(): array
|
||||||
|
{
|
||||||
|
$removedKeys = ['id', 'application_id', 'created_at', 'updated_at'];
|
||||||
|
$settings = $this->resource->settings->attributesToArray();
|
||||||
|
$settings = collect($settings)->filter(function ($value, $key) use ($removedKeys) {
|
||||||
|
return ! in_array($key, $removedKeys);
|
||||||
|
})->sortBy(function ($value, $key) {
|
||||||
|
return $key;
|
||||||
|
})->toArray();
|
||||||
|
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveJson(string $path): void
|
||||||
|
{
|
||||||
|
file_put_contents($path, json_encode($this->config, JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveYaml(string $path): void
|
||||||
|
{
|
||||||
|
file_put_contents($path, Yaml::dump($this->config, 6, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toJson(): string
|
||||||
|
{
|
||||||
|
return json_encode($this->config, JSON_PRETTY_PRINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toYaml(): string
|
||||||
|
{
|
||||||
|
return Yaml::dump($this->config, 6, 2);
|
||||||
|
}
|
||||||
|
}
|
@@ -43,7 +43,11 @@ class DockerImageParser
|
|||||||
|
|
||||||
public function getFullImageNameWithoutTag(): string
|
public function getFullImageNameWithoutTag(): string
|
||||||
{
|
{
|
||||||
return $this->registryUrl.'/'.$this->imageName;
|
if ($this->registryUrl) {
|
||||||
|
return $this->registryUrl.'/'.$this->imageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->imageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRegistryUrl(): string
|
public function getRegistryUrl(): string
|
||||||
|
42
app/Traits/HasConfiguration.php
Normal file
42
app/Traits/HasConfiguration.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
use App\Services\ConfigurationGenerator;
|
||||||
|
|
||||||
|
trait HasConfiguration
|
||||||
|
{
|
||||||
|
public function generateConfigurationFiles(): void
|
||||||
|
{
|
||||||
|
$generator = new ConfigurationGenerator($this);
|
||||||
|
|
||||||
|
$configDir = base_configuration_dir()."/{$this->uuid}";
|
||||||
|
if (! is_dir($configDir)) {
|
||||||
|
mkdir($configDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$generator->saveJson($configDir.'/coolify.json');
|
||||||
|
$generator->saveYaml($configDir.'/coolify.yaml');
|
||||||
|
|
||||||
|
// Generate a README file with basic information
|
||||||
|
file_put_contents(
|
||||||
|
$configDir.'/README.md',
|
||||||
|
generate_readme_file($this->name, now()->toIso8601String())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfigurationAsJson(): string
|
||||||
|
{
|
||||||
|
return (new ConfigurationGenerator($this))->toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfigurationAsYaml(): string
|
||||||
|
{
|
||||||
|
return (new ConfigurationGenerator($this))->toYaml();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfigurationAsArray(): array
|
||||||
|
{
|
||||||
|
return (new ConfigurationGenerator($this))->toArray();
|
||||||
|
}
|
||||||
|
}
|
10
bootstrap/getHelperVersion.php
Normal file
10
bootstrap/getHelperVersion.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// To prevent github actions from failing
|
||||||
|
function env()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = include 'config/constants.php';
|
||||||
|
echo $version['coolify']['helper_version'] ?: 'unknown';
|
10
bootstrap/getRealtimeVersion.php
Normal file
10
bootstrap/getRealtimeVersion.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// To prevent github actions from failing
|
||||||
|
function env()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = include 'config/constants.php';
|
||||||
|
echo $version['coolify']['realtime_version'] ?: 'unknown';
|
@@ -2645,7 +2645,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($value?->startsWith('$')) {
|
if ($value?->startsWith('$')) {
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
])->first();
|
])->first();
|
||||||
$value = replaceVariables($value);
|
$value = replaceVariables($value);
|
||||||
@@ -2653,7 +2654,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($value->startsWith('SERVICE_')) {
|
if ($value->startsWith('SERVICE_')) {
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
])->first();
|
])->first();
|
||||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||||
if (! is_null($command)) {
|
if (! is_null($command)) {
|
||||||
@@ -2676,7 +2678,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $fqdn,
|
'value' => $fqdn,
|
||||||
'is_build_time' => false,
|
'is_build_time' => false,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -2687,7 +2690,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $generatedValue,
|
'value' => $generatedValue,
|
||||||
'is_build_time' => false,
|
'is_build_time' => false,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -2712,7 +2716,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
])->first();
|
])->first();
|
||||||
if ($foundEnv) {
|
if ($foundEnv) {
|
||||||
@@ -2722,7 +2727,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($foundEnv) {
|
if ($foundEnv) {
|
||||||
$foundEnv->update([
|
$foundEnv->update([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
'is_build_time' => $isBuildTime,
|
'is_build_time' => $isBuildTime,
|
||||||
'value' => $defaultValue,
|
'value' => $defaultValue,
|
||||||
]);
|
]);
|
||||||
@@ -2731,7 +2737,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $defaultValue,
|
'value' => $defaultValue,
|
||||||
'is_build_time' => $isBuildTime,
|
'is_build_time' => $isBuildTime,
|
||||||
'application_id' => $resource->id,
|
'resourceable_type' => get_class($resource),
|
||||||
|
'resourceable_id' => $resource->id,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -2872,7 +2879,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
data_forget($service, 'volumes.*.is_directory');
|
data_forget($service, 'volumes.*.is_directory');
|
||||||
data_forget($service, 'exclude_from_hc');
|
data_forget($service, 'exclude_from_hc');
|
||||||
data_set($service, 'environment', $serviceVariables->toArray());
|
data_set($service, 'environment', $serviceVariables->toArray());
|
||||||
updateCompose($service);
|
|
||||||
|
|
||||||
return $service;
|
return $service;
|
||||||
});
|
});
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'coolify' => [
|
'coolify' => [
|
||||||
'version' => '4.0.0-beta.383',
|
'version' => '4.0.0-beta.389',
|
||||||
|
'helper_version' => '1.0.5',
|
||||||
|
'realtime_version' => '1.0.5',
|
||||||
'self_hosted' => env('SELF_HOSTED', true),
|
'self_hosted' => env('SELF_HOSTED', true),
|
||||||
'autoupdate' => env('AUTOUPDATE'),
|
'autoupdate' => env('AUTOUPDATE'),
|
||||||
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DB::table('application_deployment_queues')
|
||||||
|
->whereNull('finished_at')
|
||||||
|
->update(['finished_at' => DB::raw('updated_at')]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::error('Failed to update not set finished_at timestamps for application_deployment_queues: '.$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::table('scheduled_database_backup_executions')
|
||||||
|
->whereNull('finished_at')
|
||||||
|
->update(['finished_at' => DB::raw('updated_at')]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::error('Failed to update not set finished_at timestamps for scheduled_database_backup_executions: '.$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::table('scheduled_task_executions')
|
||||||
|
->whereNull('finished_at')
|
||||||
|
->update(['finished_at' => DB::raw('updated_at')]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::error('Failed to update not set finished_at timestamps for scheduled_task_executions: '.$e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\EnvironmentVariable;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
EnvironmentVariable::whereNull('resourceable_id')->each(function (EnvironmentVariable $environmentVariable) {
|
||||||
|
$environmentVariable->delete();
|
||||||
|
});
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to delete wrongly created environment variables: '.$e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@@ -1,5 +1,6 @@
|
|||||||
# Versions
|
# Versions
|
||||||
|
|
||||||
|
|
||||||
# https://hub.docker.com/_/alpine
|
# https://hub.docker.com/_/alpine
|
||||||
ARG BASE_IMAGE=alpine:3.21
|
ARG BASE_IMAGE=alpine:3.21
|
||||||
# https://download.docker.com/linux/static/stable/
|
# https://download.docker.com/linux/static/stable/
|
||||||
@@ -11,7 +12,7 @@ ARG DOCKER_BUILDX_VERSION=0.19.3
|
|||||||
# https://github.com/buildpacks/pack/releases
|
# https://github.com/buildpacks/pack/releases
|
||||||
ARG PACK_VERSION=0.36.2
|
ARG PACK_VERSION=0.36.2
|
||||||
# https://github.com/railwayapp/nixpacks/releases
|
# https://github.com/railwayapp/nixpacks/releases
|
||||||
ARG NIXPACKS_VERSION=1.30.0
|
ARG NIXPACKS_VERSION=1.32.0
|
||||||
# https://github.com/minio/mc/releases
|
# https://github.com/minio/mc/releases
|
||||||
ARG MINIO_VERSION=RELEASE.2024-11-21T17-21-54Z
|
ARG MINIO_VERSION=RELEASE.2024-11-21T17-21-54Z
|
||||||
|
|
||||||
|
@@ -119,6 +119,7 @@ COPY --chown=www-data:www-data storage ./storage
|
|||||||
COPY --chown=www-data:www-data templates ./templates
|
COPY --chown=www-data:www-data templates ./templates
|
||||||
COPY --chown=www-data:www-data resources/views ./resources/views
|
COPY --chown=www-data:www-data resources/views ./resources/views
|
||||||
COPY --chown=www-data:www-data artisan artisan
|
COPY --chown=www-data:www-data artisan artisan
|
||||||
|
COPY --chown=www-data:www-data openapi.yaml ./openapi.yaml
|
||||||
|
|
||||||
RUN composer dump-autoload
|
RUN composer dump-autoload
|
||||||
|
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@@ -22,7 +22,7 @@
|
|||||||
"pusher-js": "8.4.0-rc2",
|
"pusher-js": "8.4.0-rc2",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "3.4.17",
|
"tailwindcss": "3.4.17",
|
||||||
"vite": "6.0.7",
|
"vite": "6.0.11",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2784,9 +2784,9 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.0.7",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
|
||||||
"integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==",
|
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
"pusher-js": "8.4.0-rc2",
|
"pusher-js": "8.4.0-rc2",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "3.4.17",
|
"tailwindcss": "3.4.17",
|
||||||
"vite": "6.0.7",
|
"vite": "6.0.11",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
21
public/svgs/flipt.svg
Normal file
21
public/svgs/flipt.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="logosandtypes_com" data-name="logosandtypes com" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: #7c3aed;
|
||||||
|
fill-rule: evenodd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-2 {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="Layer_3" data-name="Layer 3">
|
||||||
|
<g id="Layer_2" data-name="Layer 2">
|
||||||
|
<path id="Layer_3-2" data-name="Layer 3-2" class="cls-2" d="M0,0H150V150H0V0Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path class="cls-1" d="M140.19,76.45c-3.24-14.68-11.77-43.35-15.1-56.52-6.68,.83-18.4,2.17-24.91,2.97,0,0-11.73,1.41-11.73,1.41-1.91,.27-3.79-.53-4.19-2.11-.33-1.03-1.18-5.12-1.95-5.88-.9-.94-2.35-.97-3.55-.69-15.06,1.87-49.7,6.21-49.7,6.21l-3.47-12.55-15.25,1.87L45.82,141.9l14.93-1.99L34.32,41.31s33.41-4.16,48.14-6.1c3.63-.62,5.03,.57,7.18,4.1,.84,1.41,1.68,1.76,3.47,1.52,.07,0,20.89-2.41,20.96-2.38,1.01,3.73,3.08,11.11,4.07,14.81l-18.09,2.35c-2.75,.35-4.55-.47-6.1-2.7-.47-.68-1.17-2.1-1.89-2.5-.7-.52-1.48-.57-2.66-.43-9.03,1.12-35.96,4.46-35.96,4.46l3.23,11.84s24.42-2.93,33.09-4.1c3.05-.61,5.65,.3,6.98,4.42,.31,.96,1.37,1.47,2.38,1.54l22.33-2.92,4.14,14.7s-18.11,2.66-18.11,2.66c-2.87,.35-4.09,.2-5.64-2.03-.17-.28-1.1-1.45-1.63-1.98-1.28-1.28-3.09-1.9-4.88-1.66l-34.58,4.5,4.55,16.65s25.11-3.45,35.45-4.45c3.31-.44,2.75,2.76,3.9,4.64,.61,.94,1.73,1.56,4.12,1.22l14.75-1.85c5.81-.71,11.8-1.61,15.16-6.4,1.51-2.16,2.52-6.64,2.34-9.02-.09-1.22-.56-4.54-.82-5.74Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@@ -22,7 +22,7 @@
|
|||||||
<a wire:navigate class="menu-item {{ $activeMenu === 'log-drains' ? 'menu-item-active' : '' }}"
|
<a wire:navigate class="menu-item {{ $activeMenu === 'log-drains' ? 'menu-item-active' : '' }}"
|
||||||
href="{{ route('server.log-drains', ['server_uuid' => $server->uuid]) }}">Log
|
href="{{ route('server.log-drains', ['server_uuid' => $server->uuid]) }}">Log
|
||||||
Drains</a>
|
Drains</a>
|
||||||
<a wire:navigate class="menu-item {{ $activeMenu === 'metrics' ? 'menu-item-active' : '' }}"
|
<a class="menu-item {{ $activeMenu === 'metrics' ? 'menu-item-active' : '' }}"
|
||||||
href="{{ route('server.charts', ['server_uuid' => $server->uuid]) }}">Metrics</a>
|
href="{{ route('server.charts', ['server_uuid' => $server->uuid]) }}">Metrics</a>
|
||||||
@endif
|
@endif
|
||||||
@if (!$server->isLocalhost())
|
@if (!$server->isLocalhost())
|
||||||
|
@@ -6,12 +6,8 @@
|
|||||||
])
|
])
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span wire:loading.delay.longer>
|
<div wire:loading.delay.longer wire:target="checkProxy(true)" class="badge badge-warning"></div>
|
||||||
<div class="badge badge-warning"></div>
|
<div wire:loading.remove.delay.longer wire:target="checkProxy(true)" class="badge badge-success"></div>
|
||||||
</span>
|
|
||||||
<span wire:loading.remove.delay.longer>
|
|
||||||
<div class="badge badge-success"></div>
|
|
||||||
</span>
|
|
||||||
<div class="pl-2 pr-1 text-xs font-bold tracking-wider text-success"
|
<div class="pl-2 pr-1 text-xs font-bold tracking-wider text-success"
|
||||||
@if ($title) title="{{ $title }}" @endif>
|
@if ($title) title="{{ $title }}" @endif>
|
||||||
@if ($lastDeploymentLink)
|
@if ($lastDeploymentLink)
|
||||||
|
@@ -74,8 +74,7 @@
|
|||||||
href="{{ route('project.application.resource-operations', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.resource-operations', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Resource Operations</a>
|
wire:navigate>Resource Operations</a>
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.metrics', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.metrics', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}" >Metrics</a>
|
||||||
wire:navigate>Metrics</a>
|
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.tags', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.tags', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Tags</a>
|
wire:navigate>Tags</a>
|
||||||
|
@@ -5,13 +5,14 @@
|
|||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
{{--
|
|
||||||
<x-forms.button wire:click="downloadConfig">
|
{{-- <x-forms.button wire:click="downloadConfig">
|
||||||
Download Config
|
Download Config
|
||||||
<x-modal-input buttonTitle="Upload Config" title="Upload Config" :closeOutside="false">
|
</x-forms.button> --}}
|
||||||
|
{{-- <x-modal-input buttonTitle="Upload Config" title="Upload Config" :closeOutside="false">
|
||||||
<livewire:project.shared.upload-config :applicationId="$application->id" />
|
<livewire:project.shared.upload-config :applicationId="$application->id" />
|
||||||
</x-modal-input>
|
</x-modal-input> --}}
|
||||||
--}}
|
|
||||||
</div>
|
</div>
|
||||||
<div>General configuration for your application.</div>
|
<div>General configuration for your application.</div>
|
||||||
<div class="flex flex-col gap-2 py-4">
|
<div class="flex flex-col gap-2 py-4">
|
||||||
|
@@ -20,8 +20,8 @@
|
|||||||
href="{{ route('project.database.persistent-storage', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
href="{{ route('project.database.persistent-storage', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
||||||
wire:navigate>Persistent Storage</a>
|
wire:navigate>Persistent Storage</a>
|
||||||
<a class='menu-item' wire:current.exact="menu-item-active"
|
<a class='menu-item' wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.database.import-backups', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
href="{{ route('project.database.import-backups', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}">Import
|
||||||
wire:navigate>Import Backups</a>
|
Backups</a>
|
||||||
<a class='menu-item' wire:current.exact="menu-item-active"
|
<a class='menu-item' wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.database.webhooks', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
href="{{ route('project.database.webhooks', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
||||||
wire:navigate>Webhooks</a>
|
wire:navigate>Webhooks</a>
|
||||||
@@ -32,8 +32,7 @@
|
|||||||
href="{{ route('project.database.resource-operations', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
href="{{ route('project.database.resource-operations', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
||||||
wire:navigate>Resource Operations</a>
|
wire:navigate>Resource Operations</a>
|
||||||
<a class='menu-item' wire:current.exact="menu-item-active"
|
<a class='menu-item' wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.database.metrics', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
href="{{ route('project.database.metrics', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}">Metrics</a>
|
||||||
wire:navigate>Metrics</a>
|
|
||||||
<a class='menu-item' wire:current.exact="menu-item-active"
|
<a class='menu-item' wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.database.tags', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
href="{{ route('project.database.tags', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'database_uuid' => $database->uuid]) }}"
|
||||||
wire:navigate>Tags</a>
|
wire:navigate>Tags</a>
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
@if ($serviceDatabase?->isBackupSolutionAvailable())
|
@if ($serviceDatabase?->isBackupSolutionAvailable())
|
||||||
<a :class="activeTab === 'backups' && 'menu-item-active'" class="menu-item"
|
<a :class="activeTab === 'backups' && 'menu-item-active'" class="menu-item"
|
||||||
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'"
|
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'"
|
||||||
wire:navigate href="#">Backups</a>
|
wire:navigate href="#backups">Backups</a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
|
@@ -55,10 +55,10 @@
|
|||||||
<h3>Preview Deployments Environment Variables</h3>
|
<h3>Preview Deployments Environment Variables</h3>
|
||||||
<div>Environment (secrets) variables for Preview Deployments.</div>
|
<div>Environment (secrets) variables for Preview Deployments.</div>
|
||||||
</div>
|
</div>
|
||||||
{{-- @foreach ($resource->environment_variables_preview as $env)
|
@foreach ($resource->environment_variables_preview as $env)
|
||||||
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
|
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
|
||||||
:env="$env" :type="$resource->type()" />
|
:env="$env" :type="$resource->type()" />
|
||||||
@endforeach --}}
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
<form wire:submit.prevent='submit' class="flex flex-col gap-2">
|
<form wire:submit.prevent='submit' class="flex flex-col gap-2">
|
||||||
|
@@ -16,43 +16,58 @@
|
|||||||
@elseif ($type === 'server')
|
@elseif ($type === 'server')
|
||||||
<x-server.navbar :server="$server" :parameters="$parameters" />
|
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||||
@endif
|
@endif
|
||||||
@if ($type === 'server')
|
|
||||||
<form class="w-full" wire:submit="$dispatchSelf('connectToServer')" wire:init="$dispatchSelf('connectToServer')">
|
@if(!$hasShell)
|
||||||
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
|
<div class="flex items-center justify-center w-full py-4 mx-auto">
|
||||||
</form>
|
<div class="p-4 w-full rounded border dark:bg-coolgray-100 dark:border-coolgray-300">
|
||||||
<div class="mx-auto w-full">
|
<div class="flex flex-col items-center justify-center space-y-4">
|
||||||
<livewire:project.shared.terminal />
|
<svg class="w-12 h-12 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||||
|
</svg>
|
||||||
|
<div class="text-center">
|
||||||
|
<h3 class="text-lg font-medium">Terminal Not Available</h3>
|
||||||
|
<p class="mt-2 text-sm text-gray-500">No shell (bash/sh) is available in this container. Please ensure either bash or sh is installed to use the terminal.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
@if (count($containers) > 0)
|
@if ($type === 'server')
|
||||||
@if (count($containers) === 1)
|
<form class="w-full" wire:submit="$dispatchSelf('connectToServer')" wire:init="$dispatchSelf('connectToServer')">
|
||||||
<form class="w-full pt-4" wire:submit="$dispatchSelf('connectToContainer')"
|
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
|
||||||
wire:init="$dispatchSelf('connectToContainer')">
|
</form>
|
||||||
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
|
|
||||||
</form>
|
|
||||||
@else
|
|
||||||
<form class="w-full pt-4 flex gap-2 flex-col" wire:submit="$dispatchSelf('connectToContainer')">
|
|
||||||
<x-forms.select label="Container" id="container" required wire:model="selected_container">
|
|
||||||
@foreach ($containers as $container)
|
|
||||||
@if ($loop->first)
|
|
||||||
<option disabled value="default">Select a container</option>
|
|
||||||
@endif
|
|
||||||
<option value="{{ data_get($container, 'container.Names') }}">
|
|
||||||
{{ data_get($container, 'container.Names') }}
|
|
||||||
({{ data_get($container, 'server.name') }})
|
|
||||||
</option>
|
|
||||||
@endforeach
|
|
||||||
</x-forms.select>
|
|
||||||
<x-forms.button class="w-full" type="submit">
|
|
||||||
Connect
|
|
||||||
</x-forms.button>
|
|
||||||
</form>
|
|
||||||
@endif
|
|
||||||
<div class="mx-auto w-full">
|
<div class="mx-auto w-full">
|
||||||
<livewire:project.shared.terminal />
|
<livewire:project.shared.terminal />
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="pt-4">No containers are running.</div>
|
@if (count($containers) === 0)
|
||||||
|
<div class="pt-4">No containers are running.</div>
|
||||||
|
@else
|
||||||
|
@if (count($containers) === 1)
|
||||||
|
<form class="w-full pt-4" wire:submit="$dispatchSelf('connectToContainer')"
|
||||||
|
wire:init="$dispatchSelf('connectToContainer')">
|
||||||
|
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<form class="w-full pt-4 flex gap-2 flex-col" wire:submit="$dispatchSelf('connectToContainer')">
|
||||||
|
<x-forms.select label="Container" id="container" required wire:model="selected_container">
|
||||||
|
@foreach ($containers as $container)
|
||||||
|
@if ($loop->first)
|
||||||
|
<option disabled value="default">Select a container</option>
|
||||||
|
@endif
|
||||||
|
<option value="{{ data_get($container, 'container.Names') }}">
|
||||||
|
{{ data_get($container, 'container.Names') }}
|
||||||
|
({{ data_get($container, 'server.name') }})
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</x-forms.select>
|
||||||
|
<x-forms.button class="w-full" type="submit">Connect</x-forms.button>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
|
<div class="mx-auto w-full">
|
||||||
|
<livewire:project.shared.terminal />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
@elseif(!$resource->destination->server->isMetricsEnabled())
|
@elseif(!$resource->destination->server->isMetricsEnabled())
|
||||||
<div class="alert alert-warning">Metrics are only available for servers with Sentinel & Metrics enabled!</div>
|
<div class="alert alert-warning">Metrics are only available for servers with Sentinel & Metrics enabled!</div>
|
||||||
<div> Go to <a class="underline dark:text-white"
|
<div> Go to <a class="underline dark:text-white"
|
||||||
href="{{ route('server.show', $resource->destination->server->uuid) }}">Server settings</a> to
|
wire:navigate href="{{ route('server.show', $resource->destination->server->uuid) }}">Server settings</a> to
|
||||||
enable
|
enable
|
||||||
it.</div>
|
it.</div>
|
||||||
@else
|
@else
|
||||||
|
@@ -1,9 +1,4 @@
|
|||||||
<div id="terminal-container" x-data="terminalData()">
|
<div id="terminal-container" x-data="terminalData()">
|
||||||
{{-- <div x-show="!terminalActive" class="flex items-center justify-center w-full py-4 mx-auto h-[510px]">
|
|
||||||
<div class="p-1 w-full h-full rounded border dark:bg-coolgray-100 dark:border-coolgray-300">
|
|
||||||
<span class="font-mono text-sm text-gray-500" x-text="message"></span>
|
|
||||||
</div>
|
|
||||||
</div> --}}
|
|
||||||
<div x-ref="terminalWrapper"
|
<div x-ref="terminalWrapper"
|
||||||
:class="fullscreen ? 'fullscreen' : 'relative w-full h-full py-4 mx-auto max-h-[510px]'">
|
:class="fullscreen ? 'fullscreen' : 'relative w-full h-full py-4 mx-auto max-h-[510px]'">
|
||||||
<div id="terminal" wire:ignore></div>
|
<div id="terminal" wire:ignore></div>
|
||||||
|
@@ -6,72 +6,75 @@
|
|||||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
|
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
|
||||||
<x-server.sidebar :server="$server" activeMenu="docker-cleanup" />
|
<x-server.sidebar :server="$server" activeMenu="docker-cleanup" />
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div>
|
<form wire:submit='submit'>
|
||||||
<div class="flex items-center gap-2">
|
<div>
|
||||||
<h2>Docker Cleanup</h2>
|
<div class="flex items-center gap-2">
|
||||||
|
<h2>Docker Cleanup</h2>
|
||||||
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-4">Configure Docker cleanup settings for your server.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 mb-4">Configure Docker cleanup settings for your server.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<h3>Docker Cleanup</h3>
|
<h3>Docker Cleanup</h3>
|
||||||
<x-modal-confirmation title="Confirm Docker Cleanup?" buttonTitle="Trigger Manual Cleanup"
|
<x-modal-confirmation title="Confirm Docker Cleanup?" buttonTitle="Trigger Manual Cleanup"
|
||||||
isHighlightedButton submitAction="manualCleanup" :actions="[
|
isHighlightedButton submitAction="manualCleanup" :actions="[
|
||||||
'Permanently deletes all stopped containers managed by Coolify (as containers are non-persistent, no data will be lost)',
|
'Permanently deletes all stopped containers managed by Coolify (as containers are non-persistent, no data will be lost)',
|
||||||
'Permanently deletes all unused images',
|
'Permanently deletes all unused images',
|
||||||
'Clears build cache',
|
'Clears build cache',
|
||||||
'Removes old versions of the Coolify helper image',
|
'Removes old versions of the Coolify helper image',
|
||||||
'Optionally permanently deletes all unused volumes (if enabled in advanced options).',
|
'Optionally permanently deletes all unused volumes (if enabled in advanced options).',
|
||||||
'Optionally permanently deletes all unused networks (if enabled in advanced options).',
|
'Optionally permanently deletes all unused networks (if enabled in advanced options).',
|
||||||
]" :confirmWithText="false"
|
]" :confirmWithText="false"
|
||||||
:confirmWithPassword="false" step2ButtonText="Trigger Docker Cleanup" />
|
:confirmWithPassword="false" step2ButtonText="Trigger Docker Cleanup" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap items-center gap-4">
|
<div class="flex flex-wrap items-center gap-4">
|
||||||
<x-forms.input placeholder="*/10 * * * *" id="dockerCleanupFrequency"
|
<x-forms.input placeholder="*/10 * * * *" id="dockerCleanupFrequency"
|
||||||
label="Docker cleanup frequency" required
|
label="Docker cleanup frequency" required
|
||||||
helper="Cron expression for Docker Cleanup.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every night at midnight." />
|
helper="Cron expression for Docker Cleanup.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every night at midnight." />
|
||||||
@if (!$forceDockerCleanup)
|
@if (!$forceDockerCleanup)
|
||||||
<x-forms.input id="dockerCleanupThreshold" label="Docker cleanup threshold (%)" required
|
<x-forms.input id="dockerCleanupThreshold" label="Docker cleanup threshold (%)" required
|
||||||
helper="The Docker cleanup tasks will run when the disk usage exceeds this threshold." />
|
helper="The Docker cleanup tasks will run when the disk usage exceeds this threshold." />
|
||||||
@endif
|
@endif
|
||||||
|
<div class="w-96">
|
||||||
|
<x-forms.checkbox
|
||||||
|
helper="Enabling Force Docker Cleanup or manually triggering a cleanup will perform the following actions:
|
||||||
|
<ul class='list-disc pl-4 mt-2'>
|
||||||
|
<li>Removes stopped containers managed by Coolify (as containers are none persistent, no data will be lost).</li>
|
||||||
|
<li>Deletes unused images.</li>
|
||||||
|
<li>Clears build cache.</li>
|
||||||
|
<li>Removes old versions of the Coolify helper image.</li>
|
||||||
|
<li>Optionally delete unused volumes (if enabled in advanced options).</li>
|
||||||
|
<li>Optionally remove unused networks (if enabled in advanced options).</li>
|
||||||
|
</ul>"
|
||||||
|
instantSave id="forceDockerCleanup" label="Force Docker Cleanup" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">
|
||||||
|
<span class="dark:text-warning font-bold">Warning: Enable these
|
||||||
|
options only if you fully understand their implications and
|
||||||
|
consequences!</span><br>Improper use will result in data loss and could cause
|
||||||
|
functional issues.
|
||||||
|
</p>
|
||||||
<div class="w-96">
|
<div class="w-96">
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox instantSave id="deleteUnusedVolumes" label="Delete Unused Volumes"
|
||||||
helper="Enabling Force Docker Cleanup or manually triggering a cleanup will perform the following actions:
|
helper="This option will remove all unused Docker volumes during cleanup.<br><br><strong>Warning: Data form stopped containers will be lost!</strong><br><br>Consequences include:<br>
|
||||||
<ul class='list-disc pl-4 mt-2'>
|
<ul class='list-disc pl-4 mt-2'>
|
||||||
<li>Removes stopped containers managed by Coolify (as containers are none persistent, no data will be lost).</li>
|
<li>Volumes not attached to running containers will be deleted and data will be permanently lost (stopped containers are affected).</li>
|
||||||
<li>Deletes unused images.</li>
|
<li>Data from stopped containers volumes will be permanently lost.</li>
|
||||||
<li>Clears build cache.</li>
|
<li>No way to recover deleted volume data.</li>
|
||||||
<li>Removes old versions of the Coolify helper image.</li>
|
</ul>" />
|
||||||
<li>Optionally delete unused volumes (if enabled in advanced options).</li>
|
<x-forms.checkbox instantSave id="deleteUnusedNetworks" label="Delete Unused Networks"
|
||||||
<li>Optionally remove unused networks (if enabled in advanced options).</li>
|
helper="This option will remove all unused Docker networks during cleanup.<br><br><strong>Warning: Functionality may be lost and containers may not be able to communicate with each other!</strong><br><br>Consequences include:<br>
|
||||||
</ul>"
|
<ul class='list-disc pl-4 mt-2'>
|
||||||
instantSave id="forceDockerCleanup" label="Force Docker Cleanup" />
|
<li>Networks not attached to running containers will be permanently deleted (stopped containers are affected).</li>
|
||||||
|
<li>Custom networks for stopped containers will be permanently deleted.</li>
|
||||||
|
<li>Functionality may be lost and containers may not be able to communicate with each other.</li>
|
||||||
|
</ul>" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">
|
</form>
|
||||||
<span class="dark:text-warning font-bold">Warning: Enable these
|
|
||||||
options only if you fully understand their implications and
|
|
||||||
consequences!</span><br>Improper use will result in data loss and could cause
|
|
||||||
functional issues.
|
|
||||||
</p>
|
|
||||||
<div class="w-96">
|
|
||||||
<x-forms.checkbox instantSave id="deleteUnusedVolumes" label="Delete Unused Volumes"
|
|
||||||
helper="This option will remove all unused Docker volumes during cleanup.<br><br><strong>Warning: Data form stopped containers will be lost!</strong><br><br>Consequences include:<br>
|
|
||||||
<ul class='list-disc pl-4 mt-2'>
|
|
||||||
<li>Volumes not attached to running containers will be deleted and data will be permanently lost (stopped containers are affected).</li>
|
|
||||||
<li>Data from stopped containers volumes will be permanently lost.</li>
|
|
||||||
<li>No way to recover deleted volume data.</li>
|
|
||||||
</ul>" />
|
|
||||||
<x-forms.checkbox instantSave id="deleteUnusedNetworks" label="Delete Unused Networks"
|
|
||||||
helper="This option will remove all unused Docker networks during cleanup.<br><br><strong>Warning: Functionality may be lost and containers may not be able to communicate with each other!</strong><br><br>Consequences include:<br>
|
|
||||||
<ul class='list-disc pl-4 mt-2'>
|
|
||||||
<li>Networks not attached to running containers will be permanently deleted (stopped containers are affected).</li>
|
|
||||||
<li>Custom networks for stopped containers will be permanently deleted.</li>
|
|
||||||
<li>Functionality may be lost and containers may not be able to communicate with each other.</li>
|
|
||||||
</ul>" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<h3 class="mb-4">Recent executions <span class="text-xs text-neutral-500">(click to check output)</span></h3>
|
<h3 class="mb-4">Recent executions <span class="text-xs text-neutral-500">(click to check output)</span></h3>
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
$traefikDashboardAvailable &&
|
$traefikDashboardAvailable &&
|
||||||
$server->proxyType() === ProxyTypes::TRAEFIK->value)
|
$server->proxyType() === ProxyTypes::TRAEFIK->value)
|
||||||
<button>
|
<button>
|
||||||
<a wire:navigate target="_blank" href="http://{{ $serverIp }}:8080">
|
<a target="_blank" href="http://{{ $serverIp }}:8080">
|
||||||
Traefik Dashboard
|
Traefik Dashboard
|
||||||
<x-external-link />
|
<x-external-link />
|
||||||
</a>
|
</a>
|
||||||
|
@@ -37,6 +37,9 @@ services:
|
|||||||
- MAILER_USER=${MAILER_USER}
|
- MAILER_USER=${MAILER_USER}
|
||||||
- MAILER_PASSWORD=${MAILER_PASSWORD}
|
- MAILER_PASSWORD=${MAILER_PASSWORD}
|
||||||
- MAILER_SENDER=${MAILER_SENDER}
|
- MAILER_SENDER=${MAILER_SENDER}
|
||||||
|
- COPILOT_FAL_API_KEY=${COPILOT_FAL_API_KEY}
|
||||||
|
- COPILOT_PERPLEXITY_API_KEY=${COPILOT_PERPLEXITY_API_KEY}
|
||||||
|
- COPILOT_OPENAI_API_KEY=${COPILOT_OPENAI_API_KEY}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/3010' || exit 1"]
|
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/3010' || exit 1"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
@@ -11,3 +11,8 @@ services:
|
|||||||
command: tunnel --no-autoupdate run
|
command: tunnel --no-autoupdate run
|
||||||
environment:
|
environment:
|
||||||
- 'TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}'
|
- 'TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}'
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "cloudflared", "--version"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
|
23
templates/compose/flipt.yaml
Normal file
23
templates/compose/flipt.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# documentation: https://docs.flipt.io/cloud/overview
|
||||||
|
# slogan: Flipt is a fully managed feature flag solution that enables you to keep your feature flags and remote config next to your code in Git.
|
||||||
|
# tags: feature flags,devops, CI, CD
|
||||||
|
# logo: svgs/flipt.svg
|
||||||
|
# port: 8080
|
||||||
|
|
||||||
|
services:
|
||||||
|
flipt:
|
||||||
|
image: 'docker.flipt.io/flipt/flipt:latest'
|
||||||
|
volumes:
|
||||||
|
- 'flipt-data:/var/opt/flipt'
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_FLIPT_8080
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
- CMD
|
||||||
|
- wget
|
||||||
|
- '--spider'
|
||||||
|
- '--quiet'
|
||||||
|
- 'http://127.0.0.1:8080'
|
||||||
|
interval: 2s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
@@ -9,24 +9,49 @@ services:
|
|||||||
image: invoiceninja/invoiceninja:5
|
image: invoiceninja/invoiceninja:5
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_FQDN_INVOICENINJA
|
- SERVICE_FQDN_INVOICENINJA
|
||||||
|
- APP_NAME=${APP_NAME:-"Invoice Ninja"}
|
||||||
- APP_ENV=${APP_ENV:-production}
|
- APP_ENV=${APP_ENV:-production}
|
||||||
- APP_URL=${SERVICE_FQDN_INVOICENINJA}
|
- APP_URL=${SERVICE_FQDN_INVOICENINJA}
|
||||||
- APP_KEY=base64:${SERVICE_REALBASE64_INVOICENINJA}
|
- APP_KEY=base64:${SERVICE_REALBASE64_INVOICENINJA}
|
||||||
- APP_DEBUG=${APP_DEBUG:-false}
|
- APP_DEBUG=${APP_DEBUG:-false}
|
||||||
- REQUIRE_HTTPS=${REQUIRE_HTTPS:-false}
|
- REQUIRE_HTTPS=${REQUIRE_HTTPS:-false}
|
||||||
- PHANTOMJS_PDF_GENERATION=${PHANTOMJS_PDF_GENERATION:-false}
|
- PHANTOMJS_PDF_GENERATION=${PHANTOMJS_PDF_GENERATION:-false}
|
||||||
- PDF_GENERATOR=${PDF_GENERATOR:-snappdf}
|
- PDF_GENERATOR=${PDF_GENERATOR:-hosted_ninja}
|
||||||
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-*}
|
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-*}
|
||||||
- QUEUE_CONNECTION=${QUEUE_CONNECTION:-database}
|
- CACHE_DRIVER=redis
|
||||||
- IN_USER_EMAIL=${IN_USER_EMAIL:-admin@example.com}
|
- QUEUE_CONNECTION=${QUEUE_CONNECTION:-redis}
|
||||||
- IN_PASSWORD=${SERVICE_PASSWORD_INVOICENINJAUSER}
|
- SESSION_DRIVER=redis
|
||||||
|
- REDIS_HOST=${REDIS_HOST:-redis}
|
||||||
|
- REDIS_PASSWORD=${SERVICE_PASSWORD_REDIS}
|
||||||
|
- REDIS_PORT=${REDIS_PORT:-6379}
|
||||||
- DB_HOST=${DB_HOST:-mariadb}
|
- DB_HOST=${DB_HOST:-mariadb}
|
||||||
- DB_PORT=${DB_PORT:-3306}
|
- DB_PORT=${DB_PORT:-3306}
|
||||||
- DB_DATABASE=${DB_DATABASE:-invoiceninja}
|
- DB_DATABASE=${DB_DATABASE:-invoiceninja}
|
||||||
- DB_USERNAME=$SERVICE_USER_MARIADB
|
- DB_USERNAME=${SERVICE_USER_MARIADB}
|
||||||
- DB_PASSWORD=$SERVICE_PASSWORD_MARIADB
|
- DB_PASSWORD=${SERVICE_PASSWORD_MARIADB}
|
||||||
|
- IN_USER_EMAIL=${IN_USER_EMAIL:-admin@example.com}
|
||||||
|
- IN_PASSWORD=${SERVICE_PASSWORD_INVOICENINJAUSER}
|
||||||
|
- MAIL_MAILER=${MAIL_MAILER:-log}
|
||||||
|
- MAIL_HOST=${MAIL_HOST}
|
||||||
|
- MAIL_PORT=${MAIL_PORT}
|
||||||
|
- MAIL_USERNAME=${MAIL_USERNAME}
|
||||||
|
- MAIL_PASSWORD=${MAIL_PASSWORD}
|
||||||
|
- MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
|
||||||
|
- MAIL_FROM_ADDRESS=${MAIL_FROM_ADDRESS}
|
||||||
|
- MAIL_FROM_NAME=${MAIL_FROM_NAME}
|
||||||
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
||||||
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
||||||
|
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
|
||||||
|
- AWS_BUCKET=${AWS_BUCKET}
|
||||||
|
- AWS_URL=${AWS_URL}
|
||||||
|
- AWS_ENDPOINT=${AWS_ENDPOINT}
|
||||||
|
- NORDIGEN_SECRET_ID=${NORDIGEN_SECRET_ID}
|
||||||
|
- NORDIGEN_SECRET_KEY=${NORDIGEN_SECRET_KEY}
|
||||||
|
- IS_DOCKER=true
|
||||||
|
- SCOUT_DRIVER=${SCOUT_DRIVER}
|
||||||
|
- LICENSE_KEY=${LICENSE_KEY}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'echo', 'ok']
|
test: ["CMD", "echo", "ok"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 20s
|
timeout: 20s
|
||||||
retries: 10
|
retries: 10
|
||||||
@@ -133,12 +158,25 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- mariadb-data:/var/lib/mysql
|
- mariadb-data:/var/lib/mysql
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_ROOT_PASSWORD=$SERVICE_PASSWORD_MARIADBROOT
|
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MARIADBROOT}
|
||||||
- MYSQL_DATABASE=${DB_DATABASE:-invoiceninja}
|
- MYSQL_DATABASE=${DB_DATABASE:-invoiceninja}
|
||||||
- MYSQL_USER=$SERVICE_USER_MARIADB
|
- MYSQL_USER=${SERVICE_USER_MARIADB}
|
||||||
- MYSQL_PASSWORD=$SERVICE_PASSWORD_MARIADB
|
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MARIADB}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 20s
|
timeout: 20s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: "redis:7.4-alpine"
|
||||||
|
command: redis-server --requirepass ${SERVICE_PASSWORD_REDIS}
|
||||||
|
environment:
|
||||||
|
- REDIS_PASSWORD=${SERVICE_PASSWORD_REDIS}
|
||||||
|
volumes:
|
||||||
|
- "invoice-ninja-redis-data:/data"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "-a", "${SERVICE_PASSWORD_REDIS}", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
@@ -25,9 +25,10 @@ services:
|
|||||||
- APP_URI=${SERVICE_FQDN_PLUNK}
|
- APP_URI=${SERVICE_FQDN_PLUNK}
|
||||||
- API_URI=${SERVICE_FQDN_PLUNK}/api
|
- API_URI=${SERVICE_FQDN_PLUNK}/api
|
||||||
- DISABLE_SIGNUPS=${DISABLE_SIGNUPS:-False}
|
- DISABLE_SIGNUPS=${DISABLE_SIGNUPS:-False}
|
||||||
|
- NODE_OPTIONS=--no-network-family-autoselection
|
||||||
entrypoint: [ "/app/entry.sh" ]
|
entrypoint: [ "/app/entry.sh" ]
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000"]
|
test: ["CMD-SHELL", "(wget -S --spider http://127.0.0.1:3000/api/health 2>&1 | grep -q \"HTTP/1.1 [1-3]\")"]
|
||||||
interval: 2s
|
interval: 2s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 15
|
retries: 15
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.383"
|
"version": "4.0.0-beta.389"
|
||||||
},
|
},
|
||||||
"nightly": {
|
"nightly": {
|
||||||
"version": "4.0.0-beta.384"
|
"version": "4.0.0-beta.390"
|
||||||
},
|
},
|
||||||
"helper": {
|
"helper": {
|
||||||
"version": "1.0.4"
|
"version": "1.0.5"
|
||||||
},
|
},
|
||||||
"realtime": {
|
"realtime": {
|
||||||
"version": "1.0.5"
|
"version": "1.0.5"
|
||||||
|
Reference in New Issue
Block a user