mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 12:33:06 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d93506a18c | ||
|
|
0bb77a671b | ||
|
|
028f883499 | ||
|
|
727133e28b | ||
|
|
1bd08cb2db | ||
|
|
bac55cd90d | ||
|
|
9b51936131 | ||
|
|
692665d0da | ||
|
|
14cdf33473 | ||
|
|
17f4f83ad6 | ||
|
|
c981606da7 | ||
|
|
e21d1bffe8 | ||
|
|
32706092f3 | ||
|
|
a7fe446550 | ||
|
|
bb01cfb330 | ||
|
|
2590efba4b | ||
|
|
186c5897a0 | ||
|
|
6150a008d5 | ||
|
|
fb2a86ba3f | ||
|
|
91fa762985 | ||
|
|
8b5c7c94cd | ||
|
|
3dd2a059bf | ||
|
|
2f724ffba2 | ||
|
|
0586ec3f42 | ||
|
|
c2c9d992e7 | ||
|
|
ce9aa636c4 | ||
|
|
68d06dcd19 | ||
|
|
03bf93eb12 | ||
|
|
163eabb76c | ||
|
|
bed1bb2429 | ||
|
|
bc802b6f19 | ||
|
|
9b67a253f1 | ||
|
|
29dc5a8bb4 | ||
|
|
b63e516274 | ||
|
|
db9d5a0fb0 | ||
|
|
3f5e6faac5 | ||
|
|
eef6b95e24 | ||
|
|
96b76aea6b |
2
.gitpod.Dockerfile
vendored
Normal file
2
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
FROM gitpod/workspace-node:2022-06-20-19-54-55
|
||||
RUN (curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.27.0/pack-v0.27.0-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack)
|
||||
@@ -1,7 +1,8 @@
|
||||
# This configuration file was automatically generated by Gitpod.
|
||||
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
|
||||
# and commit this file to your remote git repository to share the goodness with others.
|
||||
image: gitpod/workspace-node:2022-06-20-19-54-55
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
tasks:
|
||||
- init: pnpm install && pnpm db:push && pnpm db:seed
|
||||
command: pnpm dev
|
||||
|
||||
230
README.md
230
README.md
@@ -1,7 +1,108 @@
|
||||
# Coolify
|
||||
|
||||
An open-source & self-hostable Heroku / Netlify alternative
|
||||
(ARM support is in beta).
|
||||
An open-source & self-hostable Heroku / Netlify alternative.
|
||||
|
||||
## Live Demo
|
||||
|
||||
https://demo.coolify.io/
|
||||
|
||||
(If it is unresponsive, that means someone overloaded the server. 😄)
|
||||
|
||||
## Feedback
|
||||
|
||||
If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||
|
||||
---
|
||||
|
||||
## How to install
|
||||
|
||||
For more details goto the [docs](https://docs.coollabs.io/coolify/installation.html).
|
||||
|
||||
Installation is automated with the following command:
|
||||
|
||||
```bash
|
||||
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh
|
||||
```
|
||||
|
||||
If you would like no questions during installation:
|
||||
|
||||
```bash
|
||||
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Git Sources
|
||||
|
||||
Self-hosted versions also!
|
||||
|
||||
<a href="https://github.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/github.com"></a>
|
||||
<a href="https://gitlab.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/gitlab.com"></a>
|
||||
|
||||
### Destinations
|
||||
|
||||
Deploy your resource to:
|
||||
|
||||
- Local Docker Engine
|
||||
- Remote Docker Engine
|
||||
|
||||
### Applications
|
||||
|
||||
<a href="https://heroku.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/heroku.com"></a>
|
||||
<a href="https://html5.org/">
|
||||
<svg style="width:40px;height:40px" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" ><g clip-path="url(#HTML5_Clip0_4)" ><path d="M30.216 0L27.6454 28.7967L16.0907 32L4.56783 28.8012L2 0H30.216Z" fill="#E44D26" /><path d="M16.108 29.5515L25.4447 26.963L27.6415 2.35497H16.108V29.5515Z" fill="#F16529" /><path d="M11.1109 9.4197H16.108V5.88731H7.25053L7.33509 6.83499L8.20327 16.5692H16.108V13.0369H11.4338L11.1109 9.4197Z" fill="#EBEBEB" /><path d="M11.907 18.3354H8.36111L8.856 23.8818L16.0917 25.8904L16.108 25.8859V22.2108L16.0925 22.2149L12.1585 21.1527L11.907 18.3354Z" fill="#EBEBEB" /><path d="M16.0958 16.5692H20.4455L20.0354 21.1504L16.0958 22.2138V25.8887L23.3373 23.8817L23.3904 23.285L24.2205 13.9855L24.3067 13.0369H16.0958V16.5692Z" fill="white" /><path d="M16.0958 9.41105V9.41969H24.6281L24.6989 8.62572L24.8599 6.83499L24.9444 5.88731H16.0958V9.41105Z" fill="white" /></g><defs><clipPath id="HTML5_Clip0_4"><rect width="32" height="32" fill="white" /></clipPath></defs></svg></a>
|
||||
<a href="https://nodejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nodejs.org"></a>
|
||||
<a href="https://vuejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/vuejs.org"></a>
|
||||
<a href="https://nuxtjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nuxtjs.org"></a>
|
||||
<a href="https://nextjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nextjs.org"></a>
|
||||
<a href="https://reactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/reactjs.org"></a>
|
||||
<a href="https://preactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/preactjs.org"></a>
|
||||
<a href="https://gatsbyjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/gatsbyjs.org"></a>
|
||||
<a href="https://svelte.dev"><img style="width:40px;height:40px" src="https://icon.horse/icon/svelte.dev"></a>
|
||||
<a href="https://php.net"><img style="width:40px;height:40px" src="https://icon.horse/icon/php.net"></a>
|
||||
<a href="https://laravel.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/laravel.com"></a>
|
||||
<a href="https://python.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/python.org"></a>
|
||||
<a href="https://deno.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/deno.com"></a>
|
||||
<a href="https://docker.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/docker.com"></a>
|
||||
|
||||
### Databases
|
||||
|
||||
<a href="https://mongodb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mongodb.org"></a>
|
||||
<a href="https://mariadb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mariadb.org"></a>
|
||||
<a href="https://mysql.com"><svg style="width:40px;height:40px" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 25.6 25.6" ><path d="M179.076 94.886c-3.568-.1-6.336.268-8.656 1.25-.668.27-1.74.27-1.828 1.116.357.355.4.936.713 1.428.535.893 1.473 2.096 2.32 2.72l2.855 2.053c1.74 1.07 3.703 1.695 5.398 2.766.982.625 1.963 1.428 2.945 2.098.5.357.803.938 1.428 1.16v-.135c-.312-.4-.402-.98-.713-1.428l-1.34-1.293c-1.293-1.74-2.9-3.258-4.64-4.506-1.428-.982-4.55-2.32-5.13-3.97l-.088-.1c.98-.1 2.14-.447 3.078-.715 1.518-.4 2.9-.312 4.46-.713l2.143-.625v-.4c-.803-.803-1.383-1.874-2.23-2.632-2.275-1.963-4.775-3.882-7.363-5.488-1.383-.892-3.168-1.473-4.64-2.23-.537-.268-1.428-.402-1.74-.848-.805-.98-1.25-2.275-1.83-3.436l-3.658-7.763c-.803-1.74-1.295-3.48-2.275-5.086-4.596-7.585-9.594-12.18-17.268-16.687-1.65-.937-3.613-1.34-5.7-1.83l-3.346-.18c-.715-.312-1.428-1.16-2.053-1.562-2.543-1.606-9.102-5.086-10.977-.5-1.205 2.9 1.785 5.755 2.8 7.228.76 1.026 1.74 2.186 2.277 3.346.3.758.4 1.562.713 2.365.713 1.963 1.383 4.15 2.32 5.98.5.937 1.025 1.92 1.65 2.767.357.5.982.714 1.115 1.517-.625.893-.668 2.23-1.025 3.347-1.607 5.042-.982 11.288 1.293 15 .715 1.115 2.4 3.57 4.686 2.632 2.008-.803 1.56-3.346 2.14-5.577.135-.535.045-.892.312-1.25v.1l1.83 3.703c1.383 2.186 3.793 4.462 5.8 5.98 1.07.803 1.918 2.187 3.256 2.677v-.135h-.088c-.268-.4-.67-.58-1.027-.892-.803-.803-1.695-1.785-2.32-2.677-1.873-2.498-3.523-5.265-4.996-8.12-.715-1.383-1.34-2.9-1.918-4.283-.27-.536-.27-1.34-.715-1.606-.67.98-1.65 1.83-2.143 3.034-.848 1.918-.936 4.283-1.248 6.737-.18.045-.1 0-.18.1-1.426-.356-1.918-1.83-2.453-3.078-1.338-3.168-1.562-8.254-.402-11.913.312-.937 1.652-3.882 1.117-4.774-.27-.848-1.16-1.338-1.652-2.008-.58-.848-1.203-1.918-1.605-2.855-1.07-2.5-1.605-5.265-2.766-7.764-.537-1.16-1.473-2.365-2.232-3.435-.848-1.205-1.783-2.053-2.453-3.48-.223-.5-.535-1.294-.178-1.83.088-.357.268-.5.623-.58.58-.5 2.232.134 2.812.4 1.65.67 3.033 1.294 4.416 2.23.625.446 1.295 1.294 2.098 1.518h.938c1.428.312 3.033.1 4.37.5 2.365.76 4.506 1.874 6.426 3.08 5.844 3.703 10.664 8.968 13.92 15.26.535 1.026.758 1.963 1.25 3.034.938 2.187 2.098 4.417 3.033 6.56.938 2.097 1.83 4.24 3.168 5.98.67.937 3.346 1.427 4.55 1.918.893.4 2.275.76 3.08 1.25 1.516.937 3.033 2.008 4.46 3.034.713.534 2.945 1.65 3.078 2.54zm-45.5-38.772a7.09 7.09 0 0 0-1.828.223v.1h.088c.357.714.982 1.205 1.428 1.83l1.027 2.142.088-.1c.625-.446.938-1.16.938-2.23-.268-.312-.312-.625-.535-.937-.268-.446-.848-.67-1.206-1.026z" transform="matrix(.390229 0 0 .38781 -46.300037 -16.856717)" fill-rule="evenodd" fill="#00678c" /></svg></a>
|
||||
<a href="https://postgresql.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/postgresql.org"></a>
|
||||
<a href="https://couchdb.apache.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/couchdb.apache.org"></a>
|
||||
<a href="https://redis.io"><svg style="width:40px;height:40px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><defs ><path id="a" d="m45.536 38.764c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.813s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" /><path id="b" d="m45.536 28.733c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.935c2.332-.837 3.14-.867 5.126-.14s12.35 4.853 14.312 5.57 2.037 1.31.024 2.36z" /></defs ><g transform="matrix(.848327 0 0 .848327 -7.883573 -9.449691)" ><use fill="#a41e11" xlink:href="#a" /><path d="m45.536 34.95c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.936c2.332-.836 3.14-.867 5.126-.14s12.35 4.852 14.31 5.582 2.037 1.31.024 2.36z" fill="#d82c20" /><use fill="#a41e11" xlink:href="#a" y="-6.218" /><use fill="#d82c20" xlink:href="#b" /><path d="m45.536 26.098c-2.013 1.05-12.44 5.337-14.66 6.495s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.815s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" fill="#a41e11" /><use fill="#d82c20" xlink:href="#b" y="-6.449" /><g fill="#fff" ><path d="m29.096 20.712-1.182-1.965-3.774-.34 2.816-1.016-.845-1.56 2.636 1.03 2.486-.814-.672 1.612 2.534.95-3.268.34zm-6.296 3.912 8.74-1.342-2.64 3.872z" /><ellipse cx="20.444" cy="21.402" rx="4.672" ry="1.811" /></g ><path d="m42.132 21.138-5.17 2.042-.004-4.087z" fill="#7a0c00" /><path d="m36.963 23.18-.56.22-5.166-2.042 5.723-2.264z" fill="#ad2115" /></g ></svg ></a>
|
||||
|
||||
### Services
|
||||
- [Appwrite](https://appwrite.io)
|
||||
- [WordPress](https://docs.coollabs.io/coolify/services/wordpress)
|
||||
- [Ghost](https://ghost.org)
|
||||
- [Plausible Analytics](https://docs.coollabs.io/coolify/services/plausible-analytics)
|
||||
- [NocoDB](https://nocodb.com)
|
||||
- [VSCode Server](https://github.com/cdr/code-server)
|
||||
- [MinIO](https://min.io)
|
||||
- [VaultWarden](https://github.com/dani-garcia/vaultwarden)
|
||||
- [LanguageTool](https://languagetool.org)
|
||||
- [n8n](https://n8n.io)
|
||||
- [Uptime Kuma](https://github.com/louislam/uptime-kuma)
|
||||
- [MeiliSearch](https://github.com/meilisearch/meilisearch)
|
||||
- [Umami](https://github.com/mikecao/umami)
|
||||
- [Fider](https://fider.io)
|
||||
- [Hasura](https://hasura.io)
|
||||
|
||||
## Migration from v1
|
||||
|
||||
A fresh installation is necessary. v2 and v3 are not compatible with v1.
|
||||
|
||||
## Support
|
||||
|
||||
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai)
|
||||
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
|
||||
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
|
||||
- Discord: [Invitation](https://discord.gg/6rDM4fkymF)
|
||||
|
||||
## Financial Contributors
|
||||
|
||||
@@ -24,127 +125,4 @@ Support this project with your organization. Your logo will show up here with a
|
||||
<a href="https://opencollective.com/coollabsio/organization/6/website"><img src="https://opencollective.com/coollabsio/organization/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/7/website"><img src="https://opencollective.com/coollabsio/organization/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
|
||||
|
||||
---
|
||||
|
||||
## Live Demo
|
||||
|
||||
https://demo.coolify.io/
|
||||
|
||||
(If it is unresponsive, that means someone overloaded the server. 😄)
|
||||
|
||||
## Feedback
|
||||
|
||||
If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||
|
||||
---
|
||||
|
||||
## How to install
|
||||
|
||||
Installation is automated with the following command:
|
||||
|
||||
```bash
|
||||
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh
|
||||
```
|
||||
|
||||
If you would like no questions during installation:
|
||||
|
||||
```bash
|
||||
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh -f
|
||||
```
|
||||
|
||||
For more details goto the [docs](https://docs.coollabs.io/coolify/installation).
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Git Sources
|
||||
|
||||
You can use the following Git Sources to be auto-deployed to your Coolify instance! (Self-hosted versions are also supported.)
|
||||
|
||||
<a href="https://github.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/github.com"></a>
|
||||
<a href="https://gitlab.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/gitlab.com"></a>
|
||||
|
||||
### Destinations
|
||||
|
||||
You can deploy your applications to the following destinations:
|
||||
|
||||
- Local Docker Engine
|
||||
- Remote Docker Engine
|
||||
|
||||
### Applications
|
||||
|
||||
Predefined build packs to cover the basic needs to deploy applications.
|
||||
|
||||
If you have an advanced use case, you can use the Docker build pack that allows you to deploy your application based on your custom Dockerfile.
|
||||
|
||||
<a href="https://html5.org/">
|
||||
<svg style="width:40px;height:40px" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" ><g clip-path="url(#HTML5_Clip0_4)" ><path d="M30.216 0L27.6454 28.7967L16.0907 32L4.56783 28.8012L2 0H30.216Z" fill="#E44D26" /><path d="M16.108 29.5515L25.4447 26.963L27.6415 2.35497H16.108V29.5515Z" fill="#F16529" /><path d="M11.1109 9.4197H16.108V5.88731H7.25053L7.33509 6.83499L8.20327 16.5692H16.108V13.0369H11.4338L11.1109 9.4197Z" fill="#EBEBEB" /><path d="M11.907 18.3354H8.36111L8.856 23.8818L16.0917 25.8904L16.108 25.8859V22.2108L16.0925 22.2149L12.1585 21.1527L11.907 18.3354Z" fill="#EBEBEB" /><path d="M16.0958 16.5692H20.4455L20.0354 21.1504L16.0958 22.2138V25.8887L23.3373 23.8817L23.3904 23.285L24.2205 13.9855L24.3067 13.0369H16.0958V16.5692Z" fill="white" /><path d="M16.0958 9.41105V9.41969H24.6281L24.6989 8.62572L24.8599 6.83499L24.9444 5.88731H16.0958V9.41105Z" fill="white" /></g><defs><clipPath id="HTML5_Clip0_4"><rect width="32" height="32" fill="white" /></clipPath></defs></svg></a>
|
||||
<a href="https://nodejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nodejs.org"></a>
|
||||
<a href="https://vuejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/vuejs.org"></a>
|
||||
<a href="https://nuxtjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nuxtjs.org"></a>
|
||||
<a href="https://nextjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nextjs.org"></a>
|
||||
<a href="https://reactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/reactjs.org"></a>
|
||||
<a href="https://preactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/preactjs.org"></a>
|
||||
<a href="https://gatsbyjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/gatsbyjs.org"></a>
|
||||
<a href="https://svelte.dev"><img style="width:40px;height:40px" src="https://icon.horse/icon/svelte.dev"></a>
|
||||
<a href="https://php.net"><img style="width:40px;height:40px" src="https://icon.horse/icon/php.net"></a>
|
||||
<a href="https://laravel.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/laravel.com"></a>
|
||||
<a href="https://python.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/python.org"></a>
|
||||
<a href="https://deno.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/deno.com"></a>
|
||||
<a href="https://docker.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/docker.com"></a>
|
||||
|
||||
If you have a new build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||
|
||||
### Databases
|
||||
|
||||
One-click database is ready to be used internally or shared over the internet:
|
||||
|
||||
<a href="https://mongodb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mongodb.org"></a>
|
||||
<a href="https://mariadb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mariadb.org"></a>
|
||||
<a href="https://mysql.com"><svg style="width:40px;height:40px" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 25.6 25.6" ><path d="M179.076 94.886c-3.568-.1-6.336.268-8.656 1.25-.668.27-1.74.27-1.828 1.116.357.355.4.936.713 1.428.535.893 1.473 2.096 2.32 2.72l2.855 2.053c1.74 1.07 3.703 1.695 5.398 2.766.982.625 1.963 1.428 2.945 2.098.5.357.803.938 1.428 1.16v-.135c-.312-.4-.402-.98-.713-1.428l-1.34-1.293c-1.293-1.74-2.9-3.258-4.64-4.506-1.428-.982-4.55-2.32-5.13-3.97l-.088-.1c.98-.1 2.14-.447 3.078-.715 1.518-.4 2.9-.312 4.46-.713l2.143-.625v-.4c-.803-.803-1.383-1.874-2.23-2.632-2.275-1.963-4.775-3.882-7.363-5.488-1.383-.892-3.168-1.473-4.64-2.23-.537-.268-1.428-.402-1.74-.848-.805-.98-1.25-2.275-1.83-3.436l-3.658-7.763c-.803-1.74-1.295-3.48-2.275-5.086-4.596-7.585-9.594-12.18-17.268-16.687-1.65-.937-3.613-1.34-5.7-1.83l-3.346-.18c-.715-.312-1.428-1.16-2.053-1.562-2.543-1.606-9.102-5.086-10.977-.5-1.205 2.9 1.785 5.755 2.8 7.228.76 1.026 1.74 2.186 2.277 3.346.3.758.4 1.562.713 2.365.713 1.963 1.383 4.15 2.32 5.98.5.937 1.025 1.92 1.65 2.767.357.5.982.714 1.115 1.517-.625.893-.668 2.23-1.025 3.347-1.607 5.042-.982 11.288 1.293 15 .715 1.115 2.4 3.57 4.686 2.632 2.008-.803 1.56-3.346 2.14-5.577.135-.535.045-.892.312-1.25v.1l1.83 3.703c1.383 2.186 3.793 4.462 5.8 5.98 1.07.803 1.918 2.187 3.256 2.677v-.135h-.088c-.268-.4-.67-.58-1.027-.892-.803-.803-1.695-1.785-2.32-2.677-1.873-2.498-3.523-5.265-4.996-8.12-.715-1.383-1.34-2.9-1.918-4.283-.27-.536-.27-1.34-.715-1.606-.67.98-1.65 1.83-2.143 3.034-.848 1.918-.936 4.283-1.248 6.737-.18.045-.1 0-.18.1-1.426-.356-1.918-1.83-2.453-3.078-1.338-3.168-1.562-8.254-.402-11.913.312-.937 1.652-3.882 1.117-4.774-.27-.848-1.16-1.338-1.652-2.008-.58-.848-1.203-1.918-1.605-2.855-1.07-2.5-1.605-5.265-2.766-7.764-.537-1.16-1.473-2.365-2.232-3.435-.848-1.205-1.783-2.053-2.453-3.48-.223-.5-.535-1.294-.178-1.83.088-.357.268-.5.623-.58.58-.5 2.232.134 2.812.4 1.65.67 3.033 1.294 4.416 2.23.625.446 1.295 1.294 2.098 1.518h.938c1.428.312 3.033.1 4.37.5 2.365.76 4.506 1.874 6.426 3.08 5.844 3.703 10.664 8.968 13.92 15.26.535 1.026.758 1.963 1.25 3.034.938 2.187 2.098 4.417 3.033 6.56.938 2.097 1.83 4.24 3.168 5.98.67.937 3.346 1.427 4.55 1.918.893.4 2.275.76 3.08 1.25 1.516.937 3.033 2.008 4.46 3.034.713.534 2.945 1.65 3.078 2.54zm-45.5-38.772a7.09 7.09 0 0 0-1.828.223v.1h.088c.357.714.982 1.205 1.428 1.83l1.027 2.142.088-.1c.625-.446.938-1.16.938-2.23-.268-.312-.312-.625-.535-.937-.268-.446-.848-.67-1.206-1.026z" transform="matrix(.390229 0 0 .38781 -46.300037 -16.856717)" fill-rule="evenodd" fill="#00678c" /></svg></a>
|
||||
<a href="https://postgresql.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/postgresql.org"></a>
|
||||
<a href="https://couchdb.apache.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/couchdb.apache.org"></a>
|
||||
<a href="https://redis.io"><svg style="width:40px;height:40px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><defs ><path id="a" d="m45.536 38.764c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.813s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" /><path id="b" d="m45.536 28.733c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.935c2.332-.837 3.14-.867 5.126-.14s12.35 4.853 14.312 5.57 2.037 1.31.024 2.36z" /></defs ><g transform="matrix(.848327 0 0 .848327 -7.883573 -9.449691)" ><use fill="#a41e11" xlink:href="#a" /><path d="m45.536 34.95c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.936c2.332-.836 3.14-.867 5.126-.14s12.35 4.852 14.31 5.582 2.037 1.31.024 2.36z" fill="#d82c20" /><use fill="#a41e11" xlink:href="#a" y="-6.218" /><use fill="#d82c20" xlink:href="#b" /><path d="m45.536 26.098c-2.013 1.05-12.44 5.337-14.66 6.495s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.815s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" fill="#a41e11" /><use fill="#d82c20" xlink:href="#b" y="-6.449" /><g fill="#fff" ><path d="m29.096 20.712-1.182-1.965-3.774-.34 2.816-1.016-.845-1.56 2.636 1.03 2.486-.814-.672 1.612 2.534.95-3.268.34zm-6.296 3.912 8.74-1.342-2.64 3.872z" /><ellipse cx="20.444" cy="21.402" rx="4.672" ry="1.811" /></g ><path d="m42.132 21.138-5.17 2.042-.004-4.087z" fill="#7a0c00" /><path d="m36.963 23.18-.56.22-5.166-2.042 5.723-2.264z" fill="#ad2115" /></g ></svg ></a>
|
||||
|
||||
If you have a new database you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||
|
||||
|
||||
### Services
|
||||
|
||||
You quickly need to host a self-hostable, open-source service? You can do it with a few clicks!
|
||||
- [WordPress](https://docs.coollabs.io/coolify/services/wordpress)
|
||||
- [Ghost](https://ghost.org)
|
||||
- [Plausible Analytics](https://docs.coollabs.io/coolify/services/plausible-analytics)
|
||||
- [NocoDB](https://nocodb.com)
|
||||
- [VSCode Server](https://github.com/cdr/code-server)
|
||||
- [MinIO](https://min.io)
|
||||
- [VaultWarden](https://github.com/dani-garcia/vaultwarden)
|
||||
- [LanguageTool](https://languagetool.org)
|
||||
- [n8n](https://n8n.io)
|
||||
- [Uptime Kuma](https://github.com/louislam/uptime-kuma)
|
||||
- [MeiliSearch](https://github.com/meilisearch/meilisearch)
|
||||
- [Umami](https://github.com/mikecao/umami)
|
||||
- [Fider](https://fider.io)
|
||||
- [Hasura](https://hasura.io)
|
||||
|
||||
|
||||
If you have a new service you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||
|
||||
## Migration from v1
|
||||
|
||||
A fresh installation is necessary. v2 and v3 are not compatible with v1.
|
||||
|
||||
## Support
|
||||
|
||||
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai)
|
||||
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
|
||||
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
|
||||
- Discord: [Invitation](https://discord.gg/xhBCC7eGKw)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Please see the [LICENSE](/LICENSE) file in our repository for the full text.
|
||||
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Appwrite" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"serviceId" TEXT NOT NULL,
|
||||
"opensslKeyV1" TEXT NOT NULL,
|
||||
"executorSecret" TEXT NOT NULL,
|
||||
"redisPassword" TEXT NOT NULL,
|
||||
"mariadbHost" TEXT,
|
||||
"mariadbPort" INTEGER NOT NULL DEFAULT 3306,
|
||||
"mariadbUser" TEXT NOT NULL,
|
||||
"mariadbPassword" TEXT NOT NULL,
|
||||
"mariadbRootUser" TEXT NOT NULL,
|
||||
"mariadbRootUserPassword" TEXT NOT NULL,
|
||||
"mariadbDatabase" TEXT NOT NULL,
|
||||
"mariadbPublicPort" INTEGER,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "Appwrite_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Appwrite_serviceId_key" ON "Appwrite"("serviceId");
|
||||
@@ -0,0 +1,20 @@
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_ApplicationSettings" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"applicationId" TEXT NOT NULL,
|
||||
"dualCerts" BOOLEAN NOT NULL DEFAULT false,
|
||||
"debug" BOOLEAN NOT NULL DEFAULT false,
|
||||
"previews" BOOLEAN NOT NULL DEFAULT false,
|
||||
"autodeploy" BOOLEAN NOT NULL DEFAULT true,
|
||||
"isBot" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_ApplicationSettings" ("applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt") SELECT "applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt" FROM "ApplicationSettings";
|
||||
DROP TABLE "ApplicationSettings";
|
||||
ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
|
||||
CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Setting" ADD COLUMN "DNSServers" TEXT;
|
||||
@@ -20,6 +20,7 @@ model Setting {
|
||||
proxyHash String?
|
||||
isAutoUpdateEnabled Boolean @default(false)
|
||||
isDNSCheckEnabled Boolean @default(true)
|
||||
DNSServers String?
|
||||
isTraefikUsed Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -124,6 +125,7 @@ model ApplicationSettings {
|
||||
debug Boolean @default(false)
|
||||
previews Boolean @default(false)
|
||||
autodeploy Boolean @default(true)
|
||||
isBot Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
application Application @relation(fields: [applicationId], references: [id])
|
||||
@@ -312,30 +314,33 @@ model DatabaseSettings {
|
||||
}
|
||||
|
||||
model Service {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
fqdn String?
|
||||
exposePort Int?
|
||||
dualCerts Boolean @default(false)
|
||||
dualCerts Boolean @default(false)
|
||||
type String?
|
||||
version String?
|
||||
destinationDockerId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
fider Fider?
|
||||
ghost Ghost?
|
||||
hasura Hasura?
|
||||
meiliSearch MeiliSearch?
|
||||
minio Minio?
|
||||
moodle Moodle?
|
||||
plausibleAnalytics PlausibleAnalytics?
|
||||
persistentStorage ServicePersistentStorage[]
|
||||
serviceSecret ServiceSecret[]
|
||||
umami Umami?
|
||||
vscodeserver Vscodeserver?
|
||||
wordpress Wordpress?
|
||||
teams Team[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
|
||||
fider Fider?
|
||||
ghost Ghost?
|
||||
hasura Hasura?
|
||||
meiliSearch MeiliSearch?
|
||||
minio Minio?
|
||||
moodle Moodle?
|
||||
plausibleAnalytics PlausibleAnalytics?
|
||||
persistentStorage ServicePersistentStorage[]
|
||||
serviceSecret ServiceSecret[]
|
||||
umami Umami?
|
||||
vscodeserver Vscodeserver?
|
||||
wordpress Wordpress?
|
||||
appwrite Appwrite?
|
||||
|
||||
teams Team[]
|
||||
}
|
||||
|
||||
model PlausibleAnalytics {
|
||||
@@ -491,3 +496,22 @@ model Moodle {
|
||||
updatedAt DateTime @updatedAt
|
||||
service Service @relation(fields: [serviceId], references: [id])
|
||||
}
|
||||
|
||||
model Appwrite {
|
||||
id String @id @default(cuid())
|
||||
serviceId String @unique
|
||||
opensslKeyV1 String
|
||||
executorSecret String
|
||||
redisPassword String
|
||||
mariadbHost String?
|
||||
mariadbPort Int @default(3306)
|
||||
mariadbUser String
|
||||
mariadbPassword String
|
||||
mariadbRootUser String
|
||||
mariadbRootUserPassword String
|
||||
mariadbDatabase String
|
||||
mariadbPublicPort Int?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
service Service @relation(fields: [serviceId], references: [id])
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import env from '@fastify/env';
|
||||
import cookie from '@fastify/cookie';
|
||||
import path, { join } from 'path';
|
||||
import autoLoad from '@fastify/autoload';
|
||||
import { asyncExecShell, isDev, listSettings, prisma } from './lib/common';
|
||||
import { asyncExecShell, isDev, listSettings, prisma, version } from './lib/common';
|
||||
import { scheduler } from './lib/scheduler';
|
||||
import axios from 'axios';
|
||||
import compareVersions from 'compare-versions';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
@@ -113,8 +115,22 @@ fastify.listen({ port, host }, async (err: any, address: any) => {
|
||||
setInterval(async () => {
|
||||
const { isAutoUpdateEnabled } = await prisma.setting.findFirst();
|
||||
if (isAutoUpdateEnabled) {
|
||||
if (scheduler.workers.has('deployApplication')) {
|
||||
scheduler.workers.get('deployApplication').postMessage("status:autoUpdater");
|
||||
const currentVersion = version;
|
||||
const { data: versions } = await axios
|
||||
.get(
|
||||
`https://get.coollabs.io/versions.json`
|
||||
, {
|
||||
params: {
|
||||
appId: process.env['COOLIFY_APP_ID'] || undefined,
|
||||
version: currentVersion
|
||||
}
|
||||
})
|
||||
const latestVersion = versions['coolify'].main.version;
|
||||
const isUpdateAvailable = compareVersions(latestVersion, currentVersion);
|
||||
if (isUpdateAvailable === 1) {
|
||||
if (scheduler.workers.has('deployApplication')) {
|
||||
scheduler.workers.get('deployApplication').postMessage("status:autoUpdater");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, isDev ? 5000 : 60000 * 15)
|
||||
|
||||
@@ -152,6 +152,13 @@ import * as buildpacks from '../lib/buildPacks';
|
||||
.createHash('sha256')
|
||||
.update(
|
||||
JSON.stringify({
|
||||
pythonWSGI,
|
||||
pythonModule,
|
||||
pythonVariable,
|
||||
deploymentType,
|
||||
denoOptions,
|
||||
baseImage,
|
||||
baseBuildImage,
|
||||
buildPack,
|
||||
port,
|
||||
exposePort,
|
||||
|
||||
@@ -252,6 +252,20 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
|
||||
label: 'python:3.7-slim-bullseye'
|
||||
}
|
||||
];
|
||||
const herokuVersions = [
|
||||
{
|
||||
value: 'heroku/builder:22',
|
||||
label: 'heroku/builder:22'
|
||||
},
|
||||
{
|
||||
value: 'heroku/buildpacks:20',
|
||||
label: 'heroku/buildpacks:20'
|
||||
},
|
||||
{
|
||||
value: 'heroku/builder-classic:22',
|
||||
label: 'heroku/builder-classic:22'
|
||||
},
|
||||
]
|
||||
let payload: any = {
|
||||
baseImage: null,
|
||||
baseBuildImage: null,
|
||||
@@ -299,6 +313,11 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
|
||||
payload.baseBuildImage = 'node:18';
|
||||
payload.baseBuildImages = nodeVersions;
|
||||
}
|
||||
if (buildPack === 'heroku') {
|
||||
payload.baseImage = 'heroku/buildpacks:20';
|
||||
payload.baseImages = herokuVersions;
|
||||
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@ import { executeDockerCmd, prisma } from "../common"
|
||||
import { saveBuildLog } from "./common";
|
||||
|
||||
export default async function (data: any): Promise<void> {
|
||||
const { buildId, applicationId, tag, dockerId, debug, workdir } = data
|
||||
try {
|
||||
const { buildId, applicationId, tag, dockerId, debug, workdir } = data
|
||||
|
||||
await saveBuildLog({ line: `Building image started.`, buildId, applicationId });
|
||||
const { stdout } = await executeDockerCmd({
|
||||
dockerId,
|
||||
command: `pack build -p ${workdir} ${applicationId}:${tag} --builder heroku/buildpacks:20`
|
||||
})
|
||||
|
||||
if (debug) {
|
||||
const array = stdout.split('\n')
|
||||
for (const line of array) {
|
||||
@@ -24,6 +24,16 @@ export default async function (data: any): Promise<void> {
|
||||
}
|
||||
await saveBuildLog({ line: `Building image successful.`, buildId, applicationId });
|
||||
} catch (error) {
|
||||
const array = error.stdout.split('\n')
|
||||
for (const line of array) {
|
||||
if (line !== '\n') {
|
||||
await saveBuildLog({
|
||||
line: `${line.replace('\n', '')}`,
|
||||
buildId,
|
||||
applicationId
|
||||
});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { checkContainer, removeContainer } from './docker';
|
||||
import { day } from './dayjs';
|
||||
import * as serviceFields from './serviceFields'
|
||||
|
||||
export const version = '3.3.2';
|
||||
export const version = '3.5.0';
|
||||
export const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
const algorithm = 'aes-256-ctr';
|
||||
@@ -78,6 +78,8 @@ export const include: any = {
|
||||
umami: true,
|
||||
hasura: true,
|
||||
fider: true,
|
||||
moodle: true,
|
||||
appwrite: true
|
||||
};
|
||||
|
||||
export const uniqueName = (): string => uniqueNamesGenerator(customConfig);
|
||||
@@ -96,17 +98,23 @@ export const base64Decode = (text: string): string => {
|
||||
};
|
||||
export const decrypt = (hashString: string) => {
|
||||
if (hashString) {
|
||||
const hash = JSON.parse(hashString);
|
||||
const decipher = crypto.createDecipheriv(
|
||||
algorithm,
|
||||
process.env['COOLIFY_SECRET_KEY'],
|
||||
Buffer.from(hash.iv, 'hex')
|
||||
);
|
||||
const decrpyted = Buffer.concat([
|
||||
decipher.update(Buffer.from(hash.content, 'hex')),
|
||||
decipher.final()
|
||||
]);
|
||||
return decrpyted.toString();
|
||||
try {
|
||||
const hash = JSON.parse(hashString);
|
||||
const decipher = crypto.createDecipheriv(
|
||||
algorithm,
|
||||
process.env['COOLIFY_SECRET_KEY'],
|
||||
Buffer.from(hash.iv, 'hex')
|
||||
);
|
||||
const decrpyted = Buffer.concat([
|
||||
decipher.update(Buffer.from(hash.content, 'hex')),
|
||||
decipher.final()
|
||||
]);
|
||||
return decrpyted.toString();
|
||||
} catch (error) {
|
||||
console.log({ decryptionError: error.message })
|
||||
return hashString
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
export const encrypt = (text: string) => {
|
||||
@@ -252,8 +260,8 @@ export const supportedServiceTypesAndVersions = [
|
||||
fancyName: 'Hasura',
|
||||
baseImage: 'hasura/graphql-engine',
|
||||
images: ['postgres:12-alpine'],
|
||||
versions: ['latest', 'v2.8.4', 'v2.5.1'],
|
||||
recommendedVersion: 'v2.8.4',
|
||||
versions: ['latest', 'v2.10.0', 'v2.5.1'],
|
||||
recommendedVersion: 'v2.10.0',
|
||||
ports: {
|
||||
main: 8080
|
||||
}
|
||||
@@ -269,6 +277,17 @@ export const supportedServiceTypesAndVersions = [
|
||||
main: 3000
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'appwrite',
|
||||
fancyName: 'Appwrite',
|
||||
baseImage: 'appwrite/appwrite',
|
||||
images: ['mariadb:10.7', 'redis:6.2-alpine', 'appwrite/telegraf:1.4.0'],
|
||||
versions: ['latest', '0.15.3'],
|
||||
recommendedVersion: '0.15.3',
|
||||
ports: {
|
||||
main: 80
|
||||
}
|
||||
}
|
||||
// {
|
||||
// name: 'moodle',
|
||||
// fancyName: 'Moodle',
|
||||
@@ -288,6 +307,10 @@ export async function checkDoubleBranch(branch: string, projectId: number): Prom
|
||||
}
|
||||
export async function isDNSValid(hostname: any, domain: string): Promise<any> {
|
||||
const { isIP } = await import('is-ip');
|
||||
const { DNSServers } = await listSettings();
|
||||
if (DNSServers) {
|
||||
dns.setServers([DNSServers]);
|
||||
}
|
||||
let resolves = [];
|
||||
try {
|
||||
if (isIP(hostname)) {
|
||||
@@ -301,7 +324,6 @@ export async function isDNSValid(hostname: any, domain: string): Promise<any> {
|
||||
|
||||
try {
|
||||
let ipDomainFound = false;
|
||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
||||
const dnsResolve = await dns.resolve4(domain);
|
||||
if (dnsResolve.length > 0) {
|
||||
for (const ip of dnsResolve) {
|
||||
@@ -393,7 +415,12 @@ export async function checkDomainsIsValidInDNS({ hostname, fqdn, dualCerts }): P
|
||||
const { isIP } = await import('is-ip');
|
||||
const domain = getDomain(fqdn);
|
||||
const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`;
|
||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
||||
|
||||
const { DNSServers } = await listSettings();
|
||||
if (DNSServers) {
|
||||
dns.setServers([DNSServers]);
|
||||
}
|
||||
|
||||
let resolves = [];
|
||||
try {
|
||||
if (isIP(hostname)) {
|
||||
@@ -573,6 +600,11 @@ export async function executeDockerCmd({ dockerId, command }: { dockerId: string
|
||||
} else {
|
||||
engine = 'unix:///var/run/docker.sock'
|
||||
}
|
||||
if (process.env.CODESANDBOX_HOST) {
|
||||
if (command.startsWith('docker compose')) {
|
||||
command = command.replace(/docker compose/gi, 'docker-compose')
|
||||
}
|
||||
}
|
||||
return await asyncExecShell(
|
||||
`DOCKER_BUILDKIT=1 DOCKER_HOST="${engine}" ${command}`
|
||||
);
|
||||
@@ -584,6 +616,11 @@ export async function startTraefikProxy(id: string): Promise<void> {
|
||||
const { id: settingsId, ipv4, ipv6 } = await listSettings();
|
||||
|
||||
if (!found) {
|
||||
const { stdout: coolifyNetwork } = await executeDockerCmd({ dockerId: id, command: `docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"` })
|
||||
|
||||
if (!coolifyNetwork) {
|
||||
await executeDockerCmd({ dockerId: id, command: `docker network create --attachable coolify-infra` })
|
||||
}
|
||||
const { stdout: Config } = await executeDockerCmd({ dockerId: id, command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` })
|
||||
const ip = JSON.parse(Config)[0].Gateway;
|
||||
let traefikUrl = mainTraefikEndpoint
|
||||
@@ -867,6 +904,11 @@ export function generateDatabaseConfiguration(database: any, arch: string):
|
||||
}
|
||||
if (isARM(arch)) {
|
||||
configuration.volume = `${id}-${type}-data:/var/lib/postgresql`;
|
||||
configuration.environmentVariables = {
|
||||
POSTGRES_PASSWORD: dbUserPassword,
|
||||
POSTGRES_USER: dbUser,
|
||||
POSTGRES_DB: defaultDatabase
|
||||
}
|
||||
}
|
||||
return configuration
|
||||
} else if (type === 'redis') {
|
||||
@@ -903,7 +945,7 @@ export function generateDatabaseConfiguration(database: any, arch: string):
|
||||
return configuration
|
||||
}
|
||||
}
|
||||
export function isARM(arch) {
|
||||
export function isARM(arch: string) {
|
||||
if (arch === 'arm' || arch === 'arm64') {
|
||||
return true
|
||||
}
|
||||
@@ -1226,7 +1268,6 @@ export async function startTraefikTCPProxy(
|
||||
}
|
||||
traefikUrl = `${ip}/webhooks/traefik/other.json`
|
||||
}
|
||||
console.log(traefikUrl)
|
||||
const tcpProxy = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
@@ -1291,6 +1332,7 @@ export async function getServiceFromDB({ id, teamId }: { id: string; teamId: str
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
body[type] = { ...body[type], ...getUpdateableFields(type, body[type]) }
|
||||
return { ...body, settings };
|
||||
}
|
||||
@@ -1517,6 +1559,35 @@ export async function configureServiceType({
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (type === 'appwrite') {
|
||||
const opensslKeyV1 = encrypt(generatePassword());
|
||||
const executorSecret = encrypt(generatePassword());
|
||||
const redisPassword = encrypt(generatePassword());
|
||||
const mariadbHost = `${id}-mariadb`
|
||||
const mariadbUser = cuid();
|
||||
const mariadbPassword = encrypt(generatePassword());
|
||||
const mariadbDatabase = 'appwrite';
|
||||
const mariadbRootUser = cuid();
|
||||
const mariadbRootUserPassword = encrypt(generatePassword());
|
||||
await prisma.service.update({
|
||||
where: { id },
|
||||
data: {
|
||||
type,
|
||||
appwrite: {
|
||||
create: {
|
||||
opensslKeyV1,
|
||||
executorSecret,
|
||||
redisPassword,
|
||||
mariadbHost,
|
||||
mariadbUser,
|
||||
mariadbPassword,
|
||||
mariadbDatabase,
|
||||
mariadbRootUser,
|
||||
mariadbRootUserPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await prisma.service.update({
|
||||
where: { id },
|
||||
@@ -1528,6 +1599,7 @@ export async function configureServiceType({
|
||||
}
|
||||
|
||||
export async function removeService({ id }: { id: string }): Promise<void> {
|
||||
await prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.fider.deleteMany({ where: { serviceId: id } });
|
||||
@@ -1538,8 +1610,8 @@ export async function removeService({ id }: { id: string }): Promise<void> {
|
||||
await prisma.minio.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.wordpress.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
|
||||
|
||||
await prisma.moodle.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.appwrite.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.service.delete({ where: { id } });
|
||||
}
|
||||
|
||||
@@ -1604,9 +1676,9 @@ export const getServiceMainPort = (service: string) => {
|
||||
export function makeLabelForServices(type) {
|
||||
return [
|
||||
'coolify.managed=true',
|
||||
`coolify.version = ${version} `,
|
||||
`coolify.version = ${version}`,
|
||||
`coolify.type = service`,
|
||||
`coolify.service.type = ${type} `
|
||||
`coolify.service.type = ${type}`
|
||||
];
|
||||
}
|
||||
export function errorHandler({ status = 500, message = 'Unknown error.' }: { status: number, message: string | any }) {
|
||||
|
||||
@@ -71,7 +71,7 @@ export async function removeContainer({
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` })
|
||||
|
||||
console.log(id)
|
||||
if (JSON.parse(stdout).Running) {
|
||||
await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` })
|
||||
await executeDockerCmd({ dockerId, command: `docker rm ${id}` })
|
||||
|
||||
@@ -20,7 +20,6 @@ const options: any = {
|
||||
}
|
||||
if (message.caller === 'cleanupStorage') {
|
||||
if (!scheduler.workers.has('cleanupStorage')) {
|
||||
await scheduler.stop('deployApplication');
|
||||
await scheduler.run('cleanupStorage')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ export const fider = [{
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
}, {
|
||||
name: 'postgreslUser',
|
||||
name: 'postgresqlUser',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
@@ -469,6 +469,87 @@ export const moodle = [{
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
},
|
||||
{
|
||||
name: 'mariadbDatabase',
|
||||
isEditable: true,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: false
|
||||
}]
|
||||
|
||||
export const appwrite = [{
|
||||
name: 'opensslKeyV1',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
},
|
||||
{
|
||||
name: 'executorSecret',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
},
|
||||
{
|
||||
name: 'redisPassword',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
},
|
||||
{
|
||||
name: 'mariadbHost',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: false
|
||||
},
|
||||
{
|
||||
name: 'mariadbPort',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: false
|
||||
},
|
||||
{
|
||||
name: 'mariadbUser',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: false
|
||||
},
|
||||
{
|
||||
name: 'mariadbPassword',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
},
|
||||
{
|
||||
name: 'mariadbRootUser',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: false
|
||||
},
|
||||
{
|
||||
name: 'mariadbRootUserPassword',
|
||||
isEditable: false,
|
||||
isLowerCase: false,
|
||||
isNumber: false,
|
||||
isBoolean: false,
|
||||
isEncrypted: true
|
||||
},
|
||||
{
|
||||
name: 'mariadbDatabase',
|
||||
isEditable: true,
|
||||
|
||||
35
apps/api/src/lib/services.ts
Normal file
35
apps/api/src/lib/services.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { createDirectories, getServiceFromDB, getServiceImage, getServiceMainPort, makeLabelForServices } from "./common";
|
||||
|
||||
export async function defaultServiceConfigurations({ id, teamId }) {
|
||||
const service = await getServiceFromDB({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, type, serviceSecret } = service;
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const port = getServiceMainPort(type);
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
|
||||
const image = getServiceImage(type);
|
||||
let secrets = [];
|
||||
if (serviceSecret.length > 0) {
|
||||
serviceSecret.forEach((secret) => {
|
||||
secrets.push(`${secret.name}=${secret.value}`);
|
||||
});
|
||||
}
|
||||
return { ...service, network, port, workdir, image, secrets }
|
||||
}
|
||||
|
||||
export function defaultServiceComposeConfiguration(network: string): any {
|
||||
return {
|
||||
networks: [network],
|
||||
restart: 'always',
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
condition: 'on-failure',
|
||||
delay: '10s',
|
||||
max_attempts: 10,
|
||||
window: '120s'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import axios from 'axios';
|
||||
import { FastifyReply } from 'fastify';
|
||||
import { day } from '../../../../lib/dayjs';
|
||||
import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common';
|
||||
import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getFreeExposedPort, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common';
|
||||
import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getFreeExposedPort, isDev, isDomainConfigured, listSettings, prisma, stopBuild, uniqueName } from '../../../../lib/common';
|
||||
import { checkContainer, formatLabelsOnDocker, isContainerExited, removeContainer } from '../../../../lib/docker';
|
||||
import { scheduler } from '../../../../lib/scheduler';
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function listApplications(request: FastifyRequest) {
|
||||
const { teamId } = request.user
|
||||
const applications = await prisma.application.findMany({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
|
||||
include: { teams: true, destinationDocker: true }
|
||||
include: { teams: true, destinationDocker: true, settings: true }
|
||||
});
|
||||
const settings = await prisma.setting.findFirst()
|
||||
return {
|
||||
@@ -90,10 +90,11 @@ export async function getApplication(request: FastifyRequest<OnlyId>) {
|
||||
const { teamId } = request.user
|
||||
const appId = process.env['COOLIFY_APP_ID'];
|
||||
const application: any = await getApplicationFromDB(id, teamId);
|
||||
|
||||
const settings = await listSettings();
|
||||
return {
|
||||
application,
|
||||
appId
|
||||
appId,
|
||||
settings
|
||||
};
|
||||
|
||||
} catch ({ status, message }) {
|
||||
@@ -275,7 +276,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
export async function saveApplicationSettings(request: FastifyRequest<SaveApplicationSettings>, reply: FastifyReply) {
|
||||
try {
|
||||
const { id } = request.params
|
||||
const { debug, previews, dualCerts, autodeploy, branch, projectId } = request.body
|
||||
const { debug, previews, dualCerts, autodeploy, branch, projectId, isBot } = request.body
|
||||
const isDouble = await checkDoubleBranch(branch, projectId);
|
||||
if (isDouble && autodeploy) {
|
||||
await prisma.applicationSettings.updateMany({ where: { application: { branch, projectId } }, data: { autodeploy: false } })
|
||||
@@ -283,7 +284,7 @@ export async function saveApplicationSettings(request: FastifyRequest<SaveApplic
|
||||
}
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: { settings: { update: { debug, previews, dualCerts, autodeploy } } },
|
||||
data: { fqdn: isBot ? null : undefined, settings: { update: { debug, previews, dualCerts, autodeploy, isBot } } },
|
||||
include: { destinationDocker: true }
|
||||
});
|
||||
return reply.code(201).send();
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface SaveApplication extends OnlyId {
|
||||
}
|
||||
export interface SaveApplicationSettings extends OnlyId {
|
||||
Querystring: { domain: string; };
|
||||
Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; };
|
||||
Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; isBot: boolean; };
|
||||
}
|
||||
export interface DeleteApplication extends OnlyId {
|
||||
Querystring: { domain: string; };
|
||||
|
||||
@@ -3,8 +3,7 @@ import type { FastifyRequest } from 'fastify';
|
||||
import { FastifyReply } from 'fastify';
|
||||
import yaml from 'js-yaml';
|
||||
import fs from 'fs/promises';
|
||||
import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, isARM, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common';
|
||||
import { checkContainer } from '../../../../lib/docker';
|
||||
import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common';
|
||||
import { day } from '../../../../lib/dayjs';
|
||||
|
||||
import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types';
|
||||
|
||||
@@ -4,7 +4,7 @@ import axios from 'axios';
|
||||
import compare from 'compare-versions';
|
||||
import cuid from 'cuid';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { asyncExecShell, asyncSleep, cleanupDockerStorage, errorHandler, isDev, prisma, uniqueName, version } from '../../../lib/common';
|
||||
import { asyncExecShell, asyncSleep, cleanupDockerStorage, errorHandler, isDev, listSettings, prisma, uniqueName, version } from '../../../lib/common';
|
||||
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import type { Login, Update } from '.';
|
||||
@@ -97,7 +97,8 @@ export async function showDashboard(request: FastifyRequest) {
|
||||
const userId = request.user.userId;
|
||||
const teamId = request.user.teamId;
|
||||
const applications = await prisma.application.findMany({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
|
||||
include: { settings: true }
|
||||
});
|
||||
const databases = await prisma.database.findMany({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
@@ -105,10 +106,12 @@ export async function showDashboard(request: FastifyRequest) {
|
||||
const services = await prisma.service.findMany({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const settings = await listSettings();
|
||||
return {
|
||||
applications,
|
||||
databases,
|
||||
services,
|
||||
settings,
|
||||
};
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,12 +33,13 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
|
||||
minPort,
|
||||
maxPort,
|
||||
isAutoUpdateEnabled,
|
||||
isDNSCheckEnabled
|
||||
isDNSCheckEnabled,
|
||||
DNSServers
|
||||
} = request.body
|
||||
const { id } = await listSettings();
|
||||
await prisma.setting.update({
|
||||
where: { id },
|
||||
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled }
|
||||
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers }
|
||||
});
|
||||
if (fqdn) {
|
||||
await prisma.setting.update({ where: { id }, data: { fqdn } });
|
||||
@@ -54,6 +55,10 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
|
||||
export async function deleteDomain(request: FastifyRequest<DeleteDomain>, reply: FastifyReply) {
|
||||
try {
|
||||
const { fqdn } = request.body
|
||||
const { DNSServers } = await listSettings();
|
||||
if (DNSServers) {
|
||||
dns.setServers([DNSServers]);
|
||||
}
|
||||
let ip;
|
||||
try {
|
||||
ip = await dns.resolve(fqdn);
|
||||
|
||||
@@ -8,7 +8,8 @@ export interface SaveSettings {
|
||||
minPort: number,
|
||||
maxPort: number,
|
||||
isAutoUpdateEnabled: boolean,
|
||||
isDNSCheckEnabled: boolean
|
||||
isDNSCheckEnabled: boolean,
|
||||
DNSServers: string
|
||||
}
|
||||
}
|
||||
export interface DeleteDomain {
|
||||
|
||||
@@ -131,8 +131,8 @@ export const supportedServiceTypesAndVersions = [
|
||||
fancyName: 'Hasura',
|
||||
baseImage: 'hasura/graphql-engine',
|
||||
images: ['postgres:12-alpine'],
|
||||
versions: ['latest', 'v2.5.1'],
|
||||
recommendedVersion: 'v2.5.1',
|
||||
versions: ['latest', 'v2.10.0', 'v2.5.1'],
|
||||
recommendedVersion: 'v2.10.0',
|
||||
ports: {
|
||||
main: 8080
|
||||
}
|
||||
@@ -148,6 +148,17 @@ export const supportedServiceTypesAndVersions = [
|
||||
main: 3000
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'appwrite',
|
||||
fancyName: 'Appwrite',
|
||||
baseImage: 'appwrite/appwrite',
|
||||
images: ['mariadb:10.7', 'redis:6.2-alpine', 'appwrite/telegraf:1.4.0'],
|
||||
versions: ['latest', '0.15.3'],
|
||||
recommendedVersion: '0.15.3',
|
||||
ports: {
|
||||
main: 80
|
||||
}
|
||||
}
|
||||
// {
|
||||
// name: 'moodle',
|
||||
// fancyName: 'Moodle',
|
||||
@@ -218,7 +229,7 @@ export const staticDeployments = [
|
||||
'astro',
|
||||
'eleventy'
|
||||
];
|
||||
export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel'];
|
||||
export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel', 'heroku'];
|
||||
|
||||
|
||||
export function generateRemoteEngine(destination: any) {
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
on:click={() => dispatch('click')}
|
||||
on:mouseover={() => dispatch('pause')}
|
||||
on:focus={() => dispatch('pause')}
|
||||
on:mouseout={() => dispatch('resume')}
|
||||
on:blur={() => dispatch('resume')}
|
||||
class="alert shadow-lg text-white rounded"
|
||||
class="alert shadow-lg text-white rounded hover:scale-105 transition-all duration-100 cursor-pointer"
|
||||
class:bg-coollabs={type === 'success'}
|
||||
class:alert-error={type === 'error'}
|
||||
class:alert-info={type === 'info'}
|
||||
>
|
||||
<!-- {#if type === 'success'}
|
||||
{#if type === 'success'}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="stroke-current flex-shrink-0 h-6 w-6"
|
||||
@@ -53,6 +54,6 @@
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/></svg
|
||||
>
|
||||
{/if} -->
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { fade } from 'svelte/transition';
|
||||
import Toast from './Toast.svelte';
|
||||
|
||||
import { pauseToast, resumeToast, toasts } from '$lib/store';
|
||||
import { dismissToast, pauseToast, resumeToast, toasts } from '$lib/store';
|
||||
</script>
|
||||
|
||||
{#if $toasts}
|
||||
@@ -12,7 +12,8 @@
|
||||
<Toast
|
||||
type={toast.type}
|
||||
on:resume={() => resumeToast(toast.id)}
|
||||
on:pause={() => pauseToast(toast.id)}>{@html toast.message}</Toast
|
||||
on:pause={() => pauseToast(toast.id)}
|
||||
on:click={() => dismissToast(toast.id)}>{@html toast.message}</Toast
|
||||
>
|
||||
{/each}
|
||||
</article>
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
disabled={updateStatus.success === false}
|
||||
on:click={update}
|
||||
class="icons tooltip tooltip-right tooltip-primary bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-white duration-75 hover:scale-105"
|
||||
data-tip="Update available!"
|
||||
data-tip="Update Available!"
|
||||
>
|
||||
{#if updateStatus.loading}
|
||||
<svg
|
||||
|
||||
@@ -38,4 +38,6 @@
|
||||
<Icons.Deno {isAbsolute} />
|
||||
{:else if application.buildPack?.toLowerCase() === 'laravel'}
|
||||
<Icons.Laravel {isAbsolute} />
|
||||
{:else if application.buildPack?.toLowerCase() === 'heroku'}
|
||||
<Icons.Heroku {isAbsolute} />
|
||||
{/if}
|
||||
|
||||
15
apps/ui/src/lib/components/svg/applications/Heroku.svelte
Normal file
15
apps/ui/src/lib/components/svg/applications/Heroku.svelte
Normal file
@@ -0,0 +1,15 @@
|
||||
<script lang="ts">
|
||||
export let isAbsolute = true;
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class={isAbsolute ? 'absolute top-0 left-0 -m-4 h-10 w-10' : 'mx-auto w-8 h-8 '}
|
||||
viewBox="0 0 72 80"
|
||||
>
|
||||
<path
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="#430098"
|
||||
d="M64.8,0 L7.2,0 C3.224,0 0,3.224 0,7.2 L0,72.8 C0,76.776 3.224,80 7.2,80 L64.8,80 C68.776,80 72,76.776 72,72.8 L72,7.2 C72,3.224 68.776,0 64.8,0 Z M18,68 L18,52 L27,60 L18,68 Z M46,68 L46,44.11 C45.961,42.243 45.062,40 41,40 C32.866,40 23.742,44.091 23.651,44.132 L18,46.692 L18,12 L26,12 L26,34.711 C29.994,33.411 35.577,32 41,32 C45.945,32 48.905,33.944 50.517,35.575 C53.958,39.055 54.005,43.488 54.0002258,44 L54.0002258,68 L46,68 Z M48,25 L40,25 C43.144,20.875 45.118,16.534 46,12 L54,12 C53.46,16.544 51.618,20.9 48,25 Z"
|
||||
/>
|
||||
</svg>
|
||||
@@ -16,4 +16,4 @@ export { default as Astro } from './Astro.svelte';
|
||||
export { default as Eleventy } from './Eleventy.svelte';
|
||||
export { default as Deno } from './Deno.svelte';
|
||||
export { default as Laravel } from './Laravel.svelte';
|
||||
|
||||
export { default as Heroku } from './Heroku.svelte';
|
||||
|
||||
21
apps/ui/src/lib/components/svg/services/Appwrite.svelte
Normal file
21
apps/ui/src/lib/components/svg/services/Appwrite.svelte
Normal file
File diff suppressed because one or more lines are too long
@@ -32,6 +32,8 @@
|
||||
<Icons.Hasura {isAbsolute} />
|
||||
{:else if type === 'fider'}
|
||||
<Icons.Fider {isAbsolute} />
|
||||
{:else if type === 'appwrite'}
|
||||
<Icons.Appwrite {isAbsolute} />
|
||||
{:else if type === 'moodle'}
|
||||
<Icons.Moodle {isAbsolute} />
|
||||
{/if}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
//@ts-nocheck
|
||||
export { default as PlausibleAnalytics } from './PlausibleAnalytics.svelte';
|
||||
export { default as NocoDb } from './NocoDB.svelte';
|
||||
export { default as MinIo } from './MinIO.svelte';
|
||||
export { default as VsCodeServer } from './VSCodeServer.svelte';
|
||||
export { default as Wordpress } from './Wordpress.svelte';
|
||||
export { default as VaultWarden } from './VaultWarden.svelte';
|
||||
export { default as LanguageTool } from './LanguageTool.svelte';
|
||||
export { default as N8n } from './N8n.svelte';
|
||||
export { default as UptimeKuma } from './UptimeKuma.svelte';
|
||||
export { default as Ghost } from './Ghost.svelte';
|
||||
export { default as MeiliSearch } from './MeiliSearch.svelte';
|
||||
export { default as Umami } from './Umami.svelte';
|
||||
export { default as Hasura } from './Hasura.svelte';
|
||||
export { default as Fider } from './Fider.svelte';
|
||||
export { default as Moodle } from './Moodle.svelte';
|
||||
export { default as NocoDb } from './NocoDB.svelte';
|
||||
export { default as MinIo } from './MinIO.svelte';
|
||||
export { default as VsCodeServer } from './VSCodeServer.svelte';
|
||||
export { default as Wordpress } from './Wordpress.svelte';
|
||||
export { default as VaultWarden } from './VaultWarden.svelte';
|
||||
export { default as LanguageTool } from './LanguageTool.svelte';
|
||||
export { default as N8n } from './N8n.svelte';
|
||||
export { default as UptimeKuma } from './UptimeKuma.svelte';
|
||||
export { default as Ghost } from './Ghost.svelte';
|
||||
export { default as MeiliSearch } from './MeiliSearch.svelte';
|
||||
export { default as Umami } from './Umami.svelte';
|
||||
export { default as Hasura } from './Hasura.svelte';
|
||||
export { default as Fider } from './Fider.svelte';
|
||||
export { default as Appwrite } from './Appwrite.svelte';
|
||||
export { default as Moodle } from './Moodle.svelte';
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"wait_new_version_startup": "Waiting for the new version to start...",
|
||||
"new_version": "New version reachable. Reloading...",
|
||||
"switch_to_a_different_team": "Switch to a different team...",
|
||||
"update_available": "Update available"
|
||||
"update_available": "Update Available"
|
||||
},
|
||||
"error": {
|
||||
"you_can_find_your_way_back": "You can find your way back",
|
||||
@@ -144,8 +144,8 @@
|
||||
},
|
||||
"preview": {
|
||||
"need_during_buildtime": "Need during buildtime?",
|
||||
"setup_secret_app_first": "You can add secrets to PR/MR deployments. Please add secrets to the application first. <br>Useful for creating <span class='text-applications font-bold'>staging</span> environments.",
|
||||
"values_overwriting_app_secrets": "These values overwrite application secrets in PR/MR deployments. Useful for creating <span class='text-applications font-bold'>staging</span> environments.",
|
||||
"setup_secret_app_first": "You can add secrets to PR/MR deployments. Please add secrets to the application first. <br>Useful for creating <span class='text-green-500 font-bold'>staging</span> environments.",
|
||||
"values_overwriting_app_secrets": "These values overwrite application secrets in PR/MR deployments. Useful for creating <span class='text-green-500 font-bold'>staging</span> environments.",
|
||||
"redeploy": "Redeploy",
|
||||
"no_previews_available": "No previews available"
|
||||
},
|
||||
@@ -163,9 +163,9 @@
|
||||
},
|
||||
"deployment_queued": "Deployment queued.",
|
||||
"confirm_to_delete": "Are you sure you would like to delete '{{name}}'?",
|
||||
"stop_application": "Stop application",
|
||||
"stop_application": "Stop Application",
|
||||
"permission_denied_stop_application": "You do not have permission to stop the application.",
|
||||
"rebuild_application": "Rebuild application",
|
||||
"rebuild_application": "Rebuild Application",
|
||||
"permission_denied_rebuild_application": "You do not have permission to rebuild application.",
|
||||
"build_and_start_application": "Deploy",
|
||||
"permission_denied_build_and_start_application": "You do not have permission to deploy application.",
|
||||
@@ -194,14 +194,14 @@
|
||||
"application": "Application",
|
||||
"url_fqdn": "URL (FQDN)",
|
||||
"domain_fqdn": "Domain (FQDN)",
|
||||
"https_explainer": "If you specify <span class='text-applications font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-applications font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-white font-bold'>You must set your DNS to point to the server IP in advance.</span>",
|
||||
"https_explainer": "If you specify <span class='text-green-500 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-green-500 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-white font-bold'>You must set your DNS to point to the server IP in advance.</span>",
|
||||
"ssl_www_and_non_www": "Generate SSL for www and non-www?",
|
||||
"ssl_explainer": "It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-applications'>both DNS entries</span> set in advance.<br><br>Useful if you expect to have visitors on both.",
|
||||
"ssl_explainer": "It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-green-500'>both DNS entries</span> set in advance.<br><br>Useful if you expect to have visitors on both.",
|
||||
"install_command": "Install Command",
|
||||
"build_command": "Build Command",
|
||||
"start_command": "Start Command",
|
||||
"directory_to_use_explainer": "Directory to use as the base for all commands.<br>Could be useful with <span class='text-applications font-bold'>monorepos</span>.",
|
||||
"publish_directory_explainer": "Directory containing all the assets for deployment. <br> For example: <span class='text-applications font-bold'>dist</span>,<span class='text-applications font-bold'>_site</span> or <span class='text-applications font-bold'>public</span>.",
|
||||
"directory_to_use_explainer": "Directory to use as the base for all commands.<br>Could be useful with <span class='text-green-500 font-bold'>monorepos</span>.",
|
||||
"publish_directory_explainer": "Directory containing all the assets for deployment. <br> For example: <span class='text-green-500 font-bold'>dist</span>,<span class='text-green-500 font-bold'>_site</span> or <span class='text-green-500 font-bold'>public</span>.",
|
||||
"features": "Features",
|
||||
"enable_automatic_deployment": "Enable Automatic Deployment",
|
||||
"enable_auto_deploy_webhooks": "Enable automatic deployment through webhooks.",
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"features": "Caractéristiques",
|
||||
"git_repository": "Dépôt Git",
|
||||
"git_source": "Source Git",
|
||||
"https_explainer": "Si vous spécifiez <span class='text-applications font-bold'>https</span>, l'application sera accessible uniquement via https. \nUn certificat SSL sera généré pour vous.<br>Si vous spécifiez <span class='text-applications font-bold'>www</span>, l'application sera redirigée (302) à partir de non-www et vice versa \n.<br><br>Pour modifier le domaine, vous devez d'abord arrêter l'application.<br><br><span class='text-white font-bold'>Vous devez configurer, en avance, votre DNS pour pointer vers l'IP du serveur.</span>",
|
||||
"https_explainer": "Si vous spécifiez <span class='text-green-500 font-bold'>https</span>, l'application sera accessible uniquement via https. \nUn certificat SSL sera généré pour vous.<br>Si vous spécifiez <span class='text-green-500 font-bold'>www</span>, l'application sera redirigée (302) à partir de non-www et vice versa \n.<br><br>Pour modifier le domaine, vous devez d'abord arrêter l'application.<br><br><span class='text-white font-bold'>Vous devez configurer, en avance, votre DNS pour pointer vers l'IP du serveur.</span>",
|
||||
"install_command": "Commande d'installation",
|
||||
"logs": "Journaux des applications",
|
||||
"no_applications_found": "Aucune application trouvée",
|
||||
@@ -78,11 +78,11 @@
|
||||
"need_during_buildtime": "Besoin pendant la build ?",
|
||||
"no_previews_available": "Aucun aperçu disponible",
|
||||
"redeploy": "Redéployer",
|
||||
"setup_secret_app_first": "Vous pouvez ajouter des secrets aux déploiements PR/MR. \nVeuillez d'abord ajouter des secrets à l'application. \n<br>Utile pour créer des environnements <span class='text-applications font-bold'>de mise en scène</span>.",
|
||||
"values_overwriting_app_secrets": "Ces valeurs remplacent les secrets d'application dans les déploiements PR/MR. \nUtile pour créer des environnements <span class='text-applications font-bold'>de mise en scène</span>."
|
||||
"setup_secret_app_first": "Vous pouvez ajouter des secrets aux déploiements PR/MR. \nVeuillez d'abord ajouter des secrets à l'application. \n<br>Utile pour créer des environnements <span class='text-green-500 font-bold'>de mise en scène</span>.",
|
||||
"values_overwriting_app_secrets": "Ces valeurs remplacent les secrets d'application dans les déploiements PR/MR. \nUtile pour créer des environnements <span class='text-green-500 font-bold'>de mise en scène</span>."
|
||||
},
|
||||
"previews": "Aperçus",
|
||||
"publish_directory_explainer": "Répertoire contenant tous les actifs à déployer. \n<br> Par exemple : <span class='text-applications font-bold'>dist</span>,<span class='text-applications font-bold'>_site</span> ou <span \nclass='text-applications font-bold'>public</span>.",
|
||||
"publish_directory_explainer": "Répertoire contenant tous les actifs à déployer. \n<br> Par exemple : <span class='text-green-500 font-bold'>dist</span>,<span class='text-green-500 font-bold'>_site</span> ou <span \nclass='text-green-500 font-bold'>public</span>.",
|
||||
"rebuild_application": "Re-build l'application",
|
||||
"secret": "secrets",
|
||||
"secrets": {
|
||||
@@ -91,7 +91,7 @@
|
||||
"use_isbuildsecret": "Utiliser isBuildSecret"
|
||||
},
|
||||
"settings_saved": "Paramètres sauvegardés.",
|
||||
"ssl_explainer": "Il générera des certificats pour www et non-www. \n<br>Vous devez avoir <span class='font-bold text-applications'>les deux entrées DNS</span> définies à l'avance.<br><br>Utile si vous prévoyez d'avoir des visiteurs sur les deux.",
|
||||
"ssl_explainer": "Il générera des certificats pour www et non-www. \n<br>Vous devez avoir <span class='font-bold text-green-500'>les deux entrées DNS</span> définies à l'avance.<br><br>Utile si vous prévoyez d'avoir des visiteurs sur les deux.",
|
||||
"ssl_www_and_non_www": "Générer SSL pour www et non-www ?",
|
||||
"start_command": "Démarrer la commande",
|
||||
"stop_application": "Arrêter l'application",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { dev } from '$app/env';
|
||||
import cuid from 'cuid';
|
||||
import { writable, readable, type Writable } from 'svelte/store';
|
||||
|
||||
@@ -70,7 +71,11 @@ export const features = readable({
|
||||
});
|
||||
|
||||
export const location: Writable<null | string> = writable(null)
|
||||
export const setLocation = (resource: any) => {
|
||||
export const setLocation = (resource: any, settings?: any) => {
|
||||
if (resource.settings.isBot && resource.exposePort) {
|
||||
disabledButton.set(false);
|
||||
return location.set(`http://${dev ? 'localhost' : settings.ipv4}:${resource.exposePort}`)
|
||||
}
|
||||
if (GITPOD_WORKSPACE_URL && resource.exposePort) {
|
||||
const { href } = new URL(GITPOD_WORKSPACE_URL);
|
||||
const newURL = href
|
||||
@@ -81,7 +86,12 @@ export const setLocation = (resource: any) => {
|
||||
const newURL = `https://${CODESANDBOX_HOST.replace(/\$PORT/, resource.exposePort)}`
|
||||
return location.set(newURL)
|
||||
}
|
||||
return location.set(resource.fqdn)
|
||||
if (resource.fqdn) {
|
||||
return location.set(resource.fqdn)
|
||||
} else {
|
||||
location.set(null);
|
||||
disabledButton.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
export const toasts: any = writable([])
|
||||
|
||||
@@ -170,6 +170,16 @@ export function findBuildPack(pack: string, packageManager = 'npm') {
|
||||
port: 80
|
||||
};
|
||||
}
|
||||
if (pack === 'heroku') {
|
||||
return {
|
||||
...metaData,
|
||||
installCommand: null,
|
||||
buildCommand: null,
|
||||
startCommand: null,
|
||||
publishDirectory: null,
|
||||
port: 5000
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: 'node',
|
||||
fancyName: 'Node.js',
|
||||
@@ -187,119 +197,137 @@ export const buildPacks = [
|
||||
name: 'node',
|
||||
fancyName: 'Node.js',
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
color: 'bg-green-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'static',
|
||||
fancyName: 'Static',
|
||||
hoverColor: 'hover:bg-orange-700',
|
||||
color: 'bg-orange-700'
|
||||
color: 'bg-orange-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: 'php',
|
||||
fancyName: 'PHP',
|
||||
hoverColor: 'hover:bg-indigo-700',
|
||||
color: 'bg-indigo-700'
|
||||
color: 'bg-indigo-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'laravel',
|
||||
fancyName: 'Laravel',
|
||||
hoverColor: 'hover:bg-indigo-700',
|
||||
color: 'bg-indigo-700'
|
||||
color: 'bg-indigo-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'docker',
|
||||
fancyName: 'Docker',
|
||||
hoverColor: 'hover:bg-sky-700',
|
||||
color: 'bg-sky-700'
|
||||
color: 'bg-sky-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'svelte',
|
||||
fancyName: 'Svelte',
|
||||
hoverColor: 'hover:bg-orange-700',
|
||||
color: 'bg-orange-700'
|
||||
color: 'bg-orange-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'vuejs',
|
||||
fancyName: 'VueJS',
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
color: 'bg-green-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'nuxtjs',
|
||||
fancyName: 'NuxtJS',
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
color: 'bg-green-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'gatsby',
|
||||
fancyName: 'Gatsby',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
color: 'bg-blue-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'astro',
|
||||
fancyName: 'Astro',
|
||||
hoverColor: 'hover:bg-pink-700',
|
||||
color: 'bg-pink-700'
|
||||
color: 'bg-pink-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'eleventy',
|
||||
fancyName: 'Eleventy',
|
||||
hoverColor: 'hover:bg-red-700',
|
||||
color: 'bg-red-700'
|
||||
color: 'bg-red-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: 'react',
|
||||
fancyName: 'React',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
color: 'bg-blue-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'preact',
|
||||
fancyName: 'Preact',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
color: 'bg-blue-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'nextjs',
|
||||
fancyName: 'NextJS',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
color: 'bg-blue-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'nestjs',
|
||||
fancyName: 'NestJS',
|
||||
hoverColor: 'hover:bg-red-700',
|
||||
color: 'bg-red-700'
|
||||
color: 'bg-red-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'rust',
|
||||
fancyName: 'Rust',
|
||||
hoverColor: 'hover:bg-pink-700',
|
||||
color: 'bg-pink-700'
|
||||
color: 'bg-pink-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'python',
|
||||
fancyName: 'Python',
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
color: 'bg-green-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'deno',
|
||||
fancyName: 'Deno',
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
}
|
||||
// },
|
||||
// {
|
||||
// name: 'heroku',
|
||||
// fancyName: 'Heroku Buildpack',
|
||||
// hoverColor: 'hover:bg-indigo-700',
|
||||
// color: 'bg-indigo-700'
|
||||
// }
|
||||
color: 'bg-green-700',
|
||||
isCoolifyBuildPack: true,
|
||||
},
|
||||
{
|
||||
name: 'heroku',
|
||||
fancyName: 'Heroku',
|
||||
hoverColor: 'hover:bg-purple-700',
|
||||
color: 'bg-purple-700',
|
||||
isHerokuBuildPack: true,
|
||||
}
|
||||
];
|
||||
export const scanningTemplates = {
|
||||
'@sveltejs/kit': {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
export const load: Load = async ({ fetch, url, params }) => {
|
||||
try {
|
||||
const response = await get(`/applications/${params.id}`);
|
||||
let { application, appId, settings, isQueueActive } = response;
|
||||
let { application, appId, settings } = response;
|
||||
if (!application || Object.entries(application).length === 0) {
|
||||
return {
|
||||
status: 302,
|
||||
@@ -36,7 +36,8 @@
|
||||
|
||||
return {
|
||||
props: {
|
||||
application
|
||||
application,
|
||||
settings
|
||||
},
|
||||
stuff: {
|
||||
application,
|
||||
@@ -52,7 +53,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let application: any;
|
||||
|
||||
export let settings: any;
|
||||
import { page } from '$app/stores';
|
||||
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
|
||||
import { del, get, post } from '$lib/api';
|
||||
@@ -65,10 +66,10 @@
|
||||
|
||||
let loading = false;
|
||||
let statusInterval: any;
|
||||
let isQueueActive= false;
|
||||
let isQueueActive = false;
|
||||
$disabledButton =
|
||||
!$appSession.isAdmin ||
|
||||
!application.fqdn ||
|
||||
(!application.fqdn && !application.settings.isBot) ||
|
||||
!application.gitSource ||
|
||||
!application.repository ||
|
||||
!application.destinationDocker ||
|
||||
@@ -80,9 +81,9 @@
|
||||
try {
|
||||
const { buildId } = await post(`/applications/${id}/deploy`, { ...application });
|
||||
addToast({
|
||||
message: $t('application.deployment_queued'),
|
||||
type: 'success'
|
||||
});
|
||||
message: $t('application.deployment_queued'),
|
||||
type: 'success'
|
||||
});
|
||||
if ($page.url.pathname.startsWith(`/applications/${id}/logs/build`)) {
|
||||
return window.location.assign(`/applications/${id}/logs/build?buildId=${buildId}`);
|
||||
} else {
|
||||
@@ -114,7 +115,7 @@
|
||||
return window.location.reload();
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function getStatus() {
|
||||
if ($status.application.loading) return;
|
||||
@@ -126,18 +127,23 @@
|
||||
$status.application.loading = false;
|
||||
$status.application.initialLoading = false;
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
$status.application.initialLoading = true;
|
||||
$location = null;
|
||||
clearInterval(statusInterval);
|
||||
});
|
||||
onMount(async () => {
|
||||
setLocation(application);
|
||||
|
||||
setLocation(application, settings);
|
||||
$status.application.isRunning = false;
|
||||
$status.application.isExited = false;
|
||||
$status.application.loading = false;
|
||||
if (application.gitSourceId && application.destinationDockerId && application.fqdn) {
|
||||
if (
|
||||
application.gitSourceId &&
|
||||
application.destinationDockerId &&
|
||||
(application.fqdn ||
|
||||
application.settings.isBot)
|
||||
) {
|
||||
await getStatus();
|
||||
statusInterval = setInterval(async () => {
|
||||
await getStatus();
|
||||
@@ -258,7 +264,7 @@
|
||||
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2"
|
||||
data-tip={$appSession.isAdmin
|
||||
? isQueueActive
|
||||
? 'Rebuild application'
|
||||
? 'Rebuild Application'
|
||||
: 'Autoupdate inprogress. Cannot rebuild application.'
|
||||
: 'You do not have permission to rebuild application.'}
|
||||
>
|
||||
@@ -403,37 +409,39 @@
|
||||
</svg>
|
||||
</button></a
|
||||
>
|
||||
<a
|
||||
href={!$disabledButton ? `/applications/${id}/previews` : null}
|
||||
sveltekit:prefetch
|
||||
class="hover:text-orange-500 rounded"
|
||||
class:text-orange-500={$page.url.pathname === `/applications/${id}/previews`}
|
||||
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/previews`}
|
||||
>
|
||||
<button
|
||||
disabled={$disabledButton}
|
||||
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
|
||||
data-tip="Previews"
|
||||
{#if !application.settings.isBot}
|
||||
<a
|
||||
href={!$disabledButton ? `/applications/${id}/previews` : null}
|
||||
sveltekit:prefetch
|
||||
class="hover:text-orange-500 rounded"
|
||||
class:text-orange-500={$page.url.pathname === `/applications/${id}/previews`}
|
||||
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/previews`}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
<button
|
||||
disabled={$disabledButton}
|
||||
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm"
|
||||
data-tip="Previews"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<circle cx="7" cy="18" r="2" />
|
||||
<circle cx="7" cy="6" r="2" />
|
||||
<circle cx="17" cy="12" r="2" />
|
||||
<line x1="7" y1="8" x2="7" y2="16" />
|
||||
<path d="M7 8a4 4 0 0 0 4 4h4" />
|
||||
</svg></button
|
||||
></a
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<circle cx="7" cy="18" r="2" />
|
||||
<circle cx="7" cy="6" r="2" />
|
||||
<circle cx="17" cy="12" r="2" />
|
||||
<line x1="7" y1="8" x2="7" y2="16" />
|
||||
<path d="M7 8a4 4 0 0 0 4 4h4" />
|
||||
</svg></button
|
||||
></a
|
||||
>
|
||||
{/if}
|
||||
<div class="border border-coolgray-500 h-8" />
|
||||
<a
|
||||
href={!$disabledButton && $status.application.isRunning ? `/applications/${id}/logs` : null}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
import { page } from '$app/stores';
|
||||
import { get } from '$lib/api';
|
||||
import { appSession } from '$lib/store';
|
||||
import { browser } from '$app/env';
|
||||
import { t } from '$lib/translations';
|
||||
import { buildPacks, findBuildPack, scanningTemplates } from '$lib/templates';
|
||||
import { errorNotification } from '$lib/common';
|
||||
@@ -263,11 +262,27 @@
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="max-w-7xl mx-auto flex flex-wrap justify-center">
|
||||
{#each buildPacks as buildPack}
|
||||
|
||||
|
||||
<div class="max-w-7xl mx-auto ">
|
||||
<div class="title pb-2">Coolify Buildpacks</div>
|
||||
<div class="flex flex-wrap justify-center">
|
||||
{#each buildPacks.filter(bp => bp.isCoolifyBuildPack === true) as buildPack}
|
||||
<div class="p-2">
|
||||
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto ">
|
||||
<div class="title pb-2">Heroku</div>
|
||||
<div class="flex flex-wrap justify-center">
|
||||
{#each buildPacks.filter(bp => bp.isHerokuBuildPack === true) as buildPack}
|
||||
<div class="p-2">
|
||||
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
import { t } from '$lib/translations';
|
||||
import { appSession } from '$lib/store';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@@ -55,6 +56,11 @@
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
onMount(async () => {
|
||||
if (destinations.length === 1) {
|
||||
await handleSubmit(destinations[0].id);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
@@ -65,7 +71,9 @@
|
||||
<div class="flex flex-col justify-center">
|
||||
{#if !destinations || ownDestinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2 text-center font-bold">{$t('application.configuration.no_configurable_destination')}</div>
|
||||
<div class="pb-2 text-center font-bold">
|
||||
{$t('application.configuration.no_configurable_destination')}
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
if (stuff?.application?.id) {
|
||||
return {
|
||||
props: {
|
||||
application: stuff.application
|
||||
application: stuff.application,
|
||||
settings: stuff.settings
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -26,6 +27,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let application: any;
|
||||
export let settings: any;
|
||||
import { page } from '$app/stores';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import Select from 'svelte-select';
|
||||
@@ -60,6 +62,7 @@
|
||||
let previews = application.settings.previews;
|
||||
let dualCerts = application.settings.dualCerts;
|
||||
let autodeploy = application.settings.autodeploy;
|
||||
let isBot = application.settings.isBot;
|
||||
|
||||
let nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
|
||||
let isNonWWWDomainOK = false;
|
||||
@@ -99,7 +102,7 @@
|
||||
application.fqdn = `http://${cuid()}.demo.coolify.io`;
|
||||
await handleSubmit();
|
||||
}
|
||||
domainEl.focus();
|
||||
// !isBot && domainEl.focus();
|
||||
await getUsage();
|
||||
usageInterval = setInterval(async () => {
|
||||
await getUsage();
|
||||
@@ -129,11 +132,17 @@
|
||||
if (name === 'autodeploy') {
|
||||
autodeploy = !autodeploy;
|
||||
}
|
||||
if (name === 'isBot') {
|
||||
isBot = !isBot;
|
||||
application.settings.isBot = isBot;
|
||||
setLocation(application, settings);
|
||||
}
|
||||
try {
|
||||
await post(`/applications/${id}/settings`, {
|
||||
previews,
|
||||
debug,
|
||||
dualCerts,
|
||||
isBot,
|
||||
autodeploy,
|
||||
branch: application.branch,
|
||||
projectId: application.projectId
|
||||
@@ -155,24 +164,28 @@
|
||||
if (name === 'autodeploy') {
|
||||
autodeploy = !autodeploy;
|
||||
}
|
||||
if (name === 'isBot') {
|
||||
isBot = !isBot;
|
||||
}
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function handleSubmit() {
|
||||
if (loading || !application.fqdn) return;
|
||||
if (loading || (!application.fqdn && !isBot)) return;
|
||||
loading = true;
|
||||
try {
|
||||
nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
|
||||
if (application.deploymentType)
|
||||
application.deploymentType = application.deploymentType.toLowerCase();
|
||||
await post(`/applications/${id}/check`, {
|
||||
fqdn: application.fqdn,
|
||||
forceSave,
|
||||
dualCerts,
|
||||
exposePort: application.exposePort
|
||||
});
|
||||
!isBot &&
|
||||
(await post(`/applications/${id}/check`, {
|
||||
fqdn: application.fqdn,
|
||||
forceSave,
|
||||
dualCerts,
|
||||
exposePort: application.exposePort
|
||||
}));
|
||||
await post(`/applications/${id}`, { ...application });
|
||||
setLocation(application);
|
||||
setLocation(application, settings);
|
||||
$disabledButton = false;
|
||||
forceSave = false;
|
||||
addToast({
|
||||
@@ -332,53 +345,56 @@
|
||||
<label for="gitSource" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.git_source')}</label
|
||||
>
|
||||
<a
|
||||
href={!isDisabled
|
||||
? `/applications/${id}/configuration/source?from=/applications/${id}`
|
||||
: ''}
|
||||
class="no-underline"
|
||||
><input
|
||||
value={application.gitSource.name}
|
||||
id="gitSource"
|
||||
disabled
|
||||
class="cursor-pointer hover:bg-coolgray-500"
|
||||
/></a
|
||||
>
|
||||
{#if isDisabled}
|
||||
<input disabled={isDisabled} value={application.gitSource.name} />
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/source?from=/applications/${id}`}
|
||||
class="no-underline"
|
||||
><input
|
||||
value={application.gitSource.name}
|
||||
id="gitSource"
|
||||
class="cursor-pointer hover:bg-coolgray-500"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.git_repository')}</label
|
||||
>
|
||||
<a
|
||||
href={!isDisabled
|
||||
? `/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`
|
||||
: ''}
|
||||
class="no-underline"
|
||||
><input
|
||||
value="{application.repository}/{application.branch}"
|
||||
id="repository"
|
||||
disabled
|
||||
class="cursor-pointer hover:bg-coolgray-500"
|
||||
/></a
|
||||
>
|
||||
{#if isDisabled}
|
||||
<input disabled={isDisabled} value="{application.repository}/{application.branch}" />
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
|
||||
class="no-underline"
|
||||
><input
|
||||
value="{application.repository}/{application.branch}"
|
||||
id="repository"
|
||||
class="cursor-pointer hover:bg-coolgray-500"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="buildPack" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.build_pack')}</label
|
||||
>
|
||||
<a
|
||||
href={!isDisabled
|
||||
? `/applications/${id}/configuration/buildpack?from=/applications/${id}`
|
||||
: ''}
|
||||
class="no-underline "
|
||||
>
|
||||
<input
|
||||
value={application.buildPack}
|
||||
id="buildPack"
|
||||
disabled
|
||||
class="cursor-pointer hover:bg-coolgray-500"
|
||||
/></a
|
||||
>
|
||||
{#if isDisabled}
|
||||
<input class="capitalize" disabled={isDisabled} value={application.buildPack} />
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/buildpack?from=/applications/${id}`}
|
||||
class="no-underline "
|
||||
>
|
||||
<input
|
||||
value={application.buildPack}
|
||||
id="buildPack"
|
||||
class="cursor-pointer hover:bg-coolgray-500 capitalize"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<label for="destination" class="text-base font-bold text-stone-100"
|
||||
@@ -465,77 +481,88 @@
|
||||
<div class="title">{$t('application.application')}</div>
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="flex-col">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100"
|
||||
>{$t('application.url_fqdn')}</label
|
||||
>
|
||||
{#if browser && window.location.hostname === 'demo.coolify.io'}
|
||||
<Explainer
|
||||
text="<span class='text-white font-bold'>You can use the predefined random url name or enter your own domain name.</span>"
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
isCenter={false}
|
||||
bind:setting={isBot}
|
||||
on:click={() => changeSettings('isBot')}
|
||||
title="Is your application a bot?"
|
||||
description="You can deploy applications without domains. <br>They will listen on <span class='text-green-500 font-bold'>IP:EXPOSEDPORT</span> instead.<br></Setting><br>Useful to host <span class='text-green-500 font-bold'>Twitch bots.</span>"
|
||||
/>
|
||||
</div>
|
||||
{#if !isBot}
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="flex-col">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100"
|
||||
>{$t('application.url_fqdn')}</label
|
||||
>
|
||||
{#if browser && window.location.hostname === 'demo.coolify.io'}
|
||||
<Explainer
|
||||
text="<span class='text-white font-bold'>You can use the predefined random url name or enter your own domain name.</span>"
|
||||
/>
|
||||
{/if}
|
||||
<Explainer text={$t('application.https_explainer')} />
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
readonly={isDisabled}
|
||||
disabled={isDisabled}
|
||||
bind:this={domainEl}
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
required
|
||||
bind:value={application.fqdn}
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
placeholder="eg: https://coollabs.io"
|
||||
/>
|
||||
{/if}
|
||||
<Explainer text={$t('application.https_explainer')} />
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
readonly={isDisabled}
|
||||
disabled={isDisabled}
|
||||
bind:this={domainEl}
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
required
|
||||
bind:value={application.fqdn}
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
placeholder="eg: https://coollabs.io"
|
||||
/>
|
||||
{#if forceSave}
|
||||
<div class="flex-col space-y-2 pt-4 text-center">
|
||||
{#if isNonWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{#if dualCerts}
|
||||
{#if isWWWDomainOK}
|
||||
{#if forceSave}
|
||||
<div class="flex-col space-y-2 pt-4 text-center">
|
||||
{#if isNonWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
||||
class="btn btn-sm bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
||||
class="btn btn-sm bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if dualCerts}
|
||||
{#if isWWWDomainOK}
|
||||
<button
|
||||
class="btn btn-sm bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="btn btn-sm bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<Setting
|
||||
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||
disabled={$status.application.isRunning}
|
||||
isCenter={false}
|
||||
bind:setting={dualCerts}
|
||||
title={$t('application.ssl_www_and_non_www')}
|
||||
description={$t('application.ssl_explainer')}
|
||||
on:click={() => !$status.application.isRunning && changeSettings('dualCerts')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<Setting
|
||||
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||
disabled={$status.application.isRunning}
|
||||
isCenter={false}
|
||||
bind:setting={dualCerts}
|
||||
title={$t('application.ssl_www_and_non_www')}
|
||||
description={$t('application.ssl_explainer')}
|
||||
on:click={() => !$status.application.isRunning && changeSettings('dualCerts')}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if application.buildPack === 'python'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="pythonModule" class="text-base font-bold text-stone-100">WSGI / ASGI</label>
|
||||
@@ -585,7 +612,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if !staticDeployments.includes(application.buildPack)}
|
||||
{#if !staticDeployments.includes(application.buildPack) && !isBot}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
||||
<input
|
||||
@@ -606,6 +633,7 @@
|
||||
name="exposePort"
|
||||
id="exposePort"
|
||||
bind:value={application.exposePort}
|
||||
required={isBot}
|
||||
placeholder="12345"
|
||||
/>
|
||||
<Explainer
|
||||
@@ -698,7 +726,7 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if application.buildPack !== 'laravel'}
|
||||
{#if application.buildPack !== 'laravel' && application.buildPack !== 'heroku'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="flex-col">
|
||||
<label for="baseDirectory" class="pt-2 text-base font-bold text-stone-100"
|
||||
@@ -751,15 +779,17 @@
|
||||
description={$t('application.enable_auto_deploy_webhooks')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
isCenter={false}
|
||||
bind:setting={previews}
|
||||
on:click={() => changeSettings('previews')}
|
||||
title={$t('application.enable_mr_pr_previews')}
|
||||
description={$t('application.enable_preview_deploy_mr_pr_requests')}
|
||||
/>
|
||||
</div>
|
||||
{#if !application.settings.isBot}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
isCenter={false}
|
||||
bind:setting={previews}
|
||||
on:click={() => changeSettings('previews')}
|
||||
title={$t('application.enable_mr_pr_previews')}
|
||||
description={$t('application.enable_preview_deploy_mr_pr_requests')}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
isCenter={false}
|
||||
|
||||
@@ -87,6 +87,9 @@
|
||||
{#if application.fqdn}
|
||||
<div class="truncate text-center">{getDomain(application.fqdn) || ''}</div>
|
||||
{/if}
|
||||
{#if application.settings.isBot}
|
||||
<div class="truncate text-center">BOT</div>
|
||||
{/if}
|
||||
{#if application.destinationDocker?.name}
|
||||
<div class="truncate text-center">{application.destinationDocker.name}</div>
|
||||
{/if}
|
||||
@@ -98,7 +101,7 @@
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
Destination Missing
|
||||
</div>
|
||||
{:else if !application.fqdn}
|
||||
{:else if !application.fqdn && !application.settings.isBot}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
URL Missing
|
||||
</div>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
async function changeSettings(name: any) {
|
||||
if (name !== 'appendOnly') {
|
||||
if (publicLoading || !$status.database.isRunning || name !== 'appendOnly') return;
|
||||
if (publicLoading || !$status.database.isRunning) return;
|
||||
}
|
||||
publicLoading = true;
|
||||
let data = {
|
||||
@@ -247,6 +247,7 @@
|
||||
{#if database.type === 'redis'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
loading={publicLoading}
|
||||
bind:setting={appendOnly}
|
||||
on:click={() => changeSettings('appendOnly')}
|
||||
title={$t('database.change_append_only_mode')}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
import { get, post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@@ -45,6 +46,11 @@
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
onMount(async () => {
|
||||
if (destinations.length === 1) {
|
||||
await handleSubmit(destinations[0].id);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
@@ -55,7 +61,9 @@
|
||||
<div class="flex justify-center">
|
||||
{#if !destinations || destinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2 text-center font-bold">{$t('application.configuration.no_configurable_destination')}</div>
|
||||
<div class="pb-2 text-center font-bold">
|
||||
{$t('application.configuration.no_configurable_destination')}
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
|
||||
@@ -20,35 +20,38 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let applications: any;
|
||||
export let databases: any;
|
||||
export let services: any;
|
||||
export let settings: any;
|
||||
|
||||
import { get, post } from '$lib/api';
|
||||
import Usage from '$lib/components/Usage.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
import { errorNotification, asyncSleep } from '$lib/common';
|
||||
import { addToast, appSession } from '$lib/store';
|
||||
|
||||
|
||||
import ApplicationsIcons from '$lib/components/svg/applications/ApplicationIcons.svelte';
|
||||
import DatabaseIcons from '$lib/components/svg/databases/DatabaseIcons.svelte';
|
||||
import ServiceIcons from '$lib/components/svg/services/ServiceIcons.svelte';
|
||||
import { dev } from '$app/env';
|
||||
|
||||
let loading = {
|
||||
cleanup: false
|
||||
};
|
||||
|
||||
export let applications: any;
|
||||
export let databases: any;
|
||||
export let services: any;
|
||||
let numberOfGetStatus = 0;
|
||||
|
||||
function getRndInteger(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1) ) + min;
|
||||
}
|
||||
let numberOfGetStatus = 0;
|
||||
|
||||
function getRndInteger(min: number, max: number) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
async function getStatus(resources: any) {
|
||||
while (numberOfGetStatus > 1){
|
||||
await asyncSleep(getRndInteger(100,200));
|
||||
while (numberOfGetStatus > 1) {
|
||||
await asyncSleep(getRndInteger(100, 200));
|
||||
}
|
||||
try {
|
||||
numberOfGetStatus++;
|
||||
numberOfGetStatus++;
|
||||
const { id, buildPack, dualCerts } = resources;
|
||||
let isRunning = false;
|
||||
if (buildPack) {
|
||||
@@ -69,8 +72,8 @@
|
||||
} catch (error) {
|
||||
return 'Error';
|
||||
} finally {
|
||||
numberOfGetStatus--;
|
||||
}
|
||||
numberOfGetStatus--;
|
||||
}
|
||||
}
|
||||
async function manuallyCleanupStorage() {
|
||||
try {
|
||||
@@ -97,40 +100,91 @@
|
||||
<div class="mt-10 pb-12 tracking-tight sm:pb-16">
|
||||
<div class="mx-auto px-10">
|
||||
<div class="flex flex-col justify-center xl:flex-row">
|
||||
<div>
|
||||
<div class="title">Resources</div>
|
||||
<div class="flex items-start justify-center p-8">
|
||||
<table class="rounded-none text-base">
|
||||
<tbody>
|
||||
{#each applications as application}
|
||||
<tr>
|
||||
<td class="space-x-2 items-center tracking-tight font-bold">
|
||||
{#await getStatus(application)}
|
||||
<div class="inline-flex w-2 h-2 bg-yellow-500 rounded-full" />
|
||||
{:then status}
|
||||
{#if status === 'Running'}
|
||||
<div class="inline-flex w-2 h-2 bg-success rounded-full" />
|
||||
{:else}
|
||||
<div class="inline-flex w-2 h-2 bg-error rounded-full" />
|
||||
{#if applications.length > 0}
|
||||
<div>
|
||||
<div class="title">Resources</div>
|
||||
<div class="flex items-start justify-center p-8">
|
||||
<table class="rounded-none text-base">
|
||||
<tbody>
|
||||
{#each applications as application}
|
||||
<tr>
|
||||
<td class="space-x-2 items-center tracking-tight font-bold">
|
||||
{#await getStatus(application)}
|
||||
<div class="inline-flex w-2 h-2 bg-yellow-500 rounded-full" />
|
||||
{:then status}
|
||||
{#if status === 'Running'}
|
||||
<div class="inline-flex w-2 h-2 bg-success rounded-full" />
|
||||
{:else}
|
||||
<div class="inline-flex w-2 h-2 bg-error rounded-full" />
|
||||
{/if}
|
||||
{/await}
|
||||
<div class="inline-flex">{application.name}</div>
|
||||
</td>
|
||||
<td class="px-10 inline-flex">
|
||||
<ApplicationsIcons {application} isAbsolute={false} />
|
||||
</td>
|
||||
<td class="px-10">
|
||||
<div
|
||||
class="badge badge-outline text-xs border-applications rounded text-white"
|
||||
>
|
||||
Application
|
||||
{#if application.settings.isBot}
|
||||
| BOT
|
||||
{/if}
|
||||
</div></td
|
||||
>
|
||||
<td class="flex justify-end">
|
||||
{#if application.fqdn}
|
||||
<a
|
||||
href={application.fqdn}
|
||||
target="_blank"
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
|
||||
<line x1="10" y1="14" x2="20" y2="4" />
|
||||
<polyline points="15 4 20 4 20 9" />
|
||||
</svg></a
|
||||
>
|
||||
{/if}
|
||||
{#if application.settings.isBot && application.exposePort}
|
||||
<a
|
||||
href={`http://${dev ? 'localhost' : settings.ipv4}:${
|
||||
application.exposePort
|
||||
}`}
|
||||
target="_blank"
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
|
||||
<line x1="10" y1="14" x2="20" y2="4" />
|
||||
<polyline points="15 4 20 4 20 9" />
|
||||
</svg></a
|
||||
>
|
||||
{/if}
|
||||
{/await}
|
||||
<div class="inline-flex">{application.name}</div>
|
||||
</td>
|
||||
<td class="px-10 inline-flex">
|
||||
<ApplicationsIcons {application} isAbsolute={false} />
|
||||
</td>
|
||||
<td class="px-10">
|
||||
<div class="badge badge-outline text-xs border-applications rounded text-white">
|
||||
Application
|
||||
</div></td
|
||||
>
|
||||
<td class="flex justify-end">
|
||||
{#if application.fqdn}
|
||||
<a
|
||||
href={application.fqdn}
|
||||
target="_blank"
|
||||
href={`/applications/${application.id}`}
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
><svg
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -141,72 +195,72 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
|
||||
<line x1="10" y1="14" x2="20" y2="4" />
|
||||
<polyline points="15 4 20 4 20 9" />
|
||||
</svg></a
|
||||
>
|
||||
{/if}
|
||||
<a
|
||||
href={`/applications/${application.id}`}
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<rect x="4" y="8" width="4" height="4" />
|
||||
<line x1="6" y1="4" x2="6" y2="8" />
|
||||
<line x1="6" y1="12" x2="6" y2="20" />
|
||||
<rect x="10" y="14" width="4" height="4" />
|
||||
<line x1="12" y1="4" x2="12" y2="14" />
|
||||
<line x1="12" y1="18" x2="12" y2="20" />
|
||||
<rect x="16" y="5" width="4" height="4" />
|
||||
<line x1="18" y1="4" x2="18" y2="5" />
|
||||
<line x1="18" y1="9" x2="18" y2="20" />
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
<rect x="4" y="8" width="4" height="4" />
|
||||
<line x1="6" y1="4" x2="6" y2="8" />
|
||||
<line x1="6" y1="12" x2="6" y2="20" />
|
||||
<rect x="10" y="14" width="4" height="4" />
|
||||
<line x1="12" y1="4" x2="12" y2="14" />
|
||||
<line x1="12" y1="18" x2="12" y2="20" />
|
||||
<rect x="16" y="5" width="4" height="4" />
|
||||
<line x1="18" y1="4" x2="18" y2="5" />
|
||||
<line x1="18" y1="9" x2="18" y2="20" />
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
{#each services as service}
|
||||
<tr>
|
||||
<td class="space-x-2 items-center tracking-tight font-bold">
|
||||
{#await getStatus(service)}
|
||||
<div class="inline-flex w-2 h-2 bg-yellow-500 rounded-full" />
|
||||
{:then status}
|
||||
{#if status === 'Running'}
|
||||
<div class="inline-flex w-2 h-2 bg-success rounded-full" />
|
||||
{:else}
|
||||
<div class="inline-flex w-2 h-2 bg-error rounded-full" />
|
||||
{#each services as service}
|
||||
<tr>
|
||||
<td class="space-x-2 items-center tracking-tight font-bold">
|
||||
{#await getStatus(service)}
|
||||
<div class="inline-flex w-2 h-2 bg-yellow-500 rounded-full" />
|
||||
{:then status}
|
||||
{#if status === 'Running'}
|
||||
<div class="inline-flex w-2 h-2 bg-success rounded-full" />
|
||||
{:else}
|
||||
<div class="inline-flex w-2 h-2 bg-error rounded-full" />
|
||||
{/if}
|
||||
{/await}
|
||||
<div class="inline-flex">{service.name}</div>
|
||||
</td>
|
||||
<td class="px-10 inline-flex">
|
||||
<ServiceIcons type={service.type} isAbsolute={false} />
|
||||
</td>
|
||||
<td class="px-10"
|
||||
><div class="badge badge-outline text-xs border-services rounded text-white">
|
||||
Service
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="flex justify-end">
|
||||
{#if service.fqdn}
|
||||
<a
|
||||
href={service.fqdn}
|
||||
target="_blank"
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
|
||||
<line x1="10" y1="14" x2="20" y2="4" />
|
||||
<polyline points="15 4 20 4 20 9" />
|
||||
</svg></a
|
||||
>
|
||||
{/if}
|
||||
{/await}
|
||||
<div class="inline-flex">{service.name}</div>
|
||||
</td>
|
||||
<td class="px-10 inline-flex">
|
||||
<ServiceIcons type={service.type} isAbsolute={false} />
|
||||
</td>
|
||||
<td class="px-10"
|
||||
><div class="badge badge-outline text-xs border-services rounded text-white">
|
||||
Service
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="flex justify-end">
|
||||
{#if service.fqdn}
|
||||
<a
|
||||
href={service.fqdn}
|
||||
target="_blank"
|
||||
href={`/services/${service.id}`}
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
><svg
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -217,97 +271,77 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
|
||||
<line x1="10" y1="14" x2="20" y2="4" />
|
||||
<polyline points="15 4 20 4 20 9" />
|
||||
</svg></a
|
||||
<rect x="4" y="8" width="4" height="4" />
|
||||
<line x1="6" y1="4" x2="6" y2="8" />
|
||||
<line x1="6" y1="12" x2="6" y2="20" />
|
||||
<rect x="10" y="14" width="4" height="4" />
|
||||
<line x1="12" y1="4" x2="12" y2="14" />
|
||||
<line x1="12" y1="18" x2="12" y2="20" />
|
||||
<rect x="16" y="5" width="4" height="4" />
|
||||
<line x1="18" y1="4" x2="18" y2="5" />
|
||||
<line x1="18" y1="9" x2="18" y2="20" />
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
{#each databases as database}
|
||||
<tr>
|
||||
<td class="space-x-2 items-center tracking-tight font-bold">
|
||||
{#await getStatus(database)}
|
||||
<div class="inline-flex w-2 h-2 bg-yellow-500 rounded-full" />
|
||||
{:then status}
|
||||
{#if status === 'Running'}
|
||||
<div class="inline-flex w-2 h-2 bg-success rounded-full" />
|
||||
{:else}
|
||||
<div class="inline-flex w-2 h-2 bg-error rounded-full" />
|
||||
{/if}
|
||||
{/await}
|
||||
<div class="inline-flex">{database.name}</div>
|
||||
</td>
|
||||
<td class="px-10 inline-flex">
|
||||
<DatabaseIcons type={database.type} />
|
||||
</td>
|
||||
<td class="px-10">
|
||||
<div class="badge badge-outline text-xs border-databases rounded text-white">
|
||||
Database
|
||||
</div>
|
||||
</td>
|
||||
<td class="flex justify-end">
|
||||
<a
|
||||
href={`/databases/${database.id}`}
|
||||
class="icons bg-transparent text-sm inline-flex ml-11"
|
||||
>
|
||||
{/if}
|
||||
<a
|
||||
href={`/services/${service.id}`}
|
||||
class="icons bg-transparent text-sm inline-flex"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<rect x="4" y="8" width="4" height="4" />
|
||||
<line x1="6" y1="4" x2="6" y2="8" />
|
||||
<line x1="6" y1="12" x2="6" y2="20" />
|
||||
<rect x="10" y="14" width="4" height="4" />
|
||||
<line x1="12" y1="4" x2="12" y2="14" />
|
||||
<line x1="12" y1="18" x2="12" y2="20" />
|
||||
<rect x="16" y="5" width="4" height="4" />
|
||||
<line x1="18" y1="4" x2="18" y2="5" />
|
||||
<line x1="18" y1="9" x2="18" y2="20" />
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
{#each databases as database}
|
||||
<tr>
|
||||
<td class="space-x-2 items-center tracking-tight font-bold">
|
||||
{#await getStatus(database)}
|
||||
<div class="inline-flex w-2 h-2 bg-yellow-500 rounded-full" />
|
||||
{:then status}
|
||||
{#if status === 'Running'}
|
||||
<div class="inline-flex w-2 h-2 bg-success rounded-full" />
|
||||
{:else}
|
||||
<div class="inline-flex w-2 h-2 bg-error rounded-full" />
|
||||
{/if}
|
||||
{/await}
|
||||
<div class="inline-flex">{database.name}</div>
|
||||
</td>
|
||||
<td class="px-10 inline-flex">
|
||||
<DatabaseIcons type={database.type} />
|
||||
</td>
|
||||
<td class="px-10">
|
||||
<div class="badge badge-outline text-xs border-databases rounded text-white">
|
||||
Database
|
||||
</div>
|
||||
</td>
|
||||
<td class="flex justify-end">
|
||||
<a
|
||||
href={`/databases/${database.id}`}
|
||||
class="icons bg-transparent text-sm inline-flex ml-11"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<rect x="4" y="8" width="4" height="4" />
|
||||
<line x1="6" y1="4" x2="6" y2="8" />
|
||||
<line x1="6" y1="12" x2="6" y2="20" />
|
||||
<rect x="10" y="14" width="4" height="4" />
|
||||
<line x1="12" y1="4" x2="12" y2="14" />
|
||||
<line x1="12" y1="18" x2="12" y2="20" />
|
||||
<rect x="16" y="5" width="4" height="4" />
|
||||
<line x1="18" y1="4" x2="18" y2="5" />
|
||||
<line x1="18" y1="9" x2="18" y2="20" />
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<rect x="4" y="8" width="4" height="4" />
|
||||
<line x1="6" y1="4" x2="6" y2="8" />
|
||||
<line x1="6" y1="12" x2="6" y2="20" />
|
||||
<rect x="10" y="14" width="4" height="4" />
|
||||
<line x1="12" y1="4" x2="12" y2="14" />
|
||||
<line x1="12" y1="18" x2="12" y2="20" />
|
||||
<rect x="16" y="5" width="4" height="4" />
|
||||
<line x1="18" y1="4" x2="18" y2="5" />
|
||||
<line x1="18" y1="9" x2="18" y2="20" />
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $appSession.teamId === '0'}
|
||||
<Usage />
|
||||
{/if}
|
||||
|
||||
@@ -55,9 +55,12 @@
|
||||
<a href="https://fider.io" target="_blank">
|
||||
<Icons.Fider />
|
||||
</a>
|
||||
{:else if service.type === 'appwrite'}
|
||||
<a href="https://appwrite.io" target="_blank">
|
||||
<Icons.Appwrite/>
|
||||
</a>
|
||||
{:else if service.type === 'moodle'}
|
||||
<a href="https://moodle.org" target="_blank">
|
||||
<Icons.Moodle />
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
|
||||
126
apps/ui/src/routes/services/[id]/_Services/_Appwrite.svelte
Normal file
126
apps/ui/src/routes/services/[id]/_Services/_Appwrite.svelte
Normal file
@@ -0,0 +1,126 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
import Select from 'svelte-select';
|
||||
export let service: any;
|
||||
export let readOnly: any;
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">Appwrite</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="opensslKeyV1">Encryption Key</label>
|
||||
<CopyPasswordField
|
||||
name="opensslKeyV1"
|
||||
id="opensslKeyV1"
|
||||
isPasswordField
|
||||
value={service.appwrite.opensslKeyV1}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="executorSecret">Executor Secret</label>
|
||||
<CopyPasswordField
|
||||
name="executorSecret"
|
||||
id="executorSecret"
|
||||
isPasswordField
|
||||
value={service.appwrite.executorSecret}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- <div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">Redis</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="redisPassword">Password</label>
|
||||
<CopyPasswordField
|
||||
name="redisPassword"
|
||||
id="redisPassword"
|
||||
isPasswordField
|
||||
value={service.appwrite.redisPassword}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div> -->
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">MariaDB</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbHost">MariaDB Host</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbHost"
|
||||
id="mariadbHost"
|
||||
value={service.appwrite.mariadbHost}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbPort">MariaDB Port</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbPort"
|
||||
id="mariadbPort"
|
||||
value={service.appwrite.mariadbPort}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div> -->
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbUser">{$t('forms.username')}</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbUser"
|
||||
id="mariadbUser"
|
||||
value={service.appwrite.mariadbUser}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbPassword">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="mariadbPassword"
|
||||
value={service.appwrite.mariadbPassword}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbRootUser">Root User</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbRootUser"
|
||||
id="mariadbRootUser"
|
||||
value={service.appwrite.mariadbRootUser}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbRootUserPassword">Root Password</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbRootUserPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="mariadbRootUserPassword"
|
||||
value={service.appwrite.mariadbRootUserPassword}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbDatabase">{$t('index.database')}</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbDatabase"
|
||||
id="mariadbDatabase"
|
||||
value={service.appwrite.mariadbDatabase}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
@@ -26,6 +26,7 @@
|
||||
import Umami from './_Umami.svelte';
|
||||
import VsCodeServer from './_VSCodeServer.svelte';
|
||||
import Wordpress from './_Wordpress.svelte';
|
||||
import Appwrite from './_Appwrite.svelte';
|
||||
import Moodle from './_Moodle.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
@@ -37,7 +38,7 @@
|
||||
save: false,
|
||||
verification: false,
|
||||
cleanup: false
|
||||
}
|
||||
};
|
||||
let dualCerts = service.dualCerts;
|
||||
|
||||
let nonWWWDomain = service.fqdn && getDomain(service.fqdn).replace(/^www\./, '');
|
||||
@@ -321,13 +322,13 @@
|
||||
<div class="flex-col space-y-2 pt-4 text-center">
|
||||
{#if isNonWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
class="btn btn-sm bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
class="btn btn-sm bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
@@ -335,13 +336,13 @@
|
||||
{#if dualCerts}
|
||||
{#if isWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
class="btn btn-sm bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
class="btn btn-sm bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
@@ -394,6 +395,8 @@
|
||||
<Hasura bind:service />
|
||||
{:else if service.type === 'fider'}
|
||||
<Fider bind:service {readOnly} />
|
||||
{:else if service.type === 'appwrite'}
|
||||
<Appwrite bind:service {readOnly} />
|
||||
{:else if service.type === 'moodle'}
|
||||
<Moodle bind:service {readOnly} />
|
||||
{/if}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
function generateUrl(publicPort: any) {
|
||||
return browser
|
||||
? `sftp://${
|
||||
settings.fqdn ? getDomain(settings.fqdn) : window.location.hostname
|
||||
settings?.fqdn ? getDomain(settings.fqdn) : window.location.hostname
|
||||
}:${publicPort}`
|
||||
: 'Loading...';
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@
|
||||
loading = true;
|
||||
try {
|
||||
await post(`/services/${service.id}/${service.type}/start`, {});
|
||||
return window.location.reload();
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
|
||||
@@ -32,10 +32,16 @@
|
||||
import { get, post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
|
||||
onMount(async () => {
|
||||
if (destinations.length === 1) {
|
||||
await handleSubmit(destinations[0].id);
|
||||
}
|
||||
});
|
||||
async function handleSubmit(destinationId: any) {
|
||||
try {
|
||||
await post(`/services/${id}/configuration/destination`, { destinationId });
|
||||
@@ -54,7 +60,9 @@
|
||||
<div class="flex justify-center">
|
||||
{#if !destinations || destinations.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2 text-center font-bold">{$t('application.configuration.no_configurable_destination')}</div>
|
||||
<div class="pb-2 text-center font-bold">
|
||||
{$t('application.configuration.no_configurable_destination')}
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
|
||||
<svg
|
||||
|
||||
@@ -32,13 +32,20 @@
|
||||
import { get, post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import { errorNotification, supportedServiceTypesAndVersions } from '$lib/common';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
|
||||
let recommendedVersion = supportedServiceTypesAndVersions.find(
|
||||
({ name }) => name === type
|
||||
)?.recommendedVersion;
|
||||
|
||||
onMount(async () => {
|
||||
if (versions.length === 1) {
|
||||
await handleSubmit(versions[0]);
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit(version: any) {
|
||||
try {
|
||||
await post(`/services/${id}/configuration/version`, { version });
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
{#each otherServices as service}
|
||||
<a href="/services/{service.id}" class="p-2 no-underline">
|
||||
<div class="box-selection group relative hover:bg-pink-600">
|
||||
<Services type={service.type} />
|
||||
<ServiceIcons type={service.type} />
|
||||
<div class="truncate text-center text-xl font-bold">
|
||||
{service.name}
|
||||
</div>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
let dualCerts = settings.dualCerts;
|
||||
let isAutoUpdateEnabled = settings.isAutoUpdateEnabled;
|
||||
let isDNSCheckEnabled = settings.isDNSCheckEnabled;
|
||||
|
||||
let DNSServers = settings.DNSServers;
|
||||
let minPort = settings.minPort;
|
||||
let maxPort = settings.maxPort;
|
||||
|
||||
@@ -105,6 +105,10 @@
|
||||
settings.minPort = minPort;
|
||||
settings.maxPort = maxPort;
|
||||
}
|
||||
if (DNSServers !== settings.DNSServers) {
|
||||
await post(`/settings`, { DNSServers });
|
||||
settings.DNSServers = DNSServers;
|
||||
}
|
||||
forceSave = false;
|
||||
return addToast({
|
||||
message: 'Configuration saved.',
|
||||
@@ -275,6 +279,17 @@
|
||||
on:click={() => changeSettings('isDNSCheckEnabled')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="flex-col">
|
||||
<div class="pt-2 text-base font-bold text-stone-100">
|
||||
Custom DNS servers
|
||||
</div>
|
||||
<Explainer text="You can specify a custom DNS server to verify your domains all over Coolify.<br><br>By default, the OS defined DNS servers are used." />
|
||||
</div>
|
||||
<div class="mx-auto flex-row items-center justify-center space-y-2">
|
||||
<input placeholder="1.1.1.1,8.8.8.8" bind:value={DNSServers} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
dataTooltip={$t('setting.must_remove_domain_before_changing')}
|
||||
|
||||
@@ -46,7 +46,7 @@ textarea {
|
||||
}
|
||||
|
||||
#svelte .custom-select-wrapper .selectContainer {
|
||||
@apply h-12 w-96 rounded border-none bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm;
|
||||
@apply h-12 w-96 rounded border border-coolgray-300 border-dashed bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm;
|
||||
}
|
||||
|
||||
#svelte .listContainer {
|
||||
|
||||
3
csb.nix
3
csb.nix
@@ -1,9 +1,10 @@
|
||||
with import <nixpkgs> {};
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "git";
|
||||
name = "environment";
|
||||
buildInputs = [
|
||||
git
|
||||
git-lfs
|
||||
docker-compose
|
||||
];
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "coolify",
|
||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||
"version": "3.3.2",
|
||||
"version": "3.5.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": "github:coollabsio/coolify",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user