chore(template): resolve conflicts with main

This commit is contained in:
Tam Nguyen
2025-02-03 11:54:09 +11:00
95 changed files with 15410 additions and 787 deletions
@@ -0,0 +1,14 @@
version: '3.3'
services:
alist:
image: xhofe/alist:v3.41.0
volumes:
- alist-data:/opt/alist/data
environment:
- PUID=0
- PGID=0
- UMASK=022
restart: unless-stopped
volumes:
alist-data:
+22
View File
@@ -0,0 +1,22 @@
import {
type DomainSchema,
type Schema,
type Template,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 5244,
serviceName: "alist",
},
];
return {
domains,
};
}
@@ -0,0 +1,31 @@
services:
answer:
image: apache/answer:1.4.1
ports:
- '80'
restart: on-failure
volumes:
- answer-data:/data
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
networks:
- dokploy-network
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: answer
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
answer-data:
db-data:
+33
View File
@@ -0,0 +1,33 @@
import {
type DomainSchema,
type Schema,
type Template,
generateHash,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const mainDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 9080,
serviceName: "answer",
},
];
const envs = [
`ANSWER_HOST=http://${mainDomain}`,
`SERVICE_HASH=${mainServiceHash}`,
];
const mounts: Template["mounts"] = [];
return {
envs,
mounts,
domains,
};
}
@@ -0,0 +1,346 @@
x-custom-image: &custom_image
image: ${IMAGE_NAME:-docker.io/frappe/erpnext}:${VERSION:-version-15}
pull_policy: ${PULL_POLICY:-always}
deploy:
restart_policy:
condition: always
services:
backend:
<<: *custom_image
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
- wait-for-it
- '0.0.0.0:8000'
interval: 2s
timeout: 10s
retries: 30
frontend:
<<: *custom_image
command:
- nginx-entrypoint.sh
depends_on:
backend:
condition: service_started
required: true
websocket:
condition: service_started
required: true
environment:
BACKEND: backend:8000
FRAPPE_SITE_NAME_HEADER: ${FRAPPE_SITE_NAME_HEADER:-$$host}
SOCKETIO: websocket:9000
UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
UPSTREAM_REAL_IP_HEADER: X-Forwarded-For
UPSTREAM_REAL_IP_RECURSIVE: "off"
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
- wait-for-it
- '0.0.0.0:8080'
interval: 2s
timeout: 30s
retries: 30
queue-default:
<<: *custom_image
command:
- bench
- worker
- --queue
- default
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
- wait-for-it
- 'redis-queue:6379'
interval: 2s
timeout: 10s
retries: 30
depends_on:
configurator:
condition: service_completed_successfully
required: true
queue-long:
<<: *custom_image
command:
- bench
- worker
- --queue
- long
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
- wait-for-it
- 'redis-queue:6379'
interval: 2s
timeout: 10s
retries: 30
depends_on:
configurator:
condition: service_completed_successfully
required: true
queue-short:
<<: *custom_image
command:
- bench
- worker
- --queue
- short
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
- wait-for-it
- 'redis-queue:6379'
interval: 2s
timeout: 10s
retries: 30
depends_on:
configurator:
condition: service_completed_successfully
required: true
scheduler:
<<: *custom_image
healthcheck:
test:
- CMD
- wait-for-it
- 'redis-queue:6379'
interval: 2s
timeout: 10s
retries: 30
command:
- bench
- schedule
depends_on:
configurator:
condition: service_completed_successfully
required: true
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
websocket:
<<: *custom_image
healthcheck:
test:
- CMD
- wait-for-it
- '0.0.0.0:9000'
interval: 2s
timeout: 10s
retries: 30
command:
- node
- /home/frappe/frappe-bench/apps/frappe/socketio.js
depends_on:
configurator:
condition: service_completed_successfully
required: true
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
configurator:
<<: *custom_image
deploy:
mode: replicated
replicas: ${CONFIGURE:-0}
restart_policy:
condition: none
entrypoint: ["bash", "-c"]
command:
- >
[[ $${REGENERATE_APPS_TXT} == "1" ]] && ls -1 apps > sites/apps.txt;
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && exit 0;
bench set-config -g db_host $$DB_HOST;
bench set-config -gp db_port $$DB_PORT;
bench set-config -g redis_cache "redis://$$REDIS_CACHE";
bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";
bench set-config -gp socketio_port $$SOCKETIO_PORT;
environment:
DB_HOST: db
DB_PORT: "3306"
REDIS_CACHE: redis-cache:6379
REDIS_QUEUE: redis-queue:6379
SOCKETIO_PORT: "9000"
REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}"
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
create-site:
<<: *custom_image
deploy:
mode: replicated
replicas: ${CREATE_SITE:-0}
restart_policy:
condition: none
entrypoint: ["bash", "-c"]
command:
- >
wait-for-it -t 120 db:3306;
wait-for-it -t 120 redis-cache:6379;
wait-for-it -t 120 redis-queue:6379;
export start=`date +%s`;
until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]];
do
echo "Waiting for sites/common_site_config.json to be created";
sleep 5;
if (( `date +%s`-start > 120 )); then
echo "could not find sites/common_site_config.json with required keys";
exit 1
fi
done;
echo "sites/common_site_config.json found";
[[ -d "sites/${SITE_NAME}" ]] && echo "${SITE_NAME} already exists" && exit 0;
bench new-site --mariadb-user-host-login-scope='%' --admin-password=$${ADMIN_PASSWORD} --db-root-username=root --db-root-password=$${DB_ROOT_PASSWORD} $${INSTALL_APP_ARGS} $${SITE_NAME};
volumes:
- sites:/home/frappe/frappe-bench/sites
environment:
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
SITE_NAME: ${SITE_NAME}
networks:
- bench-network
migration:
<<: *custom_image
deploy:
mode: replicated
replicas: ${MIGRATE:-0}
restart_policy:
condition: none
entrypoint: ["bash", "-c"]
command:
- >
curl -f http://${SITE_NAME}:8080/api/method/ping || echo "Site busy" && exit 0;
bench --site all set-config -p maintenance_mode 1;
bench --site all set-config -p pause_scheduler 1;
bench --site all migrate;
bench --site all set-config -p maintenance_mode 0;
bench --site all set-config -p pause_scheduler 0;
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
db:
image: mariadb:10.6
deploy:
restart_policy:
condition: always
healthcheck:
test: mysqladmin ping -h localhost --password=${DB_ROOT_PASSWORD}
interval: 1s
retries: 20
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
- --skip-innodb-read-only-compressed
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
volumes:
- db-data:/var/lib/mysql
networks:
- bench-network
redis-cache:
deploy:
restart_policy:
condition: always
image: redis:6.2-alpine
volumes:
- redis-cache-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
- redis-cli
- ping
interval: 5s
timeout: 5s
retries: 3
redis-queue:
deploy:
restart_policy:
condition: always
image: redis:6.2-alpine
volumes:
- redis-queue-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
- redis-cli
- ping
interval: 5s
timeout: 5s
retries: 3
redis-socketio:
deploy:
restart_policy:
condition: always
image: redis:6.2-alpine
volumes:
- redis-socketio-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
- redis-cli
- ping
interval: 5s
timeout: 5s
retries: 3
volumes:
db-data:
redis-cache-data:
redis-queue-data:
redis-socketio-data:
sites:
networks:
bench-network:
+37
View File
@@ -0,0 +1,37 @@
import {
type DomainSchema,
type Schema,
type Template,
generatePassword,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const dbRootPassword = generatePassword(32);
const adminPassword = generatePassword(32);
const mainDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 8080,
serviceName: "frontend",
},
];
const envs = [
`SITE_NAME=${mainDomain}`,
`ADMIN_PASSWORD=${adminPassword}`,
`DB_ROOT_PASSWORD=${dbRootPassword}`,
"MIGRATE=1",
"CREATE_SITE=1",
"CONFIGURE=1",
"REGENERATE_APPS_TXT=1",
"INSTALL_APP_ARGS=--install-app erpnext",
"IMAGE_NAME=docker.io/frappe/erpnext",
"VERSION=version-15",
"FRAPPE_SITE_NAME_HEADER=",
];
return { envs, domains };
}
@@ -0,0 +1,8 @@
services:
glance:
image: glanceapp/glance
volumes:
- ../files/app/glance.yml:/app/glance.yml
ports:
- 8080
restart: unless-stopped
+108
View File
@@ -0,0 +1,108 @@
import {
type DomainSchema,
type Schema,
type Template,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 8080,
serviceName: "glance",
},
];
const mounts: Template["mounts"] = [
{
filePath: "/app/glance.yml",
content: `
branding:
hide-footer: true
logo-text: P
pages:
- name: Home
columns:
- size: small
widgets:
- type: calendar
- type: releases
show-source-icon: true
repositories:
- Dokploy/dokploy
- n8n-io/n8n
- Budibase/budibase
- home-assistant/core
- tidbyt/pixlet
- type: twitch-channels
channels:
- nmplol
- extraemily
- qtcinderella
- ludwig
- timthetatman
- mizkif
- size: full
widgets:
- type: hacker-news
- type: videos
style: grid-cards
channels:
- UC3GzdWYwUYI1ACxuP9Nm-eg
- UCGbg3DjQdcqWwqOLHpYHXIg
- UC24RSoLcjiNZbQcT54j5l7Q
limit: 3
- type: rss
limit: 10
collapse-after: 3
cache: 3h
feeds:
- url: https://daringfireball.net/feeds/main
title: Daring Fireball
- size: small
widgets:
- type: weather
location: Gansevoort, New York, United States
show-area-name: false
units: imperial
hour-format: 12h
- type: markets
markets:
- symbol: SPY
name: S&P 500
- symbol: VOO
name: Vanguard
- symbol: BTC-USD
name: Bitcoin
- symbol: ETH-USD
name: Etherium
- symbol: NVDA
name: NVIDIA
- symbol: AAPL
name: Apple
- symbol: MSFT
name: Microsoft
- symbol: GOOGL
name: Google
- symbol: AMD
name: AMD
- symbol: TSLA
name: Tesla`,
},
];
return {
domains,
mounts,
};
}
@@ -0,0 +1,11 @@
services:
homarr:
image: ghcr.io/homarr-labs/homarr:latest
restart: unless-stopped
volumes:
# - /var/run/docker.sock:/var/run/docker.sock # Optional, only if you want docker integration
- ../homarr/appdata:/appdata
environment:
- SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
ports:
- 7575
+27
View File
@@ -0,0 +1,27 @@
import {
type DomainSchema,
type Schema,
type Template,
generatePassword,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
const secretKey = generatePassword(64);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 7575,
serviceName: "homarr",
},
];
const envs = [`SECRET_ENCRYPTION_KEY=${secretKey}`];
return {
domains,
envs,
};
}
@@ -0,0 +1,37 @@
services:
app:
image: ghcr.io/maybe-finance/maybe:sha-68c570eed8810fd59b5b33cca51bbad5eabb4cb4
restart: unless-stopped
volumes:
- ../files/uploads:/app/uploads
environment:
DATABASE_URL: postgresql://maybe:maybe@db:5432/maybe
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
SELF_HOSTED: true
SYNTH_API_KEY: ${SYNTH_API_KEY}
RAILS_FORCE_SSL: "false"
RAILS_ASSUME_SSL: "false"
GOOD_JOB_EXECUTION_MODE: async
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
networks:
- dokploy-network
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: maybe
POSTGRES_USER: maybe
POSTGRES_PASSWORD: maybe
volumes:
db-data:
+43
View File
@@ -0,0 +1,43 @@
import {
type DomainSchema,
type Schema,
type Template,
generateBase64,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
const secretKeyBase = generateBase64(64);
const synthApiKey = generateBase64(32);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 3000,
serviceName: "app",
},
];
const envs = [
`SECRET_KEY_BASE=${secretKeyBase}`,
"SELF_HOSTED=true",
`SYNTH_API_KEY=${synthApiKey}`,
"RAILS_FORCE_SSL=false",
"RAILS_ASSUME_SSL=false",
"GOOD_JOB_EXECUTION_MODE=async",
];
const mounts: Template["mounts"] = [
{
filePath: "./uploads",
content: "This is where user uploads will be stored",
},
];
return {
envs,
mounts,
domains,
};
}
@@ -0,0 +1,29 @@
services:
shlink:
image: shlinkio/shlink:stable
environment:
- INITIAL_API_KEY=${INITIAL_API_KEY}
- DEFAULT_DOMAIN=${DEFAULT_DOMAIN}
# Note: you should also update SHLINK_SERVER_URL in the shlink-web service.
- IS_HTTPS_ENABLED=false
volumes:
- shlink-data:/etc/shlink/data
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/rest/v3/health"]
interval: 30s
timeout: 10s
retries: 3
shlink-web:
image: shlinkio/shlink-web-client
environment:
- SHLINK_SERVER_API_KEY=${INITIAL_API_KEY}
# Note: if you've set IS_HTTPS_ENABLED=true, change http to https.
- SHLINK_SERVER_URL=http://${DEFAULT_DOMAIN}
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
interval: 30s
timeout: 10s
retries: 3
volumes:
shlink-data:
+35
View File
@@ -0,0 +1,35 @@
import {
type DomainSchema,
type Schema,
type Template,
generatePassword,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const defaultDomain = generateRandomDomain(schema);
const initialApiKey = generatePassword(30);
const domains: DomainSchema[] = [
{
host: `web-${defaultDomain}`,
port: 8080,
serviceName: "shlink-web",
},
{
host: defaultDomain,
port: 8080,
serviceName: "shlink",
},
];
const envs = [
`INITIAL_API_KEY=${initialApiKey}`,
`DEFAULT_DOMAIN=${defaultDomain}`,
];
return {
envs,
domains,
};
}
@@ -0,0 +1,9 @@
services:
server:
image: ghcr.io/spacedriveapp/spacedrive/server:latest
ports:
- 8080
environment:
- SD_AUTH=${SD_USERNAME}:${SD_PASSWORD}
volumes:
- /var/spacedrive:/var/spacedrive
@@ -0,0 +1,28 @@
import {
type DomainSchema,
type Schema,
type Template,
generatePassword,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const randomDomain = generateRandomDomain(schema);
const secretKey = generatePassword();
const randomUsername = "admin"; // Default username
const domains: DomainSchema[] = [
{
host: randomDomain,
port: 8080,
serviceName: "server",
},
];
const envs = [`SD_USERNAME=${randomUsername}`, `SD_PASSWORD=${secretKey}`];
return {
envs,
domains,
};
}
@@ -13,8 +13,11 @@ services:
image: amancevice/superset
restart: always
depends_on:
- db
- redis
- superset_postgres
- superset_redis
volumes:
# This superset_config.py can be edited in Dokploy's UI Advanced -> Volume Mount
- ../files/superset/superset_config.py:/etc/superset/superset_config.py
environment:
SECRET_KEY: ${SECRET_KEY}
MAPBOX_API_KEY: ${MAPBOX_API_KEY}
@@ -22,11 +25,11 @@ services:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
REDIS_PASSWORD: ${REDIS_PASSWORD}
volumes:
# Note: superset_config.py can be edited in Dokploy's UI Volume Mount
- ../files/superset/superset_config.py:/etc/superset/superset_config.py
# Ensure the hosts matches your service names below.
POSTGRES_HOST: superset_postgres
REDIS_HOST: superset_redis
db:
superset_postgres:
image: postgres
restart: always
environment:
@@ -34,7 +37,7 @@ services:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres:/var/lib/postgresql/data
- superset_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 30s
@@ -43,11 +46,11 @@ services:
networks:
- dokploy-network
redis:
superset_redis:
image: redis
restart: always
volumes:
- redis:/data
- superset_redis_data:/data
command: redis-server --requirepass ${REDIS_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
@@ -58,5 +61,5 @@ services:
- dokploy-network
volumes:
postgres:
redis:
superset_postgres_data:
superset_redis_data:
+3 -2
View File
@@ -52,14 +52,15 @@ CACHE_CONFIG = {
"CACHE_REDIS_HOST": "redis",
"CACHE_REDIS_PORT": 6379,
"CACHE_REDIS_DB": 1,
"CACHE_REDIS_URL": f"redis://:{os.getenv('REDIS_PASSWORD')}@redis:6379/1",
"CACHE_REDIS_URL": f"redis://:{os.getenv('REDIS_PASSWORD')}@{os.getenv('REDIS_HOST')}:6379/1",
}
FILTER_STATE_CACHE_CONFIG = {**CACHE_CONFIG, "CACHE_KEY_PREFIX": "superset_filter_"}
EXPLORE_FORM_DATA_CACHE_CONFIG = {**CACHE_CONFIG, "CACHE_KEY_PREFIX": "superset_explore_form_"}
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{os.getenv('POSTGRES_USER')}:{os.getenv('POSTGRES_PASSWORD')}@db:5432/{os.getenv('POSTGRES_DB')}"
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{os.getenv('POSTGRES_USER')}:{os.getenv('POSTGRES_PASSWORD')}@{os.getenv('POSTGRES_HOST')}:5432/{os.getenv('POSTGRES_DB')}"
# Uncomment if you want to load example data (using "superset load_examples") at the
# same location as your metadata postgresql instance. Otherwise, the default sqlite
# will be used, which will not persist in volume when restarting superset by default.
+134 -8
View File
@@ -538,7 +538,7 @@ export const templates: TemplateData[] = [
website: "https://filebrowser.org/",
docs: "https://filebrowser.org/",
},
tags: ["file", "manager"],
tags: ["file-manager", "storage"],
load: () => import("./filebrowser/index").then((m) => m.generate),
},
{
@@ -834,7 +834,7 @@ export const templates: TemplateData[] = [
website: "https://nextcloud.com/",
docs: "https://docs.nextcloud.com/",
},
tags: ["file", "sync"],
tags: ["file-manager", "sync"],
load: () => import("./nextcloud-aio/index").then((m) => m.generate),
},
{
@@ -1074,7 +1074,7 @@ export const templates: TemplateData[] = [
website: "https://penpot.app/",
docs: "https://docs.penpot.app/",
},
tags: ["desing", "collaboration"],
tags: ["design", "collaboration"],
load: () => import("./penpot/index").then((m) => m.generate),
},
{
@@ -1097,7 +1097,7 @@ export const templates: TemplateData[] = [
name: "Unsend",
version: "v1.2.4",
description: "Open source alternative to Resend,Sendgrid, Postmark etc. ",
logo: "unsend.png", // we defined the name and the extension of the logo
logo: "unsend.png",
links: {
github: "https://github.com/unsend-dev/unsend",
website: "https://unsend.dev/",
@@ -1276,11 +1276,11 @@ export const templates: TemplateData[] = [
version: "latest",
description:
"CouchDB is a document-oriented NoSQL database that excels at replication and horizontal scaling.",
logo: "couchdb.png", // we defined the name and the extension of the logo
logo: "couchdb.png",
links: {
github: "lorem",
website: "lorem",
docs: "lorem",
github: "https://github.com/apache/couchdb",
website: "https://couchdb.apache.org/",
docs: "https://docs.couchdb.org/en/stable/",
},
tags: ["database", "storage"],
load: () => import("./couchdb/index").then((m) => m.generate),
@@ -1312,4 +1312,130 @@ export const templates: TemplateData[] = [
tags: ["analytics", "bi", "dashboard", "database", "sql"],
load: () => import("./superset/index").then((m) => m.generate),
},
{
id: "glance",
name: "Glance",
version: "latest",
description:
"A self-hosted dashboard that puts all your feeds in one place. Features RSS feeds, weather, bookmarks, site monitoring, and more in a minimal, fast interface.",
logo: "glance.png",
links: {
github: "https://github.com/glanceapp/glance",
docs: "https://github.com/glanceapp/glance/blob/main/docs/configuration.md",
},
tags: ["dashboard", "monitoring", "widgets", "rss"],
load: () => import("./glance/index").then((m) => m.generate),
},
{
id: "homarr",
name: "Homarr",
version: "latest",
description:
"A sleek, modern dashboard that puts all your apps and services in one place with Docker integration.",
logo: "homarr.png",
links: {
github: "https://github.com/homarr-labs/homarr",
docs: "https://homarr.dev/docs/getting-started/installation/docker",
website: "https://homarr.dev/",
},
tags: ["dashboard", "monitoring"],
load: () => import("./homarr/index").then((m) => m.generate),
},
{
id: "erpnext",
name: "ERPNext",
version: "version-15",
description: "100% Open Source and highly customizable ERP software.",
logo: "erpnext.svg",
links: {
github: "https://github.com/frappe/erpnext",
docs: "https://docs.frappe.io/erpnext",
website: "https://erpnext.com",
},
tags: [
"erp",
"accounts",
"manufacturing",
"retail",
"sales",
"pos",
"hrms",
],
load: () => import("./erpnext/index").then((m) => m.generate),
},
{
id: "maybe",
name: "Maybe",
version: "latest",
description:
"Maybe is a self-hosted finance tracking application designed to simplify budgeting and expenses.",
logo: "maybe.svg",
links: {
github: "https://github.com/maybe-finance/maybe",
website: "https://maybe.finance/",
docs: "https://docs.maybe.finance/",
},
tags: ["finance", "self-hosted"],
load: () => import("./maybe/index").then((m) => m.generate),
},
{
id: "spacedrive",
name: "Spacedrive",
version: "latest",
description:
"Spacedrive is a cross-platform file manager. It connects your devices together to help you organize files from anywhere. powered by a virtual distributed filesystem (VDFS) written in Rust. Organize files across many devices in one place.",
links: {
github: "https://github.com/spacedriveapp/spacedrive",
website: "https://spacedrive.com/",
docs: "https://www.spacedrive.com/docs/product/getting-started/introduction",
},
logo: "spacedrive.png",
tags: ["file-manager", "vdfs", "storage"],
load: () => import("./spacedrive/index").then((m) => m.generate),
},
{
id: "alist",
name: "AList",
version: "v3.41.0",
description:
"🗂️A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs.",
logo: "alist.svg",
links: {
github: "https://github.com/AlistGo/alist",
website: "https://alist.nn.ci",
docs: "https://alist.nn.ci/guide/install/docker.html",
},
tags: ["file", "webdav", "storage"],
load: () => import("./alist/index").then((m) => m.generate),
},
{
id: "answer",
name: "Answer",
version: "v1.4.1",
description:
"Answer is an open-source Q&A platform for building a self-hosted question-and-answer service.",
logo: "answer.png",
links: {
github: "https://github.com/apache/answer",
website: "https://answer.apache.org/",
docs: "https://answer.apache.org/docs",
},
tags: ["q&a", "self-hosted"],
load: () => import("./answer/index").then((m) => m.generate),
},
{
id: "shlink",
name: "Shlink",
version: "stable",
description:
"URL shortener that can be used to serve shortened URLs under your own domain.",
logo: "shlink.svg",
links: {
github: "https://github.com/shlinkio/shlink",
website: "https://shlink.io",
docs: "https://shlink.io/documentation",
},
tags: ["sharing", "shortener", "url"],
load: () => import("./shlink/index").then((m) => m.generate),
},
];