backend & types

This commit is contained in:
Robin Grenzdörfer 2024-01-27 18:58:35 +00:00
parent 91bfa0864d
commit 0b4a474180
219 changed files with 5211 additions and 12325 deletions

7
.env
View File

@ -1,7 +1,8 @@
PROJECT_NAME=tibi-docs PROJECT_NAME=tibi_starter
TIBI_PREFIX=tibi TIBI_PREFIX=tibi
TIBI_NAMESPACE=tibi-docs TIBI_NAMESPACE=tibi_starter
UID=100 UID=100
GID=101 GID=101
RELEASE_ORG_SLUG=webmakers-gmbh RELEASE_ORG_SLUG=webmakers-gmbh
RELEASE_PROJECT_SLUG=tibi-docs RELEASE_PROJECT_SLUG=tibi_starter
START_SCRIPT=:ssr

View File

@ -0,0 +1,76 @@
name: initialize database
description: initialize database by using database of test environment
author: BinKrassDuFass
inputs:
MONGODB_SERVICE_NAME:
description: 'Name of the MongoDB service'
required: true
default: 'mongo'
TIBI_USERNAME:
description: 'Username of the Tibi account'
required: true
default: 'admin'
TIBI_PASSWORD:
description: 'Password of the Tibi account'
required: true
default: 'admin'
TIBI_API_URL:
description: 'URL of the Tibi API'
required: true
default: 'http://tibi-server:8080/api/v1'
TIBI_API_CONFIG_PATH:
description: 'Path of the Tibi API config'
required: true
default: "${{github.workspace}}/api/config.yml}}"
TIBI_API_NAMESPACE:
description: 'Namespace of the Tibi API'
required: true
PROJECT_NAME:
description: 'Name of the project'
required: true
runs:
using: composite
steps:
- name: Setup mongo tools
shell: bash
run: |
echo "::group::setup Mongo keys"
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
sudo apt-get install -y gnupg
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
echo "::endgroup::"
echo "::group::mongodb tools"
sudo apt-get update
echo "aptitude install mongodb-database-tools"
sudo apt-get install -y mongodb-database-tools
echo "::endgroup::"
echo "mongodump --version"
mongodump --version
- name: Restore MongoDB Data
run: |
echo "::group::initialize mongo data"
mongorestore --uri "mongodb://${{inputs.MONGODB_SERVICE_NAME}}:27017" ./.github/actions/init-db/mongo-dump
echo "::endgroup::"
shell: bash
- name: set config in tibi
shell: bash
run: ./.github/actions/init-db/setConfigInTibiProject.sh ${{inputs.TIBI_USERNAME}} ${{inputs.TIBI_PASSWORD}} ${{inputs.TIBI_API_URL}} ${{inputs.TIBI_API_CONFIG_PATH}} ${{inputs.TIBI_API_NAMESPACE}} ${{inputs.PROJECT_NAME}}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"admin.system.version"}],"uuid":"c25383adb2a64a8ca31b3bc5cbcb6690"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"admin.system.version"}],"uuid":"c25383adb2a64a8ca31b3bc5cbcb6690"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi.project"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi.project"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi.project"},{"v":{"$numberInt":"2"},"unique":true,"key":{"name":{"$numberInt":"1"}},"name":"name_1","ns":"tibi.project"},{"v":{"$numberInt":"2"},"key":{"_fts":"text","_ftsx":{"$numberInt":"1"}},"name":"textindex","ns":"tibi.project","weights":{"name":{"$numberInt":"1"}},"default_language":"german","language_override":"language","textIndexVersion":{"$numberInt":"3"}}],"uuid":"a0a6733bdb52400f9f3b17985bc28bcc"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi.user"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi.user"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi.user"},{"v":{"$numberInt":"2"},"unique":true,"key":{"username":{"$numberInt":"1"}},"name":"username_1","ns":"tibi.user"},{"v":{"$numberInt":"2"},"key":{"_fts":"text","_ftsx":{"$numberInt":"1"}},"name":"textindex","ns":"tibi.user","weights":{"$**":{"$numberInt":"1"}},"default_language":"german","language_override":"language","textIndexVersion":{"$numberInt":"3"}}],"uuid":"ba627bbd4ac24b3ca92aebdc33b7d4b0"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.backups"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.backups"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.backups"}],"uuid":"4993cf280e844b5b80fe208350713002"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.banner"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.banner"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.banner"}],"uuid":"7346de51448b4a27b289a0e32336d0b6"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.content"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.content"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.content"},{"v":{"$numberInt":"2"},"key":{"meta.datum":{"$numberInt":"1"}},"name":"meta.datum_1","ns":"tibi_allkids_erfurt.content"}],"uuid":"df9951d7cf964e5e8a22360c09aa27c7"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.forms"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.forms"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.forms"}],"uuid":"7815c4dfc9d9460c8aac8cf94cc67ea6"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.lighthouse"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.lighthouse"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.lighthouse"}],"uuid":"fca0bbd4089a43689609593178154de9"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.lighthouseSubpath"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.lighthouseSubpath"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.lighthouseSubpath"}],"uuid":"b72120ec4cd34054a83833dce78c869f"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.navigation"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.navigation"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.navigation"}],"uuid":"d989bd0ea7ba4ea4ae728b8a6baa62ba"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.ssr"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.ssr"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.ssr"},{"v":{"$numberInt":"2"},"unique":true,"key":{"path":{"$numberInt":"1"}},"name":"path_1","ns":"tibi_allkids_erfurt.ssr"}],"uuid":"75869e19f8164beabe53366265b10208"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.temperature"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.temperature"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.temperature"}],"uuid":"eb60c1bc334c4fa2a473fdb6c99b3e6a"}

Binary file not shown.

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi.project"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi.project"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi.project"},{"v":{"$numberInt":"2"},"unique":true,"key":{"name":{"$numberInt":"1"}},"name":"name_1","ns":"tibi.project"},{"v":{"$numberInt":"2"},"key":{"_fts":"text","_ftsx":{"$numberInt":"1"}},"name":"textindex","ns":"tibi.project","weights":{"name":{"$numberInt":"1"}},"default_language":"german","language_override":"language","textIndexVersion":{"$numberInt":"3"}}],"uuid":"a0a6733bdb52400f9f3b17985bc28bcc"}

Binary file not shown.

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi.user"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi.user"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi.user"},{"v":{"$numberInt":"2"},"unique":true,"key":{"username":{"$numberInt":"1"}},"name":"username_1","ns":"tibi.user"},{"v":{"$numberInt":"2"},"key":{"_fts":"text","_ftsx":{"$numberInt":"1"}},"name":"textindex","ns":"tibi.user","weights":{"$**":{"$numberInt":"1"}},"default_language":"german","language_override":"language","textIndexVersion":{"$numberInt":"3"}}],"uuid":"ba627bbd4ac24b3ca92aebdc33b7d4b0"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.backups"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.backups"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.backups"}],"uuid":"4993cf280e844b5b80fe208350713002"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.banner"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.banner"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.banner"}],"uuid":"7346de51448b4a27b289a0e32336d0b6"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.content"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.content"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.content"},{"v":{"$numberInt":"2"},"key":{"meta.datum":{"$numberInt":"1"}},"name":"meta.datum_1","ns":"tibi_allkids_erfurt.content"}],"uuid":"df9951d7cf964e5e8a22360c09aa27c7"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.forms"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.forms"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.forms"}],"uuid":"7815c4dfc9d9460c8aac8cf94cc67ea6"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.navigation"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.navigation"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.navigation"}],"uuid":"d989bd0ea7ba4ea4ae728b8a6baa62ba"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.ssr"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.ssr"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.ssr"},{"v":{"$numberInt":"2"},"unique":true,"key":{"path":{"$numberInt":"1"}},"name":"path_1","ns":"tibi_allkids_erfurt.ssr"}],"uuid":"75869e19f8164beabe53366265b10208"}

View File

