Compare commits

...

54 Commits

Author SHA1 Message Date
Andras Bacsai
a07fa8ccd2 Merge pull request #1773 from coollabsio/next
v4.0.0-beta.223
2024-02-22 15:23:27 +01:00
Andras Bacsai
c77f32e696 fix: statuses 2024-02-22 15:15:16 +01:00
Andras Bacsai
4391771416 Merge pull request #1768 from coollabsio/next
v4.0.0-beta.222
2024-02-22 14:56:55 +01:00
Andras Bacsai
01ab820459 Fix error message formatting in handleError function 2024-02-22 14:56:41 +01:00
Andras Bacsai
c7218f2856 Update success messages 2024-02-22 14:53:42 +01:00
Andras Bacsai
592221b4bf fix: server validation 2024-02-22 14:46:11 +01:00
Andras Bacsai
836458ad85 fix: no coolify.yaml found 2024-02-22 14:45:56 +01:00
Andras Bacsai
7233c86f3d fix: use latest image if nothing is specified 2024-02-22 14:45:41 +01:00
Andras Bacsai
154b1b05e4 feat: able to add dynamic configurations from proxy dashboard 2024-02-22 13:29:28 +01:00
Andras Bacsai
4d88638d4d Update proxy configuration in bootstrap/helpers/proxy.php 2024-02-22 12:00:16 +01:00
Andras Bacsai
9403986643 Merge pull request #1767 from iamEvanYT/fix-stuck-connections
fix: connections being stuck and not processed until proxy restarts
2024-02-22 11:59:52 +01:00
Andras Bacsai
ad48610b2f Merge pull request #1770 from piscis/patch-2
fix: Avoid breaking the tile layout with long fqdn output
2024-02-22 11:54:25 +01:00
Andras Bacsai
63487cf3ec feat: minversion for services 2024-02-22 11:53:25 +01:00
Andras Bacsai
4ae2087c2e fix: server validation 2024-02-22 11:28:45 +01:00
Andras Bacsai
5179129a6b fix: complex container status
feat: able to change primary server
feat: links inside the logs
2024-02-22 10:57:05 +01:00
Andras Bacsai
6a00d8c88c Refactor loadData method in Destination.php 2024-02-22 09:38:09 +01:00
Andras Bacsai
50f43f9396 Update resource view to set type as 'public' 2024-02-22 09:38:03 +01:00
Alex
6f205f8931 Force browser to break all words on line end for fqdn output
Force the browser to break long lines for the fqdn output instead of overflowing the tile
2024-02-21 19:16:09 +01:00
Andras Bacsai
3776ffa49b disable administration gh permission for now 2024-02-21 14:42:38 +01:00
Andras Bacsai
318b5beac1 Update select.blade.php with responsive styling 2024-02-21 14:40:48 +01:00
Andras Bacsai
344c5d6d12 Update service configurations 2024-02-21 14:30:32 +01:00
Andras Bacsai
4d319a8caa Update service and shared helper files 2024-02-21 12:22:32 +01:00
Andras Bacsai
74b24a0690 Add file permission change for LocalFileVolume.php and add service_name parameter to fqdnLabelsForTraefik() function 2024-02-21 11:21:11 +01:00
Andras Bacsai
1ca0464957 fix: permission change updates from webhook 2024-02-20 20:17:04 +01:00
Andras Bacsai
f7ebc8a88c feat: save github app permission locally 2024-02-20 18:14:47 +01:00
Andras Bacsai
a102099ac1 icons 2024-02-20 17:08:16 +01:00
Andras Bacsai
59ac22aa05 Update redis.svg icon 2024-02-20 15:45:30 +01:00
Andras Bacsai
cd7244b3d7 Add logos for various services 2024-02-20 15:42:30 +01:00
Andras Bacsai
f81b676abe ui: updates 2024-02-20 15:07:12 +01:00
iamEvan
234b154053 fix: connections being stuck and not processed until proxy restarts 2024-02-20 17:16:43 +08:00
Andras Bacsai
a1d09ad574 Update version numbers to 4.0.0-beta.222 2024-02-19 13:39:05 +01:00
Andras Bacsai
b983b23e7e Merge pull request #1766 from coollabsio/next
v4.0.0-beta.221
2024-02-19 13:29:58 +01:00
Andras Bacsai
0b81e77a94 fix: database status 2024-02-19 13:28:14 +01:00
Andras Bacsai
b8cf314bfe fix: submodule cloning 2024-02-19 13:22:09 +01:00
Andras Bacsai
4a3338e59c Update version numbers 2024-02-19 10:44:52 +01:00
Andras Bacsai
5b8538c0f4 Merge pull request #1763 from coollabsio/next
v4.0.0-beta.220
2024-02-19 09:53:54 +01:00
Andras Bacsai
88d6320d08 Re-enable docker container removal in ApplicationDeploymentJob 2024-02-19 09:51:39 +01:00
Andras Bacsai
651c9c2c9b Merge pull request #1756 from victor-teles/fix/log-drain-parsers
fix: fluent bit parsers.conf indentation level
2024-02-19 09:22:36 +01:00
Andras Bacsai
8dd45cd388 Merge pull request #1757 from victor-teles/fix/revalidate-server-button
fix(server): revalidate server button not showing in server's page
2024-02-19 09:21:50 +01:00
Andras Bacsai
126ac354d5 fix: empty build variables 2024-02-19 09:19:50 +01:00
Victor
024769c402 fix(server): revalidate server button not showing in server's page 2024-02-17 12:43:49 -03:00
Victor
5acf141669 fix: fluent bit ident level 2024-02-17 12:25:48 -03:00
Andras Bacsai
92e3e8ab7b Merge branch 'main' into next 2024-02-17 16:17:01 +01:00
Andras Bacsai
187a29c666 Update README.md 2024-02-17 16:16:42 +01:00
Andras Bacsai
4c24631795 Add coolify.managed flag to proxy configuration 2024-02-16 23:17:29 +01:00
Andras Bacsai
7d6bd10cca Add Docker container management methods and update Livewire component 2024-02-16 23:09:35 +01:00
Andras Bacsai
f8c86769a7 fix: resources 2024-02-16 22:15:18 +01:00
Andras Bacsai
e0b0dda382 Remove unused code for displaying server resources 2024-02-16 22:04:26 +01:00
Andras Bacsai
b8708f086e feat: initial api endpoints
feat: server resources are now looks better
2024-02-16 21:56:38 +01:00
Andras Bacsai
3539e4dce9 Update Docker installation error messages 2024-02-16 09:06:28 +01:00
Andras Bacsai
5fdadcf557 fix: add openbsd ssh server check 2024-02-16 09:04:32 +01:00
Andras Bacsai
acb3f01f79 Merge pull request #1752 from ahmedrowaihi/main
👌 IMPORVE(SCRIPT/INSTALL): Support Archlinux
2024-02-16 09:03:51 +01:00
Andras Bacsai
83becdb19d fix: only show redeployment required if status is not exited 2024-02-16 08:34:30 +01:00
=
e3e8fe7895 👌 IMPORVE(SCRIPT/INSTALL): Support Archlinux 2024-02-16 01:56:16 +03:00
208 changed files with 4678 additions and 872 deletions

View File

@@ -10,6 +10,17 @@ No vendor lock-in, which means that all the configuration for your applications/
For more information, take a look at our landing page [here](https://coolify.io).
# Installation
```bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
```
You can find the installation script source [here](./scripts/install.sh).
# Support
Contact us [here](https://coolify.io/docs/contact).
# Donations
To stay completely free, open-source, no feature behind paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the future development of the project.
@@ -66,16 +77,6 @@ By subscribing to the cloud version, you get the Coolify server for the same pri
- Better support
- Less maintenance for you
# Installation
```bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
```
You can find the installation script source [here](./scripts/install.sh).
# Support
Contact us [here](https://coolify.io/docs/contact).
# Recognitions

View File

@@ -128,9 +128,9 @@ class InstallLogDrain
if ($type !== 'custom') {
$parsers = base64_encode("
[PARSER]
Name empty_line_skipper
Format regex
Regex /^(?!\s*$).+/
Name empty_line_skipper
Format regex
Regex /^(?!\s*$).+/
");
}
$compose = base64_encode("

View File

@@ -73,6 +73,18 @@ class ServicesGenerate extends Command
} else {
$slogan = str($file)->headline()->value();
}
$logo = collect(preg_grep('/^# logo:/', explode("\n", $content)))->values();
if ($logo->count() > 0) {
$logo = str($logo[0])->after('# logo:')->trim()->value();
} else {
$logo = 'svgs/unknown.svg';
}
$minversion = collect(preg_grep('/^# minversion:/', explode("\n", $content)))->values();
if ($minversion->count() > 0) {
$minversion = str($minversion[0])->after('# minversion:')->trim()->value();
} else {
$minversion = '0.0.0';
}
$env_file = collect(preg_grep('/^# env_file:/', explode("\n", $content)))->values();
if ($env_file->count() > 0) {
$env_file = str($env_file[0])->after('# env_file:')->trim()->value();
@@ -96,6 +108,8 @@ class ServicesGenerate extends Command
'slogan' => $slogan,
'compose' => $yaml,
'tags' => $tags,
'logo' => $logo,
'minversion' => $minversion,
];
if ($env_file) {
$env_file_content = file_get_contents(base_path("templates/compose/$env_file"));

View File

@@ -4,7 +4,6 @@ namespace App\Console;
use App\Jobs\CheckLogDrainContainerJob;
use App\Jobs\CleanupInstanceStuffsJob;
use App\Jobs\ComplexContainerStatusJob;
use App\Jobs\DatabaseBackupJob;
use App\Jobs\ScheduledTaskJob;
use App\Jobs\InstanceAutoUpdateJob;

View File

@@ -18,8 +18,7 @@ class Deploy extends Controller
{
public function deploy(Request $request)
{
$token = auth()->user()->currentAccessToken();
$teamId = data_get($token, 'team_id');
$teamId = get_team_id_from_token();
$uuids = $request->query->get('uuid');
$tags = $request->query->get('tag');
$force = $request->query->get('force') ?? false;

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Project as ModelsProject;
use Illuminate\Http\Request;
class Project extends Controller
{
public function projects(Request $request)
{
$teamId = get_team_id_from_token();
if (is_null($teamId)) {
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
}
$projects = ModelsProject::whereTeamId($teamId)->select('id', 'name', 'uuid')->get();
return response()->json($projects);
}
public function project_by_uuid(Request $request)
{
$teamId = get_team_id_from_token();
if (is_null($teamId)) {
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
}
$project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first()->load(['environments']);
return response()->json($project);
}
public function environment_details(Request $request)
{
$teamId = get_team_id_from_token();
if (is_null($teamId)) {
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
}
$project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
$environment = $project->environments()->whereName(request()->environment_name)->first()->load(['applications', 'postgresqls', 'redis', 'mongodbs', 'mysqls', 'mariadbs', 'services']);
return response()->json($environment);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Server as ModelsServer;
use Illuminate\Http\Request;
class Server extends Controller
{
public function servers(Request $request)
{
$teamId = get_team_id_from_token();
if (is_null($teamId)) {
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
}
$servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port')->get()->load(['settings'])->map(function ($server) {
$server['is_reachable'] = $server->settings->is_reachable;
$server['is_usable'] = $server->settings->is_usable;
return $server;
});
ray($servers);
return response()->json($servers);
}
public function server_by_uuid(Request $request)
{
$teamId = get_team_id_from_token();
if (is_null($teamId)) {
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
}
$server = ModelsServer::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
if (is_null($server)) {
return response()->json(['error' => 'Server not found.'], 404);
}
$server->load(['settings']);
$server['resources'] = $server->definedResources()->map(function ($resource) {
$payload = [
'id' => $resource->id,
'uuid' => $resource->uuid,
'name' => $resource->name,
'type' => $resource->type(),
'created_at' => $resource->created_at,
'updated_at' => $resource->updated_at,
];
if ($resource->type() === 'service') {
$payload['status'] = $resource->status();
} else {
$payload['status'] = $resource->status;
}
return $payload;
});
return response()->json($server);
}
}

View File

@@ -66,6 +66,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private Server $mainServer;
private ?ApplicationPreview $preview = null;
private ?string $git_type = null;
private bool $only_this_server = false;
private string $container_name;
private ?string $currently_running_container_name = null;
@@ -115,6 +116,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->commit = $this->application_deployment_queue->commit;
$this->force_rebuild = $this->application_deployment_queue->force_rebuild;
$this->restart_only = $this->application_deployment_queue->restart_only;
$this->only_this_server = $this->application_deployment_queue->only_this_server;
$this->git_type = data_get($this->application_deployment_queue, 'git_type');
@@ -331,7 +333,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private function deploy_dockerimage_buildpack()
{
$this->dockerImage = $this->application->docker_registry_image_name;
$this->dockerImageTag = $this->application->docker_registry_image_tag;
if (str($this->application->docker_registry_image_tag)->isEmpty()) {
$this->dockerImageTag = 'latest';
} else {
$this->dockerImageTag = $this->application->docker_registry_image_tag;
}
ray("echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.'");
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
$this->generate_image_names();
@@ -887,7 +893,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
destination: $destination,
no_questions_asked: true,
);
$this->application_deployment_queue->addLogEntry("Deploying to additional server: {$server->name}. Click here to see the deployment status: " . route('project.application.deployment.show', [
$this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: " . route('project.application.deployment.show', [
'project_uuid' => data_get($this->application, 'environment.project.uuid'),
'application_uuid' => data_get($this->application, 'uuid'),
'deployment_uuid' => $deployment_uuid,
@@ -1022,11 +1028,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->env_nixpacks_args = collect([]);
if ($this->pull_request_id === 0) {
foreach ($this->application->nixpacks_environment_variables as $env) {
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
if (!is_null($env->real_value)) {
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
}
}
} else {
foreach ($this->application->nixpacks_environment_variables_preview as $env) {
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
if (!is_null($env->real_value)) {
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
}
}
}
@@ -1037,11 +1047,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->env_args = collect([]);
if ($this->pull_request_id === 0) {
foreach ($this->application->build_environment_variables as $env) {
$this->env_args->put($env->key, $env->real_value);
if (!is_null($env->real_value)) {
$this->env_args->put($env->key, $env->real_value);
}
}
} else {
foreach ($this->application->build_environment_variables_preview as $env) {
$this->env_args->put($env->key, $env->real_value);
if (!is_null($env->real_value)) {
$this->env_args->put($env->key, $env->real_value);
}
}
}
$this->env_args->put('SOURCE_COMMIT', $this->commit);
@@ -1611,7 +1625,9 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
return;
}
if ($status === ApplicationDeploymentStatus::FINISHED->value) {
$this->deploy_to_additional_destinations();
if (!$this->only_this_server) {
$this->deploy_to_additional_destinations();
}
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
}
}

View File

@@ -44,17 +44,19 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
public function handle()
{
$applications = $this->server->applications();
$skip_these_applications = collect([]);
foreach ($applications as $application) {
if ($application->additional_servers->count() > 0) {
$is_main_server = $application->destination->server->id === $this->server->id;
if ($is_main_server) {
ComplexStatusCheck::run($application);
$applications = $applications->filter(function ($value, $key) use ($application) {
return $value->id !== $application->id;
});
}
$skip_these_applications->push($application);
ComplexStatusCheck::run($application);
$applications = $applications->filter(function ($value, $key) use ($application) {
return $value->id !== $application->id;
});
}
}
$applications = $applications->filter(function ($value, $key) use ($skip_these_applications) {
return !$skip_these_applications->pluck('id')->contains($value->id);
});
if (!$this->server->isFunctional()) {
return 'Server is not ready.';

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Jobs;
use App\Models\GithubApp;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
class GithubAppPermissionJob implements ShouldQueue, ShouldBeEncrypted
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 4;
public function backoff(): int
{
return isDev() ? 1 : 3;
}
public function __construct(public GithubApp $github_app)
{
}
public function middleware(): array
{
return [(new WithoutOverlapping($this->github_app->uuid))];
}
public function uniqueId(): int
{
return $this->github_app->uuid;
}
public function handle()
{
try {
$github_access_token = generate_github_jwt_token($this->github_app);
$response = Http::withHeaders([
'Authorization' => "Bearer $github_access_token",
'Accept' => 'application/vnd.github+json'
])->get("{$this->github_app->api_url}/app");
$response = $response->json();
$permissions = data_get($response, 'permissions');
$this->github_app->contents = data_get($permissions, 'contents');
$this->github_app->metadata = data_get($permissions, 'metadata');
$this->github_app->pull_requests = data_get($permissions, 'pull_requests');
$this->github_app->administration = data_get($permissions, 'administration');
$this->github_app->save();
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
} catch (\Throwable $e) {
send_internal_notification('GithubAppPermissionJob failed with: ' . $e->getMessage());
ray($e->getMessage());
throw $e;
}
}
}

View File

@@ -63,7 +63,7 @@ class EmailSettings extends Component
]);
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -71,7 +71,7 @@ class EmailSettings extends Component
public function sendTestNotification()
{
$this->team?->notify(new Test($this->emails));
$this->dispatch('success', 'Test Email sent successfully.');
$this->dispatch('success', 'Test Email sent.');
}
public function instantSaveInstance()
{
@@ -83,7 +83,7 @@ class EmailSettings extends Component
$this->team->resend_enabled = false;
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -131,7 +131,7 @@ class EmailSettings extends Component
]);
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
$this->team->smtp_enabled = false;
return handleError($e, $this);
@@ -148,7 +148,7 @@ class EmailSettings extends Component
]);
$this->team->save();
refreshSession();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
$this->team->resend_enabled = false;
return handleError($e, $this);

View File

@@ -27,7 +27,7 @@ class Index extends Component
'name' => $this->name,
]);
$this->dispatch('success', 'Profile updated successfully.');
$this->dispatch('success', 'Profile updated');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -232,7 +232,6 @@ class General extends Component
if (data_get($this->application, 'build_pack') === 'dockerimage') {
$this->validate([
'application.docker_registry_image_name' => 'required',
'application.docker_registry_image_tag' => 'required',
]);
}
if (data_get($this->application, 'fqdn')) {

View File

@@ -33,15 +33,11 @@ class Heading extends Component
{
if ($this->application->destination->server->isFunctional()) {
dispatch(new ContainerStatusJob($this->application->destination->server));
// $this->application->refresh();
// $this->application->previews->each(function ($preview) {
// $preview->refresh();
// });
} else {
dispatch(new ServerStatusJob($this->application->destination->server));
}
if ($showNotification) $this->dispatch('success', "Application status updated.");
if ($showNotification) $this->dispatch('success', "Success", "Application status updated.");
}
public function force_deploy_without_cache()

View File

@@ -46,7 +46,7 @@ class Form extends Component
$this->validate();
$this->application->preview_url_template = str_replace(' ', '', $this->application->preview_url_template);
$this->application->save();
$this->dispatch('success', 'Preview url template updated successfully.');
$this->dispatch('success', 'Preview url template updated.');
$this->generate_real_url();
}
}

View File

@@ -33,7 +33,7 @@ class BackupExecutions extends Component
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->destination->server);
}
$execution->delete();
$this->dispatch('success', 'Backup deleted successfully.');
$this->dispatch('success', 'Backup deleted.');
$this->dispatch('refreshBackupExecutions');
}
public function download($exeuctionId)

