├── cockpit ├── .gitignore ├── docker-compose.yml └── Readme.md ├── daptin ├── .gitignore ├── Readme.md └── docker-compose.yml ├── strapi ├── .gitignore ├── Readme.md └── docker-compose.yml ├── strapi-hasura ├── .gitignore ├── Readme.md ├── Dockerfile ├── docker-compose.yml └── wait-for.sh ├── directus-chameleon-hasura ├── .gitignore ├── chameleon │ ├── Dockerfile │ └── wait-for.sh ├── chameleon-conf │ └── configuration │ │ └── default.yml ├── Readme.md └── docker-compose.yml ├── prime ├── .gitignore ├── prime-docker │ ├── index.js │ ├── Dockerfile │ ├── package.json │ └── newrelic.js ├── Readme.md └── docker-compose.yml ├── canner ├── docker-compose.yml ├── generated │ ├── .dockerignore │ ├── .gitignore │ ├── package.json │ ├── components │ │ └── layout │ │ │ └── body.js │ ├── Dockerfile │ ├── canner.schema.js │ ├── schema │ │ ├── categories.schema.js │ │ └── posts.schema.js │ ├── canner.cloud.js │ └── canner.server.js └── Readme.md ├── quokka ├── docker-compose.yml └── Readme.md ├── directus ├── README.md └── docker-compose.yml └── Readme.md /cockpit/.gitignore: -------------------------------------------------------------------------------- 1 | db -------------------------------------------------------------------------------- /daptin/.gitignore: -------------------------------------------------------------------------------- 1 | db -------------------------------------------------------------------------------- /strapi/.gitignore: -------------------------------------------------------------------------------- 1 | db -------------------------------------------------------------------------------- /strapi-hasura/.gitignore: -------------------------------------------------------------------------------- 1 | db -------------------------------------------------------------------------------- /directus-chameleon-hasura/.gitignore: -------------------------------------------------------------------------------- 1 | db -------------------------------------------------------------------------------- /prime/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | *.log 4 | db -------------------------------------------------------------------------------- /daptin/Readme.md: -------------------------------------------------------------------------------- 1 | # Daptin 2 | 3 | ```sh 4 | docker-compose up 5 | ``` 6 | 7 | Open http://localhost:8080/ 8 | -------------------------------------------------------------------------------- /canner/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | web: 5 | build: ./generated 6 | ports: 7 | - "3000:3000" 8 | -------------------------------------------------------------------------------- /quokka/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | app: 5 | image: quokka/quokka 6 | ports: 7 | - "5000:5000" 8 | -------------------------------------------------------------------------------- /canner/generated/.dockerignore: -------------------------------------------------------------------------------- 1 | .cms 2 | node_modules 3 | canner.schema.json 4 | Dockerfile 5 | .dockerignore 6 | .DS_Store 7 | .git 8 | .gitignore 9 | -------------------------------------------------------------------------------- /quokka/Readme.md: -------------------------------------------------------------------------------- 1 | # Quokka 2 | 3 | ```sh 4 | docker-compose up 5 | ``` 6 | 7 | Open http://localhost:5000/admin/ 8 | 9 | ``` 10 | username: admin 11 | password: admin 12 | ``` -------------------------------------------------------------------------------- /strapi-hasura/Readme.md: -------------------------------------------------------------------------------- 1 | # Strapi 2 | 3 | ``` 4 | docker-compose up 5 | ``` 6 | 7 | Go to http://localhost:1337/admin/. Register. 8 | 9 | GraphQL http://localhost:8080/ 10 | -------------------------------------------------------------------------------- /canner/generated/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | 4 | # Canner generated files 5 | .cms 6 | canner.schema.json 7 | 8 | # Error files 9 | npm-debug.log 10 | yarn-error.log 11 | -------------------------------------------------------------------------------- /strapi-hasura/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hasura/graphql-engine 2 | 3 | COPY wait-for.sh /bin 4 | 5 | ENV CONNECTION db:5432 6 | 7 | ENTRYPOINT sh -c '/bin/wait-for.sh $CONNECTION -- graphql-engine serve' 8 | -------------------------------------------------------------------------------- /prime/prime-docker/index.js: -------------------------------------------------------------------------------- 1 | if (process.env.NEW_RELIC_LICENSE_KEY) { 2 | require('newrelic'); 3 | } 4 | 5 | if (process.env.SENTRY_DSN) { 6 | require('@sentry/node').init({ dsn: process.env.SENTRY_DSN }); 7 | } 8 | 9 | require('@primecms/core'); 10 | -------------------------------------------------------------------------------- /canner/generated/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "canner-project", 3 | "version": "1.0.0", 4 | "description": "canner project", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "", 9 | "license": "ISC" 10 | } 11 | -------------------------------------------------------------------------------- /cockpit/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | web: 5 | image: agentejo/cockpit 6 | ports: 7 | - "8080:80" 8 | restart: always 9 | # volumes: 10 | # - ./db/storage/:/var/www/html/storage 11 | # - ./db/config/:/var/www/html/config 12 | -------------------------------------------------------------------------------- /prime/Readme.md: -------------------------------------------------------------------------------- 1 | # Prime CMS 2 | 3 | Copied from https://github.com/primecms/heroku 4 | 5 | TODO: change to official Dockerfile as soon as it will be published. 6 | 7 | link: https://docs.primecms.app/#/ 8 | version: 0.3.4-beta.0 9 | 10 | ```sh 11 | docker-compose up 12 | ``` 13 | 14 | Open http://localhost:4000/ 15 | -------------------------------------------------------------------------------- /canner/Readme.md: -------------------------------------------------------------------------------- 1 | # Canner 2 | 3 | ```sh 4 | docker-compose up 5 | ``` 6 | 7 | Open http://localhost:3000/ 8 | 9 | ``` 10 | username: canner 11 | password: canner 12 | ``` 13 | 14 | ## Dockerfile 15 | 16 | Dockerfile and other files generated with 17 | 18 | ```sh 19 | npm i -g @canner/cli 20 | canner init 21 | ``` 22 | -------------------------------------------------------------------------------- /canner/generated/components/layout/body.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Item} from 'canner-helpers'; 3 | import {Card} from 'antd'; 4 | 5 | export default function Body() { 6 | return ( 7 |
10 | 11 | 12 | 13 |
14 | ) 15 | } -------------------------------------------------------------------------------- /prime/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres 6 | restart: always 7 | environment: 8 | POSTGRES_PASSWORD: password 9 | volumes: 10 | - ./db/data/:/var/lib/postgresql/data 11 | ports: 12 | - "5432:5432" 13 | app: 14 | build: ./prime-docker 15 | ports: 16 | - "4000:4000" 17 | -------------------------------------------------------------------------------- /canner/generated/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM canner/builder:latest AS build 2 | WORKDIR /usr/src/app 3 | COPY . . 4 | RUN canner build -s canner.schema.js -c canner.server.js 5 | 6 | # Run 7 | FROM canner/server:latest 8 | WORKDIR /usr/src/app 9 | COPY --from=build /usr/src/app /usr/src/app 10 | 11 | EXPOSE 3000 12 | ENTRYPOINT ["canner-server"] 13 | CMD [ "-c", "canner.server.js" ] 14 | -------------------------------------------------------------------------------- /strapi/Readme.md: -------------------------------------------------------------------------------- 1 | # Strapi 2 | 3 | ``` 4 | docker-compose up 5 | ``` 6 | 7 | Go to http://localhost:1337/admin/. Register. 8 | 9 | Go to http://localhost:1337/admin/marketplace. Install GraphQL plugin. 10 | 11 | Add content type. 12 | 13 | Edit permissions http://localhost:1337/admin/plugins/users-permissions/roles/edit/3 14 | 15 | Your API is ready http://localhost:1337/graphql 16 | -------------------------------------------------------------------------------- /cockpit/Readme.md: -------------------------------------------------------------------------------- 1 | # Cockpit 2 | 3 | ```sh 4 | docker-compose up 5 | ``` 6 | 7 | Open http://localhost:8080/install/ 8 | 9 | With `volumes` config get following error 10 | 11 | ``` 12 | Data folder is not writable: /storage/data 13 | Cache folder is not writable: /storage/cache 14 | Temp folder is not writable: /storage/tmp 15 | Uploads folder is not writable: /storage/uploads 16 | ``` 17 | -------------------------------------------------------------------------------- /directus/README.md: -------------------------------------------------------------------------------- 1 | # Directus 2 | 3 | Copied from https://github.com/directus/docker/tree/master/examples/single-api 4 | 5 | ```sh 6 | docker-compose up 7 | ``` 8 | 9 | Open http://localhost:8000/ 10 | 11 | ``` 12 | login: admin@localhost.com 13 | password: directusrocks 14 | ``` 15 | 16 | Myabe would be possible to use with Hasura/Postgraphile with the help of [mysql_fdw](https://github.com/EnterpriseDB/mysql_fdw). 17 | -------------------------------------------------------------------------------- /prime/prime-docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine 2 | 3 | WORKDIR app 4 | 5 | COPY index.js newrelic.js package.json yarn.lock ./ 6 | 7 | RUN yarn 8 | 9 | ENTRYPOINT yarn start 10 | 11 | EXPOSE 4000 12 | 13 | ENV PORT=4000 14 | ENV DATABASE_URL=postgresql://postgres:password@db:5432/postgres 15 | ENV SESSION_SECRET=keyboard-cat-dart 16 | 17 | LABEL version="0.3.4-beta.0" 18 | LABEL maintainer="Birkir Gudjonsson " 19 | -------------------------------------------------------------------------------- /directus-chameleon-hasura/chameleon/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-alpine 2 | 3 | RUN \ 4 | apk add --no-cache postgresql-libs && \ 5 | apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev && \ 6 | pip install pg_chameleon --no-cache-dir && \ 7 | apk --purge del .build-deps && \ 8 | chameleon set_configuration_files 9 | 10 | COPY wait-for.sh /bin 11 | VOLUME /root/.pg_chameleon 12 | 13 | ENTRYPOINT sh -c '/bin/wait-for.sh db:3306 -- /bin/wait-for.sh pg:5432 -- chameleon init_replica --config default --source mysql --debug' -------------------------------------------------------------------------------- /daptin/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres 6 | restart: always 7 | environment: 8 | POSTGRES_PASSWORD: password 9 | volumes: 10 | - ./db/data/:/var/lib/postgresql/data 11 | ports: 12 | - "5432:5432" 13 | web: 14 | image: daptin/daptin 15 | ports: 16 | - "8080:8080" 17 | restart: always 18 | environment: 19 | DAPTIN_PORT: "8080" 20 | DAPTIN_DB_TYPE: "postgres" 21 | DAPTIN_DB_CONNECTION_STRING: "host=db port=5432 user=postgres password=password dbname=postgres sslmode=disable" 22 | depends_on: 23 | - db 24 | -------------------------------------------------------------------------------- /canner/generated/canner.schema.js: -------------------------------------------------------------------------------- 1 | import CannerScript, {Body} from 'canner-script'; 2 | import Posts from './schema/posts.schema.js'; 3 | import Categories from './schema/categories.schema'; 4 | import BodyComponent from './components/layout/body'; 5 | import {ImgurStorage} from '@canner/storage'; 6 | 7 | export const imageStorage = new ImgurStorage({ 8 | clientId: 'a214c4836559c77' 9 | }); 10 | 11 | const schema = ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | 20 | export default schema; -------------------------------------------------------------------------------- /strapi/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres 6 | restart: always 7 | environment: 8 | POSTGRES_PASSWORD: password 9 | volumes: 10 | - ./db/data/:/var/lib/postgresql/data 11 | ports: 12 | - "5432:5432" 13 | strapi: 14 | image: strapi/strapi 15 | depends_on: 16 | - db 17 | ports: 18 | - 1337:1337 19 | environment: 20 | - APP_NAME=strapi-app 21 | - DATABASE_CLIENT=postgres 22 | - DATABASE_HOST=db 23 | - DATABASE_PORT=5432 24 | - DATABASE_USERNAME=postgres 25 | - DATABASE_PASSWORD=password 26 | - DATABASE_NAME=postgres 27 | volumes: 28 | - ./db/strapi-app/:/usr/src/api/strapi-app -------------------------------------------------------------------------------- /canner/generated/schema/categories.schema.js: -------------------------------------------------------------------------------- 1 | 2 | import CannerScript from 'canner-script'; 3 | 4 | export default ({attributes}) => ( 5 | 15 | 16 | 27 | 28 | ) -------------------------------------------------------------------------------- /prime/prime-docker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "primecms-heroku", 3 | "version": "0.3.4-beta.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/primecms/heroku.git" 13 | }, 14 | "author": "Birkir Gudjonsson ", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/primecms/heroku/issues" 18 | }, 19 | "homepage": "https://github.com/primecms/heroku", 20 | "dependencies": { 21 | "@primecms/core": "0.3.4-beta.0", 22 | "@primecms/ui": "0.3.4-beta.0", 23 | "@sentry/node": "5.0.7", 24 | "newrelic": "5.6.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /directus/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: mysql:5.7 6 | restart: always 7 | environment: 8 | MYSQL_DATABASE: "somedb" 9 | MYSQL_ROOT_PASSWORD: "rootpassword" 10 | MYSQL_USER: "someusername" 11 | MYSQL_PASSWORD: "somepassword" 12 | ports: 13 | - 3306:3306 14 | api: 15 | image: directus/api:latest 16 | environment: 17 | DATABASE_HOST: db 18 | DATABASE_NAME: "somedb" 19 | DATABASE_USERNAME: "someusername" 20 | DATABASE_PASSWORD: "somepassword" 21 | ADMIN_EMAIL: "admin@localhost.com" 22 | ADMIN_PASSWORD: "directusrocks" 23 | ports: 24 | - 7000:80 25 | web: 26 | image: directus/app:latest 27 | environment: 28 | API_ENDPOINT: "API; http://localhost:7000/_/" 29 | ports: 30 | - 8000:80 31 | -------------------------------------------------------------------------------- /strapi-hasura/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres 6 | restart: always 7 | environment: 8 | POSTGRES_PASSWORD: password 9 | volumes: 10 | - ./db/data/:/var/lib/postgresql/data 11 | ports: 12 | - "5432:5432" 13 | strapi: 14 | image: strapi/strapi 15 | depends_on: 16 | - db 17 | ports: 18 | - 1337:1337 19 | environment: 20 | - APP_NAME=strapi-app 21 | - DATABASE_CLIENT=postgres 22 | - DATABASE_HOST=db 23 | - DATABASE_PORT=5432 24 | - DATABASE_USERNAME=postgres 25 | - DATABASE_PASSWORD=password 26 | - DATABASE_NAME=postgres 27 | volumes: 28 | - ./db/strapi-app/:/usr/src/api/strapi-app 29 | hasura: 30 | build: ./ 31 | ports: 32 | - "8080:8080" 33 | environment: 34 | - HASURA_GRAPHQL_DATABASE_URL=postgresql://postgres:password@db:5432/postgres 35 | - HASURA_GRAPHQL_ENABLE_CONSOLE=true 36 | depends_on: 37 | - db 38 | -------------------------------------------------------------------------------- /directus-chameleon-hasura/chameleon-conf/configuration/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | #global settings 3 | pid_dir: "~/.pg_chameleon/pid/" 4 | log_dir: "~/.pg_chameleon/logs/" 5 | log_dest: file 6 | log_level: info 7 | log_days_keep: 10 8 | rollbar_key: "" 9 | rollbar_env: "" 10 | 11 | #postgres destination connection 12 | pg_conn: 13 | host: "pg" 14 | port: "5432" 15 | user: "postgres" 16 | password: "password" 17 | database: "postgres" 18 | charset: "utf8" 19 | 20 | sources: 21 | mysql: 22 | db_conn: 23 | host: "db" 24 | port: "3306" 25 | user: "someusername" 26 | password: "somepassword" 27 | charset: "utf8" 28 | connect_timeout: 10 29 | grant_select_to: 30 | - someusername 31 | lock_timeout: "120s" 32 | my_server_id: 100 33 | replica_batch_size: 10000 34 | replay_max_rows: 10000 35 | batch_retention: "1 day" 36 | copy_max_memory: "300M" 37 | copy_mode: "file" 38 | out_dir: /tmp 39 | sleep_loop: 1 40 | on_error_replay: continue 41 | on_error_read: continue 42 | auto_maintenance: "disabled" 43 | gtid_enable: No 44 | type: mysql 45 | -------------------------------------------------------------------------------- /directus-chameleon-hasura/Readme.md: -------------------------------------------------------------------------------- 1 | # Directus + Chameleon + Hasura 2 | 3 | Doesn't work :/ 4 | 5 | ``` 6 | /usr/local/lib/python3.7/site-packages/pg_chameleon/lib/global_lib.py:214: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details. 7 | self.config = yaml.load(config_file.read()) 8 | Traceback (most recent call last): 9 | File "/usr/local/bin/chameleon", line 5, in 10 | exec(compile(open(__file__).read(), __file__, 'exec')) 11 | File "/usr/local/bin/chameleon.py", line 56, in 12 | replica = replica_engine(args) 13 | File "/usr/local/lib/python3.7/site-packages/pg_chameleon/lib/global_lib.py", line 115, in __init__ 14 | self.pg_engine.type_override = self.config["type_override"] 15 | KeyError: 'type_override' 16 | Exception ignored in: 17 | Traceback (most recent call last): 18 | File "/usr/local/lib/python3.7/site-packages/pg_chameleon/lib/pg_lib.py", line 609, in __del__ 19 | self.disconnect_db() 20 | File "/usr/local/lib/python3.7/site-packages/pg_chameleon/lib/pg_lib.py", line 651, in disconnect_db 21 | if self.pgsql_cur: 22 | AttributeError: 'pg_engine' object has no attribute 'pgsql_cur' 23 | ``` -------------------------------------------------------------------------------- /directus-chameleon-hasura/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: mysql:5.7 6 | restart: always 7 | environment: 8 | MYSQL_DATABASE: "somedb" 9 | MYSQL_ROOT_PASSWORD: "rootpassword" 10 | MYSQL_USER: "someusername" 11 | MYSQL_PASSWORD: "somepassword" 12 | ports: 13 | - 3306:3306 14 | # api: 15 | # image: directus/api:latest 16 | # environment: 17 | # DATABASE_HOST: db 18 | # DATABASE_NAME: "somedb" 19 | # DATABASE_USERNAME: "someusername" 20 | # DATABASE_PASSWORD: "somepassword" 21 | # ADMIN_EMAIL: "admin@localhost.com" 22 | # ADMIN_PASSWORD: "directusrocks" 23 | # ports: 24 | # - 7000:80 25 | # web: 26 | # image: directus/app:latest 27 | # environment: 28 | # API_ENDPOINT: "API; http://localhost:7000/_/" 29 | # ports: 30 | # - 8000:80 31 | pg: 32 | image: postgres 33 | restart: always 34 | environment: 35 | POSTGRES_PASSWORD: password 36 | volumes: 37 | - ./db/data/:/var/lib/postgresql/data 38 | ports: 39 | - "5432:5432" 40 | chameleon: 41 | build: ./chameleon 42 | volumes: 43 | - ./chameleon-conf:/root/.pg_chameleon 44 | depends_on: 45 | - pg 46 | - db 47 | # hasura: 48 | # build: ./ 49 | # ports: 50 | # - "8080:8080" 51 | # environment: 52 | # - HASURA_GRAPHQL_DATABASE_URL=postgresql://postgres:password@pg:5432/postgres 53 | # - HASURA_GRAPHQL_ENABLE_CONSOLE=true 54 | # depends_on: 55 | # - pg -------------------------------------------------------------------------------- /strapi-hasura/wait-for.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TIMEOUT=60 4 | QUIET=0 5 | 6 | echoerr() { 7 | if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi 8 | } 9 | 10 | usage() { 11 | exitcode="$1" 12 | cat << USAGE >&2 13 | Usage: 14 | $cmdname host:port [-t timeout] [-- command args] 15 | -q | --quiet Do not output any status messages 16 | -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout 17 | -- COMMAND ARGS Execute command with args after the test finishes 18 | USAGE 19 | exit "$exitcode" 20 | } 21 | 22 | wait_for() { 23 | for i in `seq $TIMEOUT` ; do 24 | nc -z "$HOST" "$PORT" > /dev/null 2>&1 25 | 26 | result=$? 27 | if [ $result -eq 0 ] ; then 28 | if [ $# -gt 0 ] ; then 29 | exec "$@" 30 | fi 31 | exit 0 32 | fi 33 | sleep 1 34 | done 35 | echo "Operation timed out" >&2 36 | exit 1 37 | } 38 | 39 | while [ $# -gt 0 ] 40 | do 41 | case "$1" in 42 | *:* ) 43 | HOST=$(printf "%s\n" "$1"| cut -d : -f 1) 44 | PORT=$(printf "%s\n" "$1"| cut -d : -f 2) 45 | shift 1 46 | ;; 47 | -q | --quiet) 48 | QUIET=1 49 | shift 1 50 | ;; 51 | -t) 52 | TIMEOUT="$2" 53 | if [ "$TIMEOUT" = "" ]; then break; fi 54 | shift 2 55 | ;; 56 | --timeout=*) 57 | TIMEOUT="${1#*=}" 58 | shift 1 59 | ;; 60 | --) 61 | shift 62 | break 63 | ;; 64 | --help) 65 | usage 0 66 | ;; 67 | *) 68 | echoerr "Unknown argument: $1" 69 | usage 1 70 | ;; 71 | esac 72 | done 73 | 74 | if [ "$HOST" = "" -o "$PORT" = "" ]; then 75 | echoerr "Error: you need to provide a host and port to test." 76 | usage 2 77 | fi 78 | 79 | wait_for "$@" 80 | -------------------------------------------------------------------------------- /directus-chameleon-hasura/chameleon/wait-for.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TIMEOUT=60 4 | QUIET=0 5 | 6 | echoerr() { 7 | if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi 8 | } 9 | 10 | usage() { 11 | exitcode="$1" 12 | cat << USAGE >&2 13 | Usage: 14 | $cmdname host:port [-t timeout] [-- command args] 15 | -q | --quiet Do not output any status messages 16 | -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout 17 | -- COMMAND ARGS Execute command with args after the test finishes 18 | USAGE 19 | exit "$exitcode" 20 | } 21 | 22 | wait_for() { 23 | for i in `seq $TIMEOUT` ; do 24 | nc -z "$HOST" "$PORT" > /dev/null 2>&1 25 | 26 | result=$? 27 | if [ $result -eq 0 ] ; then 28 | if [ $# -gt 0 ] ; then 29 | exec "$@" 30 | fi 31 | exit 0 32 | fi 33 | sleep 1 34 | done 35 | echo "Operation timed out" >&2 36 | exit 1 37 | } 38 | 39 | while [ $# -gt 0 ] 40 | do 41 | case "$1" in 42 | *:* ) 43 | HOST=$(printf "%s\n" "$1"| cut -d : -f 1) 44 | PORT=$(printf "%s\n" "$1"| cut -d : -f 2) 45 | shift 1 46 | ;; 47 | -q | --quiet) 48 | QUIET=1 49 | shift 1 50 | ;; 51 | -t) 52 | TIMEOUT="$2" 53 | if [ "$TIMEOUT" = "" ]; then break; fi 54 | shift 2 55 | ;; 56 | --timeout=*) 57 | TIMEOUT="${1#*=}" 58 | shift 1 59 | ;; 60 | --) 61 | shift 62 | break 63 | ;; 64 | --help) 65 | usage 0 66 | ;; 67 | *) 68 | echoerr "Unknown argument: $1" 69 | usage 1 70 | ;; 71 | esac 72 | done 73 | 74 | if [ "$HOST" = "" -o "$PORT" = "" ]; then 75 | echoerr "Error: you need to provide a host and port to test." 76 | usage 2 77 | fi 78 | 79 | wait_for "$@" 80 | -------------------------------------------------------------------------------- /prime/prime-docker/newrelic.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * New Relic agent configuration. 4 | * 5 | * See lib/config/default.js in the agent distribution for a more complete 6 | * description of configuration variables and their potential values. 7 | */ 8 | exports.config = { 9 | /** 10 | * Array of application names. 11 | */ 12 | app_name: ['Prime CMS'], 13 | /** 14 | * Your New Relic license key. 15 | */ 16 | license_key: process.env.NEW_RELIC_LICENSE_KEY, 17 | logging: { 18 | /** 19 | * Level at which to log. 'trace' is most useful to New Relic when diagnosing 20 | * issues with the agent, 'info' and higher will impose the least overhead on 21 | * production applications. 22 | */ 23 | level: 'info' 24 | }, 25 | /** 26 | * When true, all request headers except for those listed in attributes.exclude 27 | * will be captured for all traces, unless otherwise specified in a destination's 28 | * attributes include/exclude lists. 29 | */ 30 | allow_all_headers: true, 31 | attributes: { 32 | /** 33 | * Prefix of attributes to exclude from all destinations. Allows * as wildcard 34 | * at end. 35 | * 36 | * NOTE: If excluding headers, they must be in camelCase form to be filtered. 37 | * 38 | * @env NEW_RELIC_ATTRIBUTES_EXCLUDE 39 | */ 40 | exclude: [ 41 | 'request.headers.cookie', 42 | 'request.headers.authorization', 43 | 'request.headers.proxyAuthorization', 44 | 'request.headers.setCookie*', 45 | 'request.headers.x*', 46 | 'response.headers.cookie', 47 | 'response.headers.authorization', 48 | 'response.headers.proxyAuthorization', 49 | 'response.headers.setCookie*', 50 | 'response.headers.x*' 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /canner/generated/canner.cloud.js: -------------------------------------------------------------------------------- 1 | const {FirebaseCredential} = require("canner-credential"); 2 | const {MemoryDataSource} = require('@gqlify/server'); 3 | 4 | exports.cms = { 5 | logo: { 6 | src: "https://cdn.canner.io/images/logo/logo-word-white.png", 7 | width: "140px", 8 | height: "50px", 9 | href: "#", 10 | backgroundColor: "#6ba4be" 11 | }, 12 | style: { 13 | sidebarTheme: "dark", 14 | navbarTheme: "light", 15 | navbarStyle: { 16 | lineHeight: "50px", 17 | height: "50px" 18 | }, 19 | navbarMenuStyle: { 20 | lineHeight: "50px" 21 | }, 22 | sidebarMenuStyle: { 23 | height: 'calc(100% - 50px)', 24 | background: '#4c6574' 25 | }, 26 | sidebarStyle: { 27 | width: "200px", 28 | }, 29 | theme: { 30 | "primary-color": "#f19b90", 31 | "btn-primary-bg": "#f19b90", 32 | 33 | "menu-dark-item-active-bg": "#415663", 34 | "menu-dark-bg": "#415663", 35 | "menu-dark-color": "#eee", 36 | 37 | // common 38 | "border-radius-base": "3px", 39 | 40 | // header 41 | "layout-header-background": "#fff", 42 | 43 | // body 44 | "layout-body-background": "#ecf2f6" 45 | } 46 | }, 47 | sidebarMenu: [{ 48 | title: "Posts", 49 | pathname: "posts", 50 | icon: "read" 51 | }, { 52 | title: "Categories", 53 | pathname: "categories", 54 | icon: "tag" 55 | }], 56 | } 57 | 58 | exports.graphql = { 59 | dataSources: { 60 | // "default" environment is the required in dataSources 61 | "default": [] 62 | 63 | /* See https://www.canner.io/docs/credential-firebase.html to learn how to get */ 64 | // "default": [new FirebaseCredential(require("./cert.json"))], 65 | 66 | /* See https://www.canner.io/docs/credential-prisma.html to learn how to get prisma configuration files */ 67 | // "default": [new PrismaCredential("path to yaml")], 68 | 69 | /* for PREMIUM plan, you can use more than one env */ 70 | // "test": [new FirebaseCredential(require("path to cert.json"))] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Headless CMS comparison 2 | 3 | Continuation of my [post about Headless CMS comparison](https://dev.to/stereobooster/headless-graphql-cms-51id). 4 | 5 | Comparison of open source headless CMS. Inspired by [MicheleBertoli/css-in-js](https://github.com/MicheleBertoli/css-in-js). 6 | 7 | ## Features 8 | 9 | More ticks doesn't mean "better", it depends on your needs. 10 | 11 | | | GraphQL | Mutations | Custom Fields | D&D Editor | Rich Text Editor | Group Fields | Media Library | Image Manipulation | Image Crops | Asset CDN | Previews | Releases | Localization | Localized fields | Revision history | Webhooks | 12 | | ------ | ------- | --------- | ------------- | ---------- | ---------------- | ------------ | ------------- | ------------------ | ----------- | --------- | -------- | -------- | ------------ | ---------------- | ---------------- | -------- | 13 | | Prime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 3rd-party | 3rd-party | ✅ | 3rd-party | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 14 | | Strapi | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | 3rd-party | 3rd-party | ❌ | 3rd-party | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | 15 | 16 | ## Alternatives 17 | 18 | - https://github.com/netlify/headlesscms.org/tree/master/content/projects 19 | - https://github.com/gentics/headless-cms-comparison 20 | - http://www.cmsmatrix.org/ 21 | - https://docs.primecms.app/#/features 22 | - [List of content management systems](https://en.wikipedia.org/wiki/List_of_content_management_systems) 23 | 24 | ## Contributing 25 | 26 | If your CMS is not listed here, feel free to add it. 27 | 28 | 1. Create a new folder named CMS-name in the root folder. 29 | 2. Add `docker-compose.yml` 30 | 3. Add a new entry to `Readme.md` 31 | 32 | ## Other 33 | 34 | ### Database to API 35 | 36 | - [hasura](https://hasura.io/) - Instant Realtime GraphQL on Postgres 37 | - [PostGraphile](https://www.graphile.org/postgraphile/) - Instantly spin-up a GraphQL API server by pointing PostGraphile at your existing PostgreSQL database 38 | - [PostgREST](http://postgrest.org) is a standalone web server that turns your PostgreSQL database directly into a RESTful API 39 | - [tuql](https://github.com/bradleyboy/tuql) is a simple tool that turns a sanely formatted sqlite database into a graphql endpoint 40 | 41 | ### Admin generators 42 | 43 | - [administrate](https://github.com/thoughtbot/administrate) RoR 44 | - [godmin](https://github.com/varvet/godmin) RoR 45 | - [activeadmin](https://github.com/activeadmin/activeadmin) RoR 46 | - [rails_admin](https://github.com/sferik/rails_admin) RoR 47 | - [trestle](https://github.com/TrestleAdmin/trestle) RoR 48 | - [react-admin](https://github.com/marmelab/react-admin) React 49 | - [canner](https://github.com/Canner/canner) React and co 50 | -------------------------------------------------------------------------------- /canner/generated/schema/posts.schema.js: -------------------------------------------------------------------------------- 1 | import CannerScript, { Tabs, Default } from "canner-script"; 2 | 3 | const columns = [ 4 | { 5 | title: "Title", 6 | dataIndex: "title" 7 | }, 8 | { 9 | title: "Cover", 10 | dataIndex: "coverPicture" 11 | }, 12 | { 13 | title: "Published", 14 | dataIndex: "draft", 15 | render: isDraft => { 16 | if (isDraft) return "❌"; 17 | return "✔️"; 18 | } 19 | } 20 | ]; 21 | 22 | const Posts = ({ attributes }) => ( 23 | 32 | 33 | 34 | 40 | 41 | {/* reference: https://www.cannercms.com/docs/schema-toolbar-tags#lt-export-gt */} 42 | 47 | {/* reference: https://www.cannercms.com/docs/schema-toolbar-tags#lt-import-gt */} 48 | 57 | {/* reference: https://www.cannercms.com/docs/schema-toolbar-tags#lt-filter-gt-1 */} 58 | 59 | 60 | 61 | 62 | 91 | 92 | 93 | 94 | 95 | 96 | 102 | 110 | 111 | 116 | 117 | 118 | 119 | 133 | 134 | 135 | 136 | ); 137 | 138 | export default Posts; 139 | -------------------------------------------------------------------------------- /canner/generated/canner.server.js: -------------------------------------------------------------------------------- 1 | /** Firebase required packages 2 | * 3 | * https://www.cannercms.com/docs/data-source-firebase 4 | * const {FirebaseDataSource} = require('@gqlify/firebase'); 5 | * const admin = require('firebase-admin'); 6 | * const cert = require('./cert.json'); 7 | */ 8 | 9 | /** Firestore required packages 10 | * https://www.cannercms.com/docs/data-source-firestore 11 | * const {FirestoreDataSource} = require('@gqlify/firestore); 12 | * const admin = require('firebase-admin'); 13 | * const cert = require('./cert.json'); 14 | */ 15 | 16 | 17 | exports.common = { 18 | hostname: 'http://localhost:3000', 19 | // cannerSchemaPath?: string; 20 | // cookieKeys?: string[]; 21 | // public?: boolean; 22 | // clientId?: string; 23 | // clientSecret?: string; 24 | } 25 | 26 | exports.cms = { 27 | logo: { 28 | src: "https://cdn.canner.io/images/logo/logo-word-white.png", 29 | width: "140px", 30 | height: "50px", 31 | href: "#", 32 | backgroundColor: "#6ba4be" 33 | }, 34 | style: { 35 | sidebarTheme: "dark", 36 | navbarTheme: "light", 37 | navbarStyle: { 38 | lineHeight: "50px", 39 | height: "50px" 40 | }, 41 | navbarMenuStyle: { 42 | lineHeight: "50px" 43 | }, 44 | sidebarMenuStyle: { 45 | height: 'calc(100% - 50px)', 46 | background: '#4c6574' 47 | }, 48 | sidebarStyle: { 49 | width: "200px", 50 | }, 51 | theme: { 52 | "primary-color": "#f19b90", 53 | "btn-primary-bg": "#f19b90", 54 | 55 | "menu-dark-item-active-bg": "#415663", 56 | "menu-dark-bg": "#415663", 57 | "menu-dark-color": "#eee", 58 | 59 | // common 60 | "border-radius-base": "3px", 61 | 62 | // header 63 | "layout-header-background": "#fff", 64 | 65 | // body 66 | "layout-body-background": "#ecf2f6" 67 | } 68 | }, 69 | // find more icons https://ant.design/components/icon/ 70 | sidebarMenu: [{ 71 | title: "Posts", 72 | pathname: "posts", 73 | icon: "read" 74 | }, { 75 | title: "Categories", 76 | pathname: "categories", 77 | icon: "tag" 78 | }], 79 | // hostname?: string; 80 | // staticsPath?: string; 81 | // clientBundledDir?: string; 82 | 83 | // /** 84 | // * OIDC config 85 | // * If `oidc` is null, all oidc features will be disabled 86 | // */ 87 | // oidc?: { 88 | // // issuer 89 | // // via Discovery 90 | // discoveryUrl?: string; 91 | // // manually 92 | // issuer?: string; 93 | // authorizationEndpoint?: string; 94 | // tokenEndpoint?: string; 95 | // userinfoEndpoint?: string; 96 | // jwksUri?: string; 97 | 98 | // // client 99 | // clientId?: string; 100 | // clientSecret?: string; 101 | 102 | // // What attribute of claim should we use as username 103 | // usernameClaim?: string; 104 | // // Additional scopes we ask in authorization 105 | // additionalScopes?: string[]; 106 | // // Whether we should force SSO to kill session as well or not during logout process 107 | // forceSsoLogout?: boolean; 108 | // // Customize SSO provider's logout procedure 109 | // ssoLogout?: (ctx: Context) => Promise; 110 | // } | null; 111 | 112 | // /** 113 | // * Fully auth customizable middleware 114 | // */ 115 | // beforeRenderCms?: (ctx: Context, next: () => Promise) => Promise; 116 | // authCallback?: (ctx: Context, next: () => Promise) => Promise; 117 | // logout?: (ctx: Context, next: () => Promise) => Promise; 118 | 119 | // /** 120 | // * Cookie 121 | // */ 122 | // cookieKeys?: string[]; 123 | } 124 | 125 | exports.graphql = { 126 | dataSources: { 127 | // the keys below is correspoing the `name` of `dataSource` property in your schema. 128 | // eg: 129 | // new FirebaseDataSource({ 135 | // config: { 136 | // credential: admin.credential.cert(cert), 137 | // databaseURL: `https://${cert.project_id}.firebaseio.com`, 138 | // }, 139 | // path: args.key 140 | // }), 141 | // firestore: args => new FirebaseDataSource({ 142 | // config: { 143 | // credential: admin.credential.cert(cert), 144 | // databaseURL: `https://${cert.project_id}.firebaseio.com`, 145 | // }, 146 | // collection: args.key 147 | // }) 148 | } 149 | } 150 | 151 | exports.auth = { 152 | // mountPath?: string; 153 | accounts: [{ 154 | username: 'canner', 155 | password: 'canner', 156 | }] 157 | } 158 | --------------------------------------------------------------------------------