@ -0,0 +1 @@
{"options":{},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_","ns":"tibi_allkids_erfurt.temperature"},{"v":{"$numberInt":"2"},"key":{"insertTime":{"$numberInt":"1"}},"name":"insertTime_1","ns":"tibi_allkids_erfurt.temperature"},{"v":{"$numberInt":"2"},"key":{"updateTime":{"$numberInt":"1"}},"name":"updateTime_1","ns":"tibi_allkids_erfurt.temperature"}],"uuid":"eb60c1bc334c4fa2a473fdb6c99b3e6a"}

View File

@ -0,0 +1,108 @@
#!/bin/bash
# Start a GitHub Actions group for input validation
echo "::group::Validating Inputs"
# Check if the correct number of arguments is passed
if [ "$#" -ne 6 ]; then
echo "Incorrect number of arguments provided."
echo "Usage: $0 <TIBI_USERNAME> <TIBI_PASSWORD> <TIBI_API_URL> <PROJECT_API_CONFIG> <PROJECT_NAMESPACE> <PROJECT_NAME>"
exit 1
fi
# Assigning passed arguments to variables for better readability
TIBI_USERNAME=$1
TIBI_PASSWORD=$2
TIBI_API_URL=$3
PROJECT_API_CONFIG=$4
PROJECT_NAMESPACE=$5
PROJECT_NAME=$6
echo "Provided TIBI_USERNAME: $TIBI_USERNAME"
echo "TIBI_API_URL: $TIBI_API_URL"
# Be cautious with logging sensitive data like passwords and tokens
# Echoing the password or sensitive information is generally not recommended
# End the input validation group
echo "::endgroup::"
# Start a group for authentication
echo "::group::Authenticating User"
# Prepare authentication request payload
auth_payload=$(jq -n --arg username "$TIBI_USERNAME" --arg password "$TIBI_PASSWORD" '{username: $username, password: $password}')
echo "Authentication payload: $auth_payload"
# Fetch the authentication token
echo "Requesting authentication token..."
auth_response=$(curl -s -X POST -H "Content-Type: application/json" -d "$auth_payload" "$TIBI_API_URL/login")
# Logging the response for debugging (remove sensitive data as necessary)
echo "Authentication response: $auth_response"
# Extract token from the response
TIBI_AUTH_TOKEN=$(echo $auth_response | jq -r '.token')
# Check if the token was successfully retrieved
if [ -z "$TIBI_AUTH_TOKEN" ]; then
echo "Failed to get authentication token. Exiting script."
exit 1
fi
echo "Authentication token received successfully."
echo "::endgroup::"
# Start a group for fetching project data
echo "::group::Fetching Project Data"
# Get the list of projects from the API
echo "Retrieving projects..."
response=$(curl -s -H "X-Auth-Token: $TIBI_AUTH_TOKEN" "$TIBI_API_URL/project")
echo $response
projects=$(echo $response) # Parse the JSON response to get project data
echo "::endgroup::"
# Start a group for processing project data
echo "::group::Processing Project Data"
# Initialize variables to track project existence
projectFound=false
projectId=""
# Loop through each project to find if the required project exists
for row in $(echo "${projects}" | jq -r '.[] | @base64'); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
api_name=$(_jq '.name')
# Check if the current project's namespace matches the target
if [ "$api_name" == "$PROJECT_NAME" ]; then
projectId=$(_jq '.id')
projectData=$(echo ${row} | base64 --decode)
projectFound=true
break
fi
done
echo "::endgroup::"
# Start a group for creating or updating the project
echo "::group::Creating or Updating Project"
# Conditionally create a new project or update the existing one
if [ "$projectFound" = true ]; then
echo "Project found with ID: $projectId, updating..."
# Prepare updated project data
updatedProjectData=$(echo $projectData | jq --arg configFile "$PROJECT_API_CONFIG" '.configFile = $configFile | del(.id)')
# Send a PUT request to update the project
updateResponse=$(curl -s -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: $TIBI_AUTH_TOKEN" -d "$updatedProjectData" "$TIBI_API_URL/project/$projectId")
# Logging the response for debugging (remove sensitive data as necessary)
echo "Update response: $updateResponse"
else
echo "Project not found. Creating new project..."
# Send a POST request to create a new project
createResponse=$(curl -s -X POST -H "Content-Type: application/json" -H "X-Auth-Token: $TIBI_AUTH_TOKEN" -d "{\"configFile\":\"$PROJECT_API_CONFIG\", \"name\":\"$PROJECT_NAMESPACE\", \"namespace\":\"$PROJECT_NAMESPACE\", \"description\":\"$PROJECT_NAMESPACE\"}" "$TIBI_API_URL/project")
fi
echo "::endgroup::"

View File

@ -1,11 +1,200 @@
name: deploy to production name: deploy to production
on: "push" on: "push"
# push:
# branches:
# - master
jobs: jobs:
lighthouse-evaluation:
runs-on: ubuntu-latest
container:
image: gitbase.de/actions/ubuntu:latest
volumes:
- /data:/data
services:
mongo:
image: mongo:4.2
ports:
- 27017:27017
options: --name mongo
maildev:
image: gitbase.de/robin/maildev:latest
ports:
- 80:80
- 25:25
options: --name maildev
tibi-server:
image: gitbase.de/cms/tibi-server
ports:
- 8080:8080
env:
DB_DIAL: mongodb://mongo
API_PORT: 8080
MAIL_HOST: maildev:25
SECURITY_ALLOWABSOLUTEPATHS: "true"
SECURITY_ALLOWUPPERPATHS: "true"
SECURITY_ALLOWRELATIVEPATHS: "true"
options: --name tibi-server
volumes:
- ${{ github.workspace }}:/repo
live-server:
image: gitbase.de/robin/apache-image:latest
ports:
- 8081:80
volumes:
- ${{ github.workspace }}/frontend:/usr/local/apache2/htdocs/
options: --name live-server
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: setup node 18
uses: actions/setup-node@v3
- name: Initialize database
uses: ./.github/actions/init-db
with:
TIBI_API_NAMESPACE: allkids_erfurt
TIBI_API_CONFIG_PATH: /repo/api/config.yml
PROJECT_NAME: AllKids
- name: SERVICE RESTART
uses: docker://docker
with:
args: docker restart live-server tibi-server mongo maildev
- name: Cache node modules
uses: actions/cache@v3
with:
path: |
.yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: setup yarn
run: |
corepack enable
corepack prepare yarn@3.2.4 --activate
yarn install
- name: modify config
run: |
sed -i 's#\(sentryEnvironment.*\)".*"#\1"${GITHUB_REF_NAME}"#g' frontend/src/config.ts
sed -i 's#//\( sentry\\.init.*\)#\1#g' frontend/src/config.ts
export $(cat .env | xargs)
echo "PROJECT_RELEASE=${RELEASE_PROJECT_SLUG}.r`git rev-list HEAD --count`-`git describe --all --long | sed 's+/+-+'`" >> .env
export $(cat .env | xargs)
echo ______ .env ______
cat .env
echo
sed -i 's#\(const release = \).*#\1"'${PROJECT_RELEASE}'"#g' api/hooks/config-client.js
# bash scripts/preload-meta.sh frontend/spa.html
# bash scripts/preload-meta.sh frontend/spa.html > frontend/_spa.html
# cp frontend/_spa.html frontend/spa.html
export stamp=`date +%s`
sed -i s/__TIMESTAMP__/$stamp/g frontend/spa.html
# sed -i s/__TIMESTAMP__/$stamp/g frontend/serviceworker.js
# cat frontend/serviceworker.js
# rm api/templates/spa.html
# cp frontend/spa.html api/templates/spa.html
echo ______ frontend/spa.html ______
cat frontend/spa.html
- name: build
env:
FORCE_COLOR: "true"
run: |
yarn build
- name: build ssr
env:
FORCE_COLOR: "true"
run: |
yarn build:server
#- name: Load .env file
# run: |
# set -a
# source .env
# set + a
- name: SERVICE RESTART
uses: docker://docker
with:
args: docker restart live-server tibi-server
- name: wait for boot
run: |
sleep 15
- name: Inspect Service Containers
run: |
for container_id in $(docker ps --format '{{.ID}}'); do
echo "::group:: Container logs:"
docker logs $container_id || true
echo "::endgroup::"
done
#- name: Wait for Live Server
# run: |
# attempts=0
# max_attempts=5
# same port since its inside the same network, so not 8081....
# while ! curl --fail "http://live-server:80"; do
# if [ $attempts -eq $max_attempts ]; then
# echo "Live server not ready after $max_attempts attempts"
# echo "${{ toJson(job) }}"
# curl -v "http://live-server:80" || true
# echo "::group::liveserver logs"
# docker logs live-server
# echo "::endgroup::"
# echo "::group:: tibi-server logs"
# docker logs tibi-server
# echo "::endgroup::"
# echo "::group:: tibi-server curl"
# docker exec live-server cat /var/log/apache2/access.log || true
# docker exec live-server bash -c "apt-get update && apt-get install -y curl"
# docker exec live-server echo $PATH
# docker exec live-server bash -c 'curl -v "http://tibi-server:8080/api/v1/_/allkids_erfurt/ssr?token=owshwerNwoa&url=/noindex"'
# echo "::endgroup::"
# exit 1
# fi
# attempts=$((attempts+1))
# echo "Waiting for live-server to be ready... attempt $attempts"
# sleep 5
# done
- name: Test HTTP Request
run: |
curl -v http://live-server:80
- name: Install Chrome
run: |
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
sudo apt-get update
sudo apt-get install -y google-chrome-stable
# Lighthouse Analysis Step
- name: Lighthouse Analysis
run: |
yarn add lighthouse
npx lighthouse http://live-server:80 --output json --output-path /tmp/lighthouse-report.json --chrome-flags="--headless --no-sandbox --disable-dev-shm-usage"
- name: upload-to-nextcloud
run: |
sudo apt-get update && sudo apt-get install -y curl bash findutils
export datetime=`date +%Y-%m-%d_%H-%M-%S`
mkdir -p /tmp/cloudsend/${GITHUB_REF_NAME}/$${datetime}
mv /tmp/lighthouse-report.json /tmp/cloudsend/${GITHUB_REF_NAME}/$${datetime}/
./scripts/cloudsend.sh /tmp/cloudsend/ https://www.basiswolke.de/index.php/s/xHGsypbqiifnGH5
deploy: deploy:
name: deploy name: deploy
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -13,46 +202,98 @@ jobs:
image: gitbase.de/actions/ubuntu:latest image: gitbase.de/actions/ubuntu:latest
volumes: volumes:
- /data:/data - /data:/data
services:
mongo:
image: mongo:4.2
ports:
- 27017:27017
maildev:
image: gitbase.de/robin/maildev:latest
ports:
- 80:80
- 25:25
tibi-server:
image: gitbase.de/cms/tibi-server
ports:
- 8080:8080
env:
DB_DIAL: mongodb://mongo
API_PORT: 8080
MAIL_HOST: maildev:25
SECURITY_ALLOWABSOLUTEPATHS: "true"
SECURITY_ALLOWUPPERPATHS: "true"
SECURITY_ALLOWRELATIVEPATHS: "true"
live-server:
image: gitbase.de/robin/live-server:latest
ports:
- 8081:8081
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
lfs: true
submodules: true
- run: |
git fetch --force --tags
# setup node 18
- name: setup node 18 - name: setup node 18
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with:
node-version: 18
- name: build docs - name: install dependencies
env: env:
FORCE_COLOR: "true" FORCE_COLOR: "true"
run: | run: |
node --version
cd docs
npm install -g yarn npm install -g yarn
yarn install yarn install
yarn docpress:build
- name: deploy docs - name: modify config
# only if branch is master run: |
sed -i 's#\(sentryEnvironment.*\)".*"#\1"${GITHUB_REF_NAME}"#g' frontend/src/config.ts
sed -i 's#//\( sentry\\.init.*\)#\1#g' frontend/src/config.ts
export $(cat .env | xargs)
echo "PROJECT_RELEASE=${RELEASE_PROJECT_SLUG}.r`git rev-list HEAD --count`-`git describe --all --long | sed 's+/+-+'`" >> .env
export $(cat .env | xargs)
echo ______ .env ______
cat .env
echo
sed -i 's#\(const release = \).*#\1"'${PROJECT_RELEASE}'"#g' api/hooks/config-client.js
# bash scripts/preload-meta.sh frontend/spa.html
# bash scripts/preload-meta.sh frontend/spa.html > frontend/_spa.html
# cp frontend/_spa.html frontend/spa.html
export stamp=`date +%s`
sed -i s/__TIMESTAMP__/$stamp/g frontend/spa.html
# sed -i s/__TIMESTAMP__/$stamp/g frontend/serviceworker.js
# cat frontend/serviceworker.js
# rm api/templates/spa.html
# cp frontend/spa.html api/templates/spa.html
echo ______ frontend/spa.html ______
cat frontend/spa.html
- name: build
env:
FORCE_COLOR: "true"
run: |
yarn build
- name: build ssr
env:
FORCE_COLOR: "true"
run: |
yarn build:server
- name: build legacy
env:
FORCE_COLOR: "true"
run: |
yarn build:legacy
- name: deploy
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/master'
env: env:
RSYNC_HOST: ftp1.webmakers.de RSYNC_USER: "allkids_rsync_master"
RSYNC_PORT: 22222
RSYNC_USER: webmakers_tibi_docs_rsync_master
RSYNC_PASS: ${{ secrets.rsync_master }} RSYNC_PASS: ${{ secrets.rsync_master }}
run: | run: |
cd docs scripts/deploy.sh ftp1.webmakers.de $RSYNC_USER $RSYNC_PASS
ls -la
rsync -rlcgD --perms -i -u -v --stats --progress \
--delete \
-e "sshpass -p ${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p ${RSYNC_PORT}" \
_docpress/ \
${RSYNC_USER}@${RSYNC_HOST}:./ \

View File

@ -1,14 +1,14 @@
# Tibi Docs und Demo Projekt # Tibi Docs und Demo Projekt
Diese Repo enthält die Dokumentation zum TibiCMS und eine Demo-Projekt welches die Dokumentation begleitet. Diese Repo enthält die Dokumentation zum TibiCMS und eine Demo-Projekt welches die Dokumentation begleitet.
Das Demo-Projekt kann als Vorlage für neue Tibi-Projekte verwendet werden. Das Demo-Projekt kann als Vorlage für neue Tibi-Projekte verwendet werden.
## neues Projekt - Checkliste ## neues Projekt - Checkliste
- [x] neues Projekt im gitbase.de anlegen (cms/tibi-docs) als Vorlage verwenden - [x] neues Projekt im gitbase.de anlegen (cms/tibi_starter) als Vorlage verwenden
- [ ] klonen - [ ] klonen
- [ ] bereinigen - [ ] bereinigen
```sh ```sh
git filter-branch -f --index-filter 'git rm -rf --cached --ignore-unmatch .yarn/cache' HEAD git filter-branch -f --index-filter 'git rm -rf --cached --ignore-unmatch .yarn/cache' HEAD
@ -16,13 +16,13 @@ git filter-branch -f --index-filter 'git rm -rf --cached --ignore-unmatch docs'
git push --force git push --force
``` ```
- [ ] anpassen - [ ] anpassen
- `.env` - `.env`
- `docker-compose-local.yml` -> `name:` - `docker-compose-local.yml` -> `name:`
- `api/...` - `api/...`
- [ ] upgraden - [ ] upgraden
```sh ```sh
mkdir tmp mkdir tmp
@ -34,7 +34,7 @@ make docker-pull
make fix-permissions make fix-permissions
``` ```
- [ ] los programmieren - [ ] los programmieren
```sh ```sh
make docker-start make docker-start
@ -43,17 +43,18 @@ make docker-start
make fix-permissions make fix-permissions
``` ```
- [ ] Projekt in Tibi bekannt machen: - [ ] Projekt in Tibi bekannt machen:
- <https://PROJEKTNAME-tibiadmin.code.testversion.online> - <https://PROJEKTNAME-tibiadmin.code.testversion.online>
- Pfad der API-Konfig: `/data/api/config.yml` - Pfad der API-Konfig: `/data/api/config.yml`
- [ ] Website im Browser ansehen: - [ ] Website im Browser ansehen:
- <https://PROJEKTNAME.code.testversion.online> - <https://PROJEKTNAME.code.testversion.online>
- [ ] Testmails checken: - [ ] Testmails checken:
- <https://PROJEKTNAME-maildev.testversion.online>
- [ ] deploy - <https://PROJEKTNAME-maildev.testversion.online>
1. [ ] Subdomain im basispanel anlegen auf `../frontend/`
2. [ ] rsync-Account in basispanel anlegen auf `htdocs/` - [ ] deploy
3. [ ] Passwort in Secrets eintragen: <https://drone.gitbase.de> 1. [ ] Subdomain im basispanel anlegen auf `../frontend/`
4. [ ] `.drone.yml` anpassen 2. [ ] rsync-Account in basispanel anlegen auf `htdocs/`
5. [ ] pushen 3. [ ] Passwort in Secrets eintragen: <https://drone.gitbase.de>
4. [ ] `.drone.yml` anpassen
5. [ ] pushen

View File

@ -1,12 +0,0 @@
# Ordnerpfade, die über den tibi-server direkt erreichbar seien sollen,
# können über den "path" relativ zur "config.yml" definiert werden.
# Durch die "name"-Definition werden diese Pfade eindeutig unterschieden.
# Für folgende Beispielangaben bildet sich folgende URL:
#
# TIBI-SERVER-URL/api/v1/_/NAMESPACE/_/assets/_dist_/
#
# Jeder Zugriff wird intern umgeleitet auf ../frontend/_dist_/
# (relativ zur "config.yml").
# Es ist ausschließlich ein unbeschränkter Lesezugriff (GET-Methode) möglich.
name: _dist_
path: ../frontend/_dist_

View File

@ -29,6 +29,13 @@ hooks:
create: create:
type: javascript type: javascript
file: hooks/backups/post_create.js file: hooks/backups/post_create.js
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
fields: fields:
- name: collectionName - name: collectionName

205
api/collections/content.yml Normal file
View File

@ -0,0 +1,205 @@
name: content
uploadPath: ../media/page
meta:
label: Inhalt
muiIcon: tableOfContents
allowExportAll: true
backup:
active: true
collectionName: backups
defaultSort:
field: sort
order: MANUALLY
views:
- type: simpleList
selectionPriority: 0
primaryText: pageTitle
secondaryText: path
mediaQuery: "(min-width: 0px)"
tertiaryText: type
- type: table
selectionPriority: 1
mediaQuery: "(min-width: 700px)"
columns:
- source: type
name: Typ
filter: true
- source: path
name: Pfad
filter: true
- source: pageTitle
name: Titel
filter: true
- source: active
name: Aktiv
filter: true
tablist:
activeTab: general
tabs:
- name: general
label: Allgemein
subFields:
- source: path
- source: pageTitle
- source: type
- source: active
- source: sort
- name: teaser
label: Homepage Seitenteaser
subFields:
- source: teaser
- name: site
label: Seite
subFields:
- source: rows
- name: meta
label: Meta
subFields:
- source: meta
subNavigation:
- name: seite
label:
de: Seiten
en: pages
muiIcon: book-open-page-variant
defaultSort:
field: "sort"
order: "MANUALLY"
setDefault:
field: type
value: page
views:
- type: table
columns:
- source: path
name: Pfad
filter: true
- source: pageTitle
name: Titel
filter: true
- source: active
name: Aktiv
filter: true
filter:
type: page
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
post:
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
projections:
navigation:
select:
path: 1
fields:
- type: string
name: path
meta:
label: Pfad
helperText: "Ein Pfad sollte mit einem / starten und ohne eins enden."
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- type: boolean
name: active
meta:
label: Aktiv
helperText: Ist dies Aktiviert, so wird der Inhalt verfügbar.
defaultValue: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- type: string
name: type
meta:
label: Inhaltstyp
widget: select
defaultValue: page
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
choices:
- name: Seite
id: page
- name: pageTitle
type: string
meta:
label: Titel der Seite
helperText: "Dieser Titel wird in der Seite als h1 angezeigt."
dependsOn:
eval: $.type == "page"
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: rows
type: object[]
meta:
label: Zeilen
widget: grid
metaElements: []
subFields: !include fieldLists/row.yml
- name: meta
type: object
meta:
label: Meta Agaben
dependsOn:
eval: $.type == "page"
subFields: !include fieldLists/meta.yml
- name: sort
type: number
meta:
label:
de: Manuelle Sortierung
en: Manual Sorting
inputProps:
{ readonly: true, placeholder: { de: "Wert wird automatisch gesetzt", en: "Value is set automatically" } }
helperText:
de: Dieses Feld wird für die manuelle Sortierung benötigt. Sobald ein Eintrag per Drag&Drop verschoben wurde, wird die neue Position innerhalb der Liste eingetragen.
en: This field is required for manual sorting. As soon as an entry is moved using Drag&Drop, the new position is entered in the list.

View File

@ -1,227 +0,0 @@
# Der Name der Kollektion wird in der Rest-API-URL verwendet, z.B.
# /_/demo/democol
name: democol
# Enthält die Kollektion Felder vom Typ "file", so werden die
# hochgeladenen Dateien unter dem Ordner abgelegt, der mit
# "uploadPath" bestimmt wird.
uploadPath: ../media/democol
# "fields" stellen die Eigentliche Struktur der Kollektion dar.
# "fields" ist als Array angelegt um eine Standard-Sortierung
# im tibi-admin vorzugeben.
fields:
# Das Einbinden von Feldern über extra Dateien bietet sich nur
# an, wenn das jeweilige Feld mehrfach von dieser oder anderen
# Kollektionen verwendet wird.
# Auf die möglichen Definitionen wird im Kapitel "fields"
# eingegangen.
- !include fields/title.yml
- !include fields/type.yml
- !include fields/date.yml
- !include fields/content.yml
- !include fields/info.yml
- !include fields/isEmployed.yml
- !include fields/profilePic.yml
- !include fields/skills.yml
- !include fields/image.yml
- !include fields/tags.yml
- !include fields/gender.yml
- !include fields/emplymentDetails.yml
- !include fields/employmentDetails.yml
- !include fields/description.yml
- !include fields/age.yml
- !include fields/additionalData.yml
# Neben der Definition der Indexe innerhalbd des Feld-Objektes selbst,
# ist die Index-Definition global für die Kollektion auch hier möglich.
# Diese Definition ist z.B. für zusammengesetzte Index-Typen notwendig.
# Außerdem sind hier feinere Einstellungen für den Index möglich.
# Mehr dazu im "indexes" Kapitel
indexes:
- !include democol/textindex.yml
# Standardsprache für Text-Index in der Datenbank
defaultLanguage: de
# "hooks" definieren die Algorithmen, die Daten und Abläufe zu bestimmten
# HTTP-Methoden und Schritten der API manipulieren können.
hooks:
# Hooks für die Methode "get"
get:
# "read"-Schritt wird ausgeführt, bevor die Daten von der Datenbank
# gelesen werden.
read:
# "type" ist derzeit immer "javascript"
type: javascript
# "file" zeigt auf die Datei mit dem Javascript-Code relativ zum
# Ordner der "config.yml" Datei.
file: hooks/democol/get_read.js
# "return"-Schritt wird ausgeführt, bevor die gelesenen Daten über
# HTTP übertragen werden.
return:
type: javascript
file: hooks/democol/get_return.js
# Hooks für die Methode "post"
post:
# "bind" wird ausgeführt, bevor die übertragenen Daten in eine
# Objekt-Struktur umgewandelt werden.
# Der tibi-server erwarten nach diesem Schritt gültige JSON-Daten,
# d.h. sollte es möglich gemacht werden, dass andere Daten übertragen
# werden, sind diese in diesem Hook abzufangen und zu verarbeiten.
bind:
type: javascript
file: hooks/democol/post_bind.js
# "validate" wird ausgeführt, bevor die Daten validiert werden.
validate:
type: javascript
file: hooks/democol/post_validate.js
# "create" wird ausgeführt, bevor das Objekt/Dokument in der Datenbank
# angelegt wird.
create:
type: javascript
file: hooks/democol/post_create.js
# "return" wird ausgeführt, bevor die Serverantwort über HTTP
# übertragen wird.
return:
type: javascript
file: hooks/democol/post_return.js
# Hooks für die Methode "put"
put:
bind:
type: javascript
file: hooks/democol/put_bind.js
validate:
type: javascript
file: hooks/democol/put_validate.js
# "bind" und "validate" habe die gleiche Bedeutung wie Hooks der
# Methode "post".
# "update" wird ausgeführt bevor das Objekt in der Datenbank
# aktualisiert wird.
update:
type: javascript
file: hooks/democol/put_update.js
# "return" wird auch hier vor der Serverantwort ausgeführt.
return:
type: javascript
file: hooks/democol/put_return.js
# Hooks für die Methode "delete"
delete:
# Der "delete"-Hook wird vor dem eigentlichen Löschen ausgeführt
delete:
type: javascript
file: hooks/democol/delete_delete.js
# "return"-Hook kann ebenso hier die Serverantwort manipulieren
return:
type: javascript
file: hooks/democol/delete_return.js
# Projektionen der Daten werden via GET-Parameter "projection=..."
# referenziert.
# "projections" is ein Objekt, dass die Namen der Projektionen
# als Key führt.
projections:
# "list" = Name der Projektion
list:
# "select" definiert als Keys die Felder, die beim Abruf
# dieser Projektion in den Ausgabe-Daten enthalten sind.
# Felder werden über die Punkt-Notation referenziert.
select:
title: 1
date: 1
# refenziert das "subField" "author" unterhalb von "meta"
meta.author: 1
details:
# Alternativ kann "select" auch Auschlussregeln definieren.
# Eine Mischung von Inkludieren und Auschluss ist NICHT
# möglich.
select:
comment: 0
full:
# Ein leeres "select" Objekt beschränkt die Ausgabe der
# Daten nicht und ist Standard, wenn der "projection="
# Parameter nicht verwendet wurde.
select:
# Allgeine Zugriffsregeln auf Kollektions-Ebene werden mit dem
# "permissions" Objekt festgelegt.
permissions:
# Unter "public" werden die Zugriffsrechte für die Öffentlichkeit
# definiert.
public:
# "methods" führt die HTTP-Methoden auf, die erlaubt sind
methods:
# "get: true" bedeutet hier, dass jeder die Daten lesen darf
get: true
# "post", also Einträge erstellen, "put" = Bearbeiten und
# "delete" = löschen darf die Öffentlichkeit nicht.
post: false
put: false
delete: false
# Ist "validProjections" definiert, sind auch nur genau die
# aufgelisteten Projektionen erlaubt, welche zwingend mit dem
# GET-Parameter "projection=..." ausgewählt werden müssen.
validProjections:
- list
- details
# Der Key "user" steht für ALLE Benutzer die dem Projekt
# zugeordnet sind.
# D.h. eine feinere Abstufung auf Benutzerebene ist mit dem
# Key "user" allein nicht möglich.
# Für eine feinere Abstufung können nachgelagerte Hooks
# dienen oder die Verwendung von zugeordneten benutzerdefinierten
# "permissions" (siehe meta Objekt).
user:
methods:
get: true
post: false
put: false
delete: false
# Fehlt "validProjections", sind automatisch alle Projektionen
# erlaubt, wobei hier auch der GET-Parameter "projection="
# weggelassen werden darf und somit alle Felder in der Ausgabe
# zu finden sind.
# Folgende Brechtigung wird angewandt, wenn der Zugriff über
# den GET-Parameter "token=" oder die Header-Anweisung "token: "
# angefragt wird.
# "token" ist dabei die Markierung, dass es sich um einen Token
# handelt und "${TOKEN}" ist der benutzerdefinierte Token selbst.
# Dieser wird hier über eine Umgebungsvariable "TOKEN" injiziert,
# die in "config.yml.env" definiert werden kann mit "TOKEN=...".
token:${TOKEN}:
methods:
get: true
post: true
put: true
delete: true
# Alle Berechtigungs-Namen, die nicht "public", "user" oder "token:..."
# heißen, sind benutzerdefinierte Berechtigungen, die Benutzern
# zugeordnet werden können.
# Eine mögliche Auflistung um Vorschläge im tibi-admin anzubieten,
# werden im Top-Level meta-Objekt der "config.yml" unter "permissions"
# definiert.
pages:
methods:
get: true
post: true
put: true
delete: true
# "imageFilter" definieren Filter, die Bilder bearbeiten, wie
# z.B. Verkleinerung.
# Mögliche Angaben werden im seperaten Kapitel behandelt.
imageFilter: !include democol/imageFilter.yml
# Wie auch in der Top-Level-Konfig "config.yml" ist auch hier ein
# "meta" Objekt möglich und nötig für die Konfiguration des
# tibi-admin.
# Mögliche Angaben werden im seperaten Kapitel behandelt.
meta: !include democol/meta.yml

View File

@ -1,15 +0,0 @@
type: cardList
mediaQuery: "(min-width:600px)"
selectionPriority: 3 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
fields:
- source: updateTime
label:
de: letztes Update
en: last update
type: date
- source: title
filter: true
- source: date
filter: true
- source: type
filter: true

View File

@ -1,25 +0,0 @@
# Der Key des Objektes definiert den Namen des Filters.
# Jeder Filter ist eine Liste von Bildmanipulationen, die
# nacheinander angewandt werden.
# Die manipulierten Bilder werden gecachet. Ein nachträgliches
# Anpassen der Filter erfordert also das Löschen der gecachten
# Dateien welche sich jeweils neben den original Bilddateien
# im "uploadPath" der Kollektion befinden.
s:
- fit: true
height: 300
width: 300
resampling: lanczos
quality: 60
m:
- fit: true
height: 600
width: 600
resampling: lanczos
quality: 60
l:
- fit: true
height: 1200
width: 1200
resampling: lanczos
quality: 60

View File

@ -1,129 +0,0 @@
# Ein Label für tibi-admin wird mehrsprachig folgendermaßen definiert
label:
de: Demo-Kolletion
en: Demo-Collection
# Jede Kolletion kann ein eigenes Icon aus mdijs bekommen.
muiIcon: web
# erlabt gleichzeitigen export von allen einträgen
allowExportAll: true
# backup objekt
backup:
active: true # backup ist aktiviert
collectionName: backups # name der backups collection
# wenn keine fields gesetzt sind, werden alle Felder der Kollektion angezeigt
quickEdit:
enabled: true # Standardmäßig ist die Schnellbearbeitung aktiviert
fields:
- title
- age
- date
# Die Standardsortierung bei ersten Aufruf der Kollektion.
defaultSort:
# Nach welchem Feld soll sortiert werden?
field: updatedTime
# ASC für aufsteigend oder DESC für absteigend oder MANUALLY um manuell sortieren zu können
order: DESC
# Ist ein Javascript Message-Object-Empfänger implementiert, der empfangene
# Daten als Vorschau rendern kann, so ist dieser hier zu definieren.
# Implementierungshinweise zu einem Solchen gibt es später.
previewUrl: https://demo.testversion.online/preview
# Aus den definierten "imageFilter"-Angaben kann ein Filter für die
# Ausgabe der Thunbnails in der Admin-Ansicht ausgewählt werden.
defaultImageFilter: s
# Jede Kollektion kann über media-Querys mit mehreren Ansichten veknüpft werden.
# Mögliche Ansichten und die dazugehörigen CSS-Queries sind hier zu defineren.
views:
# Natürlich können die Angaben auch ausgelagert und mehrfach verwendet werden.
# Die möglichen Angaben werden im Kapitel "views" gezeigt.
- !include simpleList.yml
- !include table.yml
# Wird eine Kollektion als eine Gesamtliste schnell unübersichtlich, hild die
# Definition von "subNavigation".
# Die meisten Angaben sind aus obiger Beschreibung den meta-Objektes bekannt.
# Es wird hier nur auf die zusätzlichen Angaben eingegangen.
subNavigation:
- # Jede Unternavigation braucht einen eindeutigen Namen um diese später
# in z.B. Javascript-Code wieder erkennen zu können.
name: pages
# Die Angabe des "label" ist optional. Wird sie nicht angegeben, wird
# wird diese Unternavigation nicht in der Navigation angezeigt.
# Ohne "label" kann die Unternavigation aber weiterhin für die Referenzierung
# z.B. in der Mediathek-Ansicht des ContentBuilders verwendet werden.
label:
de: Seiten
en: Pages
muiIcon: page-layout-body
defaultSort:
field: titel
order: ASC
# Standardmäßig wird man beim Klick auf einen Eintrag der Kollektion
# (z.B. Zeile in der Tabelle) direkt zum Editieren des Datensatzes weitergeleitet.
# Möchte man das nicht, so kann hier ein alternatives Verhalten definiert werden.
# Mögliche Werte sind:
# - "edit" (Standard)
# - "view" (Anzeigen des Datensatzes)
# - Objekt mit "eval"-Attribut
#
# Beim Objekt mit "eval"-Attribut wird der Code mit dem Javascript-Kontext für
# Kollektionen im tibi-admin ausgeführt. Das Ergebnis kann hierbei wieder "edit"
# oder "view" sein.
# Außerdem ist es möglich, eine eigene Funktion zu definieren, die den Datensatz
# als Parameter erhält. Diese Funktion wird dann für den jweiligen Datensatz
# ausgeführt, auf den geklickt wurde. Mehr dazu unter dem Widget "ContentBuilder".
defaultCallback: view
views:
- !include simpleList.yml
- !include table.yml
- !include cardList.yml
# Um mehr Übersicht zu bekommen können zum Einen andere "views" und "defaultSort"
# genutzt werden. Es kann aber auch eine Einschränkung der Daten über eine
# Vorfilterung via "filter" geben. "filter" ist ein Objekt mit MongoDB-Filterangaben.
# siehe: https://www.mongodb.com/docs/compass/current/query/filter/
filter:
type: page
- name: news
label:
de: Neuigkeiten
en: News
muiIcon: newspaper
defaultSort:
field: date
order: DESC
defaultCallback: edit
views:
- !include simpleList.yml
- !include table.yml
filter:
type: news
# Standardmäßig werden im Formular zu Eingabe der Daten alle Felder von "fields"
# untereinander angeordnet.
# Um diese Anordnung in Tabs zu strukturieren, ist die Verwendung von "tablist"
# vorgesehen.
# Die Definition befindet sich in einem gesonderten Kapitel
tablist: !include tablist.yml
# OpenAPI-Spezifikation für die API-Endpunkte der Kollektion
openapi:
get:
summary:
en: list all datasets of democol
de: listet alle Datensätze der Kollektion democol auf
description:
en: list all datasets of democol with pagination and/or filtering
de: listet alle Datensätze der Kollektion democol mit Paginierung und/oder Filterung

View File

@ -1,19 +0,0 @@
# "type" legt den Typ des Views fest.
type: simpleList
# Die Auswahl erfolgt über folgende "mediaQuery".
mediaQuery: "(min-width:0px)"
selectionPriority: 2 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
# 3 Blöcke können in der simpleList verwendet werden.
# Haupttext "primaryText" und optional 2 weitere Angaben über
# "secondaryText" und "tertiaryText".
# Die Angabe des jeweiligen Feldes erfolgt als String oder
# Objekt mit der "source"-Eigenschaft.
# Das Feld selbst wird in Punkt-Notation angegeben.
# Die Darstellung selbst ist abhängig von der Feld-Konfiguration
# selbst, die unter fields in der Kollektions-Konfiguration
# stattfindet.
primaryText: title
secondaryText:
source: date
tertiaryText: meta.author

View File

@ -1,15 +0,0 @@
type: table
mediaQuery: "(min-width:600px)"
selectionPriority: 1 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
columns:
- source: updateTime
label:
de: letztes Update
en: last update
type: date
- source: title
filter: true
- source: date
filter: true
- source: type
filter: true

View File

@ -1,41 +0,0 @@
# Hier wird der initial zu öffnende Tab festgelegt.
# Ist dieser nicht festgelegt, wird automatisch der erste Tab
# aus der "tabs" Liste gewaählt.
activeTab: general
# "tabs" ist die eigentliche Liste
tabs:
- # Jeder Tab braucht einen Namen, über den er refereziert
# werden kann.
name: general
# Die übliche Labelangabe kann auch hier mehrpsrachig erfolgen.
label:
de: Allgemein
en: General
# Welche Felder dieser Tab anzeigen soll, wird über "subFields"
# beschrieben.
subFields:
- source: type
- source: title
- source: date
- source: additionalData
- source: age
- source: description
- source: paymentValues
- source: gender
- source: isEmployed
- source: profilePic
- source: skills
- source: image
- source: tags
- name: content
label:
de: Inhalt
en: Content
subFields:
- source: content
- name: info
label:
de: Informationen
en: Information
subFields:
- source: info

View File

@ -1,6 +0,0 @@
name: fulltextindex # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$** # definiert einen Volltextindex über alle Felder. Der spezielle Operator $text wird verwendet, um einen Volltextindex zu erstellen, und der Operator $\*\* bezeichnet alle Felder in der Sammlung.
background: true # Wenn auf true gesetzt, erzwingt dies, dass der Index eindeutige Werte enthält. Wenn Sie versuchen, einen Eintrag mit einem bereits indizierten Wert hinzuzufügen, wird ein Fehler ausgelöst.
unique: false # Wenn auf true gesetzt, erzwingt dies, dass der Index eindeutige Werte enthält. Wenn Sie versuchen, einen Eintrag mit einem bereits indizierten Wert hinzuzufügen, wird ein Fehler ausgelöst.
defaultLanguage: german # Wird verwendet, um die Sprache für Textindizes festzulegen. Dies ist wichtig für die Volltextsuche, da verschiedene Sprachen unterschiedliche Tokenisierungs- und Stemmungsregeln haben.

View File

@ -0,0 +1,16 @@
# attribute auf column ebene
- name: contentType
type: string
meta:
label: ""
widget: select
choices:
- name: Bild
id: image
- name: Modul Import
id: moduleImport
- name: Text
id: text

View File

@ -0,0 +1,28 @@
name: checkboxGroupInput
type: object
meta:
label:
de: Checkbox Gruppe
en: Checkbox Group
dependsOn:
eval: $parent?.inputWidgets?.includes('checkboxGroup')
helperText:
de: Ansammlung von Checkboxen
en: Collection of checkboxes
subFields:
- name: groupTitle
type: string
meta:
label: Checkbox Gruppe Titel
- name: checkboxes
type: object[]
meta:
label: Checkbox Gruppe
direction: row
widget: containerLessObjectArray
subFields:
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@ -0,0 +1,16 @@
name: dateInput
type: object
meta:
label:
de: Normaler Kalender
en: Normal calendar
helperText:
de: Datumsfeld
en: Date field
dependsOn:
eval: $parent?.inputWidgets?.includes('defaultCalendar')
subFields:
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@ -0,0 +1,74 @@
name: datePickerInput
type: object
meta:
label:
de: Custom Kalender
en: Custom Calendar
dependsOn:
eval: $parent?.inputWidgets?.includes('customCalendar')
subFields:
- name: props
type: object
meta:
label: Datumauswahl Eigenschaften
subFields:
- name: allowedDateRanges
type: object[]
meta:
label: Erlaubte Datumsbereiche
widget: containerLessObjectArray
subFields:
- name: from
type: date
meta:
label: Von
widget: date
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: to
type: date
meta:
label: Bis
widget: date
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: excludeDays
type: string[]
meta:
label: Auszuschließende Wochentage
widget: selectArray
choices:
- id: monday
name: Montag
- id: tuesday
name: Dienstag
- id: wednesday
name: Mittwoch
- id: thursday
name: Donnerstag
- id: friday
name: Freitag
- id: saturday
name: Samstag
- id: sunday
name: Sonntag
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@ -0,0 +1,133 @@
- name: emailSubject
type: string
meta:
label:
de: Email Betreff
en: Email Subject
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailReciever
type: string
meta:
label:
de: Email Empfänger
en: Email Reciever
helperText:
de: "Bsp: xyz@gmail.com"
en: "E.g.: xyz@gmail.com"
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailCC
type: string[]
meta:
label:
de: Email CC
en: Email CC
widget: string
useDefaultArray: true
helperText:
de: "Bsp: zyx@gmail.com"
en: "E.g.: zyx@gmail.com"
- name: emailIntroduction
type: string
meta:
label:
de: Email Einleitungssatz
en: Email Introduction Sentence
helperText:
de: "Bsp: Hallo xyz, sie haben eine neue Kaufanfrage erhalten!"
en: "E.g.: Hello xyz, you have received a new purchase request!"
- name: rows
type: object[]
meta:
label: Zeile
widget: grid
addElementLabel: Zeile Hinzufügen
subFields:
- name: title
type: string
meta:
label: Zeilenname
helperText:
de: "Sollte der Titel keinen Wert enthalten, wird kein Zeilenname angezeigt!"
en: "If the title does not contain a value, no row name will be displayed!"
- name: emailTitle
type: string
meta:
label: Email Abschnitt Titel
helperText:
de: "Sollte der Titel keinen Wert enthalten, wird kein Abschnitt Titel angezeigt!"
en: "If the title does not contain a value, no section title will be displayed!"
- name: columns
type: object[]
meta:
label: Spalte
addElementLabel: Spalte hinzufügen
widget: grid
direction: horizontal
subFields:
- name: title
type: string
meta:
label: Überschrift
helperText: Optional
- name: inputWidgets
type: string[]
meta:
label:
de: Angezeigte Eingabefelder
en: Displayed input fields
widget: selectArray
choices:
- name: Nummernblock
id: labelNumber
- name: Zeitenauswahlfeld
id: times
- name: Auswahlfeld
id: select
- name: Datumsauswahl - Standard Kalender
id: defaultCalendar
- name: Datumauswahl - Custom Kalender
id: customCalendar
- name: Nummerfeld
id: number
- name: Checkbox Gruppe
id: checkboxGroup
- name: Mehrfachauswahl
id: multiSelect
- name: Textfeld
id: text
- !include labelNumberInput.yml
- !include timesInput.yml
- !include dateInput.yml
- !include numberInput.yml
- !include checkboxGroup.yml
- !include datePicker.yml
- !include multiSelectInput.yml
- !include textInputs.yml

View File

@ -0,0 +1,71 @@
name: labelNumberInput
type: object[]
meta:
label: Nummer block
dependsOn:
eval: $parent?.inputWidgets?.includes('labelNumber')
helperText:
de: Links beschreibender Text, rechts zahleneingabe
en: Left descriptive text, right number input
subFields:
- name: group
type: number
meta:
label: Gruppe
helpterText:
de: Pflichtfeld seperierung. Aus einem Nummernblock muss mindestens eine Gruppe input haben.
en: Mandatory field separation. A number block must have at least one group input.
- name: title
type: string
meta:
label: Titel
helperText:
de: Block Titel
en: Block title
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailName
type: string
meta:
label: Email Name
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: block
type: object[]
meta:
label: Block
widget: containerLessObjectArray
subFields:
- name: label
type: string
meta:
label: Label
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailName
type: string
meta:
label: Email Name
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@ -0,0 +1,41 @@
name: multiSelectInput
type: object
meta:
label:
de: Mehrfachauswahl Input
en: Multi Select Input
dependsOn:
eval: $parent?.inputWidgets?.includes('multiSelect')
subFields:
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml
- name: options
type: object[]
meta:
label: Mehrfachauswahl Optionen
direction: row
widget: containerLessObjectArray
subFields:
- name: name
type: string
meta:
label: Name
- name: props
type: object
meta:
label: Mehrfachauswahl Eigenschaften
subFields:
- name: additionalAddableValues
type: boolean
meta:
label: Zusätzliche hinzufügbare Werte
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@ -0,0 +1,13 @@
name: numberInput
type: object
meta:
label:
de: Nummereingabe
en: Number Input
dependsOn:
eval: $parent?.inputWidgets?.includes('number')
subFields:
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@ -0,0 +1,51 @@
- name: emailTitle
type: string
meta:
label: Email Titel
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: placeholder
type: string
meta:
label: Platzhalter
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: notRequired
type: boolean
meta:
label: nicht Notwendig
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: fieldOrder
type: number
meta:
label: Reihenfolge
helperText:
de: Die kleinste angegebene Zahl wird am weitesten oben in der Formularspalte stehen
en: The smallest specified number will be at the top of the form column.
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: textTitle
type: string
meta:
label: Text Titel
helperText: Alternative zu textPlaceholder

View File

@ -0,0 +1,45 @@
name: textInput
type: object[]
meta:
label: Textfeld
addElementLabel: Textfeld hinzufügen
dependsOn:
eval: $parent?.inputWidgets?.includes('text')
subFields:
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml
- name: textArea
type: boolean
meta:
label: Großes Textfeld
containerProps:
layout:
size:
default: "col-4"
small: "col-6"
large: "col-4"
- name: emailValidation
type: boolean
meta:
label: E-Mail-Validierung
containerProps:
layout:
size:
default: "col-4"
small: "col-6"
large: "col-4"
- name: telValidation
type: boolean
meta:
label: Telefon-Validierung
containerProps:
layout:
size:
default: "col-4"
small: "col-6"
large: "col-4"

View File

@ -0,0 +1,49 @@
name: timesInput
type: object
meta:
label:
de: Zeitenauswahlfeld
en: Time input
dependsOn:
eval: $parent?.inputWidgets?.includes('times')
helperText:
de: Selectfeld mit von - bis Angabe
en: Select field with from - to specification
subFields:
- name: times
type: object[]
meta:
label: Zeitenangabe
helperText: "Die Angaben werden in folgendes Übersetzt: Anfangspunkt - Endpunkt"
direction: horizontal
widget: containerLessObjectArray
subFields:
- name: from
type: string
meta:
label: Anfangspunkt
helperText: Bspw. 14:30
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: to
type: string
meta:
label: Endpunkt
helperText: Bspw. 15:30
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@ -0,0 +1,25 @@
- name: title
type: string
meta:
label: Titel
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: description
type: string
meta:
label: Beschreibung
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: keywords
type: string
meta:
label: Schlüsselwörter

View File

@ -0,0 +1,9 @@
# attribute auf row ebene
- name: columns
type: object[]
meta:
label: Spalten
direction: row
widget: grid
subFields: !include ../fieldLists/column.yml

View File

@ -1,76 +0,0 @@
- name: testArray
type: string[]
meta:
label: { de: "Test Array richtext", en: "test array" }
widget: richtext
useDefaultArray: true
- name: testArrayString
type: string[]
meta:
label: { de: "Test Array string", en: "test array" }
widget: string
useDefaultArray: true
- name: testArrayNumber
type: number[]
meta:
label: { de: "Test Array number", en: "test array" }
widget: number
useDefaultArray: true
- name: testArrayBool
type: boolean[]
meta:
label: { de: "Test Array checkbox", en: "test array" }
widget: checkbox
useDefaultArray: true
- name: paymentValueObjdefault # Name des Eingabefelds für das erste Tab.
type: object[] # Datentyp des Eingabefelds, in diesem Fall ein Array von Objekten.
meta:
label: Zeilen # Tab-Label.
useDefaultArray: true
subFields: # Liste der Unterfelder für das Tab.
- name: test
type: string
meta:
label: test1
- name: test2
type: string
meta:
label: test2
- name: paymentValue # Name des ersten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert1 # Feldlabel.
- name: paymentValuee # Name des zweiten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert2 # Feldlabel.
- name: paymentValueObj2 # Name des Eingabefelds für das zweite Tab.
type: object[] # Datentyp des Eingabefelds, in diesem Fall ein Array von Objekten.
meta:
label: Spalten # Tab-Label.
direction: horizontal
widget: grid
metaElements:
- test1
- test2
subFields: # Liste der Unterfelder für das Tab.
- name: test
type: string
meta:
label: test1
- name: test2
type: string
meta:
label: test2
- name: paymentValue # Name des ersten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert1 # Feldlabel.
- name: paymentValuee # Name des zweiten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert2 # Feldlabel.

View File

@ -1,5 +0,0 @@
name: additionalData # Name des Eingabefelds.
type: object # Datentyp des Eingabefelds.
meta:
label: { de: "Zusätzliche Daten", en: "Additional Data" } # Feldlabel.
widget: jsonField # Verwendetes Widget.

View File

@ -1,5 +0,0 @@
name: age # Name des Eingabefelds.
type: int # Datentyp des Eingabefelds.
meta:
label: { de: "Alter", en: "Age" } # Feldlabel.
widget: number # Verwendetes Widget.

View File

@ -1,117 +0,0 @@
# Der Name des Feldes ist natürlich beliebig wählbar.
name: content
# "string" als Datentyp ist zwingend.
type: string
meta:
label:
de: Inhalt
en: content
# Die Bezeichnung des ContentBuilder-Widgets ist "contentbuilder".
widget: contentbuilder
# Die Anzeige des ContentBuilder im tibi-admin geschieht innerhalb
# eines iframes. Das ist notwendig, da der ContentBuilder eigene
# Styles mitbringet, die sich nicht mit den Styles des tibi-admin
# vermischen sollten.
# Via "baseHref" wird der <base>-Tag im iframe gesetzt.
# somit können alle relativen Pfade im ContentBuilder (z.B. Bilder)
# aufgelöst werden.
# Wie man hier sieht, ist die Angabe via "eval" mittels möglich.
# Der Kontext ist auf Feldebene, wie bei "dependsOn" und "defaultValue".
# Alternativ kann die Angabe auch direkt als String erfolgend.
# Dann natürlich ohne die Evaluierung der Variable "$projectBase", wie hier.
baseHref:
eval: $projectBase
# Sollen weitere CSS-Datei in das iframe geladen werden, können diese
# hier aufgelistet werden.
# Die Angabe kann direkt als Array erfolgen oder via "eval", dessen
# Code das Array der Strings mit den Dateipfaden zurückgibt.
# Auch zu beachten ist hier die relative Angabe. Da "baseHref" gesetzt
# ist, wird der Pfad relativ zu dieser Projekt-Basis innerhalb des
# tibi-server aufgelöst.
# Die Auslieferung der CSS-Dateien direkt über den tibi-server kann
# nur funktionieren, wenn "_dist_" in der "assets" Konfiguration der
# "config.yml" definiert ist.
cssHref:
- _/assets/_dist_/index.css
# Um eine Kollektion stellvertretend als Mediathek anzubinden, sind die
# Angaben unter "imageSelect", "fileSelect" und "videoSelect" zu tätigen.
# "imageSelect" betrifft die Einbindung von Bildern, "fileSelect" die
# Einbindung von Dateien, "videoSelect" die Einbindung von Videos.
imageSelect:
# Die Angabe "collection" ist zwingend. Hier wird die Kollektion
# definiert, die als Sammlung für die Bilder/Datei dient.
# Der Aufbau der Kollektion ist dabei frei, solange ein Upload-Feld
# für die Dateien existiert, welches die URL zur Datei zurückgibt.
collection: medialib
# Optional kann ein Filter und View für die Einbindung der Bilder/Dateien
# definiert werden. Dies geschieht über einen "subNavigation"
# Eintrag innerhalb des "meta.subNavigation" Arrays, der Kollektion
# (hier bei "medialib").
# Die Angabe hier ist die auszuwählende Navigation per Index des Arrays.
subNavigation: 0
fileSelect:
collection: medialib
subNavigation: 0
videoSelect:
collection: medialib
subNavigation: 0
# "customTags" des ContentBuilder können verwendet werden um die Einbindung
# von Modulen ins HTML zu ermöglichen.
# Die folgende Auflistung ist dabei ein Beispiel für ein Modul.
customTags:
- # Der Platzhalter wird 1:1 ins HTML übernommen und ist dabei frei
# definierbar.
# Die eigentliche Funktion eines Modul-Systems muss dann später
# im Frontend implementiert werden.
placeholder: "<my-module class='tibi-module' title='Titel' description='Beschreibung'>Mein Modul</my-module>"
# Die Benennung für die UI des ContentBuilder geschieht über die
# "label" Angabe, die mehrsprachig erfolgen kann.
label:
de: "Mein Modul"
en: "My Module"
# Um direkt Style-Angaben in das iframe des ContentBuilder zu übernehmen,
# werden diese hier angegeben.
# Natürlich ist auch hier wieder die Angabe via "eval" möglich.
# Nachfolgendes Beispiel erzeugt im ContentBuilder eine deutliche Darstellung
# des eingebundenen Moduls.
style: |
/*css*/
.is-builder {
max-width: 1200px;
margin: 0 auto;
}
.tibi-module {
padding: 10px;
border: 3px dashed #c4c4c4;
display: block;
text-align: center;
font-size: 14px;
color: black;
}
.tibi-module::before {
content: "\1F5BD ";
font-size: 16px;
color: black;
}
.tibi-module::after {
content: " title=\"" attr(title) "\" description=\"" attr(description) "\"";
font-size: 10px;
color: #555;
display: block;
padding-top: 5px;
}
/*!css*/

View File

@ -1,57 +0,0 @@
# Der Name des Feldes wird in der Datenbank zum Objekt ebenso
# wie in der Ein- und Ausgabe über die API verwendet.
name: date
# Über "type" wird der Datentyp in der Datenbank festgelegt.
# Mögliche Typen sind weiter unten aufgelistet.
type: date
# Direkt am Feld kann eine Index-Definition erfolgen.
# Folgende mögliche Werte können ihn die Liste aufgenommen werden:
# "single" - Standard-Index für diese Feld
# "unique" - Das Feld muss einen eindeutigen Wert haben
# "text" - Alle "text"-Indexanganben aller Felder werden zu einem
# gemeinsamen Volltext-Index kombiniert
#
# Die Angabe des Volltextindex ist besser unter "collections.X.indexes"
# vorzunehmen.
index:
- single
# Jede Datenübertragung an des Server wird validiert, d.h. es werden
# keine Datentypen angenommen, die nicht zu "type" passen.
# Darüber hinaus kann via "validator" eine zusätzliche Validierung
# vorgenommen werden.
# Dazu gibt es ein extra Kapitel.
validator:
required: true
eval: new Date($this) > new Date()
# Und natürlich gibt es auch hier ein "meta" Objekt zur Steuerung
# des tibi-admin.
meta:
# Das "label" des Feldes wird als Label vor dem Widget verwendet.
label:
de: Titel
en: title
# Abgelkeitet vom "type" gibt es Standard-Widgets. für spezielle
# Aufgaben stehen aber eine Hand voll Widgets bereit, die später
# beschrieben werden.
widget: date
# Standardwerte für neue Enträge können entweder direkt angegeben
# werden oder via Javascript client-seitig generiert werden.
# In den Kontext injizierte Variablen werden später beschrieben.
defaultValue:
# Das Ergebnis von "eval" wird hier als Standardwert verwendet.
# (hier das aktuelle Datum)
eval: new Date()
# Sollen Felder abhängig von bestimmten Bedingungen ein- oder
# ausgeblendet werden, geschieht das über Anweisungen in "dependsOn".
dependsOn:
# Das Feld wird nur eingeblendet wenn der Wert von "type"
# (auf gleicher Ebene wie das Feld "date" selbst)
# gleich "news" ist.
eval: $parent?.type == "news"

View File

@ -1,5 +0,0 @@
name: description # Name des Eingabefelds.
type: string # Datentyp des Eingabefelds.
meta:
label: { de: "Beschreibung", en: "Description" } # Feldlabel.
widget: richtext # Verwendetes Widget.

View File

@ -1,60 +0,0 @@
name: paymentValueObj
type: object[]
meta:
label: Zeilen
widget: grid
metaElements:
- test1
- test2
direction: vertical
pathStep: #widget spezifisch, gibt dem objekt einen namen und ein zugehöriges icon, Zeilen und spalten sind hier bereits default (Oberste Objekt zeile verschachtelte objekt spalte mit zugehörigen icons)
title: "Zeile"
icon: viewSequentialOutline
folding:
previewFolded:
eval: $this.test
previewUnfolded:
eval: $this.test
subFields:
- name: test
type: string
meta:
label: test1
- name: test2
type: string
meta:
label: test2
- name: paymentValue
type: number
meta:
label: Überweisungswert1
- name: paymentValuee
type: number
meta:
label: Überweisungswert2
- name: paymentValueObj2
type: object[]
meta:
label: Spalten
direction: horizontal
widget: grid
metaElements:
- test1
- test2
subFields:
- name: test
type: string
meta:
label: test1
- name: test2
type: string
meta:
label: test2
- name: paymentValue
type: number
meta:
label: Überweisungswert1
- name: paymentValuee
type: number
meta:
label: Überweisungswert2

View File

@ -1,32 +0,0 @@
name: paymentValues # Name des Eingabefelds.
type: object # Datentyp des Eingabefelds, in diesem Fall ein Objekt.
meta:
label: "Überweisungswerte" # Feldlabel.
widget: tabs # Verwendetes Widget. Die tabs Widget wird zur Organisation von komplexen Eingaben in Tab-Form verwendet.
subFields: # Liste der Unterfelder für jedes Tab.
- name: paymentValueObj # Name des Eingabefelds für das erste Tab.
type: object[] # Datentyp des Eingabefelds, in diesem Fall ein Array von Objekten.
meta:
label: Überweisungswerte1 # Tab-Label.
subFields: # Liste der Unterfelder für das Tab.
- name: paymentValue # Name des ersten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert1 # Feldlabel.
- name: paymentValuee # Name des zweiten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert2 # Feldlabel.
- name: paymentValueObj2 # Name des Eingabefelds für das zweite Tab.
type: object[] # Datentyp des Eingabefelds, in diesem Fall ein Array von Objekten.
meta:
label: Überweisungswerte2 # Tab-Label.
subFields: # Liste der Unterfelder für das Tab.
- name: paymentValue # Name des ersten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert1 # Feldlabel.
- name: paymentValuee # Name des zweiten Eingabefelds in diesem Tab.
type: number # Datentyp des Eingabefelds.
meta:
label: Überweisungswert2 # Feldlabel.

View File

@ -1,23 +0,0 @@
name: gender # Name des Eingabefelds.
type: string # Datentyp des Eingabefelds.
meta:
label: { de: "Geschlecht", en: "Gender" } # Feldlabel.
widget: select # Verwendetes Widget.
choices: # Auswahlmöglichkeiten.
- name: "männlich" # Anzeigename der Auswahl.
id: "male" # Wert der Auswahl.
- name: "weiblich" # Anzeigename der Auswahl.
id: "female" # Wert der Auswahl.
chipStyle:
backgroundImage: "linear-gradient(black 33.3%, red 33.3%, red 66.6%, gold 66.6%);"
color: white
textShadow: 0px 0px 4px black
#alternative:
#choices:
#DEPRECATED - FOREIGNKEY STATTDESSEN!
#endpoint: content
#params:
#sort:
#mapping:
#id: id
#name: path

View File

@ -1,20 +0,0 @@
name: image # Name des Eingabefelds.
type: string # Datentyp des Eingabefelds.
meta:
label: { de: "Bild", en: "Image" } # Feldlabel.
widget: foreignKey # Verwendetes Widget.
foreign:
collection: medialib # Name der Sammlung, in der die ausgewählten Daten gespeichert sind.
id: id # Feldname, das als eindeutige Kennung für die ausgewählten Daten verwendet wird.
subNavigation: 1 # Bestimmt, welche Navigation für die Auswahl der ausgewählten Daten angezeigt wird.
#projection: xyz
#sort: "title"
render:
#alternativ zu raw und eval kann hier auch das attribut "defaultCollectionViews" auf true gesetzt werden, dabei werden dann die ausgewählten elemente in der in collection definierten collectionview angezeigt.
raw: true
eval: |
(function() {
var out = "";
out += "<div style=\"color: #999;\">" + $foreignEntry.title + "</div>";
return out;
})()

View File

@ -1,51 +0,0 @@
name: info
type: object
meta:
label:
de: Info
en: Info
direction: horizontal # vertical oder horizontal
metaElements: # macht bestimmte Widgets im Zahnrad verfügbar und entfernt sie aus dem drop down
# alternaitv wären auch diese Angabenformen anstatt von tablist möglich:
#- author
#- source: author
tablist: # macht im Modal eine tabliste
tabs:
- name: authorInfos
label: Autorkram
subFields:
- source: author
- name: publishingInfos
label: Veröffentlichungskram
subFields:
- source: published
subFields:
- name: author
type: string
meta:
label:
de: Autor
en: Author
- name: published
type: date
meta:
label: Veröffentlicht
- name: tags
type: object[]
meta:
label:
de: Tags
en: Tags
subFields:
- name: name
type: string
meta:
label:
de: Name
en: Name
- name: color
type: string
meta:
label:
de: Farbe
en: Color

View File

@ -1,5 +0,0 @@
name: isEmployed # Name des Eingabefelds.
type: boolean # Datentyp des Eingabefelds.
meta:
label: { de: "Angestellt?", en: "Employed?" } # Feldlabel.
widget: checkbox # Verwendetes Widget.

View File

@ -1,5 +0,0 @@
name: profilePic # Name des Eingabefelds.
type: file # Datentyp des Eingabefelds.
meta:
label: { de: "Profilbild", en: "Profile Picture" } # Feldlabel.
widget: file # Verwendetes Widget.

View File

@ -1,10 +0,0 @@
name: skills # Name des Eingabefelds.
type: string[] # Datentyp des Eingabefelds.
meta:
label: { de: "Fähigkeiten", en: "Skills" } # Feldlabel.
widget: checkboxArray # Verwendetes Widget.
choices: # Auswahlmöglichkeiten.
- name: "Kochen" # Anzeigename der Auswahl.
id: "cooking" # Wert der Auswahl.
- name: "Backen" # Anzeigename der Auswahl.
id: "baking" # Wert der Auswahl.

View File

@ -1,11 +0,0 @@
name: tags # Name des Eingabefelds.
type: string[] # Datentyp des Eingabefelds.
meta:
label: { de: "Tags", en: "Tags" } # Feldlabel.
widget: chipArray # Verwendetes Widget.
choices: # Auswahlmöglichkeiten.
- name: "Tech" # Anzeigename der Auswahl.
id: "tech" # Wert der Auswahl.
- name: "Wissenschaft" # Anzeigename der Auswahl.
id: "science" # Wert der Auswahl.
autocomplete: true # Option für Autovervollständigung.

View File

@ -1,11 +0,0 @@
name: title
type: string
meta:
label:
de: Titel
en: Title
inputProps:
multiline: true
placeholder: Ihr Titel
openapi:
example: Demo Titel

View File

@ -1,16 +0,0 @@
name: type
type: string
meta:
label:
de: Typ
en: Type
widget: select
choices:
- name:
de: Standardseite
en: Standard page
id: page
- name:
de: News
en: News
id: news

42
api/collections/forms.yml Normal file
View File

@ -0,0 +1,42 @@
name: forms
uploadPath: ../media/forms
meta:
label: Formulare
muiIcon: web
backup:
active: true
collectionName: backups
views:
- type: table
columns:
- source: formular
permissions:
public:
methods:
get: true
post: true
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
post:
create:
type: javascript
file: hooks/forms/post_create.js
return:
type: javascript
file: hooks/forms/post_return.js
fields:
- type: object
name: formular
meta:
label: Formular
widget: jsonField

View File

@ -0,0 +1,119 @@
name: lighthouse
meta:
label: Lighthouse
muiIcon: web
views:
- type: table
mediaQuery: "(min-width: 600px)"
columns:
- source: insertTime
filter: true
- source: perfomance
filter: true
- source: accessibility
filter: true
- source: bestPractices
filter: true
- source: seo
filter: true
- type: simpleList
mediaQuery: "(max-width: 599px)"
primaryText: insertTime
secondaryText: performance
tertiaryText: accessibility
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
projections:
dashboard:
hooks:
post:
create:
type: javascript
file: hooks/lighthouse/post_create.js
fields:
- name: analyzedPaths
type: string[]
meta:
label: Analyzed Paths
- name: performance
type: number
meta:
label: Performance
- name: accessibility
type: number
meta:
label: Accessibility
- name: bestPractices
type: number
meta:
label: Best Practices
- name: seo
type: number
meta:
label: SEO
- name: lighthouseMetrics
type: object
meta:
label: Lighthouse Metrics
subFields:
- name: FCPS
type: number
meta:
label: First Contentful Paint Score
- name: FCPV
type: number
meta:
label: First Contentful Paint Value
- name: FMPV
type: number
meta:
label: First Meaningful Paint Value
- name: FMPS
type: number
meta:
label: First Meaningful Paint Score
- name: SIS
type: number
meta:
label: Speed Index Score
- name: SIV
type: number
meta:
label: Speed Index Value
- name: TTIS
type: number
meta:
label: Time to Interactive Score
- name: TTIV
type: number
meta:
label: Time to Interactive Value
- name: FPIDS
type: number
meta:
label: First Potential Input Delay Score
- name: FPIDV
type: number
meta:
label: First Potential Input Delay Value

View File

@ -0,0 +1,29 @@
name: lighthouseSubpath
meta:
label: Lighthouse Subpaths
muiIcon: web
views:
- type: table
columns:
- source: lighthouseSubpath
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- type: string
name: lighthouseSubpath
meta:
label: PagespeedPaths

View File

@ -4,70 +4,39 @@ name: medialib
uploadPath: ../media/medialib uploadPath: ../media/medialib
meta: meta:
allowExportAll: true
label: label:
de: Medienbibliothek de: Medienbibliothek
en: Media Library en: Media Library
muiIcon: multimedia muiIcon: multimedia
defaultSort: defaultSort:
field: sort field: sort
order: MANUALLY #alternativ auch ASC und DESC möglich order: MANUALLY
backup:
active: true
collectionName: backups
quickEdit:
enabled: true
fields:
- title
- alt
- file
# "defaultImageFilter" dient auch hier nur zur Reduzierung der # "defaultImageFilter" dient auch hier nur zur Reduzierung der
# Bildgröße bei der Anzeige im tibi-admin (Listen). # Bildgröße bei der Anzeige im tibi-admin (Listen).
# Die Bildgröße für die Einbindung ins erzeugte HTML des ContentBuilder # Die Bildgröße für die Einbindung ins erzeugte HTML des ContentBuilder
# hat hiermit nix zu tun. # hat hiermit nix zu tun.
defaultImageFilter: s defaultImageFilter: xs
multiupload: multiupload:
fields: fields: []
- source: description #specify wich fields should be editable in Modal, if property isnt set, then all fields will automatically be selected
prefilledFields: #specifies wich fields should have a default value, wont be visible to the user, just an informational text for wich fields will recieve an default value.
- source: title
defaultValue:
eval: |
(function(){
return "Title" + $file.name
})()
# Wird unter "image-/file-/videoSelect" im ContentBuilder Feld kein
# "subNavigation" Index definiert, werden auch folgende "views"
# verwendet.
views: views:
- type: simpleList
mediaQuery: "(min-width: 0px)"
selectionPriority: 3 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
primaryText:
source: path
filter: true
secondaryText:
source: title
filter: true
tertiaryText:
source: description
filter: true
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file
pageAsDropArea: true
columns:
- source: file
- source: updateTime
type: datetime
label: letztes Update
- source: title
filter: true
- source: description
filter: true
- type: table - type: table
mediaQuery: "(min-width: 768px)" mediaQuery: "(min-width: 0px)"
defaultSelect: false
selectionPriority: 2 selectionPriority: 2
fileDropArea: fileDropArea:
label: label:
@ -77,16 +46,13 @@ meta:
} }
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" } helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file targetField: file
pageAsDropArea: true pageAsDropArea: false
columns: columns:
- source: file - source: file
name: Datei
- source: updateTime - source: updateTime
type: datetime type: datetime
label: letztes Update label: letztes Update
- source: title
filter: true
- source: description
filter: true
- type: cardList - type: cardList
mediaQuery: "(min-width: 1200px)" mediaQuery: "(min-width: 1200px)"
@ -103,73 +69,27 @@ meta:
fields: fields:
- source: file - source: file
name: Datei
- source: updateTime - source: updateTime
type: datetime type: datetime
label: letztes Update label: letztes Update
- source: title
filter: true
- source: description
filter: true
# Wird ein "subNavigation" Index für "image-/file-/videoSelect" definiert,
# wird die entsprechende Navigation aus folgender Liste angesprochen.
# "0" ist dabei der Index für das erste Element dieser Liste.
subNavigation: subNavigation:
- # Der "name" der Navigation ist für die Mediathek nicht von Bedeutung,
# kann aber für "eval"-Code interessant sein.
name: modal
# Auf "label" wurde hier verzichtet, damit dieses Element nicht in der
# Hauptnavigation des tibi-admin auftaucht.
# Folgende Ansicht wird für unsere Auswahl der Datei im ContentBuilder
# angeboten.
views:
- type: cards
mediaQuery: "(min-width: 0px)"
fields:
- source: file
- source: updateTime
type: datetime
label: letztes Update
- source: title
filter: true
- source: description
filter: true
# Damit der ContentBuilder weiß, welche Datei ausgewählt wurde, ist
# ist folgender "defaultCallback" notwendig.
# Die Funktion wird beim Klick auf die entsprechende Datei aufgerufen.
# Als Funktionsparameter steht der gesamte Datensatz der Auswahl zur
# Verfügung.
# Die Funktionen "parent.selectAsset" und "parent.focus" sind ContentBuilder
# spezifisch und schließen die Listenansicht direkt nach Übergabe der
# Datei-URL.
# Die URL setzt sich aus dem Pfad zur Datei und dem Filter "l" zusammen.
# Es wurde eine relative URL konstruiert, da das ContentBuilder-Widget
# mit "baseHref" zur Projekt-URL erstellt wird.
defaultCallback:
eval: |
//js
(entry) => {
parent.selectAsset("medialib/" + entry.id + "/" + entry.file?.src + "?filter=l")
parent.focus()
}
//!js
- name: modalForeign # Name des Eingabefelds oder der Ansicht. - name: modalForeign # Name des Eingabefelds oder der Ansicht.
defaultSort: # Standard-Sortierkriterien, die angewendet werden, wenn keine anderen Sortierkriterien spezifiziert sind. defaultSort: # Standard-Sortierkriterien, die angewendet werden, wenn keine anderen Sortierkriterien spezifiziert sind.
field: "path" # Standardmäßig wird nach dem "path"-Feld sortiert. field: "path" # Standardmäßig wird nach dem "path"-Feld sortiert.
order: "ASC" # Standardmäßig wird in aufsteigender Reihenfolge (ASC) sortiert. order: "ASC" # Standardmäßig wird in aufsteigender Reihenfolge (ASC) sortiert.
views: # Liste der Ansichten, die in diesem Feld angezeigt werden können. views: # Liste der Ansichten, die in diesem Feld angezeigt werden können.
- type: table # Es wird eine Tabellenansicht verwendet. - type: table # Es wird eine Tabellenansicht verwendet.
mediaQuery: "(min-width: 0px)" # Die Tabellenansicht wird nur angezeigt, wenn die Bildschirmbreite mindestens 0px beträgt.
columns: # Liste der Spalten, die in der Tabelle angezeigt werden. columns: # Liste der Spalten, die in der Tabelle angezeigt werden.
- path # Es wird nur die Spalte "path" angezeigt. - source: file
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist. defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
eval: | # Der Code wird als JavaScript evaluiert. eval: | # Der Code wird als JavaScript evaluiert.
//js //js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument. (entry) => {
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen. parent.selectEntry(entry)
} }
//!js //!js
@ -191,37 +111,76 @@ projections:
dashboard: dashboard:
select: select:
hooks: hooks:
delete: post:
return: return:
type: javascript type: javascript
file: hooks/medialib/delete_return.js file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
imageFilter:
xs:
- fit: true
height: 90
width: 90
resampling: lanczos
quality: 60
s:
- fit: true
height: 300
width: 300
resampling: lanczos
quality: 60
m:
- fit: true
height: 600
width: 600
resampling: lanczos
quality: 60
l:
- fit: true
height: 1200
width: 1200
resampling: lanczos
quality: 60
xl:
- fit: true
height: 2000
width: 2000
resampling: lanczos
quality: 60
fields: fields:
# Ein Feld vom Typ "file" wird für die Mediathek natürlich
# benötigt.
- name: file - name: file
type: file type: file
meta: meta:
label: label:
de: Datei de: Datei
en: File en: File
- name: alt
type: string
meta:
label:
de: Alternativtext
en: Alternative text
helperText:
de: Der Alternativtext wird angezeigt, wenn die Datei nicht geladen werden kann.
en: The alternative text is displayed if the file cannot be loaded.
- name: title - name: title
type: string type: string
meta: meta:
label: label:
de: Titel de: Titel
en: Title en: Title
- name: description helperText:
type: string de: Der Titel wird angezeigt, wenn die Datei geladen wird.
meta: en: The title is displayed when the file is loaded.
widget: richtext
label:
de: Kurzbeschreibung
en: Short Description
- name: sort - name: sort
type: number type: number
meta: meta:
label: label:
de: Manuelle Sortierung de: Manuelle Sortierung