View File

@@ -59,7 +59,7 @@ class General extends Component
return;
}
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
@@ -73,7 +73,7 @@ class General extends Component
}
$this->validate();
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
} catch (Exception $e) {
return handleError($e, $this);
}

View File

@@ -58,7 +58,7 @@ class General extends Component
return;
}
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
@@ -75,7 +75,7 @@ class General extends Component
}
$this->validate();
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
} catch (Exception $e) {
return handleError($e, $this);
}

View File

@@ -60,7 +60,7 @@ class General extends Component
return;
}
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
@@ -74,7 +74,7 @@ class General extends Component
}
$this->validate();
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
} catch (Exception $e) {
return handleError($e, $this);
}

View File

@@ -66,7 +66,7 @@ class General extends Component
return;
}
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
@@ -105,7 +105,7 @@ class General extends Component
$this->database->init_scripts = filter($this->database->init_scripts, fn ($s) => $s['filename'] !== $script['filename']);
$this->database->init_scripts = array_merge($this->database->init_scripts, [$script]);
$this->database->save();
$this->dispatch('success', 'Init script saved successfully.');
$this->dispatch('success', 'Init script saved.');
}
public function delete_init_script($script)
@@ -116,7 +116,7 @@ class General extends Component
$this->database->init_scripts = $collection->filter(fn ($s) => $s['filename'] !== $script['filename'])->toArray();
$this->database->save();
$this->refresh();
$this->dispatch('success', 'Init script deleted successfully.');
$this->dispatch('success', 'Init script deleted.');
return;
}
}
@@ -148,7 +148,7 @@ class General extends Component
]
]);
$this->database->save();
$this->dispatch('success', 'Init script added successfully.');
$this->dispatch('success', 'Init script added.');
$this->new_content = '';
$this->new_filename = '';
}
@@ -161,7 +161,7 @@ class General extends Component
}
$this->validate();
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
} catch (Exception $e) {
return handleError($e, $this);
}

View File

@@ -52,7 +52,7 @@ class General extends Component
return;
}
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
@@ -66,7 +66,7 @@ class General extends Component
$this->database->redis_conf = null;
}
$this->database->save();
$this->dispatch('success', 'Database updated successfully.');
$this->dispatch('success', 'Database updated.');
} catch (Exception $e) {
return handleError($e, $this);
}

View File

@@ -38,7 +38,7 @@ class ScheduledBackups extends Component
public function delete($scheduled_backup_id): void
{
$this->database->scheduledBackups->find($scheduled_backup_id)->delete();
$this->dispatch('success', 'Scheduled backup deleted successfully.');
$this->dispatch('success', 'Scheduled backup deleted.');
$this->refreshScheduledBackups();
}

View File

@@ -71,10 +71,10 @@ class Select extends Component
// }
// }
public function loadServices()
public function loadServices(bool $force = false)
{
try {
if (count($this->allServices) > 0) {
if (count($this->allServices) > 0 && !$force) {
if (!$this->search) {
$this->services = $this->allServices;
return;

View File

@@ -104,7 +104,7 @@ class Index extends Component
'environment_name' => data_get($service, 'environment.name'),
'service_uuid' => data_get($service, 'uuid')
]);
$service->status = serviceStatus($service);
$service->status = $service->status();
}
return $service;
});

View File

@@ -77,7 +77,7 @@ class Database extends Component
$this->validate();
$this->database->save();
updateCompose($this->database);
$this->dispatch('success', 'Database saved successfully.');
$this->dispatch('success', 'Database saved.');
} catch (\Throwable $e) {
ray($e);
} finally {

View File

@@ -42,7 +42,7 @@ class FileStorage extends Component
}
$this->fileStorage->save();
$this->fileStorage->saveStorageOnServer();
$this->dispatch('success', 'File updated successfully.');
$this->dispatch('success', 'File updated.');
} catch (\Throwable $e) {
$this->fileStorage->setRawAttributes($original);
$this->fileStorage->save();

View File

@@ -64,9 +64,9 @@ class Navbar extends Component
StopService::run($this->service);
$this->service->refresh();
if ($forceCleanup) {
$this->dispatch('success', 'Force cleanup service successfully.');
$this->dispatch('success', 'Force cleanup service.');
} else {
$this->dispatch('success', 'Service stopped successfully.');
$this->dispatch('success', 'Service stopped.');
}
ServiceStatusChanged::dispatch();
}

View File

@@ -41,7 +41,7 @@ class ServiceApplicationView extends Component
{
try {
$this->application->delete();
$this->dispatch('success', 'Application deleted successfully.');
$this->dispatch('success', 'Application deleted.');
return redirect()->route('project.service.configuration', $this->parameters);
} catch (\Throwable $e) {
return handleError($e, $this);
@@ -58,7 +58,7 @@ class ServiceApplicationView extends Component
$this->validate();
$this->application->save();
updateCompose($this->application);
$this->dispatch('success', 'Application saved successfully.');
$this->dispatch('success', 'Application saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {

View File

@@ -48,7 +48,7 @@ class StackForm extends Component
public function instantSave()
{
$this->service->save();
$this->dispatch('success', 'Service settings saved successfully.');
$this->dispatch('success', 'Service settings saved.');
}
public function submit()
@@ -62,7 +62,7 @@ class StackForm extends Component
$this->service->saveComposeConfigs();
$this->dispatch('refreshStacks');
$this->dispatch('refreshEnvs');
$this->dispatch('success', 'Service saved successfully.');
$this->dispatch('success', 'Service saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -4,6 +4,7 @@ namespace App\Livewire\Project\Shared;
use App\Actions\Application\StopApplicationOneServer;
use App\Events\ApplicationStatusChanged;
use App\Jobs\ContainerStatusJob;
use App\Models\Server;
use App\Models\StandaloneDocker;
use Livewire\Component;
@@ -40,6 +41,17 @@ class Destination extends Component
$this->networks = $this->networks->reject(function ($network) {
return $this->resource->destination->server->id == $network->server->id;
});
if ($this->resource?->additional_servers?->count() > 0) {
$this->networks = $this->networks->reject(function ($network) {
return $this->resource->additional_servers->pluck('id')->contains($network->server->id);
});
}
}
public function stop(int $server_id)
{
$server = Server::find($server_id);
StopApplicationOneServer::run($this->resource, $server);
$this->refreshServers();
}
public function redeploy(int $network_id, int $server_id)
{
@@ -55,6 +67,7 @@ class Destination extends Component
application: $this->resource,
server: $server,
destination: $destination,
only_this_server: true,
no_questions_asked: true,
);
return redirect()->route('project.application.deployment.show', [
@@ -64,12 +77,29 @@ class Destination extends Component
'environment_name' => data_get($this->resource, 'environment.name'),
]);
}
public function promote(int $network_id, int $server_id)
{
$main_destination = $this->resource->destination;
$this->resource->update([
'destination_id' => $network_id,
'destination_type' => StandaloneDocker::class,
]);
$this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
$this->resource->additional_networks()->attach($main_destination->id, ['server_id' => $main_destination->server->id]);
$this->refreshServers();
}
public function refreshServers()
{
ContainerStatusJob::dispatchSync($this->resource->destination->server);
$this->loadData();
$this->dispatch('refresh');
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
}
public function addServer(int $network_id, int $server_id)
{
$this->resource->additional_networks()->attach($network_id, ['server_id' => $server_id]);
$this->resource->load(['additional_networks']);
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
$this->loadData();
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
}
public function removeServer(int $network_id, int $server_id)
{
@@ -80,8 +110,7 @@ class Destination extends Component
$server = Server::find($server_id);
StopApplicationOneServer::run($this->resource, $server);
$this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
$this->resource->load(['additional_networks']);
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
$this->loadData();
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
}
}

View File

@@ -120,9 +120,9 @@ class All extends Component
}
}
if ($isPreview) {
$this->dispatch('success', 'Preview environment variables updated successfully.');
$this->dispatch('success', 'Preview environment variables updated.');
} else {
$this->dispatch('success', 'Environment variables updated successfully.');
$this->dispatch('success', 'Environment variables updated.');
}
$this->refreshEnvs();
}

View File

@@ -90,7 +90,7 @@ class Show extends Component
}
$this->serialize();
$this->env->save();
$this->dispatch('success', 'Environment variable updated successfully.');
$this->dispatch('success', 'Environment variable updated.');
$this->dispatch('refreshEnvs');
} catch (\Exception $e) {
return handleError($e);

View File

@@ -52,7 +52,7 @@ class ResourceLimits extends Component
}
$this->validate();
$this->resource->save();
$this->dispatch('success', 'Resource limits updated successfully.');
$this->dispatch('success', 'Resource limits updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -48,7 +48,7 @@ class All extends Component
}
$task->save();
$this->refreshTasks();
$this->dispatch('success', 'Scheduled task added successfully.');
$this->dispatch('success', 'Scheduled task added.');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -49,7 +49,7 @@ class Show extends Component
{
$this->validate();
$this->task->save();
$this->dispatch('success', 'Scheduled task updated successfully.');
$this->dispatch('success', 'Scheduled task updated.');
$this->dispatch('refreshTasks');
}

View File

@@ -64,7 +64,7 @@ class Form extends Component
refresh_server_connection($this->server->privateKey);
$this->validateServer(false);
$this->server->settings->save();
$this->dispatch('success', 'Server updated successfully.');
$this->dispatch('success', 'Server updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -88,7 +88,7 @@ class Form extends Component
}
public function validateServer($install = true)
{
$this->dispatch('validateServer', $install);
$this->dispatch('init', $install);
}
public function submit()
@@ -113,6 +113,6 @@ class Form extends Component
$this->server->settings->cleanup_after_percentage = $this->cleanup_after_percentage;
$this->server->settings->save();
$this->server->save();
$this->dispatch('success', 'Server updated successfully.');
$this->dispatch('success', 'Server updated.');
}
}

View File