100
api/collections/module.yml Normal file
View File

@ -0,0 +1,100 @@
name: module
meta:
label: Module
allowExportAll: true
backup:
active: true
collectionName: backups
views:
- type: table
columns:
- source: type
name: Typ
filter: true
subNavigation:
- name: modal
views:
- type: table
columns:
- source: type
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
eval: | # Der Code wird als JavaScript evaluiert.
//js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument.
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen.
}
//!js
hooks:
post:
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
imageFilter:
xs:
- fit: true
height: 90
width: 90
resampling: lanczos
quality: 60
s:
- fit: true
height: 300
width: 300
resampling: lanczos
quality: 60
m:
- fit: true
height: 600
width: 600
resampling: lanczos
quality: 60
l:
- fit: true
height: 1240
width: 1240
resampling: lanczos
quality: 60
xl:
- fit: true
height: 2000
width: 2000
resampling: lanczos
quality: 60
fields:
- name: type
type: string
meta:
label: Modultyp
helperText: "Wählen Sie den Typ des Moduls aus."
widget: select
choices:
- name: { de: "Formular", en: "Form" }
id: form
- name: form
type: object
meta:
widget: containerLessObject
subFields: !include fieldLists/formular/form.yml

View File

@ -0,0 +1,96 @@
name: navigation
uploadPath: ../media/navigation
meta:
label: "Navigation"
muiIcon: navigation
allowExportAll: true
backup:
active: true
collectionName: backups
views:
- type: simpleList
mediaQuery: "(max-width:599px)"
primaryText: tree
- type: table
mediaQuery: "(min-width:600px)"
columns:
- source: tree
name: Navigationsbaum
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: false
put: true
delete: false
hooks:
post:
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
fields:
- name: tree
type: number
meta:
label: Baum
widget: select
helperText: Die Servicenavigation sollte Seiten wie bspw. die Datneschutzerklärung oder das Impressum umfassen.
choices:
- id: 0
name:
de: Hauptnavigation
en: main navigation
- id: 1
name:
de: Servicenavigation
en: service navigation
- name: pages
type: object[]
meta:
label:
de: Seiten
en: pages
folding:
previewUnfolded: name
previewFolded: name
widget: containerLessObjectArray
subFields:
- name: name
type: string
meta:
label:
de: Name
en: name
helperText: Dieser Name wird zur Anzeige in der Navigation verwendet.
- name: page
type: string
meta:
label:
de: Seite
en: page
widget: select
choices:
endpoint: page
params:
sort: path
projection: navigation
mapping:
id: id
name: path