@@ -60,7 +60,7 @@ class LogDrains extends Component
return;
}
$this->dispatch('serverRefresh');
$this->dispatch('success', 'Log drain service started successfully.');
$this->dispatch('success', 'Log drain service started.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -126,7 +126,7 @@ class LogDrains extends Component
]);
}
$this->server->settings->save();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
return true;
} catch (\Throwable $e) {
if ($type === 'newrelic') {

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Livewire\Server\Proxy;
use App\Models\Server;
use Livewire\Component;
class DynamicConfigurationNavbar extends Component
{
public $server_id;
public $fileName = '';
public $value = '';
public $newFile = false;
public function delete(string $fileName)
{
$server = Server::ownedByCurrentTeam()->whereId($this->server_id)->first();
$proxy_path = get_proxy_path();
$file = str_replace('|', '.', $fileName);
instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $server);
$this->dispatch('success', 'File deleted.');
$this->dispatch('loadDynamicConfigurations');
$this->dispatch('refresh');
}
public function render()
{
return view('livewire.server.proxy.dynamic-configuration-navbar');
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Livewire\Server\Proxy;
use App\Models\Server;
use Illuminate\Support\Collection;
use Livewire\Component;
class DynamicConfigurations extends Component
{
public ?Server $server = null;
public $parameters = [];
public Collection $contents;
protected $listeners = ['loadDynamicConfigurations', 'refresh' => '$refresh'];
protected $rules = [
'contents.*' => 'nullable|string',
];
public function loadDynamicConfigurations()
{
$proxy_path = get_proxy_path();
$files = instant_remote_process(["mkdir -p $proxy_path/dynamic && ls -1 {$proxy_path}/dynamic"], $this->server);
$files = collect(explode("\n", $files))->filter(fn ($file) => !empty($file));
$files = $files->map(fn ($file) => trim($file));
$files = $files->sort();
if ($files->contains('coolify.yaml')) {
$files = $files->filter(fn ($file) => $file !== 'coolify.yaml')->prepend('coolify.yaml');
}
$contents = collect([]);
foreach ($files as $file) {
$without_extension = str_replace('.', '|', $file);
$contents[$without_extension] = instant_remote_process(["cat {$proxy_path}/dynamic/{$file}"], $this->server);
}
$this->contents = $contents;
}
public function mount()
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.index');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.proxy.dynamic-configurations');
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace App\Livewire\Server\Proxy;
use App\Models\Server;
use Illuminate\Routing\Route;
use Livewire\Component;
use Symfony\Component\Yaml\Yaml;
class NewDynamicConfiguration extends Component
{
public string $fileName = '';
public string $value = '';
public bool $newFile = false;
public Server $server;
public $server_id;
public $parameters = [];
public function mount()
{
$this->parameters = get_route_parameters();
if ($this->fileName !== '') {
$this->fileName = str_replace('|', '.', $this->fileName);
}
}
public function addDynamicConfiguration()
{
try {
$this->validate([
'fileName' => 'required',
'value' => 'required',
]);
if (data_get($this->parameters, 'server_uuid')) {
$this->server = Server::ownedByCurrentTeam()->whereUuid(data_get($this->parameters, 'server_uuid'))->first();
}
if (!is_null($this->server_id)) {
$this->server = Server::ownedByCurrentTeam()->whereId($this->server_id)->first();
}
if (is_null($this->server)) {
return redirect()->route('server.index');
}
if (!str($this->fileName)->endsWith('.yaml') && !str($this->fileName)->endsWith('.yml')) {
$this->fileName = "{$this->fileName}.yaml";
}
if ($this->fileName === 'coolify.yaml') {
$this->dispatch('error', 'File name is reserved.');
return;
}
$proxy_path = get_proxy_path();
$file = "{$proxy_path}/dynamic/{$this->fileName}";
if ($this->newFile) {
$exists = instant_remote_process(["test -f $file && echo 1 || echo 0"], $this->server);
if ($exists == 1) {
$this->dispatch('error', 'File already exists');
return;
}
}
$yaml = Yaml::parse($this->value);
$yaml = Yaml::dump($yaml, 10, 2);
$this->value = $yaml;
$base64_value = base64_encode($this->value);
instant_remote_process(["echo '{$base64_value}' | base64 -d > {$file}"], $this->server);
$this->dispatch('loadDynamicConfigurations');
$this->dispatch('dynamic-configuration-added');
$this->dispatch('success', 'Dynamic configuration saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.proxy.new-dynamic-configuration');
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Livewire\Server;
use App\Models\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Collection;
use Livewire\Component;
class Resources extends Component
{
use AuthorizesRequests;
public ?Server $server = null;
public $parameters = [];
public Collection $unmanagedContainers;
public function getListeners()
{
$teamId = auth()->user()->currentTeam()->id;
return [
"echo-private:team.{$teamId},ApplicationStatusChanged" => 'refreshStatus',
];
}
public function startUnmanaged($id) {
$this->server->startUnmanaged($id);
$this->dispatch('success', 'Container started.');
$this->loadUnmanagedContainers();
}
public function restartUnmanaged($id) {
$this->server->restartUnmanaged($id);
$this->dispatch('success', 'Container restarted.');
$this->loadUnmanagedContainers();
}
public function stopUnmanaged($id) {
$this->server->stopUnmanaged($id);
$this->dispatch('success', 'Container stopped.');
$this->loadUnmanagedContainers();
}
public function refreshStatus() {
$this->server->refresh();
$this->loadUnmanagedContainers();
$this->dispatch('success', 'Resource statuses refreshed.');
}
public function loadUnmanagedContainers() {
$this->unmanagedContainers = $this->server->loadUnmanagedContainers();
}
public function mount() {
$this->unmanagedContainers = collect();
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.index');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
$this->loadUnmanagedContainers();
}
public function render()
{
return view('livewire.server.resources');
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Livewire\Server;
use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Models\Server;
use Livewire\Component;
@@ -21,7 +22,15 @@ class ValidateAndInstall extends Component
public $error = null;
public bool $ask = false;
protected $listeners = ['validateServer' => 'init', 'validateDockerEngine', 'validateServerNow' => 'validateServer'];
protected $listeners = [
'init',
'validateConnection',
'validateOS',
'validateDockerEngine',
'validateDockerVersion',
'startProxy',
'refresh' => '$refresh',
];
public function init(bool $install = true)
{
@@ -35,31 +44,29 @@ class ValidateAndInstall extends Component
$this->error = null;
$this->number_of_tries = 0;
if (!$this->ask) {
$this->dispatch('validateServerNow');
$this->dispatch('validateConnection');
}
}
public function startValidatingAfterAsking() {
public function startValidatingAfterAsking()
{
$this->ask = false;
$this->init();
}
public function validateServer()
public function startProxy()
{
try {
$this->validateConnection();
$this->validateOS();
$this->validateDockerEngine();
if ($this->server->isSwarm()) {
$swarmInstalled = $this->server->validateDockerSwarm();
if ($swarmInstalled) {
$this->dispatch('success', 'Docker Swarm is initiated.');
$shouldStart = CheckProxy::run($this->server);
if ($shouldStart) {
$proxy = StartProxy::run($this->server, false);
if ($proxy === 'OK') {
$this->proxy_started = true;
} else {
throw new \Exception("Proxy could not be started.");
}
} else {
$proxy = StartProxy::run($this->server);
if ($proxy) {
$this->proxy_started = true;
}
$this->proxy_started = true;
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -71,6 +78,7 @@ class ValidateAndInstall extends Component
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.';
return;
}
$this->dispatch('validateOS');
}
public function validateOS()
{
@@ -79,6 +87,7 @@ class ValidateAndInstall extends Component
$this->error = 'Server OS type is not supported. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
return;
}
$this->dispatch('validateDockerEngine');
}
public function validateDockerEngine()
{
@@ -90,29 +99,39 @@ class ValidateAndInstall extends Component
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
return;
} else {
$activity = $this->server->installDocker();
$this->number_of_tries++;
$this->dispatch('newActivityMonitor', $activity->id, 'validateDockerEngine');
if ($this->number_of_tries == 0) {
$activity = $this->server->installDocker();
$this->number_of_tries++;
$this->dispatch('newActivityMonitor', $activity->id, 'init');
}
return;
}
} else {
$this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
return;
}
} else {
$this->validateDockerVersion();
}
$this->dispatch('validateDockerVersion');
}
public function validateDockerVersion()
{
$this->docker_version = $this->server->validateDockerEngineVersion();
if ($this->docker_version) {
$this->dispatch('serverInstalled');
$this->dispatch('success', 'Server validated successfully.');
if ($this->server->isSwarm()) {
$swarmInstalled = $this->server->validateDockerSwarm();
if ($swarmInstalled) {
$this->dispatch('success', 'Docker Swarm is initiated.');
}
} else {
$this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
return;
$this->docker_version = $this->server->validateDockerEngineVersion();
if ($this->docker_version) {
$this->dispatch('serverInstalled');
$this->dispatch('success', 'Server validated.');
} else {
$this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
return;
}
}
$this->dispatch('startProxy');
}
public function render()
{

View File

@@ -81,6 +81,6 @@ class Backup extends Component
}
public function submit()
{
$this->dispatch('success', 'Backup updated successfully.');
$this->dispatch('success', 'Backup updated.');
}
}

View File

@@ -49,7 +49,7 @@ class Email extends Component
'settings.smtp_from_name' => 'required',
]);
$this->settings->save();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -61,7 +61,7 @@ class Email extends Component
'settings.resend_api_key' => 'required'
]);
$this->settings->save();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
$this->settings->resend_enabled = false;
return handleError($e, $this);
@@ -98,7 +98,7 @@ class Email extends Component
'settings.smtp_timeout' => 'nullable',
]);
$this->settings->save();
$this->dispatch('success', 'Settings saved successfully.');
$this->dispatch('success', 'Settings saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -2,8 +2,10 @@
namespace App\Livewire\Source\Github;
use App\Jobs\GithubAppPermissionJob;
use App\Models\GithubApp;
use App\Models\InstanceSettings;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class Change extends Component
@@ -15,6 +17,7 @@ class Change extends Component
public ?bool $default_permissions = true;
public ?bool $preview_deployment_permissions = true;
public ?bool $administration = false;
public $parameters;
public ?GithubApp $github_app;
@@ -34,8 +37,52 @@ class Change extends Component
'github_app.client_secret' => 'required|string',
'github_app.webhook_secret' => 'required|string',
'github_app.is_system_wide' => 'required|bool',
'github_app.contents' => 'nullable|string',
'github_app.metadata' => 'nullable|string',
'github_app.pull_requests' => 'nullable|string',
'github_app.administration' => 'nullable|string',
];
public function checkPermissions()
{
GithubAppPermissionJob::dispatchSync($this->github_app);
$this->github_app->refresh()->makeVisible('client_secret')->makeVisible('webhook_secret');
$this->dispatch('success', 'Github App permissions updated.');
}
// public function check()
// {
// Need administration:read:write permission
// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#list-self-hosted-runners-for-a-repository
// $github_access_token = generate_github_installation_token($this->github_app);
// $repositories = Http::withToken($github_access_token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100");
// $runners_by_repository = collect([]);
// $repositories = $repositories->json()['repositories'];
// foreach ($repositories as $repository) {
// $runners_downloads = Http::withToken($github_access_token)->get("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners/downloads");
// $runners = Http::withToken($github_access_token)->get("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners");
// $token = Http::withHeaders([
// 'Authorization' => "Bearer $github_access_token",
// 'Accept' => 'application/vnd.github+json'
// ])->withBody(null)->post("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners/registration-token");
// $token = $token->json();
// $remove_token = Http::withHeaders([
// 'Authorization' => "Bearer $github_access_token",
// 'Accept' => 'application/vnd.github+json'
// ])->withBody(null)->post("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners/remove-token");
// $remove_token = $remove_token->json();
// $runners_by_repository->put($repository['full_name'], [
// 'token' => $token,
// 'remove_token' => $remove_token,
// 'runners' => $runners->json(),
// 'runners_downloads' => $runners_downloads->json()
// ]);
// }
// ray($runners_by_repository);
// }
public function mount()
{
$github_app_uuid = request()->github_app_uuid;
@@ -103,7 +150,7 @@ class Change extends Component
'github_app.is_system_wide' => 'required|bool',
]);
$this->github_app->save();
$this->dispatch('success', 'Github App updated successfully.');
$this->dispatch('success', 'Github App updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -111,6 +158,13 @@ class Change extends Component
public function instantSave()
{
try {
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
$this->github_app->save();
$this->dispatch('success', 'Github App updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function delete()

View File

@@ -37,7 +37,7 @@ class Index extends Component
try {
$this->team->save();
refreshSession();
$this->dispatch('success', 'Team updated successfully.');
$this->dispatch('success', 'Team updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -79,7 +79,7 @@ class InviteLink extends Component
]);
$mail->subject('You have been invited to ' . currentTeam()->name . ' on ' . config('app.name') . '.');
send_user_an_email($mail, $this->email);
$this->dispatch('success', 'Invitation sent via email successfully.');
$this->dispatch('success', 'Invitation sent via email.');
$this->dispatch('refreshInvitations');
return;
} else {

View File

@@ -212,6 +212,10 @@ class Application extends BaseModel
);
}
public function isExited()
{
return (bool) str($this->status)->startsWith('exited');
}
public function realStatus()
{
return $this->getRawOriginal('status');
@@ -269,15 +273,11 @@ class Application extends BaseModel
foreach ($additional_servers_status as $status) {
$server_status = str($status)->before(':')->value();
$server_health = str($status)->after(':')->value() ?? 'unhealthy';
if ($server_status !== 'running') {
if ($main_server_status !== $server_status) {
$complex_status = 'degraded';
}
if ($main_server_status !== $server_status) {
$complex_status = 'degraded';
}
if ($server_health !== 'healthy') {
if ($main_server_health !== $server_health) {
$complex_health = 'unhealthy';
}
if ($main_server_health !== $server_health) {
$complex_health = 'unhealthy';
}
}
return "$complex_status:$complex_health";
@@ -518,17 +518,21 @@ class Application extends BaseModel
{
return "/artifacts/{$uuid}";
}
function setGitImportSettings(string $deployment_uuid, string $git_clone_command)
function setGitImportSettings(string $deployment_uuid, string $git_clone_command, bool $public = false)
{
$baseDir = $this->generateBaseDir($deployment_uuid);
if ($this->git_commit_sha !== 'HEAD') {
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && git -c advice.detachedHead=false checkout {$this->git_commit_sha} >/dev/null 2>&1";
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git -c advice.detachedHead=false checkout {$this->git_commit_sha} >/dev/null 2>&1";
}
if ($this->settings->is_git_submodules_enabled) {
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && git submodule update --init --recursive";
if ($public) {
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && sed -i \"s#git@\(.*\):#https://\\1/#g\" {$baseDir}/.gitmodules || true";
}
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git submodule update --init --recursive";
}
if ($this->settings->is_git_lfs_enabled) {
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && git lfs pull";
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git lfs pull";
}
return $git_clone_command;
}
@@ -556,7 +560,7 @@ class Application extends BaseModel
$fullRepoUrl = "{$this->source->html_url}/{$customRepository}";
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$customRepository} {$baseDir}";
if (!$only_checkout) {
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command);
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true);
}
if ($exec_in_docker) {
$commands->push(executeInDocker($deployment_uuid, $git_clone_command));
@@ -655,7 +659,7 @@ class Application extends BaseModel
if ($this->deploymentType() === 'other') {
$fullRepoUrl = $customRepository;
$git_clone_command = "{$git_clone_command} {$customRepository} {$baseDir}";
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command);
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true);
if ($pull_request_id !== 0) {
if ($git_type === 'gitlab') {

View File

@@ -26,7 +26,6 @@ class Environment extends Model
{
return $this->hasMany(Application::class);
}
public function postgresqls()
{
return $this->hasMany(StandalonePostgresql::class);

View File

@@ -57,6 +57,7 @@ class LocalFileVolume extends BaseModel
if ($content) {
$content = base64_encode($content);
$commands->push("echo '$content' | base64 -d > $path");
$commands->push("chmod +x $path");
}
} else if ($isDir == 'NOK' && $fileVolume->is_directory) {
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");

View File

@@ -6,7 +6,10 @@ use Illuminate\Database\Eloquent\Model;
class ProjectSetting extends Model
{
protected $fillable = [
'project_id'
];
protected $guarded = [];
public function project()
{
return $this->belongsTo(Project::class);
}
}

View File

@@ -225,6 +225,32 @@ class Server extends BaseModel
$services = $this->services();
return $applications->concat($databases)->concat($services->get());
}
public function stopUnmanaged($id)
{
return instant_remote_process(["docker stop -t 0 $id"], $this);
}
public function restartUnmanaged($id)
{
return instant_remote_process(["docker restart $id"], $this);
}
public function startUnmanaged($id)
{
return instant_remote_process(["docker start $id"], $this);
}
public function loadUnmanagedContainers()
{
$containers = instant_remote_process(["docker ps -a --format '{{json .}}' "], $this);
$containers = format_docker_command_output_to_json($containers);
$containers = $containers->map(function ($container) {
$labels = data_get($container, 'Labels');
if (!str($labels)->contains("coolify.managed")) {
return $container;
}
return null;
});
$containers = $containers->filter();
return collect($containers);
}
public function hasDefinedResources()
{
$applications = $this->applications()->count() > 0;
@@ -245,6 +271,8 @@ class Server extends BaseModel
$mysqls = data_get($standaloneDocker, 'mysqls', collect([]));
$mariadbs = data_get($standaloneDocker, 'mariadbs', collect([]));
return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs);
})->filter(function ($item) {
return data_get($item, 'name') !== 'coolify-db';
})->flatten();
}
public function applications()
@@ -370,10 +398,10 @@ class Server extends BaseModel
}
});
if ($supported->count() === 1) {
ray('supported');
// ray('supported');
return str($supported->first());
} else {
ray('not supported');
// ray('not supported');
return false;
}
}
@@ -440,6 +468,16 @@ class Server extends BaseModel
}
return false;
}
try {
instant_remote_process(["docker version"], $this);
} catch (\Throwable $e) {
$this->settings->is_usable = false;
$this->settings->save();
if ($throwError) {
throw new \Exception('Server is not usable. Docker Engine is not running.');
}
return false;
}
$this->settings->is_usable = true;
$this->settings->save();
$this->validateCoolifyNetwork(isSwarm: false, isBuildServer: $this->settings->is_build_server);