View File

@ -7,6 +7,7 @@ meta:
label: { de: "SSR Dummy", en: "ssr dummy" } label: { de: "SSR Dummy", en: "ssr dummy" }
muiIcon: server muiIcon: server
rowIdentTpl: { twig: "{{ id }}" } rowIdentTpl: { twig: "{{ id }}" }
views: views:
- type: simpleList - type: simpleList
mediaQuery: "(max-width: 600px)" mediaQuery: "(max-width: 600px)"
@ -55,6 +56,7 @@ fields:
- name: path - name: path
type: string type: string
index: [single, unique] index: [single, unique]
- name: content - name: content
type: string type: string
meta: meta:

View File

@ -1,58 +1,25 @@
# Der Namespace legt die eigentliche Projektbezeichnung und den Datenbankkontext fest. namespace: tibi_starter
# Er sollte nach Projektinitialisierung auf dem tibi-server nicht mehr angepasst werden.
# In den Projekteinstellungen im tibi-server kann der Namespace durch einen Datenbankeintrag
# überschrieben werden.
# Über die Bezeichnung des Namespace plus einen Prefix der in der globalen Server-Konfig
# hinterlegt ist, definiert sich der Datenbank-Name innerhalb der MongoDB.
namespace: demo
# Das "meta"-Objekt ist frei definierbar, wird aber vom tibi-admin in spezieller Form erwartet.
# Mögliche Angaben, die der tibi-admin versteht, sind hier mit aufgeführt.
meta: meta:
# OpenAPI Spezifikationen
openapi: openapi:
#info:
# title: Demo API
# version: 1.0.0
# description: Eine Demo-API für den tibi-server
servers: servers:
- url: https://tibi-admin-server.code.testversion.online/api/v1/_/demo - url: https://tibi-admin-server.code.testversion.online/api/v1/_/demo
description: code-server description: code-server
# Pfad zu einer Bilddatei die als Projektbild im tibi-admin verwendet wird dashboard: helper/dashboard.yml
imageUrl:
eval: "$projectBase + '_/assets/img/pic.jpg'"
# Liste möglicher Berechtigungen, die Benutzern zugeordnet werden können
permissions:
- # Name der Berechtigung
name: news
# Label für die Anzeige im Admin
# (kann string oder object mit Sprachen als keys sein)
label:
de: Neuigkeiten
en: News
- name: pages
label:
de: Seiten
en: Pages
# "collections" ist eine Auflistung von Kollektions-Konfigurationen.
# Hier bietet sich eine Auslagerung und Einbindung via YAML-Tag "!include" an.
collections: collections:
- !include collections/democol.yml - !include collections/backups.yml
- !include collections/content.yml
- !include collections/forms.yml
- !include collections/lighthouse.yml
- !include collections/lighthouseSubpath.yml
- !include collections/medialib.yml - !include collections/medialib.yml
# Dummy Kollektion für Hooks, die für serverseitiges Rendering benötigt werden - !include collections/module.yml
- !include collections/navigation.yml
- !include collections/ssr.yml - !include collections/ssr.yml
# Unter "jobs" können Jobs definiert werden, die regelmäßig ausgeführt werden sollen.
jobs: jobs:
- !include jobs/demojob.yml - cron: "0 0 * * 1"
type: javascript
# Werden Dateien innerhalb vom tibi-admin benötigt, bietet es sich an diese über file: jobs/lighthouse.js
# "assets"-Pfade erreichbar zu machen.
assets:
- !include assets/demoassets.yml
- name: img
path: img