View File

@@ -28,6 +28,48 @@ class Service extends BaseModel
{
return $this->morphToMany(Tag::class, 'taggable');
}
public function status() {
$foundRunning = false;
$isDegraded = false;
$foundRestaring = false;
$applications = $this->applications;
$databases = $this->databases;
foreach ($applications as $application) {
if ($application->exclude_from_status) {
continue;
}
if (Str::of($application->status)->startsWith('running')) {
$foundRunning = true;
} else if (Str::of($application->status)->startsWith('restarting')) {
$foundRestaring = true;
} else {
$isDegraded = true;
}
}
foreach ($databases as $database) {
if ($database->exclude_from_status) {
continue;
}
if (Str::of($database->status)->startsWith('running')) {
$foundRunning = true;
} else if (Str::of($database->status)->startsWith('restarting')) {
$foundRestaring = true;
} else {
$isDegraded = true;
}
}
if ($foundRestaring) {
return 'degraded';
}
if ($foundRunning && !$isDegraded) {
return 'running';
} else if ($foundRunning && $isDegraded) {
return 'degraded';
} else if (!$foundRunning && !$isDegraded) {
return 'exited';
}
return 'exited';
}
public function extraFields()
{
$fields = collect([]);

View File

@@ -82,6 +82,9 @@ class StandaloneMariadb extends BaseModel
{
return $this->morphToMany(Tag::class, 'taggable');
}
public function project() {
return data_get($this, 'environment.project');
}
public function team()
{
return data_get($this, 'environment.project.team');

View File

@@ -85,6 +85,9 @@ class StandaloneMongodb extends BaseModel
{
return $this->morphToMany(Tag::class, 'taggable');
}
public function project() {
return data_get($this, 'environment.project');
}
public function team()
{
return data_get($this, 'environment.project.team');

View File

@@ -82,6 +82,9 @@ class StandaloneMysql extends BaseModel
{
return $this->morphToMany(Tag::class, 'taggable');
}
public function project() {
return data_get($this, 'environment.project');
}
public function team()
{
return data_get($this, 'environment.project.team');

View File

@@ -82,6 +82,10 @@ class StandalonePostgresql extends BaseModel
{
return $this->morphToMany(Tag::class, 'taggable');
}
public function project()
{
return data_get($this, 'environment.project');
}
public function link()
{
if (data_get($this, 'environment.project.uuid')) {

View File

@@ -77,6 +77,10 @@ class StandaloneRedis extends BaseModel
{
return $this->morphToMany(Tag::class, 'taggable');
}
public function project()
{
return data_get($this, 'environment.project');
}
public function team()
{
return data_get($this, 'environment.project.team');

View File

@@ -0,0 +1,31 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class ResourceView extends Component
{
/**
* Create a new component instance.
*/
public function __construct(
public ?string $wire = null,
public ?string $logo = null,
public ?string $documentation = null,
public bool $upgrade = false,
)
{
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.resource-view');
}
}

View File

@@ -11,11 +11,11 @@ class Index extends Component
/**
* Create a new component instance.
*/
public function __construct(
public string $status = 'exited',
)
{
//
public $resource = null,
public bool $showRefreshButton = true,
) {
}
/**

View File

@@ -15,8 +15,9 @@ class Services extends Component
public function __construct(
public Service $service,
public string $complexStatus = 'exited',
public bool $showRefreshButton = true
) {
$this->complexStatus = serviceStatus($service);
$this->complexStatus = $service->status();
}
/**

View File

@@ -0,0 +1,7 @@
<?php
function get_team_id_from_token()
{
$token = auth()->user()->currentAccessToken();
return data_get($token, 'team_id');
}

View File

@@ -8,7 +8,7 @@ use App\Models\Server;
use App\Models\StandaloneDocker;
use Spatie\Url\Url;
function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null)
function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null, bool $only_this_server = false)
{
$application_id = $application->id;
$deployment_link = Url::fromString($application->link() . "/deployment/{$deployment_uuid}");
@@ -37,7 +37,8 @@ function queue_application_deployment(Application $application, string $deployme
'is_webhook' => $is_webhook,
'restart_only' => $restart_only,
'commit' => $commit,
'git_type' => $git_type
'git_type' => $git_type,
'only_this_server' => $only_this_server
]);
if ($no_questions_asked) {

View File

@@ -212,7 +212,7 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource,
}
return $payload;
}
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true)
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?string $service_name = null)
{
$labels = collect([]);
$labels->push('traefik.enable=true');
@@ -264,6 +264,10 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
}
$http_label = "http-{$loop}-{$uuid}";
$https_label = "https-{$loop}-{$uuid}";
if ($service_name) {
$http_label = "http-{$loop}-{$uuid}-{$service_name}";
$https_label = "https-{$loop}-{$uuid}-{$service_name}";
}
if ($schema === 'https') {
// Set labels for https

View File

@@ -86,3 +86,8 @@ function get_installation_path(GithubApp $source)
$installation_path = $github->html_url === 'https://github.com' ? 'apps' : 'github-apps';
return "$github->html_url/$installation_path/$name/installations/new";
}
function get_permissions_path(GithubApp $source) {
$github = GithubApp::where('uuid', $source->uuid)->first();
$name = Str::of(Str::kebab($github->name));
return "$github->html_url/settings/apps/$name/permissions";
}

View File

@@ -103,6 +103,7 @@ function generate_default_proxy_configuration(Server $server)
"traefik.http.routers.traefik.entrypoints=http",
"traefik.http.routers.traefik.service=api@internal",
"traefik.http.services.traefik.loadbalancer.server.port=8080",
"coolify.managed=true",
];
$config = [
"version" => "3.8",
@@ -139,7 +140,9 @@ function generate_default_proxy_configuration(Server $server)
"--entrypoints.http.address=:80",
"--entrypoints.https.address=:443",
"--entrypoints.http.http.encodequerysemicolons=true",
"--entryPoints.http.http2.maxConcurrentStreams=50",
"--entrypoints.https.http.encodequerysemicolons=true",
"--entryPoints.https.http2.maxConcurrentStreams=50",
"--providers.docker.exposedbydefault=false",
"--providers.file.directory=/traefik/dynamic/",
"--providers.file.watch=true",

View File

@@ -4,8 +4,8 @@ use App\Models\EnvironmentVariable;
use App\Models\Service;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml;
function replaceRegex(?string $name = null)
@@ -21,49 +21,6 @@ function replaceVariables($variable)
return $variable->replaceFirst('$', '')->replaceFirst('{', '')->replaceLast('}', '');
}
function serviceStatus(Service $service)
{
$foundRunning = false;
$isDegraded = false;
$foundRestaring = false;
$applications = $service->applications;
$databases = $service->databases;
foreach ($applications as $application) {
if ($application->exclude_from_status) {
continue;
}
if (Str::of($application->status)->startsWith('running')) {
$foundRunning = true;
} else if (Str::of($application->status)->startsWith('restarting')) {
$foundRestaring = true;
} else {
$isDegraded = true;
}
}
foreach ($databases as $database) {
if ($database->exclude_from_status) {
continue;
}
if (Str::of($database->status)->startsWith('running')) {
$foundRunning = true;
} else if (Str::of($database->status)->startsWith('restarting')) {
$foundRestaring = true;
} else {
$isDegraded = true;
}
}
if ($foundRestaring) {
return 'degraded';
}
if ($foundRunning && !$isDegraded) {
return 'running';
} else if ($foundRunning && $isDegraded) {
return 'degraded';
} else if (!$foundRunning && !$isDegraded) {
return 'exited';
}
return 'exited';
}
function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneService, bool $isInit = false)
{
// TODO: make this async
@@ -138,12 +95,17 @@ function updateCompose($resource)
// Update FQDN
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
$fqdn = Url::fromString($resource->fqdn);
$fqdn = $fqdn->getScheme() . '://' . $fqdn->getHost();
if ($generatedEnv) {
$generatedEnv->value = $resource->fqdn;
$generatedEnv->value = $fqdn;
$generatedEnv->save();
}
$variableName = "SERVICE_URL_" . Str::of($resource->name)->upper();
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
$url = Url::fromString($resource->fqdn);
$url = $url->getHost();
ray($url);
if ($generatedEnv) {
$url = Str::of($resource->fqdn)->after('://');
$generatedEnv->value = $url;

View File

@@ -104,13 +104,13 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
ray($error);
if ($error instanceof TooManyRequestsException) {
if (isset($livewire)) {
return $livewire->dispatch('error', "Too many requests.", "Please try again in {$error->secondsUntilAvailable} seconds.");
return $livewire->dispatch('error', 'Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.');
}
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
}
if ($error instanceof UniqueConstraintViolationException) {
if (isset($livewire)) {
return $livewire->dispatch('error', "Duplicate entry found.", "Please use a different name.");
return $livewire->dispatch('error', 'Duplicate entry found. Please use a different name.');
}
return "Duplicate entry found. Please use a different name.";
}
@@ -125,9 +125,6 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
}
if (isset($livewire)) {
if (str($message)->length() > 20) {
return $livewire->dispatch('error', 'Error occured', $message);
}
return $livewire->dispatch('error', $message);
}
throw new Exception($message);
@@ -975,7 +972,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
]);
}
if (!$isDatabase) {
if ($command->value() === 'FQDN' && is_null($savedService->fqdn)) {
if ($command->value() === 'FQDN' && is_null($savedService->fqdn) && !$foundEnv) {
$savedService->fqdn = $fqdn;
$savedService->save();
}
@@ -1039,7 +1036,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
$serviceLabels = $serviceLabels->merge($defaultLabels);
if (!$isDatabase && $fqdns->count() > 0) {
if ($fqdns) {
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($resource->uuid, $fqdns, true, serviceLabels: $serviceLabels, is_gzip_enabled: $savedService->isGzipEnabled()));
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($resource->uuid, $fqdns, true, serviceLabels: $serviceLabels, is_gzip_enabled: $savedService->isGzipEnabled(), service_name: $serviceName));
}
}
if ($resource->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) {
@@ -1480,7 +1477,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
return $preview_fqdn;
});
}
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($uuid, $fqdns,serviceLabels: $serviceLabels));
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($uuid, $fqdns, serviceLabels: $serviceLabels));
}
}
}

View File

@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.219',
'release' => '4.0.0-beta.223',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),

View File

@@ -1,3 +1,3 @@
<?php
return '4.0.0-beta.219';
return '4.0.0-beta.223';

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('github_apps', function (Blueprint $table) {
$table->string('contents')->nullable();
$table->string('metadata')->nullable();
$table->string('pull_requests')->nullable();
$table->string('administration')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('github_apps', function (Blueprint $table) {
$table->dropColumn('contents');
$table->dropColumn('metadata');
$table->dropColumn('pull_requests');
$table->dropColumn('administration');
});
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('application_deployment_queues', function (Blueprint $table) {
$table->boolean('only_this_server')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('application_deployment_queues', function (Blueprint $table) {
$table->dropColumn('only_this_server');
});
}
};

19
public/svgs/appsmith.svg Normal file
View File

@@ -0,0 +1,19 @@
<svg width="924" height="235" viewBox="0 0 924 235" fill="ffffff" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_41)">
<path d="M602.936 59.0637C601.82 58.0005 600.937 56.7175 600.342 55.2956C599.746 53.8738 599.452 52.344 599.478 50.8028C599.478 47.673 600.722 44.6712 602.935 42.4581C605.148 40.2449 608.15 39.0016 611.28 39.0016C612.821 38.9758 614.351 39.2697 615.772 39.8648C617.194 40.46 618.477 41.3434 619.54 42.4593C620.635 43.5541 621.498 44.8581 622.078 46.2936C622.658 47.7291 622.943 49.2667 622.916 50.8146C622.941 52.3558 622.648 53.8856 622.052 55.3074C621.457 56.7293 620.574 58.0123 619.458 59.0755C618.389 60.1594 617.114 61.0169 615.706 61.5968C614.299 62.1767 612.79 62.4671 611.268 62.4507C609.723 62.4725 608.19 62.184 606.758 61.6022C605.327 61.0204 604.027 60.1572 602.936 59.0637V59.0637Z" fill="#ffffff"/>
<path d="M62.7915 160.047C61.7766 158.246 60.9899 154.705 60.4313 149.426C54.5778 157.876 45.2351 162.097 32.4032 162.089C22.8284 162.089 15.2009 159.784 9.52053 155.173C3.84018 150.563 1 144.143 1 135.914C1 120.045 12.1443 110.997 34.433 108.771L47.6033 107.591C51.9934 107.036 55.1443 105.986 57.0443 104.475C58.023 103.637 58.7921 102.581 59.29 101.393C59.788 100.204 60.001 98.9159 59.912 97.6303C59.912 93.9169 58.7043 91.1868 56.289 89.4402C53.8737 87.6936 49.7904 86.8204 44.0393 86.8204C37.8554 86.8204 33.4103 87.8628 30.7038 89.9477C28.0013 92.0365 26.42 95.6005 25.9833 100.675H5.03605C6.27125 80.8646 19.3313 70.9555 44.2163 70.9476C68.4247 70.9476 80.5249 79.6727 80.5171 97.1229V143.561C80.5171 151.224 81.6972 156.731 84.0574 160.083L62.7915 160.047ZM53.6691 141.425C57.8389 137.766 59.9199 132.503 59.912 125.635V117.704C57.894 119.51 54.566 120.69 49.9517 121.245L38.4691 122.543C32.8045 123.227 28.792 124.553 26.4318 126.52C25.2054 127.563 24.2386 128.876 23.6077 130.357C22.9769 131.838 22.6993 133.446 22.797 135.052C22.7027 136.7 22.9938 138.348 23.6473 139.864C24.3008 141.379 25.2986 142.722 26.5616 143.785C29.1028 145.862 32.7337 146.901 37.4542 146.901C44.1022 146.877 49.5072 145.052 53.6691 141.425Z" fill="#ffffff"/>
<path d="M186.056 83.2092C193.042 91.5409 196.531 102.63 196.524 116.477C196.516 130.324 193.026 141.338 186.056 149.521C178.975 157.852 169.463 162.018 157.52 162.018C145.577 162.018 136.569 157.573 130.495 148.683V193.091H109.253V72.9067H129.681V85.4042C135.975 75.7272 145.263 70.8847 157.544 70.8768C169.463 70.8768 178.967 74.9876 186.056 83.2092V83.2092ZM152.458 144.505C159.428 144.505 164.935 141.972 168.979 136.905C173.023 131.838 174.99 124.805 174.88 115.804C174.88 106.906 172.937 100.12 169.05 95.4471C165.164 90.7738 159.621 88.4371 152.422 88.4371C145.341 88.4371 139.834 90.8603 135.9 95.7067C131.967 100.553 130 107.477 130 116.477C130 125.588 132.026 132.511 136.077 137.247C139.901 142.086 145.361 144.505 152.458 144.505Z" fill="#ffffff"/>
<path d="M295.501 83.2092C302.487 91.5409 305.977 102.63 305.969 116.477C305.961 130.324 302.472 141.338 295.501 149.521C288.42 157.852 278.908 162.018 266.965 162.018C255.023 162.018 246.014 157.573 239.941 148.683V193.091H218.698V72.9067H239.138V85.4042C245.432 75.7272 254.72 70.8847 267.001 70.8768C278.873 70.8768 288.373 74.9876 295.501 83.2092ZM261.903 144.505C268.873 144.505 274.381 141.972 278.424 136.905C282.468 131.838 284.435 124.805 284.325 115.804C284.325 106.906 282.382 100.12 278.495 95.4471C274.609 90.7738 269.066 88.4371 261.867 88.4371C254.787 88.4371 249.279 90.8603 245.346 95.7067C241.412 100.553 239.445 107.477 239.445 116.477C239.445 125.588 241.475 132.511 245.534 137.247C249.311 142.086 254.747 144.505 261.844 144.505H261.903Z" fill="#ffffff"/>
<path d="M325.158 132.35H345.928C346.494 137.755 348.268 141.582 351.25 143.832C354.232 146.082 358.933 147.208 365.353 147.208C376.839 147.208 382.583 143.718 382.583 136.74C382.644 135.312 382.333 133.892 381.682 132.62C381.03 131.348 380.06 130.267 378.865 129.482C376.387 127.79 371.938 126.382 365.518 125.257L355.558 123.57C336.534 120.423 327.022 111.642 327.022 97.2291C327.022 89.0075 330.169 82.5601 336.463 77.8868C342.757 73.2135 351.651 70.8768 363.146 70.8768C388.023 70.8768 400.859 80.7112 401.653 100.38H381.591C381.363 95.2111 379.731 91.5251 376.694 89.3222C373.657 87.1193 369.153 86.0218 363.181 86.0297C353.048 86.0297 347.981 89.4088 347.981 96.167C347.928 97.4972 348.209 98.8196 348.799 100.013C349.388 101.207 350.268 102.234 351.356 103C353.614 104.628 357.332 105.895 362.509 106.8L373.484 108.488C384.066 110.399 391.748 113.44 396.532 117.61C401.315 121.78 403.707 127.578 403.707 135.005C403.707 143.785 400.332 150.539 393.581 155.268C386.831 159.996 377.315 162.356 365.034 162.349C339.591 162.388 326.298 152.388 325.158 132.35V132.35Z" fill="#ffffff"/>
<path d="M549.335 79.3265C554.677 84.9597 557.352 92.6699 557.36 102.457V160.047H536.117V105.832C536.117 94.8177 531.106 89.3104 521.082 89.3104C518.592 89.2151 516.113 89.6885 513.833 90.6945C511.553 91.7006 509.532 93.2129 507.924 95.1167C504.612 98.9954 502.952 104.652 502.944 112.087V160.047H481.867V105.832C481.867 94.8177 476.804 89.3104 466.678 89.3104C464.224 89.2393 461.785 89.7271 459.546 90.7371C457.307 91.7471 455.327 93.2527 453.756 95.1403C450.428 99.0189 448.768 104.676 448.776 112.111V160.071H427.534V72.9067H448.139V85.4042C454.094 75.7272 462.355 70.8847 472.921 70.8768C486.21 70.8768 495.218 76.2818 499.946 87.0918C506.468 76.2818 515.473 70.8768 526.959 70.8768C536.534 70.8768 543.993 73.6934 549.335 79.3265V79.3265Z" fill="#ffffff"/>
<path d="M720.347 89.1216H693.204V136.232C693.204 139.041 693.963 141.008 695.482 142.133C697 143.258 699.545 143.809 703.117 143.785H718.66V160C714.045 160.449 702.055 160.673 699.235 160.673C689.794 160.673 682.898 158.899 678.547 155.35C674.196 151.802 672.029 146.145 672.044 138.38V89.1216H652.289V72.9066H672.044V43.8165H693.204V72.9066H720.347V89.1216Z" fill="#ffffff"/>
<path d="M815.536 79.0669C821.004 84.5348 823.734 92.2765 823.726 102.292V160.047H802.484V105.832C802.484 94.8177 797.024 89.3104 786.104 89.3104C783.52 89.2569 780.955 89.746 778.572 90.7461C776.19 91.7463 774.044 93.2352 772.273 95.1167C768.512 98.9953 766.628 104.369 766.62 111.237V160.047H745.378V43.8165H766.62V84.5545C773.26 75.4439 782.095 70.8847 793.126 70.8768C802.614 70.8768 810.084 73.6069 815.536 79.0669V79.0669Z" fill="#ffffff"/>
<path d="M840.909 188.748V172.533H923.99V188.748H840.909Z" fill="#FF6D2D"/>
<path d="M622.101 143.832V72.9066H577.363V89.1216H600.836V143.832H577.363V160.047H645.574V143.832H622.101Z" fill="#ffffff"/>
</g>
<defs>
<clipPath id="clip0_1_41">
<rect width="924" height="235" fill="black"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

1
public/svgs/appwrite.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="112" height="98" fill="none" class="u-max-width-100-percent" viewBox="0 0 112 98"><path fill="#FD366E" d="M111.1 73.473v24.49H48.87c-18.13 0-33.96-9.849-42.429-24.49A48.7 48.7 0 0 1 0 52.293V45.67a48.5 48.5 0 0 1 1.732-10.048C7.545 15.064 26.448 0 48.871 0c22.422 0 41.323 15.064 47.136 35.623H69.398C65.03 28.922 57.47 24.491 48.872 24.491s-16.16 4.43-20.528 11.132a24.3 24.3 0 0 0-3.042 6.68 24.5 24.5 0 0 0-.921 6.679c0 7.02 2.952 13.348 7.685 17.811a24.4 24.4 0 0 0 16.806 6.68z"/><path fill="#FD366E" d="M111.1 42.303v24.49H65.676a24.4 24.4 0 0 0 7.686-17.81c0-2.316-.321-4.556-.922-6.68z"/></svg>

After

Width:  |  Height:  |  Size: 649 B

BIN
public/svgs/babybuddy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

59
public/svgs/bitwarden.svg Normal file
View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
xml:space="preserve"
width="64"
height="64"
viewBox="0 0 64 63.999999"
sodipodi:docname="bitwarden-icon.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="M 0,1500 H 1500 V 0 H 0 Z"
id="path16"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="799"
id="namedview4"
showgrid="false"
fit-margin-top="50"
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:zoom="5.3400704"
inkscape:cx="72.883247"
inkscape:cy="23.722997"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="logo-vertical"
transform="matrix(1.3333333,0,0,-1.3333333,31.882666,774.35078)"><path
d="m 20.088053,578.76279 v -24.00016 c 0,-1.79111 -0.34893,-3.56734 -1.046785,-5.32749 -0.698165,-1.76104 -1.562895,-3.32302 -2.593423,-4.68822 -1.031908,-1.36442 -2.261363,-2.69188 -3.687599,-3.98376 -1.427771,-1.29219 -2.745111,-2.36474 -3.9537075,-3.21903 -1.2081373,-0.85369 -2.4685751,-1.66122 -3.7808519,-2.42195 -1.3125864,-0.76028 -2.2452616,-1.27562 -2.7971051,-1.54665 -0.5518437,-0.27117 -0.9947907,-0.47961 -1.3280751,-0.6253 -0.2500014,-0.12451 -0.5211689,-0.18713 -0.8124295,-0.18713 -0.2917201,0 -0.5624267,0.0627 -0.81258076,0.18713 -0.33343844,0.14566 -0.77607884,0.35413 -1.32776984,0.6253 -0.552611,0.27103 -1.4845188,0.78637 -2.7972576,1.54665 -1.3125851,0.76073 -2.5731749,1.56826 -3.7814668,2.42195 -1.2081351,0.85429 -2.5257829,1.92684 -3.9529389,3.21903 -1.427156,1.29188 -2.655998,2.61934 -3.687139,3.98376 -1.031297,1.3652 -1.896026,2.92718 -2.594036,4.68822 -0.69801,1.76015 -1.046939,3.53638 -1.046939,5.32749 v 24.00016 c 0,0.54172 0.198161,1.01088 0.594021,1.40629 0.395556,0.39586 0.864578,0.59402 1.405992,0.59402 h 36.000846 c 0.540954,0 1.009208,-0.19816 1.405377,-0.59402 0.396014,-0.39541 0.593868,-0.86457 0.593868,-1.40629 m -6.000346,-24.00016 v 20.00043 H 0.0880769 v -35.53105 c 2.4786974,1.31259 4.6980372,2.73943 6.6564844,4.281 4.8952787,3.83317 7.3431457,7.58318 7.3431457,11.24962"
style="fill:#3c8dbc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.15337521"
id="path28"
inkscape:connector-curvature="0" /></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,15 @@
<svg width="45" height="31" viewBox="0 0 45 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5345_61190)">
<path d="M42.9532 13.469C42.0762 13.469 41.4914 12.9612 41.4914 11.919V5.93276C41.4914 2.1112 39.8966 0 35.7767 0H33.8629V4.03534H34.4477C36.069 4.03534 36.8399 4.91724 36.8399 6.49396V11.7854C36.8399 14.0836 37.5309 15.019 39.046 15.5C37.5309 15.9544 36.8399 16.9164 36.8399 19.2146C36.8399 20.5242 36.8399 21.8336 36.8399 23.1432C36.8399 24.2388 36.8399 25.3078 36.5475 26.4034C36.2552 27.419 35.7767 28.381 35.1122 29.2094C34.7401 29.6906 34.3148 30.0914 33.8364 30.4656V31H35.7501C39.87 31 41.4649 28.8888 41.4649 25.0672V19.081C41.4649 18.012 42.023 17.531 42.9267 17.531H44.0165V13.4956H42.9532V13.469Z" fill="white"/>
<path d="M29.929 6.09391H24.0282C23.8953 6.09391 23.7891 5.98701 23.7891 5.85339V5.39909C23.7891 5.26547 23.8953 5.15857 24.0282 5.15857H29.9556C30.0884 5.15857 30.1948 5.26547 30.1948 5.39909V5.85339C30.1948 5.98701 30.0618 6.09391 29.929 6.09391Z" fill="white"/>
<path d="M30.9388 11.8661H26.6328C26.4999 11.8661 26.3936 11.7591 26.3936 11.6255V11.1713C26.3936 11.0377 26.4999 10.9307 26.6328 10.9307H30.9388C31.0717 10.9307 31.1779 11.0377 31.1779 11.1713V11.6255C31.1779 11.7325 31.0717 11.8661 30.9388 11.8661Z" fill="white"/>
<path d="M32.6401 8.97996H24.0282C23.8953 8.97996 23.7891 8.87306 23.7891 8.73944V8.28513C23.7891 8.1515 23.8953 8.04462 24.0282 8.04462H32.6135C32.7464 8.04462 32.8528 8.1515 32.8528 8.28513V8.73944C32.8528 8.84634 32.773 8.97996 32.6401 8.97996Z" fill="white"/>
<path d="M17.1972 7.40258C17.7819 7.40258 18.3668 7.45604 18.9249 7.58966V6.49396C18.9249 4.94396 19.7223 4.03534 21.3171 4.03534H21.9019V0H19.9881C15.8682 0 14.2734 2.1112 14.2734 5.93276V7.91034C15.2037 7.58966 16.1872 7.40258 17.1972 7.40258Z" fill="white"/>
<path d="M34.4476 21.94C34.0223 18.546 31.4175 15.7132 28.0684 15.0718C27.1381 14.8848 26.2078 14.858 25.3041 15.0184C25.2775 15.0184 25.2775 14.9916 25.2509 14.9916C23.789 11.9184 20.6527 9.88733 17.2504 9.88733C13.8481 9.88733 10.7383 11.865 9.24981 14.9382C9.22324 14.9382 9.22324 14.965 9.19665 14.965C8.23978 14.858 7.2829 14.9114 6.32602 15.152C3.03011 15.9537 0.531599 18.733 0.0797398 22.1002C0.0265799 22.4476 0 22.795 0 23.1158C0 24.1312 0.691078 25.0666 1.70111 25.2002C2.95037 25.3874 4.04014 24.4252 4.01357 23.196C4.01357 23.0088 4.01357 22.795 4.04014 22.608C4.25279 20.8976 5.5552 19.4546 7.25631 19.0537C7.78792 18.92 8.31951 18.8934 8.82454 18.9736C10.4459 19.1874 12.0407 18.3588 12.7318 16.9158C13.2368 15.8468 14.0342 14.9114 15.0974 14.4037C16.2669 13.8425 17.5959 13.7624 18.8186 14.19C20.0944 14.6442 21.0513 15.6062 21.6361 16.8088C22.2474 17.9848 22.5397 18.8132 23.8422 18.9736C24.3738 19.0537 25.8622 19.027 26.4205 19.0002C27.5102 19.0002 28.6 19.3744 29.3708 20.1494C29.8758 20.6838 30.2479 21.352 30.4074 22.1002C30.6466 23.3028 30.3543 24.5054 29.6366 25.414C29.1316 26.0554 28.4405 26.5364 27.6697 26.7502C27.2975 26.8572 26.9254 26.8838 26.5533 26.8838C26.3407 26.8838 26.0484 26.8838 25.7028 26.8838C24.6396 26.8838 22.3803 26.8838 20.6791 26.8838C19.5097 26.8838 18.5793 25.9486 18.5793 24.7726V20.8175V16.9425C18.5793 16.6218 18.3136 16.3546 17.9946 16.3546H17.1706C15.5492 16.3812 14.2468 18.1986 14.2468 20.1226C14.2468 22.0468 14.2468 27.1512 14.2468 27.1512C14.2468 29.2356 15.9213 30.9192 17.9946 30.9192C17.9946 30.9192 27.2179 30.8925 27.3507 30.8925C29.4771 30.6787 31.444 29.583 32.773 27.8994C34.1021 26.2692 34.7134 24.1312 34.4476 21.94Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_5345_61190">
<rect width="44.2857" height="31" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

31
public/svgs/directus.svg Normal file
View File

@@ -0,0 +1,31 @@
<svg width="1024" height="1028" viewBox="0 0 1024 1028" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1255_4057)">
<rect width="1024" height="1028" fill="#6644FF"/>
<path d="M0 856.177V0H1024V1028H987.478C944.858 1005.08 881.857 978.413 792.583 956.099C706.535 934.591 579.091 924.288 443.621 913.336C289.815 900.902 125.662 887.631 0 856.177Z" fill="#754DFC"/>
<path d="M0 630.724V0H1024V864.167C987.48 836.871 914.997 793.6 788.518 757.39C703.262 732.982 576.241 718.365 441.22 702.828C288.002 685.197 124.482 666.38 0 630.724Z" fill="#8555F8"/>
<path d="M0 385.079V0H1024V661.623C992.243 634.157 920.217 583.508 783.219 539.058C698.867 511.689 572.433 492.648 438.037 472.408C285.691 449.465 123.114 424.981 0 385.079Z" fill="#945EF5"/>
<path d="M1024 0V470.993C995.948 444.51 924.692 389.046 780.011 339.296C696.15 310.459 570.068 289.215 436.045 266.632C284.289 241.062 122.352 213.776 0 171.81V0H1024Z" fill="#A366F1"/>
<path d="M170.96 0H1024V278.073C1008.47 260.248 941.186 192.346 771.386 130.624C688.04 100.328 562.349 76.8867 428.741 51.9689C343.042 35.9861 254.087 19.396 170.96 0Z" fill="#B36EEE"/>
<g filter="url(#filter0_dd_1255_4057)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M751.713 578.4C748 577.472 744.906 576.544 742.122 575.306C740.063 574.391 738.343 573.308 736.836 572.055C735.835 571.222 735.405 569.911 735.529 568.615C737.022 553.073 735.38 539.364 736.862 523.951C743.05 461.46 782.345 481.259 817.617 471.05C837.872 465.345 858.126 454.117 865.527 432.032C866.739 428.417 865.672 424.486 863.154 421.622C840.049 395.355 814.469 372.145 786.676 352.254C693.499 285.923 572.404 258.379 461.196 274.491C456.983 275.101 454.775 279.768 457.077 283.348C471.161 305.263 489.743 323.197 511.052 336.397C514.925 338.796 513.368 343.978 508.923 342.981C498.473 340.639 485.045 336.07 472.417 327.159C471.2 326.301 469.632 326.084 468.249 326.636C462.603 328.887 454.451 332.133 447.714 335.041C443.836 336.715 443.046 341.715 446.238 344.482C502.095 392.893 583.352 400.252 646.98 361.511C650.856 359.151 657.062 364.001 655.813 368.363C653.814 375.352 651.478 384.958 648.991 398.04C633.211 477.856 587.728 471.669 531.417 451.56C418.895 410.784 355.06 445.604 298.306 376.675C294.363 371.885 287.431 370.225 282.74 374.285C271.024 384.427 264.09 399.231 264.09 415.055C264.09 433.797 273.766 449.851 288.108 459.461C289.902 460.664 292.286 460.156 293.624 458.461C297.119 454.039 299.978 451.107 303.538 449.253C307.434 447.224 309.335 452.797 306.045 455.709C293.991 466.38 290.532 479.092 282.655 504.152C270.278 543.441 275.538 583.659 217.679 594.177C187.048 595.724 187.667 616.452 176.528 647.388C163.601 684.728 146.674 701.267 115.345 733.897C111.061 738.359 110.693 745.495 115.402 749.508C127.916 760.172 140.822 760.758 153.942 755.357C186.429 741.745 211.491 699.671 235.006 672.447C261.306 642.129 324.424 655.122 372.073 625.423C397.77 609.668 413.21 589.543 408.273 559.396C407.477 554.54 413.034 551.622 415.049 556.111C418.875 564.633 421.383 573.723 422.426 583.116C422.699 585.578 424.9 587.4 427.374 587.261C478.926 584.363 545.591 641.216 607.891 656.599C611.681 657.535 614.375 653.158 612.232 649.896C608.291 643.894 604.94 637.666 602.271 631.301C599.515 624.689 597.427 618.274 595.951 612.082C594.796 607.24 601.872 605.938 604.288 610.292C620.266 639.089 652.198 666.13 696.639 669.353C711.8 670.591 728.508 668.734 745.835 663.475C766.565 657.288 785.748 649.244 808.644 653.576C825.661 656.669 841.441 665.331 851.342 679.872C865.235 700.13 894.563 705.498 910.194 684.325C912.321 681.444 912.5 677.592 911.094 674.298C876.675 593.634 789.279 588.093 751.713 578.4Z" fill="white"/>
</g>
</g>
<defs>
<filter id="filter0_dd_1255_4057" x="52" y="222" width="920" height="608.703" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="12"/>
<feGaussianBlur stdDeviation="30"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0901961 0 0 0 0 0.160784 0 0 0 0 0.25098 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1255_4057"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="16"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0901961 0 0 0 0 0.160784 0 0 0 0 0.25098 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1255_4057" result="effect2_dropShadow_1255_4057"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1255_4057" result="shape"/>
</filter>
<clipPath id="clip0_1255_4057">
<rect width="1024" height="1028" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

1
public/svgs/docker.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
public/svgs/dokuwiki.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
public/svgs/duplicati.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
public/svgs/emby.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 KiB

1
public/svgs/fider.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB

147
public/svgs/filebrowser.svg Normal file
View File

@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xml:space="preserve"
width="560"
height="560"
version="1.1"
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
viewBox="0 0 560 560"
id="svg44"
sodipodi:docname="icon_raw.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
inkscape:export-filename="/home/umarcor/filebrowser/logo/icon_raw.svg.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><metadata
id="metadata48"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="711"
id="namedview46"
showgrid="false"
inkscape:zoom="0.33714286"
inkscape:cx="-172.33051"
inkscape:cy="280"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="svg44" />
<defs
id="defs4">
<style
type="text/css"
id="style2">
<![CDATA[
.fil1 {fill:#FEFEFE}
.fil6 {fill:#006498}
.fil7 {fill:#0EA5EB}
.fil8 {fill:#2979FF}
.fil3 {fill:#2BBCFF}
.fil0 {fill:#455A64}
.fil4 {fill:#53C6FC}
.fil5 {fill:#BDEAFF}
.fil2 {fill:#332C2B;fill-opacity:0.149020}
]]>
</style>
</defs>
<g
id="g85"
transform="translate(-70,-70)"><path
class="fil1"
d="M 350,71 C 504,71 629,196 629,350 629,504 504,629 350,629 196,629 71,504 71,350 71,196 196,71 350,71 Z"
id="path9"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil2"
d="M 475,236 593,387 C 596,503 444,639 301,585 L 225,486 339,330 c 0,0 138,-95 136,-94 z"
id="path11"
inkscape:connector-curvature="0"
style="fill:#332c2b;fill-opacity:0.14902003" /><path
class="fil3"
d="m 231,211 h 208 l 38,24 v 246 c 0,5 -3,8 -8,8 H 231 c -5,0 -8,-3 -8,-8 V 219 c 0,-5 3,-8 8,-8 z"
id="path13"
inkscape:connector-curvature="0"
style="fill:#2bbcff" /><path
class="fil4"
d="m 231,211 h 208 l 38,24 v 2 L 440,214 H 231 c -4,0 -7,3 -7,7 v 263 c -1,-1 -1,-2 -1,-3 V 219 c 0,-5 3,-8 8,-8 z"
id="path15"
inkscape:connector-curvature="0"
style="fill:#53c6fc" /><polygon
class="fil5"
points="305,212 418,212 418,310 305,310 "
id="polygon17"
style="fill:#bdeaff" /><path
class="fil5"
d="m 255,363 h 189 c 3,0 5,2 5,4 V 483 H 250 V 367 c 0,-2 2,-4 5,-4 z"
id="path19"
inkscape:connector-curvature="0"
style="fill:#bdeaff" /><polygon
class="fil6"
points="250,470 449,470 449,483 250,483 "
id="polygon21"
style="fill:#006498" /><path
class="fil6"
d="m 380,226 h 10 c 3,0 6,2 6,5 v 40 c 0,3 -3,6 -6,6 h -10 c -3,0 -6,-3 -6,-6 v -40 c 0,-3 3,-5 6,-5 z"
id="path23"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil1"
d="m 254,226 c 10,0 17,7 17,17 0,9 -7,16 -17,16 -9,0 -17,-7 -17,-16 0,-10 8,-17 17,-17 z"
id="path25"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil6"
d="m 267,448 h 165 c 2,0 3,1 3,3 v 0 c 0,1 -1,3 -3,3 H 267 c -2,0 -3,-2 -3,-3 v 0 c 0,-2 1,-3 3,-3 z"
id="path27"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil6"
d="m 267,415 h 165 c 2,0 3,1 3,3 v 0 c 0,1 -1,2 -3,2 H 267 c -2,0 -3,-1 -3,-2 v 0 c 0,-2 1,-3 3,-3 z"
id="path29"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil6"
d="m 267,381 h 165 c 2,0 3,2 3,3 v 0 c 0,2 -1,3 -3,3 H 267 c -2,0 -3,-1 -3,-3 v 0 c 0,-1 1,-3 3,-3 z"
id="path31"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil1"
d="m 236,472 c 3,0 5,2 5,5 0,2 -2,4 -5,4 -3,0 -5,-2 -5,-4 0,-3 2,-5 5,-5 z"
id="path33"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil1"
d="m 463,472 c 3,0 5,2 5,5 0,2 -2,4 -5,4 -3,0 -5,-2 -5,-4 0,-3 2,-5 5,-5 z"
id="path35"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><polygon
class="fil6"
points="305,212 284,212 284,310 305,310 "
id="polygon37"
style="fill:#006498" /><path
class="fil7"
d="m 477,479 v 2 c 0,5 -3,8 -8,8 H 231 c -5,0 -8,-3 -8,-8 v -2 c 0,4 3,8 8,8 h 238 c 5,0 8,-4 8,-8 z"
id="path39"
inkscape:connector-curvature="0"
style="fill:#0ea5eb" /><path
class="fil8"
d="M 350,70 C 505,70 630,195 630,350 630,505 505,630 350,630 195,630 70,505 70,350 70,195 195,70 350,70 Z m 0,46 C 479,116 584,221 584,350 584,479 479,584 350,584 221,584 116,479 116,350 116,221 221,116 350,116 Z"
id="path41"
inkscape:connector-curvature="0"
style="fill:#2979ff" /></g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
public/svgs/formbricks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

9
public/svgs/ghost.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB

1
public/svgs/git.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#F34F29" d="M124.737 58.378L69.621 3.264c-3.172-3.174-8.32-3.174-11.497 0L46.68 14.71l14.518 14.518c3.375-1.139 7.243-.375 9.932 2.314 2.703 2.706 3.461 6.607 2.294 9.993l13.992 13.993c3.385-1.167 7.292-.413 9.994 2.295 3.78 3.777 3.78 9.9 0 13.679a9.673 9.673 0 01-13.683 0 9.677 9.677 0 01-2.105-10.521L68.574 47.933l-.002 34.341a9.708 9.708 0 012.559 1.828c3.778 3.777 3.778 9.898 0 13.683-3.779 3.777-9.904 3.777-13.679 0-3.778-3.784-3.778-9.905 0-13.683a9.65 9.65 0 013.167-2.11V47.333a9.581 9.581 0 01-3.167-2.111c-2.862-2.86-3.551-7.06-2.083-10.576L41.056 20.333 3.264 58.123a8.133 8.133 0 000 11.5l55.117 55.114c3.174 3.174 8.32 3.174 11.499 0l54.858-54.858a8.135 8.135 0 00-.001-11.501z"/></svg>

After

Width:  |  Height:  |  Size: 778 B

31
public/svgs/gitea.svg Normal file
View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="100 100 800 520" xml:space="preserve">
<style type="text/css">
.st0{fill:#73A952;}
.st1{fill:#303030;}
</style>
<g id="Layer_2_1_">
<g>
<path class="st0" d="M822.9,149.5c-4.8-4.8-10.8-4.4-10.8-4.4s-132.1,7.3-200.3,8.9c-14.9,0.3-29.8,0.6-44.5,0.6v132.1
c-6.4-2.9-12.4-6-18.7-8.9c0-41,0-122.9,0-122.9c-32.7,0.3-100.3-2.5-100.3-2.5s-159.4-7.9-176.5-9.5c-11.1-0.6-25.4-2.2-43.8,1.6
c-9.8,1.9-37.8,8.3-60.6,30.2c-50.8,45.1-37.8,117.2-36.2,128c1.9,13,7.6,49.8,35.6,81.6c51.4,63.2,162.6,61.6,162.6,61.6
s13.7,32.7,34.6,62.5c28.3,37.1,57.2,66.4,85.1,69.9c70.8,0,212.7,0,212.7,0s13.7,0,31.8-11.7c15.9-9.5,29.8-26.4,29.8-26.4
s14.6-15.6,34.9-51.1c6.4-10.8,11.4-21.6,15.9-31.4c0,0,62.2-131.8,62.2-260.4C834.6,158.7,825.1,151.7,822.9,149.5L822.9,149.5z
M263.1,379.3c-29.2-9.5-41.6-21-41.6-21s-21.6-15.2-32.4-44.8c-18.4-50.2-1.6-80.3-1.6-80.3s9.5-25.4,43.5-33.7
c15.6-4.1,34.9-3.5,34.9-3.5s7.9,67,17.8,106c8.3,33,27.9,87.6,27.9,87.6S282.1,386,263.1,379.3L263.1,379.3z M601.2,500.3
c0,0-7,16.2-22.2,17.5c-6.7,0.3-11.7-1.3-11.7-1.3s-0.3,0-6-2.2l-127-61.9c0,0-12.4-6.4-14.3-17.5c-2.5-9.2,3.2-20.3,3.2-20.3
l61.3-126.1c0,0,5.4-10.8,13.7-14.6c0.6-0.3,2.5-1.3,5.1-1.6c9.2-2.2,20.3,3.2,20.3,3.2l124.8,60.3c0,0,14.3,6.4,17.1,18.1
c2.2,8.3-0.6,15.9-1.9,19.4C656.2,390.4,601.2,500.3,601.2,500.3L601.2,500.3z"/>
<path class="st0" d="M489.8,408.9c-9.2,0-17.5,6.7-19.4,15.6c-2.2,8.9,2.2,18.4,10.2,22.5c8.6,4.4,19.7,1.9,25.7-6
c5.7-7.9,4.8-19.1-1.9-26l27-55.2c1.6,0,4.1,0.3,7-0.6c4.8-1,7.9-4.1,7.9-4.1c4.8,1.9,9.8,4.1,14.9,7c5.4,2.9,10.5,5.4,15.2,8.3
c1,0.6,1.9,1.3,3.2,2.2c1.9,1.6,3.8,3.5,5.4,6.4c2.2,6.4-2.2,16.8-2.2,16.8c-2.5,8.6-20.6,45.7-20.6,45.7c-9.2-0.3-17.1,5.7-20,14
c-2.9,9.2,1.3,19.4,10.2,24.1s19.7,1.9,25.4-6c5.7-7.6,5.1-18.4-1.3-25.4c2.2-4.1,4.1-8.3,6.4-12.7c5.7-11.7,15.2-34.3,15.2-34.3
c1-1.9,6.4-11.7,3.2-24.1c-2.9-12.7-14.3-18.7-14.3-18.7c-13.7-8.9-33-17.1-33-17.1s0-4.8-1.3-7.9c-1.3-3.5-3.2-5.7-4.4-7
c5.4-10.8,10.5-21.6,15.9-32.7c-4.8-2.2-9.2-4.4-13.7-7c-5.4,11.1-10.8,22.2-16.2,33.3c-7.6,0-14.6,3.8-18.1,10.5
c-3.8,7-3.2,15.9,2.2,22.2L489.8,408.9L489.8,408.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

1
public/svgs/github.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill="#ffffff"><path fill-rule="evenodd" clip-rule="evenodd" d="M64 1.512c-23.493 0-42.545 19.047-42.545 42.545 0 18.797 12.19 34.745 29.095 40.37 2.126.394 2.907-.923 2.907-2.047 0-1.014-.04-4.366-.058-7.92-11.837 2.573-14.334-5.02-14.334-5.02-1.935-4.918-4.724-6.226-4.724-6.226-3.86-2.64.29-2.586.29-2.586 4.273.3 6.523 4.385 6.523 4.385 3.794 6.504 9.953 4.623 12.38 3.536.383-2.75 1.485-4.628 2.702-5.69-9.45-1.075-19.384-4.724-19.384-21.026 0-4.645 1.662-8.44 4.384-11.42-.442-1.072-1.898-5.4.412-11.26 0 0 3.572-1.142 11.7 4.363 3.395-.943 7.035-1.416 10.65-1.432 3.616.017 7.258.49 10.658 1.432 8.12-5.504 11.688-4.362 11.688-4.362 2.316 5.86.86 10.187.418 11.26 2.728 2.978 4.378 6.774 4.378 11.42 0 16.34-9.953 19.938-19.427 20.99 1.526 1.32 2.886 3.91 2.886 7.88 0 5.692-.048 10.273-.048 11.674 0 1.13.766 2.458 2.922 2.04 16.896-5.632 29.07-21.574 29.07-40.365C106.545 20.56 87.497 1.512 64 1.512z"/><path d="M37.57 62.596c-.095.212-.428.275-.73.13-.31-.14-.482-.427-.382-.64.09-.216.424-.277.733-.132.31.14.486.43.38.642zM39.293 64.52c-.203.187-.6.1-.87-.198-.278-.297-.33-.694-.124-.884.208-.188.593-.1.87.197.28.3.335.693.123.884zm1.677 2.448c-.26.182-.687.012-.95-.367-.262-.377-.262-.83.005-1.013.264-.182.684-.018.95.357.262.385.262.84-.005 1.024zm2.298 2.368c-.233.257-.73.188-1.093-.163-.372-.343-.475-.83-.242-1.087.237-.257.736-.185 1.102.163.37.342.482.83.233 1.086zm3.172 1.374c-.104.334-.582.485-1.064.344-.482-.146-.796-.536-.7-.872.1-.336.582-.493 1.067-.342.48.144.795.53.696.87zm3.48.255c.013.35-.396.642-.902.648-.508.012-.92-.272-.926-.618 0-.354.4-.642.908-.65.506-.01.92.272.92.62zm3.24-.551c.06.342-.29.694-.793.787-.494.092-.95-.12-1.014-.46-.06-.35.297-.7.79-.792.503-.088.953.118 1.017.466zm0 0"/></g><path d="M24.855 108.302h-10.7a.5.5 0 00-.5.5v5.232a.5.5 0 00.5.5h4.173v6.5s-.937.32-3.53.32c-3.056 0-7.327-1.116-7.327-10.508 0-9.393 4.448-10.63 8.624-10.63 3.614 0 5.17.636 6.162.943.31.094.6-.216.6-.492l1.193-5.055a.468.468 0 00-.192-.39c-.403-.288-2.857-1.66-9.058-1.66-7.144 0-14.472 3.038-14.472 17.65 0 14.61 8.39 16.787 15.46 16.787 5.854 0 9.405-2.502 9.405-2.502.146-.08.162-.285.162-.38v-16.316a.5.5 0 00-.5-.5zM79.506 94.81H73.48a.5.5 0 00-.498.503l.002 11.644h-9.392V95.313a.5.5 0 00-.497-.503H57.07a.5.5 0 00-.498.503v31.53c0 .277.224.503.498.503h6.025a.5.5 0 00.497-.504v-13.486h9.392l-.016 13.486c0 .278.224.504.5.504h6.038a.5.5 0 00.497-.504v-31.53a.497.497 0 00-.497-.502zm-47.166.717c-2.144 0-3.884 1.753-3.884 3.923 0 2.167 1.74 3.925 3.884 3.925 2.146 0 3.885-1.758 3.885-3.925 0-2.17-1.74-3.923-3.885-3.923zm2.956 9.608H29.29c-.276 0-.522.284-.522.56v20.852c0 .613.382.795.876.795h5.41c.595 0 .74-.292.74-.805v-20.899a.5.5 0 00-.498-.502zm67.606.047h-5.98a.5.5 0 00-.496.504v15.46s-1.52 1.11-3.675 1.11-2.727-.977-2.727-3.088v-13.482a.5.5 0 00-.497-.504h-6.068a.502.502 0 00-.498.504v14.502c0 6.27 3.495 7.804 8.302 7.804 3.944 0 7.124-2.18 7.124-2.18s.15 1.15.22 1.285c.07.136.247.273.44.273l3.86-.017a.502.502 0 00.5-.504l-.003-21.166a.504.504 0 00-.5-.502zm16.342-.708c-3.396 0-5.706 1.515-5.706 1.515V95.312a.5.5 0 00-.497-.503H107a.5.5 0 00-.5.503v31.53a.5.5 0 00.5.503h4.192c.19 0 .332-.097.437-.268.103-.17.254-1.454.254-1.454s2.47 2.34 7.148 2.34c5.49 0 8.64-2.784 8.64-12.502s-5.03-10.988-8.428-10.988zm-2.36 17.764c-2.073-.063-3.48-1.004-3.48-1.004v-9.985s1.388-.85 3.09-1.004c2.153-.193 4.228.458 4.228 5.594 0 5.417-.935 6.486-3.837 6.398zm-63.689-.118c-.263 0-.937.107-1.63.107-2.22 0-2.973-1.032-2.973-2.368v-8.866h4.52a.5.5 0 00.5-.504v-4.856a.5.5 0 00-.5-.502h-4.52l-.007-5.97c0-.227-.116-.34-.378-.34h-6.16c-.238 0-.367.106-.367.335v6.17s-3.087.745-3.295.805a.5.5 0 00-.36.48v3.877a.5.5 0 00.497.503h3.158v9.328c0 6.93 4.86 7.61 8.14 7.61 1.497 0 3.29-.48 3.586-.59.18-.067.283-.252.283-.453l.004-4.265a.51.51 0 00-.5-.502z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
public/svgs/glitchtip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

1
public/svgs/grafana.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><linearGradient id="a" x1="45.842" x2="45.842" y1="89.57" y2="8.802" gradientTransform="translate(-2.405 27.316) scale(1.4463)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcee1f"/><stop offset="1" stop-color="#f15b2a"/></linearGradient><path fill="url(#a)" d="M69.162 0c-9.91 6.4-11.77 14.865-11.77 14.865s.002.206-.101.412c-.62.104-1.033.31-1.549.413-.722.206-1.445.413-2.168.826l-2.168.93c-1.445.722-2.89 1.341-4.336 2.167-1.342.826-2.683 1.548-4.025 2.477a1.266 1.266 0 0 1-.309-.205c-13.316-5.161-25.084 1.031-25.084 1.031-1.032 14.245 5.367 23.02 6.606 24.672-.31.929-.62 1.754-.93 2.58a52.973 52.973 0 0 0-2.166 9.91c-.103.413-.104 1.033-.207 1.445C8.671 67.613 5.06 80.103 5.06 80.103c10.219 11.768 22.193 12.49 22.193 12.49 1.445 2.685 3.302 5.369 5.264 7.743.825 1.032 1.756 1.96 2.582 2.992-3.716 10.632.619 19.613.619 19.613 11.458.413 18.992-4.955 20.54-6.297 1.136.31 2.272.724 3.407 1.034a47.25 47.25 0 0 0 10.633 1.549h4.644C80.31 126.969 89.807 128 89.807 128c6.71-7.123 7.123-14.038 7.123-15.69v-.62c1.342-1.033 2.683-2.064 4.129-3.2 2.684-2.374 4.955-5.264 7.02-8.154.206-.207.309-.62.618-.826 7.639.413 12.903-4.748 12.903-4.748-1.24-7.949-5.78-11.768-6.71-12.49l-.103-.104-.103-.104-.104-.103c0-.413.104-.93.104-1.445.103-.93.103-1.755.103-2.58v-3.407c0-.206 0-.413-.103-.722l-.104-.723-.103-.723c-.104-.929-.31-1.754-.413-2.58-.825-3.406-2.166-6.71-3.818-9.498-1.858-2.993-4.026-5.471-6.504-7.742-2.477-2.168-5.264-4.025-8.154-5.264-2.994-1.342-5.884-2.167-8.98-2.476-1.446-.207-3.098-.207-4.544-.207H79.69c-.825.103-1.546.205-2.27.308-3.096.62-5.883 1.756-8.36 3.201-2.478 1.446-4.646 3.407-6.504 5.575-1.858 2.167-3.2 4.438-4.13 6.916a23.313 23.313 0 0 0-1.548 7.431v2.684c0 .31 0 .62.104.93.103 1.238.31 2.374.722 3.51.723 2.27 1.756 4.334 3.098 6.09a19.973 19.973 0 0 0 4.54 4.335c1.756 1.136 3.408 1.96 5.266 2.477 1.858.516 3.509.826 5.16.722h2.376c.206 0 .412-.101.619-.101.206 0 .31-.104.619-.104.31-.103.825-.207 1.135-.31.722-.207 1.342-.62 2.064-.826.723-.31 1.24-.722 1.756-1.032.103-.103.309-.207.412-.31.62-.413.723-1.238.207-1.858-.413-.413-1.136-.62-1.756-.31-.103.103-.205.104-.412.207-.413.206-1.032.413-1.445.619-.62.103-1.135.31-1.754.414-.31 0-.62.102-.93.102h-2.58c-.103 0-.31.001-.414-.102-1.239-.206-2.58-.62-3.818-1.137-1.239-.619-2.478-1.34-3.51-2.373a15.894 15.894 0 0 1-2.89-3.51c-.826-1.341-1.24-2.89-1.446-4.335-.103-.826-.207-1.55-.103-2.375v-1.239c0-.413.103-.825.207-1.238.619-3.406 2.27-6.71 4.851-9.187.723-.723 1.342-1.238 2.168-1.754.826-.62 1.547-1.032 2.373-1.342.826-.31 1.756-.723 2.582-.93.93-.206 1.858-.414 2.684-.414.413 0 .929-.101 1.342-.101h1.238c1.032.103 2.065.205 2.994.412 1.961.413 3.82 1.135 5.678 2.168 3.613 2.064 6.708 5.16 8.566 8.877.93 1.858 1.548 3.82 1.961 5.988.103.62.104 1.03.207 1.547v2.787c0 .62-.103 1.136-.103 1.756-.104.62-.102 1.134-.205 1.754-.104.619-.208 1.136-.311 1.755-.206 1.136-.722 2.168-1.031 3.303-.826 2.168-1.963 4.232-3.305 5.986-2.684 3.717-6.502 6.815-10.63 8.776-2.169.929-4.337 1.755-6.608 2.064a19.003 19.003 0 0 1-3.407.309h-1.755c-.62 0-1.238.002-1.858-.102-2.477-.206-4.85-.724-7.224-1.343-2.375-.723-4.647-1.548-6.815-2.684-4.335-2.27-8.153-5.573-11.25-9.289-1.445-1.961-2.892-4.027-4.027-6.092-1.136-2.064-1.961-4.438-2.58-6.709-.723-2.27-1.032-4.645-1.135-7.02v-3.613c0-1.135.102-2.372.309-3.61.103-1.24.309-2.376.619-3.614.206-1.239.62-2.375.93-3.614.722-2.374 1.444-4.644 2.476-6.812 2.064-4.335 4.645-8.155 7.742-11.252a24.86 24.86 0 0 1 2.479-2.168c.31-.31 1.135-1.033 2.064-1.549s1.858-1.136 2.89-1.549c.414-.206.93-.413 1.446-.722.206-.103.411-.206.824-.309.207-.103.414-.207.826-.31 1.033-.413 2.066-.825 3.098-1.135.207-.103.62-.104.826-.207.207-.103.618-.102.824-.205.62-.103 1.033-.208 1.55-.414.206-.104.619-.104.825-.207.207 0 .62-.102.827-.102.206 0 .62-.103.826-.103l.412-.104.412-.103c.206 0 .62-.104.826-.104.31 0 .62-.104.93-.104.206 0 .721-.101.928-.101.206 0 .311 0 .62-.104h.723c.31 0 .618 0 .928-.103h4.647c2.064.103 4.128.31 5.986.723 3.82.722 7.638 1.961 10.941 3.613 3.304 1.548 6.4 3.611 8.877 5.78.104.102.311.207.414.413.104.103.31.206.412.412.31.207.62.62.93.826.31.207.62.62.93.827.206.31.618.618.824.927 1.136 1.136 2.169 2.375 3.098 3.51a41.422 41.422 0 0 1 4.44 7.02c.102.103.1.207.204.414.103.103.104.205.207.412.103.206.206.62.412.826.104.206.208.62.31.826.104.207.208.62.311.826.413 1.033.826 2.064 1.135 3.096.62 1.548.929 2.993 1.239 4.13.103.412.62.825 1.033.825.619 0 .927-.414.927-1.033-.31-1.755-.308-3.198-.412-4.953-.206-2.168-.619-4.647-1.238-7.434-.62-2.787-1.86-5.677-3.305-8.877-1.548-3.096-3.509-6.4-6.09-9.394-1.032-1.239-2.167-2.373-3.302-3.612 1.858-7.122-2.168-13.42-2.168-13.42-6.916-.412-11.253 2.168-12.801 3.303-.206-.103-.618-.205-.824-.308-1.136-.413-2.375-.93-3.613-1.342-1.24-.31-2.478-.827-3.717-1.033-1.239-.31-2.58-.62-4.026-.827-.206 0-.413-.103-.722-.103C77.833 4.128 69.162 0 69.162 0z"/></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

21
public/svgs/grocy.svg Normal file
View File

@@ -0,0 +1,21 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="185.000000pt" height="222.000000pt" viewBox="0 0 185.000000 222.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,222.000000) scale(0.100000,-0.100000)"
fill="#337ab7" stroke="none">
<path d="M983 2210 c-468 -66 -828 -418 -944 -920 -29 -124 -36 -358 -15 -478
57 -328 272 -604 565 -727 125 -53 193 -67 353 -72 112 -4 171 -1 250 12 247
41 496 156 611 284 l37 41 -5 172 c-3 95 -8 316 -11 491 l-6 319 -267 -8
c-146 -3 -342 -9 -436 -13 l-170 -6 -8 -213 c-5 -118 -7 -215 -5 -217 2 -2 81
-7 176 -11 l172 -7 0 -27 c0 -65 -12 -90 -51 -111 -60 -30 -172 -44 -241 -30
-249 52 -347 418 -180 677 105 163 290 242 537 231 68 -4 153 -15 195 -25 41
-11 77 -16 80 -11 9 13 43 526 37 542 -8 22 -124 64 -236 87 -115 23 -342 34
-438 20z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

15
public/svgs/jellyfin.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg id="banner-dark" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-50 0 600 512">
<defs>
<linearGradient id="linear-gradient" x1="110.25" y1="213.3" x2="496.14" y2="436.09" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#aa5cc3"/>
<stop offset="1" stop-color="#00a4dc"/>
</linearGradient>
</defs>
<title>banner-dark</title>
<g id="banner-dark">
<g id="banner-dark-icon">
<path id="inner-shape" d="M261.42,201.62c-20.44,0-86.24,119.29-76.2,139.43s142.48,19.92,152.4,0S281.86,201.63,261.42,201.62Z" fill="url(#linear-gradient)"/>
<path id="outer-shape" d="M261.42,23.3C199.83,23.3,1.57,382.73,31.8,443.43s429.34,60,459.24,0S323,23.3,261.42,23.3ZM411.9,390.76c-19.59,39.33-281.08,39.77-300.9,0S221.1,115.48,261.45,115.48,431.49,351.42,411.9,390.76Z" fill="url(#linear-gradient)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 952 B

1
public/svgs/mariadb.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#fff" d="M127.434 12.182a1.727 1.727 0 0 0-1.174-.392c-1.168 0-2.68.793-3.495 1.218l-.322.165a11.095 11.095 0 0 1-4.365 1.1c-1.554.049-2.892.14-4.635.322-10.327 1.06-14.933 8.975-19.37 16.63-2.416 4.164-4.91 8.489-8.33 11.793a22.472 22.472 0 0 1-2.252 1.913c-3.54 2.631-7.985 4.51-11.443 5.84-3.329 1.273-6.964 2.417-10.474 3.524-3.219 1.012-6.255 1.97-9.048 3.008a96.902 96.902 0 0 1-3.275 1.14c-2.545.825-4.378 1.458-7.06 3.304a45.386 45.386 0 0 0-2.804 2.066 29.585 29.585 0 0 0-5.597 5.894 34.802 34.802 0 0 1-4.701 5.642c-.566.554-1.57.826-3.074.826-1.76 0-3.895-.363-6.154-.747-2.33-.413-4.738-.805-6.803-.805-1.677 0-2.962.273-3.92.826 0 0-1.617.942-2.298 2.16l.67.302a13.718 13.718 0 0 1 2.859 2.065 14.342 14.342 0 0 0 2.973 2.115 2.553 2.553 0 0 1 .918.582c-.281.413-.694.946-1.129 1.516-2.384 3.119-3.774 5.09-2.977 6.163a2.507 2.507 0 0 0 1.239.28c5.196 0 7.989-1.35 11.52-3.06 1.024-.495 2.066-1.004 3.305-1.528 2.065-.896 4.288-2.325 6.647-3.838 3.084-2.01 6.31-4.076 9.442-5.072a25.734 25.734 0 0 1 7.943-1.115c3.305 0 6.783.441 10.138.872 2.499.322 5.089.652 7.63.805.986.057 1.9.086 2.787.086a32.307 32.307 0 0 0 3.557-.185l.284-.1c1.781-1.094 2.617-3.444 3.425-5.717.52-1.462.96-2.775 1.652-3.61a1.054 1.054 0 0 1 .132-.11.166.166 0 0 1 .202.032v.066c-.412 8.885-3.99 14.527-7.608 19.543l-2.416 2.59s3.383 0 5.307-.744c7.024-2.099 12.324-6.725 16.181-14.103a60.185 60.185 0 0 0 2.549-5.82c.065-.165.673-.47.616.384-.021.252-.038.533-.059.827 0 .173 0 .35-.033.528-.1 1.24-.392 3.859-.392 3.859l2.169-1.162c5.229-3.304 9.26-9.97 12.318-20.343 1.272-4.321 2.205-8.613 3.027-12.392.983-4.545 1.83-8.44 2.801-9.952 1.524-2.37 3.85-3.973 6.101-5.53.306-.211.616-.414.917-.637 2.83-1.986 5.643-4.279 6.263-8.555v-.095c.45-3.189.07-4.002-.364-4.373zm-7.283 103.727h-10.327V97.92h9.315c3.56 0 6.952.67 6.902 4.66 0 2.813-1.747 3.59-3.589 3.886 2.615.224 4.188 1.892 4.188 4.586.017 4.035-3.523 4.858-6.489 4.858zm-.772-10.14c3.565 0 4.362-1.372 4.362-3.115 0-2.619-1.595-3.214-4.362-3.214h-7.402v6.328zm.099 1.52h-7.501v7.1h7.823c2.194 0 4.511-.723 4.511-3.486 0-3.19-2.665-3.615-4.833-3.615zm-31.497-9.37h8.125c6.828 0 10.24 3.764 10.19 8.994.05 5.436-3.716 8.997-9.591 8.997H87.98zm2.242 1.596v14.825h6.197c5.432 0 7.501-3.665 7.501-7.477 0-4.309-2.59-7.348-7.5-7.348zm-10.838 5.357v-2.095h3.404v13.132h-3.392v-2.114c-.896 1.52-2.739 2.391-4.982 2.391-4.684 0-7.303-3.305-7.303-7.105 0-3.664 2.479-6.609 6.804-6.609 2.454.029 4.498.855 5.469 2.4zm-8.675 4.387c0 2.416 1.52 4.485 4.462 4.485 2.841 0 4.386-2.02 4.386-4.411 0-2.392-1.599-4.436-4.544-4.436-2.828 0-4.3 2.04-4.3 4.362zm-10.013-9.947a1.722 1.722 0 0 1 1.818-1.768 1.788 1.788 0 0 1 1.847 1.821 1.714 1.714 0 0 1-1.847 1.744 1.743 1.743 0 0 1-1.818-1.797zm.15 3.465h3.39v9.596c0 .595.125 1.02.62 1.02a3.657 3.657 0 0 0 .648-.073l.525 2.478a5.931 5.931 0 0 1-2.242.414c-1.421 0-2.942-.414-2.942-3.64zM52.15 115.91h-3.386v-13.132h3.386v2.942a5.197 5.197 0 0 1 4.735-3.218 6.13 6.13 0 0 1 2.119.347l-.723 2.479a7.435 7.435 0 0 0-1.793-.249c-2.445 0-4.338 1.843-4.338 4.545zm-11.037-11.037v-2.095h3.392v13.132h-3.392v-2.114c-.896 1.52-2.738 2.391-4.982 2.391-4.688 0-7.303-3.305-7.303-7.105 0-3.664 2.479-6.609 6.804-6.609 2.466.029 4.51.855 5.481 2.4zm-8.675 4.387c0 2.416 1.52 4.485 4.462 4.485 2.838 0 4.383-2.02 4.383-4.411 0-2.391-1.595-4.436-4.544-4.436-2.826 0-4.296 2.04-4.296 4.362zm-9.24-11.34 4.651 17.99h-3.51L21.24 102.95 15.4 115.91h-2.965l-5.808-12.883-3.19 12.883H0l4.61-17.99h3.04l6.28 13.93 6.253-13.93z"/></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,19 @@
<svg width="495" height="74" viewBox="0 0 130 74" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.825012 73.993L24.0688 14.5224C27.3443 6.14179 35.4223 0.625977 44.4203 0.625977H58.4336L35.1899 60.0966C31.9143 68.4772 23.8363 73.993 14.8384 73.993H0.825012Z" fill="url(#paint0_linear_0_3)"/>
<path d="M34.9246 73.9932L58.1684 14.5226C61.444 6.14197 69.5219 0.626152 78.5199 0.626152H92.5333L69.2895 60.0968C66.014 68.4774 57.936 73.9932 48.938 73.9932H34.9246Z" fill="url(#paint1_linear_0_3)"/>
<path d="M69.0262 73.9932L92.27 14.5226C95.5456 6.14197 103.624 0.626152 112.622 0.626152H126.635L103.391 60.0968C100.116 68.4774 92.0376 73.9932 83.0396 73.9932H69.0262Z" fill="url(#paint2_linear_0_3)"/>
<defs>
<linearGradient id="paint0_linear_0_3" x1="126.635" y1="-4.97799" x2="0.825008" y2="66.0978" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF5CAA"/>
<stop offset="1" stop-color="#FF4E62"/>
</linearGradient>
<linearGradient id="paint1_linear_0_3" x1="126.635" y1="-4.97799" x2="0.825008" y2="66.0978" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF5CAA"/>
<stop offset="1" stop-color="#FF4E62"/>
</linearGradient>
<linearGradient id="paint2_linear_0_3" x1="126.635" y1="-4.97799" x2="0.825008" y2="66.0978" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF5CAA"/>
<stop offset="1" stop-color="#FF4E62"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
public/svgs/metabase.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" preserveAspectRatio="xMidYMid"><g transform="matrix(.197726 0 0 .197726 6.691093 -.000001)" fill="#509ee3"><ellipse ry="19.704" rx="19.394" cy="82.757" cx="19.394"/><ellipse ry="19.704" rx="19.394" cy="137.928" cx="19.394"/><ellipse ry="19.704" rx="19.394" cy="82.757" cx="73.697" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="138.464" cx="73.697"/><ellipse ry="19.704" rx="19.394" cy="82.757" cx="128" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="19.704" cx="128" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="138.464" cx="128" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="82.757" cx="182.303" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="82.757" cx="236.606"/><ellipse ry="19.704" rx="19.394" cy="138.464" cx="182.303"/><ellipse ry="19.704" rx="19.394" cy="138.464" cx="236.606"/><ellipse ry="19.704" rx="19.394" cy="193.099" cx="19.394"/><ellipse ry="19.704" rx="19.394" cy="193.635" cx="73.697" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="193.635" cx="128"/><ellipse ry="19.704" rx="19.394" cy="193.635" cx="182.303" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="193.635" cx="236.606"/><ellipse ry="19.704" rx="19.394" cy="248.27" cx="19.394"/><ellipse ry="19.704" rx="19.394" cy="248.806" cx="73.697" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="248.806" cx="128" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="303.977" cx="128" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="248.806" cx="182.303" opacity=".2"/><ellipse ry="19.704" rx="19.394" cy="248.806" cx="236.606"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
public/svgs/minio.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M40.25 3.108l8.387 13.714c.04.055.04.128 0 .183-.06.06-.158.06-.22 0L37.593 5.68z" fill="#f05a28"/><path d="M21.733 39.997c1.838-3.9 4.337-7.45 7.388-10.496a37.79 37.79 0 0 1 3.657-3.243v8.01zm-6.4 7.4l17.47-8.9V58.83L36.74 64V36.474l2.438-1.22a11.85 11.85 0 0 0 3.255-18.749l-9.02-9.4a2 2 0 0 1 .098-2.804 2.01 2.01 0 0 1 2.828.098l1.22 1.317 2.694-2.584C37.07-1 33.168-.525 30.9 1.584a5.73 5.73 0 0 0-.244 8.095l9.07 9.448c1.68 1.8 2.458 4.244 2.116 6.674s-1.765 4.575-3.872 5.834l-1.22.634V19.42a41.13 41.13 0 0 0-21.407 27.977" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 624 B

1
public/svgs/mongodb.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/svgs/moodle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Some files were not shown because too many files have changed in this diff Show More