View File

@ -1 +1,2 @@
TOKEN=geheim TOKEN=geheim
SSR_TOKEN=owshwerNwoa

279
api/helper/dashboard.yml Normal file
View File

@ -0,0 +1,279 @@
majorItems:
- type: "sectionTitle"
title: { de: "Website Perfomance", en: "Website Perfomance" }
appendix:
collection: lighthouse
eval: |
(function(){
return " " + new Date($date).toLocaleDateString() + ""
})()
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: performance
yAxis: latestValue
graphName: { de: "Perfomance Score", en: "Perfomance Score" }
dateTimeField: insertTime
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: accessibility
yAxis: latestValue
graphName: { de: "Accessibility Score", en: "Accessibility Score" }
dateTimeField: insertTime
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: bestPractices
yAxis: latestValue
graphName: { de: "Best Practices Score", en: "Best Practices Score" }
dateTimeField: insertTime
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: seo
yAxis: latestValue
graphName: { de: "SEO Score", en: "SEO Score" }
dateTimeField: insertTime
- type: swiper # Art des Elements, hier ein Swiper
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-12"
small: "col-12"
large: "col-6 row-2-4"
elements: # Liste der Elemente in diesem Swiper
- type: graph
title:
value: { de: "Ladezeit (Score)", en: "Loadtime (Score)" }
xAxis: manual
until: "lastYear"
filter: false #deaktiviert die Filter möglichkeit für den Nutzer beim diagramm, normalerweise aktiviert. Hierbei sind alle kombinationen x >= until möglich
columns:
- name: { de: '["Erstes sichtbares", "Element"]', en: '["First Contentful", "Paint"]' }
field: lighthouseMetrics.FCPS
- name: { de: '["Erstes bedeutsames", "Element"]', en: '["First Meaningful", "Paint"]' }
field: lighthouseMetrics.FMPS
- name:
{
de: '["Maximale potenzielle", "erste", "ingabeverzögerung"]',
en: '["Max Potential", "First Input", "Delay"]',
}
field: lighthouseMetrics.FPIDS
- name: { de: '["Zeit bis", "zur", "Interaktivität"]', en: '["Time to", "Interactive"]' }
field: lighthouseMetrics.TTIS
- name: { de: '["Geschwindigkeitsindex"]', en: '["Speed Index"]' }
field: lighthouseMetrics.SIS
graphType: "bar"
graphs:
- graphName: { de: "Lighthouse Metriken", en: "Lighthouse Metrics" }
yAxis: latestValue
collection: lighthouse
dateTimeField: insertTime
- type: graph
title:
value: { de: "Ladezeit (Sekunden)", en: "Loadtime (seconds)" }
xAxis: manual
until: "lastYear"
filter: false #deaktiviert die Filter möglichkeit für den Nutzer beim diagramm, normalerweise aktiviert. Hierbei sind alle kombinationen x >= until möglich
columns:
- name: { de: '["Erstes sichtbares", "Element"]', en: '["First Contentful", "Paint"]' }
field: lighthouseMetrics.FCPV
- name: { de: '["Erstes bedeutsames", "Element"]', en: '["First Meaningful", "Paint"]' }
field: lighthouseMetrics.FMPV
- name:
{
de: '["Maximale potenzielle", "erste", "ingabeverzögerung"]',
en: '["Max Potential", "First Input", "Delay"]',
}
field: lighthouseMetrics.FPIDV
- name: { de: '["Zeit bis", "zur", "Interaktivität"]', en: '["Time to", "Interactive"]' }
field: lighthouseMetrics.TTIV
- name: { de: '["Geschwindigkeitsindex"]', en: '["Speed Index"]' }
field: lighthouseMetrics.SIV
graphType: "bar"
graphs:
- graphName: { de: "Lighthouse Metriken", en: "Lighthouse Metrics" }
yAxis: latestValue
collection: lighthouse
dateTimeField: insertTime
- type: "sectionTitle"
title: { de: "Seiteninhalte", en: "Page content" }
- collection: content
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: navigation
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: forms
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- type: "sectionTitle"
title: { de: "Aktionen", en: "Actions" }
- collection: lighthouse
type: action
action: "Lighthouse Durchlauf starten"
backgroundAction: true
modalText:
{
de: "Zur Analyse der Website werden einige Zeitintensive prozesse gestartet, daher wird dies im Hintergrund ausgeführt. Es kann einige Minuten dauern bis das Dashboard aktuallisiert wird, bitte haben Sie etwas Geduld.",
en: "To analyze the website, some time-intensive processes are started, so this is done in the background. It may take a few minutes for the dashboard to be updated, please be patient.",
}
properties:
url: https://allkids-erfurt.de
type: post
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
minorItems: []

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