generated from cms/tibi-docs
zwischenstand
This commit is contained in:
parent
e5fba13002
commit
5763db4e22
BIN
.yarn/cache/@floating-ui-core-npm-1.6.0-47cc2a9b3a-2e25c53b0c.zip
vendored
Normal file
BIN
.yarn/cache/@floating-ui-core-npm-1.6.0-47cc2a9b3a-2e25c53b0c.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@floating-ui-dom-npm-1.6.1-55a222b4ad-5565e4dee6.zip
vendored
Normal file
BIN
.yarn/cache/@floating-ui-dom-npm-1.6.1-55a222b4ad-5565e4dee6.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@floating-ui-utils-npm-0.2.1-5ad70234fc-9ed4380653.zip
vendored
Normal file
BIN
.yarn/cache/@floating-ui-utils-npm-0.2.1-5ad70234fc-9ed4380653.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/fluent-svelte-npm-1.6.0-b51efa5efd-1b2ac33343.zip
vendored
Normal file
BIN
.yarn/cache/fluent-svelte-npm-1.6.0-b51efa5efd-1b2ac33343.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/focus-trap-npm-6.9.4-64b032bc16-0b4cebcc11.zip
vendored
Normal file
BIN
.yarn/cache/focus-trap-npm-6.9.4-64b032bc16-0b4cebcc11.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/ssr-window-npm-4.0.2-01f9c0151e-df18260092.zip
vendored
Normal file
BIN
.yarn/cache/ssr-window-npm-4.0.2-01f9c0151e-df18260092.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/svelte-floating-ui-npm-1.5.8-f85bef77a4-f35ec8828d.zip
vendored
Normal file
BIN
.yarn/cache/svelte-floating-ui-npm-1.5.8-f85bef77a4-f35ec8828d.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/svelte-select-npm-5.8.3-55828a830b-f3cf89f221.zip
vendored
Normal file
BIN
.yarn/cache/svelte-select-npm-5.8.3-55828a830b-f3cf89f221.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/swiper-npm-9.4.1-38d46d35a3-1180b3b766.zip
vendored
Normal file
BIN
.yarn/cache/swiper-npm-9.4.1-38d46d35a3-1180b3b766.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/tabbable-npm-5.3.3-baf35cffe9-1aa56e1bb6.zip
vendored
Normal file
BIN
.yarn/cache/tabbable-npm-5.3.3-baf35cffe9-1aa56e1bb6.zip
vendored
Normal file
Binary file not shown.
2
Makefile
2
Makefile
@ -10,6 +10,8 @@ help: ## show this help
|
|||||||
@echo MAKE TARGETS
|
@echo MAKE TARGETS
|
||||||
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
docker-up: ## bring docker compose stack up in background
|
docker-up: ## bring docker compose stack up in background
|
||||||
$(DOCKER_COMPOSE) --profile tibi up -d
|
$(DOCKER_COMPOSE) --profile tibi up -d
|
||||||
|
|
||||||
|
12
api/assets/dist.yml
Normal file
12
api/assets/dist.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# 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
|
@ -41,22 +41,30 @@ fields:
|
|||||||
- name: collectionName
|
- name: collectionName
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Collection Name
|
label:
|
||||||
|
de: Collection Name
|
||||||
|
en: Collection Name
|
||||||
|
|
||||||
- name: entryId
|
- name: entryId
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Entry ID
|
label:
|
||||||
|
de: Entry ID
|
||||||
|
en: Entry ID
|
||||||
|
|
||||||
- name: versionNr
|
- name: versionNr
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Version Nr
|
label:
|
||||||
|
de: Version Nr
|
||||||
|
en: Version Nr
|
||||||
|
|
||||||
- name: manipulatedBy
|
- name: manipulatedBy
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Manipulated By
|
label:
|
||||||
|
de: Manipulated By
|
||||||
|
en: Manipulated By
|
||||||
|
|
||||||
- name: eventDescription
|
- name: eventDescription
|
||||||
type: string
|
type: string
|
||||||
@ -65,38 +73,59 @@ fields:
|
|||||||
widget: select
|
widget: select
|
||||||
choices:
|
choices:
|
||||||
- id: create
|
- id: create
|
||||||
name: Create
|
name:
|
||||||
|
de: Erstellt
|
||||||
|
en: Create
|
||||||
- id: update
|
- id: update
|
||||||
name: Update
|
name:
|
||||||
|
de: Update
|
||||||
|
en: Update
|
||||||
- id: delete
|
- id: delete
|
||||||
name: Delete
|
name:
|
||||||
|
de: Gelöscht
|
||||||
|
en: Delete
|
||||||
- id: recreate
|
- id: recreate
|
||||||
name: Recreate
|
name:
|
||||||
|
de: Wiederhergestellt
|
||||||
|
en: Recreate
|
||||||
- id: activate
|
- id: activate
|
||||||
name: Activate
|
name:
|
||||||
|
de: Aktiviert
|
||||||
|
en: Activate
|
||||||
|
|
||||||
- name: updateLogs
|
- name: updateLogs
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Veränderungen
|
label:
|
||||||
|
de: Veränderungen
|
||||||
|
en: Update Logs
|
||||||
|
|
||||||
subFields:
|
subFields:
|
||||||
- name: field
|
- name: field
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Feldname
|
label:
|
||||||
|
de: Feldname
|
||||||
|
en: Fieldname
|
||||||
|
|
||||||
- name: previous
|
- name: previous
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Vorheriger Wert
|
label:
|
||||||
|
de: Vorheriger Wert
|
||||||
|
en: Previous Value
|
||||||
|
|
||||||
- name: current
|
- name: current
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Aktueller Wert
|
label:
|
||||||
|
|
||||||
|
de: Aktueller Wert
|
||||||
|
en: Current Value
|
||||||
|
|
||||||
- name: entry
|
- name: entry
|
||||||
type: object
|
type: object
|
||||||
meta:
|
meta:
|
||||||
label: Entry
|
label:
|
||||||
|
de: Eintrag
|
||||||
|
en: Entry
|
||||||
|
@ -37,7 +37,6 @@ meta:
|
|||||||
|
|
||||||
tablist:
|
tablist:
|
||||||
activeTab: general
|
activeTab: general
|
||||||
|
|
||||||
tabs:
|
tabs:
|
||||||
- name: general
|
- name: general
|
||||||
label: Allgemein
|
label: Allgemein
|
||||||
@ -124,8 +123,12 @@ fields:
|
|||||||
- type: string
|
- type: string
|
||||||
name: path
|
name: path
|
||||||
meta:
|
meta:
|
||||||
label: Pfad
|
label:
|
||||||
helperText: "Ein Pfad sollte mit einem / starten und ohne eins enden."
|
de: Pfad
|
||||||
|
en: Path
|
||||||
|
helperText:
|
||||||
|
de: "Ein Pfad sollte mit einem / starten und ohne eins enden."
|
||||||
|
en: "A path should start with a / and end without one."
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -133,73 +136,20 @@ fields:
|
|||||||
small: "col-12"
|
small: "col-12"
|
||||||
large: "col-6"
|
large: "col-6"
|
||||||
|
|
||||||
- type: boolean
|
- !include fields/active.yml
|
||||||
name: active
|
- !include fields/contentType.yml
|
||||||
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
|
- !include fields/pageTitle.yml
|
||||||
name: type
|
- !include fields/rows.yml
|
||||||
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
|
- name: meta
|
||||||
type: object
|
type: object
|
||||||
meta:
|
meta:
|
||||||
label: Meta Agaben
|
label:
|
||||||
|
de: Meta Agaben
|
||||||
|
en: Meta Data
|
||||||
dependsOn:
|
dependsOn:
|
||||||
eval: $.type == "page"
|
eval: $.type == "page"
|
||||||
subFields: !include fieldLists/meta.yml
|
subFields: !include fieldLists/meta.yml
|
||||||
|
|
||||||
- name: sort
|
- !include fields/manualSort.yml
|
||||||
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.
|
|
||||||
|
@ -1,16 +1,49 @@
|
|||||||
# attribute auf column ebene
|
|
||||||
|
|
||||||
- name: contentType
|
- name: contentType
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: ""
|
label:
|
||||||
|
de: Inhaltstyp
|
||||||
|
en: Content Type
|
||||||
widget: select
|
widget: select
|
||||||
choices:
|
choices:
|
||||||
- name: Bild
|
- name:
|
||||||
id: image
|
de: Bilder
|
||||||
|
en: Images
|
||||||
|
id: images
|
||||||
|
|
||||||
- name: Modul Import
|
- name:
|
||||||
|
de: Modul Import
|
||||||
|
en: Module Import
|
||||||
id: moduleImport
|
id: moduleImport
|
||||||
|
- name:
|
||||||
|
de: Formular
|
||||||
|
en: form
|
||||||
|
id: form
|
||||||
|
|
||||||
- name: Text
|
- name:
|
||||||
|
de: Text
|
||||||
|
en: Text
|
||||||
id: text
|
id: text
|
||||||
|
- name:
|
||||||
|
de: Google Maps
|
||||||
|
en: Google Maps
|
||||||
|
id: googleMaps
|
||||||
|
- !include ../fields/images.yml
|
||||||
|
|
||||||
|
- name: moduleImport
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Modul Import
|
||||||
|
en: Module Import
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent.contentType == 'moduleImport' || $parent.contentType == 'form'
|
||||||
|
widget: foreignKey
|
||||||
|
foreign:
|
||||||
|
collection: module
|
||||||
|
id: id
|
||||||
|
subNavigation: 0
|
||||||
|
render:
|
||||||
|
defaultCollectionViews: true
|
||||||
|
|
||||||
|
- !include ../fields/text.yml
|
||||||
|
@ -13,12 +13,17 @@ subFields:
|
|||||||
- name: groupTitle
|
- name: groupTitle
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Checkbox Gruppe Titel
|
label:
|
||||||
|
de: Gruppe Titel
|
||||||
|
en: Group title
|
||||||
|
|
||||||
- name: checkboxes
|
- name: checkboxes
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Checkbox Gruppe
|
label:
|
||||||
|
|
||||||
|
de: Checkbox Gruppe
|
||||||
|
en: Checkbox Group
|
||||||
direction: row
|
direction: row
|
||||||
widget: containerLessObjectArray
|
widget: containerLessObjectArray
|
||||||
subFields:
|
subFields:
|
||||||
|
@ -11,6 +11,7 @@ meta:
|
|||||||
eval: $parent?.inputWidgets?.includes('defaultCalendar')
|
eval: $parent?.inputWidgets?.includes('defaultCalendar')
|
||||||
subFields:
|
subFields:
|
||||||
- name: standardInputProperties
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
meta:
|
meta:
|
||||||
widget: containerLessObject
|
widget: containerLessObject
|
||||||
subFields: !include standardInputProperties.yml
|
subFields: !include standardInputProperties.yml
|
||||||
|
@ -10,29 +10,25 @@ subFields:
|
|||||||
- name: props
|
- name: props
|
||||||
type: object
|
type: object
|
||||||
meta:
|
meta:
|
||||||
label: Datumauswahl Eigenschaften
|
label:
|
||||||
|
de: Datumauswahl Eigenschaften
|
||||||
|
en: Date selection properties
|
||||||
subFields:
|
subFields:
|
||||||
- name: allowedDateRanges
|
- name: allowedDateRanges
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Erlaubte Datumsbereiche
|
label:
|
||||||
|
de: Erlaubte Datumsbereiche
|
||||||
|
en: Allowed date ranges
|
||||||
widget: containerLessObjectArray
|
widget: containerLessObjectArray
|
||||||
subFields:
|
subFields:
|
||||||
- name: from
|
- !include ../../fields/from.yml
|
||||||
type: date
|
|
||||||
meta:
|
|
||||||
label: Von
|
|
||||||
widget: date
|
|
||||||
containerProps:
|
|
||||||
layout:
|
|
||||||
size:
|
|
||||||
default: "col-6"
|
|
||||||
small: "col-12"
|
|
||||||
large: "col-6"
|
|
||||||
- name: to
|
- name: to
|
||||||
type: date
|
type: date
|
||||||
meta:
|
meta:
|
||||||
label: Bis
|
label:
|
||||||
|
de: Bis
|
||||||
|
en: To
|
||||||
widget: date
|
widget: date
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
@ -41,34 +37,10 @@ subFields:
|
|||||||
small: "col-12"
|
small: "col-12"
|
||||||
large: "col-6"
|
large: "col-6"
|
||||||
|
|
||||||
- name: excludeDays
|
- !include ../../fields/excludedDays.yml
|
||||||
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
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
meta:
|
meta:
|
||||||
widget: containerLessObject
|
widget: containerLessObject
|
||||||
subFields: !include standardInputProperties.yml
|
subFields: !include standardInputProperties.yml
|
||||||
|
@ -27,17 +27,7 @@
|
|||||||
small: "col-12"
|
small: "col-12"
|
||||||
large: "col-6"
|
large: "col-6"
|
||||||
|
|
||||||
- name: emailCC
|
- !include ../../fields/emailCC.yml
|
||||||
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
|
- name: emailIntroduction
|
||||||
type: string
|
type: string
|
||||||
@ -49,10 +39,22 @@
|
|||||||
de: "Bsp: Hallo xyz, sie haben eine neue Kaufanfrage erhalten!"
|
de: "Bsp: Hallo xyz, sie haben eine neue Kaufanfrage erhalten!"
|
||||||
en: "E.g.: Hello xyz, you have received a new purchase request!"
|
en: "E.g.: Hello xyz, you have received a new purchase request!"
|
||||||
|
|
||||||
|
- name: sendFormBtnText
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Formular Absenden Button Text
|
||||||
|
en: Form Submit Button Text
|
||||||
|
helperText:
|
||||||
|
de: "Bsp: Absenden"
|
||||||
|
en: "E.g.: Submit"
|
||||||
|
|
||||||
- name: rows
|
- name: rows
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Zeile
|
label:
|
||||||
|
de: Zeile
|
||||||
|
en: Row
|
||||||
widget: grid
|
widget: grid
|
||||||
addElementLabel: Zeile Hinzufügen
|
addElementLabel: Zeile Hinzufügen
|
||||||
|
|
||||||
@ -60,7 +62,9 @@
|
|||||||
- name: title
|
- name: title
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Zeilenname
|
label:
|
||||||
|
de: Zeilenname
|
||||||
|
en: Row name
|
||||||
helperText:
|
helperText:
|
||||||
de: "Sollte der Titel keinen Wert enthalten, wird kein Zeilenname angezeigt!"
|
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!"
|
en: "If the title does not contain a value, no row name will be displayed!"
|
||||||
@ -68,7 +72,9 @@
|
|||||||
- name: emailTitle
|
- name: emailTitle
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Email Abschnitt Titel
|
label:
|
||||||
|
de: Email Abschnitt Titel
|
||||||
|
en: Email section title
|
||||||
helperText:
|
helperText:
|
||||||
de: "Sollte der Titel keinen Wert enthalten, wird kein Abschnitt Titel angezeigt!"
|
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!"
|
en: "If the title does not contain a value, no section title will be displayed!"
|
||||||
@ -77,16 +83,38 @@
|
|||||||
type: object[]
|
type: object[]
|
||||||
|
|
||||||
meta:
|
meta:
|
||||||
label: Spalte
|
label:
|
||||||
addElementLabel: Spalte hinzufügen
|
de: Spalte
|
||||||
|
en: Column
|
||||||
|
addElementLabel:
|
||||||
|
de: Spalte hinzufügen
|
||||||
|
en: Add column
|
||||||
widget: grid
|
widget: grid
|
||||||
direction: horizontal
|
direction: horizontal
|
||||||
subFields:
|
subFields:
|
||||||
- name: title
|
- name: title
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Überschrift
|
label:
|
||||||
helperText: Optional
|
de: Überschrift
|
||||||
|
en: Headline
|
||||||
|
helperText:
|
||||||
|
de: Optional
|
||||||
|
en: Optional
|
||||||
|
|
||||||
|
- name: emailTitle
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Email Abschnitt Titel
|
||||||
|
en: Email section title
|
||||||
|
|
||||||
|
- name: annotation
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Zusatzinformation
|
||||||
|
en: Additional information
|
||||||
|
|
||||||
- name: inputWidgets
|
- name: inputWidgets
|
||||||
type: string[]
|
type: string[]
|
||||||
@ -96,33 +124,63 @@
|
|||||||
en: Displayed input fields
|
en: Displayed input fields
|
||||||
widget: selectArray
|
widget: selectArray
|
||||||
choices:
|
choices:
|
||||||
- name: Nummernblock
|
- name:
|
||||||
|
de: Nummernblock
|
||||||
|
en: Number block
|
||||||
id: labelNumber
|
id: labelNumber
|
||||||
|
|
||||||
- name: Zeitenauswahlfeld
|
- name:
|
||||||
|
de: Zeitenauswahlfeld
|
||||||
|
en: Time selection field
|
||||||
id: times
|
id: times
|
||||||
|
|
||||||
- name: Auswahlfeld
|
- name:
|
||||||
|
de: Auswahlfeld
|
||||||
|
en: Selection field
|
||||||
id: select
|
id: select
|
||||||
|
|
||||||
- name: Datumsauswahl - Standard Kalender
|
- name:
|
||||||
|
de: Datumsauswahl - Standard Kalender
|
||||||
|
en: Date selection - Standard calendar
|
||||||
id: defaultCalendar
|
id: defaultCalendar
|
||||||
|
|
||||||
- name: Datumauswahl - Custom Kalender
|
- name:
|
||||||
|
de: Datumauswahl - Custom Kalender
|
||||||
|
en: Date selection - Custom calendar
|
||||||
id: customCalendar
|
id: customCalendar
|
||||||
|
|
||||||
- name: Nummerfeld
|
- name:
|
||||||
|
de: Nummerfeld
|
||||||
|
en: Number field
|
||||||
id: number
|
id: number
|
||||||
|
|
||||||
- name: Checkbox Gruppe
|
- name:
|
||||||
|
de: Checkbox Gruppe
|
||||||
|
en: Checkbox group
|
||||||
id: checkboxGroup
|
id: checkboxGroup
|
||||||
|
|
||||||
- name: Mehrfachauswahl
|
- name:
|
||||||
|
de: Mehrfachauswahl
|
||||||
|
en: Multiple selection
|
||||||
id: multiSelect
|
id: multiSelect
|
||||||
|
|
||||||
- name: Textfeld
|
- name:
|
||||||
|
de: Textfeld
|
||||||
|
en: Text field
|
||||||
id: text
|
id: text
|
||||||
|
|
||||||
|
- name:
|
||||||
|
de: Zeitenauswahl
|
||||||
|
en: Time selection
|
||||||
|
id: timeSelect
|
||||||
|
|
||||||
|
- name:
|
||||||
|
de: Standardauswahl
|
||||||
|
en: Standard selection
|
||||||
|
id: standardSelect
|
||||||
|
|
||||||
|
- !include standardSelect.yml
|
||||||
|
|
||||||
- !include labelNumberInput.yml
|
- !include labelNumberInput.yml
|
||||||
- !include timesInput.yml
|
- !include timesInput.yml
|
||||||
- !include dateInput.yml
|
- !include dateInput.yml
|
||||||
@ -131,3 +189,4 @@
|
|||||||
- !include datePicker.yml
|
- !include datePicker.yml
|
||||||
- !include multiSelectInput.yml
|
- !include multiSelectInput.yml
|
||||||
- !include textInputs.yml
|
- !include textInputs.yml
|
||||||
|
- !include timeSelect.yml
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
name: labelNumberInput
|
name: labelNumberInput
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Nummer block
|
label:
|
||||||
|
de: Nummer block
|
||||||
|
en: Number block
|
||||||
dependsOn:
|
dependsOn:
|
||||||
eval: $parent?.inputWidgets?.includes('labelNumber')
|
eval: $parent?.inputWidgets?.includes('labelNumber')
|
||||||
helperText:
|
helperText:
|
||||||
@ -12,7 +14,9 @@ subFields:
|
|||||||
- name: group
|
- name: group
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Gruppe
|
label:
|
||||||
|
de: Gruppe
|
||||||
|
en: Group
|
||||||
helpterText:
|
helpterText:
|
||||||
de: Pflichtfeld seperierung. Aus einem Nummernblock muss mindestens eine Gruppe input haben.
|
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.
|
en: Mandatory field separation. A number block must have at least one group input.
|
||||||
@ -34,7 +38,9 @@ subFields:
|
|||||||
- name: emailName
|
- name: emailName
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Email Name
|
label:
|
||||||
|
de: Email Name
|
||||||
|
en: Email name
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -62,7 +68,9 @@ subFields:
|
|||||||
- name: emailName
|
- name: emailName
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Email Name
|
label:
|
||||||
|
de: Email Name
|
||||||
|
en: Email name
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
|
@ -8,6 +8,7 @@ meta:
|
|||||||
eval: $parent?.inputWidgets?.includes('multiSelect')
|
eval: $parent?.inputWidgets?.includes('multiSelect')
|
||||||
subFields:
|
subFields:
|
||||||
- name: standardInputProperties
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
meta:
|
meta:
|
||||||
widget: containerLessObject
|
widget: containerLessObject
|
||||||
subFields: !include standardInputProperties.yml
|
subFields: !include standardInputProperties.yml
|
||||||
@ -15,24 +16,32 @@ subFields:
|
|||||||
- name: options
|
- name: options
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Mehrfachauswahl Optionen
|
label:
|
||||||
|
de: Mehrfachauswahl Optionen
|
||||||
|
en: Multi Select Options
|
||||||
direction: row
|
direction: row
|
||||||
widget: containerLessObjectArray
|
widget: containerLessObjectArray
|
||||||
subFields:
|
subFields:
|
||||||
- name: name
|
- name: name
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Name
|
label:
|
||||||
|
de: Name
|
||||||
|
en: Name
|
||||||
|
|
||||||
- name: props
|
- name: props
|
||||||
type: object
|
type: object
|
||||||
meta:
|
meta:
|
||||||
label: Mehrfachauswahl Eigenschaften
|
label:
|
||||||
|
de: Mehrfachauswahl Eigenschaften
|
||||||
|
en: Multi Select Properties
|
||||||
subFields:
|
subFields:
|
||||||
- name: additionalAddableValues
|
- name: additionalAddableValues
|
||||||
type: boolean
|
type: boolean
|
||||||
meta:
|
meta:
|
||||||
label: Zusätzliche hinzufügbare Werte
|
label:
|
||||||
|
de: Zusätzliche hinzufügbare Werte
|
||||||
|
en: Additional addable values
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
|
@ -8,6 +8,7 @@ meta:
|
|||||||
eval: $parent?.inputWidgets?.includes('number')
|
eval: $parent?.inputWidgets?.includes('number')
|
||||||
subFields:
|
subFields:
|
||||||
- name: standardInputProperties
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
meta:
|
meta:
|
||||||
widget: containerLessObject
|
widget: containerLessObject
|
||||||
subFields: !include standardInputProperties.yml
|
subFields: !include standardInputProperties.yml
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
- name: emailTitle
|
- name: emailTitle
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Email Titel
|
label:
|
||||||
|
de: Email Titel
|
||||||
|
en: Email title
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -12,7 +14,9 @@
|
|||||||
- name: placeholder
|
- name: placeholder
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Platzhalter
|
label:
|
||||||
|
de: Platzhalter
|
||||||
|
en: Placeholder
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -23,7 +27,9 @@
|
|||||||
- name: notRequired
|
- name: notRequired
|
||||||
type: boolean
|
type: boolean
|
||||||
meta:
|
meta:
|
||||||
label: nicht Notwendig
|
label:
|
||||||
|
de: nicht Notwendig
|
||||||
|
en: not required
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -34,7 +40,9 @@
|
|||||||
- name: fieldOrder
|
- name: fieldOrder
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Reihenfolge
|
label:
|
||||||
|
de: Reihenfolge
|
||||||
|
en: Order
|
||||||
helperText:
|
helperText:
|
||||||
de: Die kleinste angegebene Zahl wird am weitesten oben in der Formularspalte stehen
|
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.
|
en: The smallest specified number will be at the top of the form column.
|
||||||
@ -44,8 +52,20 @@
|
|||||||
default: "col-6"
|
default: "col-6"
|
||||||
small: "col-12"
|
small: "col-12"
|
||||||
large: "col-6"
|
large: "col-6"
|
||||||
|
|
||||||
- name: textTitle
|
- name: textTitle
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Text Titel
|
label:
|
||||||
helperText: Alternative zu textPlaceholder
|
de: Text Titel
|
||||||
|
en: Text title
|
||||||
|
helperText:
|
||||||
|
de: Alternative zu textPlaceholder, steht dann über dem Inputfeld
|
||||||
|
en: Alternative to textPlaceholder, then stands above the input field
|
||||||
|
|
||||||
|
- name: groupTitle
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Gruppe Titel
|
||||||
|
en: Group title
|
||||||
|
58
api/collections/fieldLists/formular/standardSelect.yml
Normal file
58
api/collections/fieldLists/formular/standardSelect.yml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
name: standardSelect
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label: Standardauswahl
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent?.inputWidgets?.includes('standardSelect')
|
||||||
|
subFields:
|
||||||
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
widget: containerLessObject
|
||||||
|
subFields: !include standardInputProperties.yml
|
||||||
|
|
||||||
|
- name: selectEntries
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Auswahleingabe Möglichkeiten
|
||||||
|
en: Selection input options
|
||||||
|
widget: containerLessObjectArray
|
||||||
|
addElementLabel: Auswahleingabe hinzufügen
|
||||||
|
direction: horizontal
|
||||||
|
subFields:
|
||||||
|
- name: shownValue
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Angezeigter Wert
|
||||||
|
en: Displayed value
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
||||||
|
|
||||||
|
- name: value
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: per Email gesendeter Wert
|
||||||
|
en: Value sent by email
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
||||||
|
|
||||||
|
- name: defaultValue
|
||||||
|
type: boolean
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Standardwert
|
||||||
|
en: Default value
|
||||||
|
helperText:
|
||||||
|
de: "Wird dieser Wert ausgewählt, wird er als Standardwert gesetzt"
|
||||||
|
en: "If this value is selected, it will be set as the default value"
|
@ -7,6 +7,7 @@ meta:
|
|||||||
eval: $parent?.inputWidgets?.includes('text')
|
eval: $parent?.inputWidgets?.includes('text')
|
||||||
subFields:
|
subFields:
|
||||||
- name: standardInputProperties
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
meta:
|
meta:
|
||||||
widget: containerLessObject
|
widget: containerLessObject
|
||||||
subFields: !include standardInputProperties.yml
|
subFields: !include standardInputProperties.yml
|
||||||
@ -14,7 +15,9 @@ subFields:
|
|||||||
- name: textArea
|
- name: textArea
|
||||||
type: boolean
|
type: boolean
|
||||||
meta:
|
meta:
|
||||||
label: Großes Textfeld
|
label:
|
||||||
|
de: Großes Textfeld
|
||||||
|
en: Large text field
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -25,7 +28,9 @@ subFields:
|
|||||||
- name: emailValidation
|
- name: emailValidation
|
||||||
type: boolean
|
type: boolean
|
||||||
meta:
|
meta:
|
||||||
label: E-Mail-Validierung
|
label:
|
||||||
|
de: E-Mail-Validierung
|
||||||
|
en: E-mail validation
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -36,7 +41,9 @@ subFields:
|
|||||||
- name: telValidation
|
- name: telValidation
|
||||||
type: boolean
|
type: boolean
|
||||||
meta:
|
meta:
|
||||||
label: Telefon-Validierung
|
label:
|
||||||
|
de: Telefon-Validierung
|
||||||
|
en: Phone validation
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
|
45
api/collections/fieldLists/formular/timeSelect.yml
Normal file
45
api/collections/fieldLists/formular/timeSelect.yml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: timeSelect
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label: Zeitenwahl
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent?.inputWidgets?.includes('timeSelect')
|
||||||
|
subFields:
|
||||||
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
widget: containerLessObject
|
||||||
|
subFields: !include standardInputProperties.yml
|
||||||
|
|
||||||
|
- name: selectEntries
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label: Auswahleingabe
|
||||||
|
widget: containerLessObjectArray
|
||||||
|
helperText: "Die Angaben werden in folgendes Übersetzt: Anfangspunkt - Endpunkt"
|
||||||
|
direction: horizontal
|
||||||
|
|
||||||
|
subFields:
|
||||||
|
- name: leftSide
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: Anfangspunkt
|
||||||
|
helperText: Bspw. 14:30
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
||||||
|
|
||||||
|
- name: rightSide
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: Endpunkt
|
||||||
|
helperText: Bspw. 15:30
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
@ -14,8 +14,12 @@ subFields:
|
|||||||
- name: times
|
- name: times
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Zeitenangabe
|
label:
|
||||||
helperText: "Die Angaben werden in folgendes Übersetzt: Anfangspunkt - Endpunkt"
|
de: Zeitenauswahl Möglichkeiten
|
||||||
|
en: Time selection options
|
||||||
|
helperText:
|
||||||
|
de: "Die Angaben werden in folgendes Übersetzt: Anfangspunkt - Endpunkt"
|
||||||
|
en: "The information is translated into the following: starting point - end point"
|
||||||
direction: horizontal
|
direction: horizontal
|
||||||
widget: containerLessObjectArray
|
widget: containerLessObjectArray
|
||||||
|
|
||||||
@ -23,8 +27,12 @@ subFields:
|
|||||||
- name: from
|
- name: from
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Anfangspunkt
|
label:
|
||||||
helperText: Bspw. 14:30
|
de: Anfangspunkt
|
||||||
|
en: Starting point
|
||||||
|
helperText:
|
||||||
|
de: Bspw. 14:30
|
||||||
|
en: E.g. 14:30
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -36,7 +44,9 @@ subFields:
|
|||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Endpunkt
|
label: Endpunkt
|
||||||
helperText: Bspw. 15:30
|
helperText:
|
||||||
|
de: Bspw. 15:30
|
||||||
|
en: E.g. 15:30
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -44,6 +54,7 @@ subFields:
|
|||||||
small: "col-12"
|
small: "col-12"
|
||||||
large: "col-6"
|
large: "col-6"
|
||||||
- name: standardInputProperties
|
- name: standardInputProperties
|
||||||
|
type: object
|
||||||
meta:
|
meta:
|
||||||
widget: containerLessObject
|
widget: containerLessObject
|
||||||
subFields: !include standardInputProperties.yml
|
subFields: !include standardInputProperties.yml
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
- name: title
|
- name: title
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Titel
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: Title
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -12,7 +14,11 @@
|
|||||||
- name: description
|
- name: description
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Beschreibung
|
label:
|
||||||
|
de: Beschreibung
|
||||||
|
en: Description
|
||||||
|
inputProps:
|
||||||
|
multiline: true
|
||||||
containerProps:
|
containerProps:
|
||||||
layout:
|
layout:
|
||||||
size:
|
size:
|
||||||
@ -22,4 +28,8 @@
|
|||||||
- name: keywords
|
- name: keywords
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Schlüsselwörter
|
inputProps:
|
||||||
|
multiline: true
|
||||||
|
label:
|
||||||
|
de: Schlüsselwörter
|
||||||
|
en: Keywords
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
# attribute auf row ebene
|
- name: title
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: Title
|
||||||
|
|
||||||
|
- name: backgroundImage
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Hintergrundbild
|
||||||
|
en: Background Image
|
||||||
|
widget: foreignKey
|
||||||
|
foreign:
|
||||||
|
collection: medialib
|
||||||
|
id: id
|
||||||
|
subNavigation: 0
|
||||||
|
render:
|
||||||
|
defaultCollectionViews: true
|
||||||
|
|
||||||
- name: columns
|
- name: columns
|
||||||
type: object[]
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label: Spalten
|
label:
|
||||||
|
de: Spalten
|
||||||
|
en: Columns
|
||||||
direction: row
|
direction: row
|
||||||
widget: grid
|
widget: grid
|
||||||
subFields: !include ../fieldLists/column.yml
|
subFields: !include ./column.yml
|
||||||
|
16
api/collections/fields/active.yml
Normal file
16
api/collections/fields/active.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
type: boolean
|
||||||
|
name: active
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Aktiv
|
||||||
|
en: Active
|
||||||
|
helperText:
|
||||||
|
de: Ist dies Aktiviert, so wird der Inhalt verfügbar.
|
||||||
|
en: If this is activated, the content will be available.
|
||||||
|
defaultValue: true
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
3
api/collections/fields/backup.yml
Normal file
3
api/collections/fields/backup.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
backup:
|
||||||
|
active: true # sollen backups beim verändern erstellt werden
|
||||||
|
collectionName: backups # in welcher collection es gespeichert werden soll
|
19
api/collections/fields/contentType.yml
Normal file
19
api/collections/fields/contentType.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
type: string
|
||||||
|
name: type
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Inhaltstyp
|
||||||
|
en: Content Type
|
||||||
|
widget: select
|
||||||
|
defaultValue: page
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
||||||
|
choices:
|
||||||
|
- name: # name der im admin angezeigt wird
|
||||||
|
de: Seite
|
||||||
|
en: Page
|
||||||
|
id: page # wert der in der datenbank gespeichert wird
|
11
api/collections/fields/emailCC.yml
Normal file
11
api/collections/fields/emailCC.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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"
|
40
api/collections/fields/excludedDays.yml
Normal file
40
api/collections/fields/excludedDays.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: excludeDays
|
||||||
|
type: string[]
|
||||||
|
meta:
|
||||||
|
label: Auszuschließende Wochentage
|
||||||
|
widget: checkboxArray
|
||||||
|
choices:
|
||||||
|
- id: monday
|
||||||
|
name:
|
||||||
|
de: Montag
|
||||||
|
en: Monday
|
||||||
|
|
||||||
|
- id: tuesday
|
||||||
|
name:
|
||||||
|
de: Dienstag
|
||||||
|
en: Tuesday
|
||||||
|
|
||||||
|
- id: wednesday
|
||||||
|
name:
|
||||||
|
de: Mittwoch
|
||||||
|
en: Wednesday
|
||||||
|
|
||||||
|
- id: thursday
|
||||||
|
name:
|
||||||
|
de: Donnerstag
|
||||||
|
en: Thursday
|
||||||
|
|
||||||
|
- id: friday
|
||||||
|
name:
|
||||||
|
de: Freitag
|
||||||
|
en: Friday
|
||||||
|
|
||||||
|
- id: saturday
|
||||||
|
name:
|
||||||
|
de: Samstag
|
||||||
|
en: Saturday
|
||||||
|
|
||||||
|
- id: sunday
|
||||||
|
name:
|
||||||
|
de: Sonntag
|
||||||
|
en: Sunday
|
6
api/collections/fields/file.yml
Normal file
6
api/collections/fields/file.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
name: file
|
||||||
|
type: file
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Datei
|
||||||
|
en: File
|
7
api/collections/fields/form.yml
Normal file
7
api/collections/fields/form.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
type: object
|
||||||
|
name: formular
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Formular
|
||||||
|
en: Form
|
||||||
|
widget: jsonField
|
13
api/collections/fields/from.yml
Normal file
13
api/collections/fields/from.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
name: from
|
||||||
|
type: date
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Von
|
||||||
|
en: From
|
||||||
|
widget: date
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
37
api/collections/fields/imageFilter.yml
Normal file
37
api/collections/fields/imageFilter.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# 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.
|
||||||
|
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
|
25
api/collections/fields/images.yml
Normal file
25
api/collections/fields/images.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: images
|
||||||
|
type: string[]
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Bild
|
||||||
|
en: Image
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent.contentType == 'images'
|
||||||
|
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: 0 # Bestimmt, welche Navigation für die Auswahl der ausgewählten Daten angezeigt wird.
|
||||||
|
#projection: xyz
|
||||||
|
#sort: "title"
|
||||||
|
render:
|
||||||
|
defaultCollectionViews: true
|
||||||
|
# alternativ könnte auch folgendes verwendet werden:
|
||||||
|
#raw: true
|
||||||
|
#eval: |
|
||||||
|
# (function() {
|
||||||
|
# var out = "";
|
||||||
|
# out += "<div style=\"color: #999;\">" + $foreignEntry.title + "</div>";
|
||||||
|
# return out;
|
||||||
|
# })()
|
11
api/collections/fields/manualSort.yml
Normal file
11
api/collections/fields/manualSort.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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.
|
27
api/collections/fields/medialibCardList.yml
Normal file
27
api/collections/fields/medialibCardList.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
type: cardList
|
||||||
|
mediaQuery: "(min-width: 1200px)"
|
||||||
|
selectionPriority: 1
|
||||||
|
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: false
|
||||||
|
|
||||||
|
fields:
|
||||||
|
- source: file
|
||||||
|
name: Datei
|
||||||
|
- source: category
|
||||||
|
name:
|
||||||
|
de: Kategorie
|
||||||
|
en: Category
|
||||||
|
filter: true
|
||||||
|
- source: updateTime
|
||||||
|
type: datetime
|
||||||
|
filter: true
|
||||||
|
label:
|
||||||
|
de: letztes Update
|
||||||
|
en: last update
|
25
api/collections/fields/medialibSimpleList.yml
Normal file
25
api/collections/fields/medialibSimpleList.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
type: simpleList
|
||||||
|
mediaQuery: "(min-width: 0px)"
|
||||||
|
defaultSelect: false
|
||||||
|
selectionPriority: 3 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
|
||||||
|
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 # gibt an, in welches feld die datei hochgeladen werden soll
|
||||||
|
pageAsDropArea: false # wenn true, wird filedrop area garnicht erst angezeigt, da die ganze seite drag n drop funktionalität hat
|
||||||
|
|
||||||
|
primaryText:
|
||||||
|
source: file
|
||||||
|
filter: true
|
||||||
|
|
||||||
|
secondaryText:
|
||||||
|
source: alt
|
||||||
|
filter: true
|
||||||
|
|
||||||
|
tertiaryText:
|
||||||
|
source: category
|
||||||
|
filter: true
|
30
api/collections/fields/medialibTable.yml
Normal file
30
api/collections/fields/medialibTable.yml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
type: table
|
||||||
|
mediaQuery: "(min-width: 800px)"
|
||||||
|
defaultSelect: false
|
||||||
|
selectionPriority: 2
|
||||||
|
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: false
|
||||||
|
columns:
|
||||||
|
- source: file
|
||||||
|
name:
|
||||||
|
de: Datei
|
||||||
|
en: File
|
||||||
|
filter: true
|
||||||
|
- source: category
|
||||||
|
name:
|
||||||
|
de: Kategorie
|
||||||
|
en: Category
|
||||||
|
filter: true
|
||||||
|
- source: updateTime
|
||||||
|
type: datetime
|
||||||
|
label:
|
||||||
|
de: letztes Update
|
||||||
|
en: last update
|
||||||
|
filter: true
|
10
api/collections/fields/mutliupload.yml
Normal file
10
api/collections/fields/mutliupload.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
multiupload:
|
||||||
|
fields:
|
||||||
|
- source: category # gibt an, welche Felder in der Modalansicht bearbeitet werden können, wenn die Eigenschaft nicht festgelegt ist, werden automatisch alle Felder ausgewählt
|
||||||
|
prefilledFields: # gibt an, welche Felder in der Modalansicht vorbefüllt werden können, wenn die Eigenschaft nicht festgelegt ist, werden automatisch alle Felder ausgewählt
|
||||||
|
- source: title
|
||||||
|
defaultValue: # extrahiert den namen des files und fügt ihn in das feld "title" ein
|
||||||
|
eval: |
|
||||||
|
(function(){
|
||||||
|
return "Title" + $file.name
|
||||||
|
})()
|
23
api/collections/fields/pageTitle.yml
Normal file
23
api/collections/fields/pageTitle.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: pageTitle
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel der Seite
|
||||||
|
en: Page Title
|
||||||
|
helperText:
|
||||||
|
de: "Dieser Titel wird in der Seite als h1 angezeigt."
|
||||||
|
en: "This title is displayed in the page as h1."
|
||||||
|
dependsOn:
|
||||||
|
eval: $.type == "page"
|
||||||
|
inputProps:
|
||||||
|
#multiline: true
|
||||||
|
#placeholder: Seitentitel
|
||||||
|
#...
|
||||||
|
#openapi:
|
||||||
|
# example: Demo Titel
|
||||||
|
containerProps:
|
||||||
|
layout:
|
||||||
|
size:
|
||||||
|
default: "col-6"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-6"
|
6
api/collections/fields/quickEditMedialib.yml
Normal file
6
api/collections/fields/quickEditMedialib.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
quickEdit: # Erlaubt das Bearbeiten von Einträgen in der Listenansicht, ohne dass eine neue Seite geöffnet wird
|
||||||
|
enabled: true
|
||||||
|
fields: # felder, die in dieser Ansicht bearbeitet werden können
|
||||||
|
- title
|
||||||
|
- alt
|
||||||
|
- file
|
9
api/collections/fields/rows.yml
Normal file
9
api/collections/fields/rows.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name: rows
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Zeilen
|
||||||
|
en: Rows
|
||||||
|
widget: grid
|
||||||
|
metaElements: []
|
||||||
|
subFields: !include ../fieldLists/row.yml
|
9
api/collections/fields/text.yml
Normal file
9
api/collections/fields/text.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name: text
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
widget: richtext
|
||||||
|
label:
|
||||||
|
de: Text
|
||||||
|
en: text
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent.contentType == 'text'
|
6
api/collections/fields/textIndex.yml
Normal file
6
api/collections/fields/textIndex.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
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
|
||||||
|
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.
|
@ -35,8 +35,4 @@ hooks:
|
|||||||
file: hooks/forms/post_return.js
|
file: hooks/forms/post_return.js
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
- type: object
|
- !include fields/form.yml
|
||||||
name: formular
|
|
||||||
meta:
|
|
||||||
label: Formular
|
|
||||||
widget: jsonField
|
|
||||||
|
@ -46,11 +46,16 @@ hooks:
|
|||||||
type: javascript
|
type: javascript
|
||||||
file: hooks/lighthouse/post_create.js
|
file: hooks/lighthouse/post_create.js
|
||||||
|
|
||||||
|
indexes:
|
||||||
|
- !include fields/textIndex.yml
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
- name: analyzedPaths
|
- name: analyzedPaths
|
||||||
type: string[]
|
type: string[]
|
||||||
meta:
|
meta:
|
||||||
label: Analyzed Paths
|
label:
|
||||||
|
de: Analysierten Pfade
|
||||||
|
en: Analyzed Paths
|
||||||
- name: performance
|
- name: performance
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
@ -58,15 +63,21 @@ fields:
|
|||||||
- name: accessibility
|
- name: accessibility
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Accessibility
|
label:
|
||||||
|
en: Accessibility
|
||||||
|
de: Zugänglichkeit
|
||||||
- name: bestPractices
|
- name: bestPractices
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Best Practices
|
label:
|
||||||
|
en: Best Practices
|
||||||
|
de: Beste Praktiken
|
||||||
- name: seo
|
- name: seo
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: SEO
|
label:
|
||||||
|
en: SEO
|
||||||
|
de: SEO
|
||||||
- name: lighthouseMetrics
|
- name: lighthouseMetrics
|
||||||
type: object
|
type: object
|
||||||
meta:
|
meta:
|
||||||
@ -75,45 +86,67 @@ fields:
|
|||||||
- name: FCPS
|
- name: FCPS
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: First Contentful Paint Score
|
label:
|
||||||
|
en: First Contentful Paint Score
|
||||||
|
de: Erster Inhaltlicher Anstrich Score
|
||||||
- name: FCPV
|
- name: FCPV
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: First Contentful Paint Value
|
label:
|
||||||
|
en: First Contentful Paint Value
|
||||||
|
de: Erster Inhaltlicher Anstrich Wert
|
||||||
- name: FMPV
|
- name: FMPV
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: First Meaningful Paint Value
|
label:
|
||||||
|
de: Erster Bedeutungsvoller Anstrich Wert
|
||||||
|
en: First Meaningful Paint Value
|
||||||
|
|
||||||
- name: FMPS
|
- name: FMPS
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: First Meaningful Paint Score
|
label:
|
||||||
|
en: First Meaningful Paint Score
|
||||||
|
de: Erster Bedeutungsvoller Anstrich Score
|
||||||
|
|
||||||
- name: SIS
|
- name: SIS
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Speed Index Score
|
label:
|
||||||
|
en: Speed Index Score
|
||||||
|
de: Geschwindigkeitsindex Score
|
||||||
|
|
||||||
- name: SIV
|
- name: SIV
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Speed Index Value
|
label:
|
||||||
|
en: Speed Index Value
|
||||||
|
de: Geschwindigkeitsindex Wert
|
||||||
|
|
||||||
- name: TTIS
|
- name: TTIS
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Time to Interactive Score
|
label:
|
||||||
|
en: Time to Interactive Score
|
||||||
|
de: Zeit bis zur Interaktion Score
|
||||||
|
|
||||||
- name: TTIV
|
- name: TTIV
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: Time to Interactive Value
|
label:
|
||||||
|
en: Time to Interactive Value
|
||||||
|
de: Zeit bis zur Interaktion Wert
|
||||||
|
|
||||||
- name: FPIDS
|
- name: FPIDS
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: First Potential Input Delay Score
|
label:
|
||||||
|
de: Erste potenzielle Eingabe Verzögerung Score
|
||||||
|
en: First Potential Input Delay Score
|
||||||
|
|
||||||
- name: FPIDV
|
- name: FPIDV
|
||||||
type: number
|
type: number
|
||||||
meta:
|
meta:
|
||||||
label: First Potential Input Delay Value
|
label:
|
||||||
|
en: First Potential Input Delay Value
|
||||||
|
de: Erste potenzielle Eingabe Verzögerung Wert
|
||||||
|
@ -26,4 +26,6 @@ fields:
|
|||||||
- type: string
|
- type: string
|
||||||
name: lighthouseSubpath
|
name: lighthouseSubpath
|
||||||
meta:
|
meta:
|
||||||
label: PagespeedPaths
|
label:
|
||||||
|
de: Zu analysierenden Pfad
|
||||||
|
en: Path to analyze
|
||||||
|
@ -1,25 +1,29 @@
|
|||||||
# Der Name der Kollektion ist beliebig, aber wird in unserem
|
# Der Name der Kollektion wird in der Rest-API-URL verwendet, z.B.
|
||||||
# Beispiel vom ContentBuilder als "medialib" referenziert.
|
# /_/tibi_starter/medialib
|
||||||
name: medialib
|
name: medialib
|
||||||
|
|
||||||
|
# Enthält die Kollektion Felder vom Typ "file", so werden die
|
||||||
|
# hochgeladenen Dateien unter dem Ordner abgelegt, der mit
|
||||||
|
# "uploadPath" bestimmt wird.
|
||||||
uploadPath: ../media/medialib
|
uploadPath: ../media/medialib
|
||||||
|
|
||||||
meta:
|
meta:
|
||||||
allowExportAll: true
|
allowExportAll: true # Erlaubt das Exportieren aller Einträge in dieser Sammlung - Nur für Admins
|
||||||
label:
|
label: # label der Collection in der Sidebar
|
||||||
de: Medienbibliothek
|
de: Medienbibliothek
|
||||||
en: Media Library
|
en: Media Library
|
||||||
muiIcon: multimedia
|
muiIcon: multimedia # icon in navigation
|
||||||
defaultSort:
|
defaultSort:
|
||||||
field: sort
|
field: sort
|
||||||
order: MANUALLY
|
order: MANUALLY #alternativ auch ASC und DESC möglich
|
||||||
|
|
||||||
backup:
|
backup:
|
||||||
active: true
|
active: true # sollen backups beim verändern erstellt werden
|
||||||
collectionName: backups
|
collectionName: backups # in welcher collection es gespeichert werden soll
|
||||||
|
|
||||||
quickEdit:
|
quickEdit: # Erlaubt das Bearbeiten von Einträgen in der Listenansicht, ohne dass eine neue Seite geöffnet wird
|
||||||
enabled: true
|
enabled: true
|
||||||
fields:
|
fields: # felder, die in dieser Ansicht bearbeitet werden können
|
||||||
- title
|
- title
|
||||||
- alt
|
- alt
|
||||||
- file
|
- file
|
||||||
@ -31,48 +35,20 @@ meta:
|
|||||||
defaultImageFilter: xs
|
defaultImageFilter: xs
|
||||||
|
|
||||||
multiupload:
|
multiupload:
|
||||||
fields: []
|
fields:
|
||||||
|
- source: category # gibt an, welche Felder in der Modalansicht bearbeitet werden können, wenn die Eigenschaft nicht festgelegt ist, werden automatisch alle Felder ausgewählt
|
||||||
|
prefilledFields: # gibt an, welche Felder in der Modalansicht vorbefüllt werden können, wenn die Eigenschaft nicht festgelegt ist, werden automatisch alle Felder ausgewählt
|
||||||
|
- source: title
|
||||||
|
defaultValue: # extrahiert den namen des files und fügt ihn in das feld "title" ein
|
||||||
|
eval: |
|
||||||
|
(function(){
|
||||||
|
return "Title" + $file.name
|
||||||
|
})()
|
||||||
|
|
||||||
views:
|
views:
|
||||||
- type: table
|
- !include fields/medialibSimpleList.yml
|
||||||
mediaQuery: "(min-width: 0px)"
|
- !include fields/medialibTable.yml
|
||||||
defaultSelect: false
|
- !include fields/medialibCardList.yml
|
||||||
selectionPriority: 2
|
|
||||||
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: false
|
|
||||||
columns:
|
|
||||||
- source: file
|
|
||||||
name: Datei
|
|
||||||
- source: updateTime
|
|
||||||
type: datetime
|
|
||||||
label: letztes Update
|
|
||||||
|
|
||||||
- type: cardList
|
|
||||||
mediaQuery: "(min-width: 1200px)"
|
|
||||||
selectionPriority: 1
|
|
||||||
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: false
|
|
||||||
|
|
||||||
fields:
|
|
||||||
- source: file
|
|
||||||
name: Datei
|
|
||||||
- source: updateTime
|
|
||||||
type: datetime
|
|
||||||
label: letztes Update
|
|
||||||
|
|
||||||
subNavigation:
|
subNavigation:
|
||||||
- name: modalForeign # Name des Eingabefelds oder der Ansicht.
|
- name: modalForeign # Name des Eingabefelds oder der Ansicht.
|
||||||
@ -93,71 +69,168 @@ meta:
|
|||||||
}
|
}
|
||||||
//!js
|
//!js
|
||||||
|
|
||||||
|
# Allgeine Zugriffsregeln auf Kollektions-Ebene werden mit dem
|
||||||
|
# "permissions" Objekt festgelegt.
|
||||||
permissions:
|
permissions:
|
||||||
|
# Unter "public" werden die Zugriffsrechte für die Öffentlichkeit
|
||||||
|
# definiert.
|
||||||
public:
|
public:
|
||||||
|
# "methods" führt die HTTP-Methoden auf, die erlaubt sind
|
||||||
methods:
|
methods:
|
||||||
|
# "get: true" bedeutet hier, dass jeder die Daten lesen darf
|
||||||
get: true
|
get: true
|
||||||
|
# "post", also Einträge erstellen, "put" = Bearbeiten und
|
||||||
|
# "delete" = löschen darf die Öffentlichkeit nicht.
|
||||||
post: false
|
post: false
|
||||||
put: false
|
put: false
|
||||||
delete: 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:
|
user:
|
||||||
methods:
|
methods:
|
||||||
get: true
|
get: true
|
||||||
post: true
|
post: true
|
||||||
put: true
|
put: true
|
||||||
delete: true
|
delete: true
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Projektionen der Daten werden via GET-Parameter "projection=..."
|
||||||
|
# referenziert.
|
||||||
|
# "projections" is ein Objekt, dass die Namen der Projektionen
|
||||||
|
# als Key führt.
|
||||||
projections:
|
projections:
|
||||||
|
# dashboard = name der Projektion
|
||||||
|
|
||||||
dashboard:
|
dashboard:
|
||||||
|
# "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:
|
select:
|
||||||
|
# keine auflistung von feldern, da alle felder ausgewählt werden
|
||||||
|
details:
|
||||||
|
# Alternativ kann "select" auch Auschlussregeln definieren.
|
||||||
|
# Eine Mischung von Inkludieren und Auschluss ist NICHT
|
||||||
|
# möglich.
|
||||||
|
select:
|
||||||
|
file: 0
|
||||||
|
list:
|
||||||
|
select:
|
||||||
|
file: 1
|
||||||
|
alt: 1
|
||||||
hooks:
|
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:
|
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:
|
return:
|
||||||
type: javascript
|
type: javascript
|
||||||
file: hooks/clear_cache.js
|
file: hooks/clear_cache.js
|
||||||
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:
|
return:
|
||||||
type: javascript
|
type: javascript
|
||||||
file: hooks/clear_cache.js
|
file: hooks/clear_cache.js
|
||||||
|
|
||||||
imageFilter:
|
imageFilter: !include fields/imageFilter.yml
|
||||||
xs:
|
|
||||||
- fit: true
|
# "fields" stellen die Eigentliche Struktur der Kollektion dar.
|
||||||
height: 90
|
# "fields" ist als Array angelegt um eine Standard-Sortierung
|
||||||
width: 90
|
# im tibi-admin vorzugeben.
|
||||||
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:
|
||||||
- name: file
|
# Das Einbinden von Feldern über extra Dateien bietet sich nur
|
||||||
type: file
|
# an, wenn das jeweilige Feld mehrfach von dieser oder anderen
|
||||||
meta:
|
# Kollektionen verwendet wird.
|
||||||
label:
|
# Auf die möglichen Definitionen wird im Kapitel "fields"
|
||||||
de: Datei
|
# eingegangen.
|
||||||
en: File
|
- !include fields/file.yml
|
||||||
|
|
||||||
- name: alt
|
- name: alt
|
||||||
type: string
|
type: string
|
||||||
@ -179,14 +252,11 @@ fields:
|
|||||||
de: Der Titel wird angezeigt, wenn die Datei geladen wird.
|
de: Der Titel wird angezeigt, wenn die Datei geladen wird.
|
||||||
en: The title is displayed when the file is loaded.
|
en: The title is displayed when the file is loaded.
|
||||||
|
|
||||||
- name: sort
|
- name: category
|
||||||
type: number
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label:
|
label:
|
||||||
de: Manuelle Sortierung
|
de: Kategorie
|
||||||
en: Manual Sorting
|
en: Category
|
||||||
inputProps:
|
|
||||||
{ readonly: true, placeholder: { de: "Wert wird automatisch gesetzt", en: "Value is set automatically" } }
|
- !include fields/manualSort.yml
|
||||||
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.
|
|
||||||
|
@ -87,8 +87,12 @@ fields:
|
|||||||
- name: type
|
- name: type
|
||||||
type: string
|
type: string
|
||||||
meta:
|
meta:
|
||||||
label: Modultyp
|
label:
|
||||||
helperText: "Wählen Sie den Typ des Moduls aus."
|
de: Modultyp
|
||||||
|
en: Module Type
|
||||||
|
helperText:
|
||||||
|
de: "Wählen Sie den Typ des Moduls aus."
|
||||||
|
en: "Choose the type of the module."
|
||||||
widget: select
|
widget: select
|
||||||
choices:
|
choices:
|
||||||
- name: { de: "Formular", en: "Form" }
|
- name: { de: "Formular", en: "Form" }
|
||||||
|
@ -4,10 +4,6 @@ uploadPath: ../media/navigation
|
|||||||
meta:
|
meta:
|
||||||
label: "Navigation"
|
label: "Navigation"
|
||||||
muiIcon: navigation
|
muiIcon: navigation
|
||||||
allowExportAll: true
|
|
||||||
backup:
|
|
||||||
active: true
|
|
||||||
collectionName: backups
|
|
||||||
views:
|
views:
|
||||||
- type: simpleList
|
- type: simpleList
|
||||||
mediaQuery: "(max-width:599px)"
|
mediaQuery: "(max-width:599px)"
|
||||||
@ -17,7 +13,6 @@ meta:
|
|||||||
mediaQuery: "(min-width:600px)"
|
mediaQuery: "(min-width:600px)"
|
||||||
columns:
|
columns:
|
||||||
- source: tree
|
- source: tree
|
||||||
name: Navigationsbaum
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
public:
|
public:
|
||||||
@ -32,15 +27,60 @@ permissions:
|
|||||||
post: false
|
post: false
|
||||||
put: true
|
put: true
|
||||||
delete: false
|
delete: false
|
||||||
hooks:
|
|
||||||
post:
|
x-endpoint: &endpoint
|
||||||
return:
|
name: endpoint
|
||||||
type: javascript
|
type: boolean
|
||||||
file: hooks/clear_cache.js
|
meta:
|
||||||
put:
|
defaultValue:
|
||||||
return:
|
eval: 1 == 1
|
||||||
type: javascript
|
label: Endpunkt
|
||||||
file: hooks/clear_cache.js
|
|
||||||
|
x-elemente: &elemente
|
||||||
|
name: elements
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Elemente
|
||||||
|
en: elements
|
||||||
|
folding:
|
||||||
|
previewUnfolded: name
|
||||||
|
previewFolded: name
|
||||||
|
|
||||||
|
x-name: &name
|
||||||
|
name: name
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Name
|
||||||
|
en: name
|
||||||
|
helperText:
|
||||||
|
de: Dieser Name wird zur Anzeige in der Navigation verwendet.
|
||||||
|
en: This name is used for display in the navigation.
|
||||||
|
|
||||||
|
x-page: &seite
|
||||||
|
name: page
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Seite
|
||||||
|
en: page
|
||||||
|
widget: select
|
||||||
|
dependsOn:
|
||||||
|
eval: |
|
||||||
|
(function(){
|
||||||
|
if($parent.endpoint == undefined) return true;
|
||||||
|
return $parent.endpoint
|
||||||
|
})()
|
||||||
|
|
||||||
|
choices:
|
||||||
|
endpoint: content
|
||||||
|
params:
|
||||||
|
sort: path
|
||||||
|
projection: navigation
|
||||||
|
mapping:
|
||||||
|
id: id
|
||||||
|
name: path
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
- name: tree
|
- name: tree
|
||||||
@ -48,7 +88,9 @@ fields:
|
|||||||
meta:
|
meta:
|
||||||
label: Baum
|
label: Baum
|
||||||
widget: select
|
widget: select
|
||||||
helperText: Die Servicenavigation sollte Seiten wie bspw. die Datneschutzerklärung oder das Impressum umfassen.
|
helperText:
|
||||||
|
de: Die Servicenavigation sollte Seiten wie bspw. die Datneschutzerklärung oder das Impressum umfassen.
|
||||||
|
en: The service navigation should include pages such as the data protection declaration or the imprint.
|
||||||
choices:
|
choices:
|
||||||
- id: 0
|
- id: 0
|
||||||
name:
|
name:
|
||||||
@ -59,38 +101,37 @@ fields:
|
|||||||
de: Servicenavigation
|
de: Servicenavigation
|
||||||
en: service navigation
|
en: service navigation
|
||||||
|
|
||||||
- name: pages
|
- <<: *elemente
|
||||||
type: object[]
|
|
||||||
meta:
|
|
||||||
label:
|
|
||||||
de: Seiten
|
|
||||||
en: pages
|
|
||||||
folding:
|
|
||||||
previewUnfolded: name
|
|
||||||
previewFolded: name
|
|
||||||
|
|
||||||
widget: containerLessObjectArray
|
|
||||||
subFields:
|
subFields:
|
||||||
- name: name
|
- *endpoint
|
||||||
type: string
|
- *name
|
||||||
|
- *seite
|
||||||
|
- name: image
|
||||||
|
type: file
|
||||||
meta:
|
meta:
|
||||||
label:
|
label: Bild
|
||||||
de: Name
|
dependsOn:
|
||||||
en: name
|
eval: |
|
||||||
helperText: Dieser Name wird zur Anzeige in der Navigation verwendet.
|
(function(){
|
||||||
|
if($parent.endpoint == undefined) return false;
|
||||||
|
return !$parent.endpoint
|
||||||
|
})()
|
||||||
|
|
||||||
- name: page
|
- name: elements
|
||||||
type: string
|
type: object[]
|
||||||
meta:
|
meta:
|
||||||
label:
|
label:
|
||||||
de: Seite
|
de: Elemente
|
||||||
en: page
|
en: elements
|
||||||
widget: select
|
dependsOn:
|
||||||
choices:
|
eval: |
|
||||||
endpoint: page
|
(function(){
|
||||||
params:
|
if($parent.endpoint == undefined) return false;
|
||||||
sort: path
|
return !$parent.endpoint
|
||||||
projection: navigation
|
})()
|
||||||
mapping:
|
folding:
|
||||||
id: id
|
previewUnfolded: name
|
||||||
name: path
|
previewFolded: name
|
||||||
|
subFields:
|
||||||
|
- *name
|
||||||
|
- *seite
|
||||||
|
@ -8,6 +8,12 @@ meta:
|
|||||||
|
|
||||||
dashboard: helper/dashboard.yml
|
dashboard: helper/dashboard.yml
|
||||||
|
|
||||||
|
# Liste möglicher Berechtigungen, die Benutzern zugeordnet werden können
|
||||||
|
permissions:
|
||||||
|
- name: pages
|
||||||
|
label:
|
||||||
|
de: Seiten
|
||||||
|
en: Pages
|
||||||
collections:
|
collections:
|
||||||
- !include collections/backups.yml
|
- !include collections/backups.yml
|
||||||
- !include collections/content.yml
|
- !include collections/content.yml
|
||||||
@ -20,6 +26,7 @@ collections:
|
|||||||
- !include collections/ssr.yml
|
- !include collections/ssr.yml
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- cron: "0 0 * * 1"
|
- !include jobs/lighthouse.yml
|
||||||
type: javascript
|
|
||||||
file: jobs/lighthouse.js
|
assets:
|
||||||
|
- !include assets/dist.yml
|
||||||
|
@ -4,6 +4,13 @@
|
|||||||
backup.updateLogs = updateLogs
|
backup.updateLogs = updateLogs
|
||||||
return { data: backup }
|
return { data: backup }
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Object} entry
|
||||||
|
* @param {string} collectionName
|
||||||
|
* @param {number} versionNr
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
function compareAndUpdateEntry(entry, collectionName, versionNr) {
|
function compareAndUpdateEntry(entry, collectionName, versionNr) {
|
||||||
let updateLogs
|
let updateLogs
|
||||||
if (versionNr == 0) {
|
if (versionNr == 0) {
|
||||||
@ -25,6 +32,11 @@
|
|||||||
return updateLogs
|
return updateLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {any[]} array
|
||||||
|
* @returns {any[]}
|
||||||
|
*/
|
||||||
function filterValidObjects(array) {
|
function filterValidObjects(array) {
|
||||||
return array.filter((object) => {
|
return array.filter((object) => {
|
||||||
for (let key in object) {
|
for (let key in object) {
|
||||||
@ -35,6 +47,14 @@
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Object} oldObj
|
||||||
|
* @param {Object} newObj
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {any[]}
|
||||||
|
*/
|
||||||
function getUpdateLogs(oldObj = {}, newObj = {}, path = "") {
|
function getUpdateLogs(oldObj = {}, newObj = {}, path = "") {
|
||||||
let updateLogs = []
|
let updateLogs = []
|
||||||
const ignoredKeys = ["id", "insertTime", "updateTime"]
|
const ignoredKeys = ["id", "insertTime", "updateTime"]
|
||||||
|
@ -8,7 +8,6 @@ var { setUpQuery, calculateAverageDynamically, run } = require("../hooks/lib/uti
|
|||||||
}
|
}
|
||||||
let dbObjs = []
|
let dbObjs = []
|
||||||
urls.forEach((url) => {
|
urls.forEach((url) => {
|
||||||
console.log("URL:", url)
|
|
||||||
dbObjs.push(run(url))
|
dbObjs.push(run(url))
|
||||||
})
|
})
|
||||||
let dbObject = calculateAverageDynamically(dbObjs)
|
let dbObject = calculateAverageDynamically(dbObjs)
|
||||||
|
14
api/jobs/lighthouse.yml
Normal file
14
api/jobs/lighthouse.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Jedem Job muss ein "cron" Eintrag zugeordnet werden, der die
|
||||||
|
# Ausführungszeitpunkte definiert.
|
||||||
|
# Das cron-Schema ist dem üblichen Linux cron-Schema nachempfunden.
|
||||||
|
cron: "0 0 * * 1"
|
||||||
|
|
||||||
|
# "type" des Jobs ist derzeit immer "javascript" mit der "file"-Referenz
|
||||||
|
# relativ zur "config.yml".
|
||||||
|
type: javascript
|
||||||
|
file: jobs/lighthouse.js
|
||||||
|
# Es können beliebige "meta"-Daten hinterlegt werden, die im Javascript
|
||||||
|
# des Jobs über "context.job.meta" abgerufen werden können.
|
||||||
|
|
||||||
|
meta:
|
||||||
|
name: Lighthouse job
|
@ -16,6 +16,15 @@
|
|||||||
<div id="appContainer"><!--HTML--></div>
|
<div id="appContainer"><!--HTML--></div>
|
||||||
<script type="module" src="/dist/index.mjs?t=__TIMESTAMP__"></script>
|
<script type="module" src="/dist/index.mjs?t=__TIMESTAMP__"></script>
|
||||||
<script nomodule src="/dist/index.es5.js?t=__TIMESTAMP__"></script>
|
<script nomodule src="/dist/index.es5.js?t=__TIMESTAMP__"></script>
|
||||||
|
<script
|
||||||
|
src="//cc.webmakers.de/cc.js"
|
||||||
|
defer
|
||||||
|
id="ccScript"
|
||||||
|
data-cc-tags="googleMaps"
|
||||||
|
data-cc-privacy-policy-url="/datenschutz"
|
||||||
|
data-cc-secondary-color="#c4253e"
|
||||||
|
data-cc-necessary-cookies="likecmsSession"
|
||||||
|
></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<!--SSR.ERROR-->
|
<!--SSR.ERROR-->
|
||||||
|
@ -5,11 +5,14 @@ services:
|
|||||||
docpress:
|
docpress:
|
||||||
profiles:
|
profiles:
|
||||||
- docpress
|
- docpress
|
||||||
image: node:18
|
- tibi-dev
|
||||||
|
image: node:20
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/data
|
- ./:/data
|
||||||
- ./tmp:/tmp
|
- ./tmp:/tmp
|
||||||
- ./tmp/nonexistent:/nonexistent
|
- ./tmp/nonexistent:/nonexistent
|
||||||
|
- ./tmp/.npm:/.npm
|
||||||
|
- ./tmp/.yarn:/.yarn
|
||||||
working_dir: /data/docs
|
working_dir: /data/docs
|
||||||
command: sh -c "yarn install && yarn docpress:serve"
|
command: sh -c "yarn install && yarn docpress:serve"
|
||||||
expose:
|
expose:
|
||||||
@ -23,12 +26,13 @@ services:
|
|||||||
profiles:
|
profiles:
|
||||||
- tibi
|
- tibi
|
||||||
- tibi-dev
|
- tibi-dev
|
||||||
image: node:18
|
image: node:20
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/data
|
- ./:/data
|
||||||
- ./tmp:/tmp
|
- ./tmp:/tmp
|
||||||
- ./tmp/nonexistent:/nonexistent
|
- ./tmp/nonexistent:/nonexistent
|
||||||
- ./tmp/.npm:/.npm
|
- ./tmp/.npm:/.npm
|
||||||
|
- ./tmp/.yarn:/.yarn
|
||||||
working_dir: /data
|
working_dir: /data
|
||||||
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1/_/${TIBI_NAMESPACE} yarn start${START_SCRIPT}"
|
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1/_/${TIBI_NAMESPACE} yarn start${START_SCRIPT}"
|
||||||
expose:
|
expose:
|
||||||
@ -112,7 +116,7 @@ services:
|
|||||||
tibiadmin-dev:
|
tibiadmin-dev:
|
||||||
profiles:
|
profiles:
|
||||||
- tibi-dev
|
- tibi-dev
|
||||||
image: node:18
|
image: node:20
|
||||||
volumes:
|
volumes:
|
||||||
- ./../../cms/tibi-admin:/data
|
- ./../../cms/tibi-admin:/data
|
||||||
working_dir: /data
|
working_dir: /data
|
||||||
|
21
docs/README.md
Normal file
21
docs/README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# TibiCMS Dokumentation
|
||||||
|
|
||||||
|
![TibiCMS Aufbau](./md/tibi-aufbau.svg)
|
||||||
|
|
||||||
|
## Einleitung
|
||||||
|
|
||||||
|
_TibiCMS_ ist der Sammelbegriff für die Komponenten _tibi-server_ und _tibi-admin_, welche einen Rest-API Server und eine Administrationsoberfläche zur Verfügung stellen. Auf Basis dieser beiden Komponenten und der _MongoDB_ als Abhängigkeit lassen sich WebCMS Anwendungen abbilden.
|
||||||
|
|
||||||
|
Das CMS ist multi-mandanten-fähig, d.h. es kann mehrer Projekte mit unterschiedlichen Zugriffsbeschränkungen verwalten.
|
||||||
|
|
||||||
|
### tibi-server
|
||||||
|
|
||||||
|
Der Server selbst kommt ohne grafische Oberfläche oder WebUI. Er ist ausschließlich nach außen über eine Rest-API erreichbar.
|
||||||
|
|
||||||
|
Als einzige Abhängigkeit ist eine _MongoDB_ zu erwähnen. Da der Server in Go geschrieben ist, sind keine externen Bibliotheken notwendig. Er lässt sich daher prima via Docker-Container verteilen.
|
||||||
|
|
||||||
|
### tibi-admin
|
||||||
|
|
||||||
|
Die Administrationsoberfläche ist wie jeder andere Service, der die Rest-API des Servers nutzt, nur ein Frontend. _tibi-admin_ läuft vollständig im Browser und benötigt nur einen Webserver, der statischen Content ausliefert.
|
||||||
|
|
||||||
|
Die Version des _tibi-admin_ sollte synchron zur _tibi-server_ Version gehalten werden, damit alle Datentypen bedient werden können.
|
9
docs/docpress.json
Normal file
9
docs/docpress.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"docs": "md",
|
||||||
|
"markdown": {
|
||||||
|
"plugins": {
|
||||||
|
"code-include": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"css": ["md/docpress.css", "md/github-dark-dimmed.css"]
|
||||||
|
}
|
106
docs/markdown-it-code-include/index.js
Normal file
106
docs/markdown-it-code-include/index.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const INCLUDE_RE = /!{3}\s*include(.+?)!{3}/i;
|
||||||
|
const BRACES_RE = /\((.+?)\)/i;
|
||||||
|
|
||||||
|
const include_plugin = (md, options) => {
|
||||||
|
const defaultOptions = {
|
||||||
|
root: '.',
|
||||||
|
getRootDir: (pluginOptions/*, state, startLine, endLine*/) => pluginOptions.root,
|
||||||
|
includeRe: INCLUDE_RE,
|
||||||
|
throwError: false,
|
||||||
|
bracesAreOptional: false,
|
||||||
|
notFoundMessage: 'File \'{{FILE}}\' not found.',
|
||||||
|
circularMessage: 'Circular reference between \'{{FILE}}\' and \'{{PARENT}}\'.'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
options = {
|
||||||
|
...defaultOptions,
|
||||||
|
root: options
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
options = {
|
||||||
|
...defaultOptions,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const _replaceIncludeByContent = (src, rootdir, parentFilePath, filesProcessed) => {
|
||||||
|
filesProcessed = filesProcessed ? filesProcessed.slice() : []; // making a copy
|
||||||
|
let cap, filePath, mdSrc, errorMessage;
|
||||||
|
|
||||||
|
// store parent file path to check circular references
|
||||||
|
if (parentFilePath) {
|
||||||
|
filesProcessed.push(parentFilePath);
|
||||||
|
}
|
||||||
|
while ((cap = options.includeRe.exec(src))) {
|
||||||
|
let includePath = cap[1].trim();
|
||||||
|
const sansBracesMatch = BRACES_RE.exec(includePath);
|
||||||
|
|
||||||
|
if (!sansBracesMatch && !options.bracesAreOptional) {
|
||||||
|
errorMessage = `INCLUDE statement '${src.trim()}' MUST have '()' braces around the include path ('${includePath}')`;
|
||||||
|
} else if (sansBracesMatch) {
|
||||||
|
includePath = sansBracesMatch[1].trim();
|
||||||
|
} else if (!/^\s/.test(cap[1])) {
|
||||||
|
// path SHOULD have been preceeded by at least ONE whitespace character!
|
||||||
|
/* eslint max-len: "off" */
|
||||||
|
errorMessage = `INCLUDE statement '${src.trim()}': when not using braces around the path ('${includePath}'), it MUST be preceeded by at least one whitespace character to separate the include keyword and the include path.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errorMessage) {
|
||||||
|
filePath = path.resolve(rootdir, includePath);
|
||||||
|
|
||||||
|
// check if child file exists or if there is a circular reference
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
// child file does not exist
|
||||||
|
errorMessage = options.notFoundMessage.replace('{{FILE}}', filePath);
|
||||||
|
} else if (filesProcessed.indexOf(filePath) !== -1) {
|
||||||
|
// reference would be circular
|
||||||
|
errorMessage = options.circularMessage.replace('{{FILE}}', filePath).replace('{{PARENT}}', parentFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there were any errors
|
||||||
|
if (errorMessage) {
|
||||||
|
if (options.throwError) {
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
mdSrc = `\n\n# INCLUDE ERROR: ${errorMessage}\n\n`;
|
||||||
|
} else {
|
||||||
|
// get content of child file
|
||||||
|
mdSrc = fs.readFileSync(filePath, 'utf8');
|
||||||
|
// check if child file also has includes
|
||||||
|
mdSrc = _replaceIncludeByContent(mdSrc, path.dirname(filePath), filePath, filesProcessed);
|
||||||
|
// remove one trailing newline, if it exists: that way, the included content does NOT
|
||||||
|
// automatically terminate the paragraph it is in due to the writer of the included
|
||||||
|
// part having terminated the content with a newline.
|
||||||
|
// However, when that snippet writer terminated with TWO (or more) newlines, these, minus one,
|
||||||
|
// will be merged with the newline after the #include statement, resulting in a 2-NL paragraph
|
||||||
|
// termination.
|
||||||
|
const len = mdSrc.length;
|
||||||
|
if (mdSrc[len - 1] === '\n') {
|
||||||
|
mdSrc = mdSrc.substring(0, len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelStyle = `padding: 0 4px; font-size: 12px; font-weight: bold; color: #ffffff; background: #444444; opacity: .6;`
|
||||||
|
|
||||||
|
const fileLabel = `<div style="position:relative; height: 0px;"><div class="code-file-label" style="position:absolute; top: -10px;${labelStyle}">${includePath}</div></div>\n\n`
|
||||||
|
const fileExt = includePath.replace(/^.+\./, "")
|
||||||
|
|
||||||
|
// replace include by file content
|
||||||
|
src = src.slice(0, cap.index) + fileLabel + "```" + fileExt + "\n" + mdSrc + "\n```" + src.slice(cap.index + cap[0].length, src.length);
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
};
|
||||||
|
|
||||||
|
const _includeFileParts = (state, startLine, endLine/*, silent*/) => {
|
||||||
|
state.src = _replaceIncludeByContent(state.src, options.getRootDir(options, state, startLine, endLine));
|
||||||
|
};
|
||||||
|
|
||||||
|
md.core.ruler.before('normalize', 'include', _includeFileParts);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = include_plugin;
|
24
docs/markdown-it-code-include/package.json
Normal file
24
docs/markdown-it-code-include/package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "markdown-it-code-include",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A markdown-it plugin to include code blocks.",
|
||||||
|
"main": "./index.js",
|
||||||
|
"scripts": {
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"markdown",
|
||||||
|
"markdown-it",
|
||||||
|
"markdown-it-plugin",
|
||||||
|
"code-blocks",
|
||||||
|
"fence"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-html-parser": "^1.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"markdown-it": "^12.0.0",
|
||||||
|
"markdown-it-testgen": "^0.1.6",
|
||||||
|
"path": "^0.12.7"
|
||||||
|
}
|
||||||
|
}
|
52
docs/md/README.md
Normal file
52
docs/md/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
- [TibiCMS](../README.md)
|
||||||
|
- [Begriffe](begriffe.md)
|
||||||
|
- [Probleme und Lösungen](probleme.md)
|
||||||
|
- Servergrundlagen
|
||||||
|
|
||||||
|
- [Konfiguration](servergrundlagen/konfiguration.md)
|
||||||
|
- [Entitäten](servergrundlagen/entitaeten.md)
|
||||||
|
- [SSR & htaccess](servergrundlagen/ssr&htaccess.md)
|
||||||
|
|
||||||
|
- RestAPI Endpunkte
|
||||||
|
- [/login](restapi/login.md)
|
||||||
|
- [/user](restapi/user.md)
|
||||||
|
- [/project](restapi/project.md)
|
||||||
|
- [/\_/NS/COLLECTION](restapi/collection.md)
|
||||||
|
- [/_/NS/_/assets/ASSETSNAME](restapi/assets.md)
|
||||||
|
- Projekt Konfiguration
|
||||||
|
- [Ordnerstruktur](projektkonfig/ordnerstruktur.md)
|
||||||
|
- [config.yml](projektkonfig/config.yml.md)
|
||||||
|
- [collections](projektkonfig/collections.md)
|
||||||
|
- [fields](projektkonfig/collections/fields.md)
|
||||||
|
- [Datentypen](projektkonfig/collections/fields/datentypen.md)
|
||||||
|
- [Admin Widgets](projektkonfig/collections/fields/widgets.md)
|
||||||
|
- [indexes](projektkonfig/collections/indexes.md)
|
||||||
|
- [hooks](projektkonfig/collections/hooks.md)
|
||||||
|
- [imageFilter](projektkonfig/collections/imageFilter.md)
|
||||||
|
- [meta](projektkonfig/collections/meta.md)
|
||||||
|
- [jobs](projektkonfig/jobs.md)
|
||||||
|
- [assets](projektkonfig/assets.md)
|
||||||
|
- [dashboard](projektkonfig/dashboard.md)
|
||||||
|
- Admin Javascript Kontext
|
||||||
|
- [Allgemeines](admin-javascript-kontext/allgemeines.md)
|
||||||
|
- [collection.meta..eval](admin-javascript-kontext/collection.meta..eval.md)
|
||||||
|
- [field.meta..eval](admin-javascript-kontext/field.meta..eval.md)
|
||||||
|
- Server Javascript Kontext
|
||||||
|
- [Allgmeines](server-javascript-kontext/allgemeines.md)
|
||||||
|
- Packages
|
||||||
|
- [user](server-javascript-kontext/packages/user.md)
|
||||||
|
- [response](server-javascript-kontext/packages/response.md)
|
||||||
|
- [cookie](server-javascript-kontext/packages/cookie.md)
|
||||||
|
- [db](server-javascript-kontext/packages/db.md)
|
||||||
|
- [http](server-javascript-kontext/packages/http.md)
|
||||||
|
- [smtp](server-javascript-kontext/packages/smtp.md)
|
||||||
|
- [fs](server-javascript-kontext/packages/fs.md)
|
||||||
|
- [tpl](server-javascript-kontext/packages/tpl.md)
|
||||||
|
- [jwt](server-javascript-kontext/packages/jwt.md)
|
||||||
|
- [pdf](server-javascript-kontext/packages/pdf.md)
|
||||||
|
- [image](server-javascript-kontext/packages/image.md)
|
||||||
|
- [bcrypt](server-javascript-kontext/packages/bcrypt.md)
|
||||||
|
- [xml](server-javascript-kontext/packages/xml.md)
|
||||||
|
- [charset](server-javascript-kontext/packages/charset.md)
|
||||||
|
- [pdf](server-javascript-kontext/packages/pdf.md)
|
||||||
|
- [debug](server-javascript-kontext/packages/debug.md)
|
47
docs/md/admin-javascript-kontext/allgemeines.md
Normal file
47
docs/md/admin-javascript-kontext/allgemeines.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Javascript-Kontext im tibi-admin
|
||||||
|
|
||||||
|
Diverse `meta`-Angaben ermöglichen neben der eigentliche Angabe eines festen Wertes wie z.B:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
defaultValue: "Hallo Welt"
|
||||||
|
```
|
||||||
|
|
||||||
|
auch die Angabe eines Javascript-Ausdrucks, der zur Laufzeit ausgewertet wird. Dieser Ausdruck wird in einem Javascript-Kontext clientseitig ausgeführt und ist mit diversen Variablen vorbelegt.
|
||||||
|
Die Angabe des Javascript-Codes erfolgt dabei meist mit dem `eval`-Attribut dessen Wert der String des Codes ist:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
defaultValue:
|
||||||
|
eval: "new Date().toISOString().substr(0, 10)"
|
||||||
|
```
|
||||||
|
|
||||||
|
In den Fällen in denen ein Oneliner nicht ausreiched ist, bieten sich "selbst ausführende Funktionen" an, wie z.B.:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(function() {
|
||||||
|
return new Date().toISOString().substr(0, 10)
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
Um diese im YAML unterzubringen nutzt man YAML-Multiline-Modifizierer:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
defaultValue:
|
||||||
|
eval: |
|
||||||
|
(function() {
|
||||||
|
return new Date().toISOString().substr(0, 10)
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kontext-Variablen
|
||||||
|
|
||||||
|
Der Javascript-Kontext ist mit folgenden Variablen standardmäßig angereichert:
|
||||||
|
|
||||||
|
| Variable | Datentyp | Bedeutung |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `$namespace` | string | Der Namespacebezeichner des aktuellen Projekts |
|
||||||
|
| `$apiBase` | string | Basis-URL des API-Endpunkts |
|
||||||
|
| `$projectBase` | string | Basis-URL des Projekts-API-Endpunkts (`$apiBase`_/`$namespace`/) |
|
||||||
|
| `$auth` TODO | object | Das aktuelle Auth-Objetc des eingeloggten Benutzers |
|
||||||
|
| `$project` | object | Das aktuelle Projekt-Objekt, siehe [API /project](./../restapi/project.md) |
|
||||||
|
|
||||||
|
Die `meta`-Daten der Collections und Fields bekommen in den Javascript-Kontext der `eval`-Eigenschaften noch jeweils zusätzliche Variablen.
|
@ -0,0 +1,9 @@
|
|||||||
|
# collection.meta..eval Javascript-Kontext
|
||||||
|
|
||||||
|
Die `eval`-Properties der Eigenschaften (wo möglich) bekommen unterhalb des `collection.meta`-Objektes zusätzlich zu den bereits bekannten Variablen (siehe [Allgemeines zum Kontext](./allgemeines.md)) folgende Variable zur Verfügung:
|
||||||
|
|
||||||
|
|
||||||
|
| Variable | Datentyp | Bedeutung |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `$object` | object | Das aktuelle Kollektion-Objekt, siehe [API /collection](./../restapi/collection.md) |
|
||||||
|
| `$navigation` | object | Das aktuelle Navigation-Objekt, also den entsprechenden aktiven Eintrag aus `meta.subNavigation` |
|
104
docs/md/admin-javascript-kontext/field.meta..eval.md
Normal file
104
docs/md/admin-javascript-kontext/field.meta..eval.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# field.meta..eval Javascript-Kontext
|
||||||
|
|
||||||
|
Zuätzlich zu den allgemeinen und Kollektions-spezifischen Variablen, die im Javascript-Kontext der `eval`-Eigenschaften unterhalb des zur Verfügung stehen, gibt es noch folgende Variablen unterhalb des `field.meta`-Objektes für die Evaluierung:
|
||||||
|
|
||||||
|
| Variable | Datentyp | Bedeutung |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `$field` TODO | object | Das aktuelle Feld-Objekt |
|
||||||
|
| `$method` | `"post"`/`"put"` | `"put"` bedeuted, dass der Datensatz gerade in Bearbeitung ist, `"post"` = Datensatz soll angelegt werden |
|
||||||
|
| `$this` | any | Der aktuelle Wert des Feldes |
|
||||||
|
| `$` | object | Das gesamte Objekt des Dokuments |
|
||||||
|
| `$parent` | object oder array | Der Wert des Elternknotens zum aktuellen Feld |
|
||||||
|
| `$stack` | array | Der Stack bis zum Ursprung des gesamten Objekts |
|
||||||
|
|
||||||
|
## Der Stack
|
||||||
|
|
||||||
|
Um die Abhängigkeiten zu bestimmten Werten ausdrücken zu können (z.B. in `meta.dependsOn.eval`), sind die Variablen `$this`, `$`, `$parent` und `$stack` verfügbar.
|
||||||
|
|
||||||
|
Folgendes Beispiel eines Datensatzes verdeutlicht die Belegung, während die Maske zum Editieren im *tibi-admin* geöffnet ist:
|
||||||
|
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "Mein Datensatz",
|
||||||
|
"meta": {
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
wobei wir den `"key": "pla"` betrachten, wären die Inhalte der Variablen folgende:
|
||||||
|
|
||||||
|
`$this`:
|
||||||
|
|
||||||
|
plah
|
||||||
|
|
||||||
|
`$parent` und `$stack[0]`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`$stack[1]`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
`$stack[2]`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`$stack[3]`, `entry` und `$`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "Mein Datensatz",
|
||||||
|
"meta": {
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
53
docs/md/begriffe.md
Normal file
53
docs/md/begriffe.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Begriffe
|
||||||
|
|
||||||
|
## TibiCMS
|
||||||
|
|
||||||
|
Oberbegrff der den gesamten Stack, bestehend aus _tibi-server_ mit *MongoDB\*\* und *tibi-admin\* beschreibt.
|
||||||
|
|
||||||
|
## tibi-server
|
||||||
|
|
||||||
|
Rest-API Server des _TibiCMS_ Stack
|
||||||
|
|
||||||
|
## tibi-admin
|
||||||
|
|
||||||
|
Admin-UI/Backend zur Verwaltung der Inhalte im _tibi-server_
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
Schnittstelle (hier Rest-API) des _tibi-server_ (im Projektkontext ebenso für Projektspezifische Schnittstelle vrwendet)
|
||||||
|
|
||||||
|
## project / Projekt
|
||||||
|
|
||||||
|
Projekt innerhalb des _TibiCMS_ welches üblicherweise die Datengrundlage für eine Website im _TibiCMS_ ist
|
||||||
|
|
||||||
|
## collection / Kollektion
|
||||||
|
|
||||||
|
Datensammlung innerhalb eines Projekte (z.B. Newsartikel), in relationalen Datenbanken oft eine Tabelle
|
||||||
|
|
||||||
|
## field / Feld
|
||||||
|
|
||||||
|
Ein Datenfeld innerhalb einer Kollektion mit einem bestimmten Datentyp (z.B. string, number, ...)
|
||||||
|
|
||||||
|
## validator / Validator
|
||||||
|
|
||||||
|
Code oder Anweisung zur Überprüfung der Gültigkeit von Feld-Daten
|
||||||
|
|
||||||
|
## filter / Filter
|
||||||
|
|
||||||
|
Bildfilter zum Verkleinern oder Bearbeiten von Bildern beim Abruf von der API
|
||||||
|
|
||||||
|
## projection / Projektion
|
||||||
|
|
||||||
|
Abbildung der Daten auf ein Subset der Originaldaten
|
||||||
|
|
||||||
|
## hook
|
||||||
|
|
||||||
|
Vorerst nur in Javascript geschriebene Algorithmen, die die sich in die API einklinken um Daten oder Abläufe zu manipulieren
|
||||||
|
|
||||||
|
## user / Benutzer
|
||||||
|
|
||||||
|
Ein Benutzer mit Login innerhalb des _TibiCMS_
|
||||||
|
|
||||||
|
## permission / Berechtigung
|
||||||
|
|
||||||
|
Berechtigung innerhalb eines Projektes, welche einem Benutzer zugeordnet werden kann
|
34
docs/md/docpress.css
Normal file
34
docs/md/docpress.css
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.title, h1, h2, h3, h4, h5, .link.title.link-index {
|
||||||
|
color: #531414!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link.title {
|
||||||
|
color: black!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-menu .link.-active, .toc-menu .hlink.-active {
|
||||||
|
box-shadow: inset -2px 0 #7c2828!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.heading-list .hlink, ul.heading-list .hlink:visited {
|
||||||
|
color: #414141!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-toggle:hover, .footer-nav a:hover, .footer-nav a:hover:after, .footer-nav a:hover:before {
|
||||||
|
color: #7c2828!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-file-label {
|
||||||
|
background: #dcd9d9!important;
|
||||||
|
color: #3a0909!important;
|
||||||
|
right: 0px;
|
||||||
|
opacity: 1!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #7c2828!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color:#3a0909!important;
|
||||||
|
}
|
130
docs/md/github-dark-dimmed.css
Normal file
130
docs/md/github-dark-dimmed.css
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*!
|
||||||
|
Theme: GitHub Dark Dimmed
|
||||||
|
Description: Dark dimmed theme as seen on github.com
|
||||||
|
Author: github.com
|
||||||
|
Maintainer: @Hirse
|
||||||
|
Updated: 2021-05-15
|
||||||
|
|
||||||
|
Colors taken from GitHub's CSS
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs, pre, pre code {
|
||||||
|
color: #adbac7!important;
|
||||||
|
background: #22272e!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-doctag,
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-meta .hljs-keyword,
|
||||||
|
.hljs-template-tag,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-variable.language_,
|
||||||
|
.pl-k {
|
||||||
|
/* prettylights-syntax-keyword */
|
||||||
|
color: #f47067!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-title.class_,
|
||||||
|
.hljs-title.class_.inherited__,
|
||||||
|
.hljs-title.function_i,
|
||||||
|
.pl-s {
|
||||||
|
/* prettylights-syntax-entity */
|
||||||
|
color: #dcbdfb!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-operator,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.pl-e {
|
||||||
|
/* prettylights-syntax-constant */
|
||||||
|
color: #6cb6ff!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-meta .hljs-string,
|
||||||
|
.pl-s {
|
||||||
|
/* prettylights-syntax-string */
|
||||||
|
color: #96d0ff!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-symbol,
|
||||||
|
.pl-c1 {
|
||||||
|
/* prettylights-syntax-variable */
|
||||||
|
color: #f69d50!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-code,
|
||||||
|
.hljs-formula,
|
||||||
|
.pl-c {
|
||||||
|
/* prettylights-syntax-comment */
|
||||||
|
color: #768390!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-quote,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
/* prettylights-syntax-entity-tag */
|
||||||
|
color: #8ddb8c!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-subst {
|
||||||
|
/* prettylights-syntax-storage-modifier-import */
|
||||||
|
color: #adbac7!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section {
|
||||||
|
/* prettylights-syntax-markup-heading */
|
||||||
|
color: #316dca!important;
|
||||||
|
font-weight: bold!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-bullet {
|
||||||
|
/* prettylights-syntax-markup-list */
|
||||||
|
color: #eac55f!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
/* prettylights-syntax-markup-italic */
|
||||||
|
color: #adbac7!important;
|
||||||
|
font-style: italic!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
/* prettylights-syntax-markup-bold */
|
||||||
|
color: #adbac7!important;
|
||||||
|
font-weight: bold!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
/* prettylights-syntax-markup-inserted */
|
||||||
|
color: #b4f1b4!important;
|
||||||
|
background-color: #1b4721!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
/* prettylights-syntax-markup-deleted */
|
||||||
|
color: #ffd8d3!important;
|
||||||
|
background-color: #78191b!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-char.escape_,
|
||||||
|
.hljs-link,
|
||||||
|
.hljs-params,
|
||||||
|
.hljs-property,
|
||||||
|
.hljs-punctuation,
|
||||||
|
.hljs-tag {
|
||||||
|
/* purposely ignored */
|
||||||
|
}
|
58
docs/md/probleme.md
Normal file
58
docs/md/probleme.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Bekannte Probleme im Entwicklungsprozess mit TibiCMS
|
||||||
|
|
||||||
|
In diesem Abschnitt werden bekannte Probleme während des Entwicklungsprozesses mit TibiCMS beschrieben und Lösungsansätze aufgezeigt. Sollten ein Problem auftauchen, welches hier nicht beschrieben ist, ist es gerne gesehen, wenn dieses Problem hier dokumentiert wird.
|
||||||
|
|
||||||
|
## Probleme mit CollectionEntry Objekten
|
||||||
|
|
||||||
|
### Problemstellung
|
||||||
|
|
||||||
|
Wenn ein Objekt vom Typ CollectionEntry zurückgegeben wird, zeigt sich teilweise eine eingeschränkte Kompatibilität mit JavaScript. Beispielsweise funktioniert die push-Methode nicht bei Attributen, die einen Array-Datentyp speichern.
|
||||||
|
|
||||||
|
### Ursache
|
||||||
|
|
||||||
|
Die Problematik entsteht durch die Übersetzung des Objekts von Go nach JavaScript. Hierbei werden die Attribute nicht als native JavaScript-Objekte, sondern als Go-Objekte übersetzt, was zu einer eingeschränkten Kompatibilität führt. Insbesondere unterstützen sie nicht gängige Methoden wie push, pop etc. Ein weiteres Problem ist, dass bei diesen Inkompatibilitäten _keine Fehlermeldungen generiert_ werden, sondern schlichtweg _keine Aktion_ erfolgt.
|
||||||
|
|
||||||
|
### Lösungsansatz
|
||||||
|
|
||||||
|
Beim Manipulieren von CollectionEntry-Objekten innerhalb eines Hooks sollte man zur Sicherheit eine tiefe Kopie (Deep Copy) des Objekts erstellen, um es vollständig in ein JavaScript-Objekt zu konvertieren. Die Verwendung von {...} reicht hierbei nicht aus, da dies nur die oberste Ebene des Objekts konvertiert. JSON.stringify und JSON.parse sind nur dann zu empfehlen, wenn die Reihenfolge der Attribute irrelevant ist. Für Fälle, in denen die Reihenfolge wichtig ist, existiert bereits eine spezielle Funktion, die dies beibehält. Diese Funktion ist unter dem Namen „obj2str“ in der Utils-Datei zu finden.
|
||||||
|
|
||||||
|
### Warum die Ursache nicht behoben wurde
|
||||||
|
|
||||||
|
Die Ursache wurde nicht behoben, da die Standardmäßige, uneingeschränkte übersetzung von Go zu JS einen performancemäßigen totalschaden darstellt.
|
||||||
|
|
||||||
|
## Probleme mit SSR kompilierung
|
||||||
|
|
||||||
|
### Problemstellung
|
||||||
|
|
||||||
|
Website wird nur teilweise oder gar nicht gerendert.
|
||||||
|
|
||||||
|
### Ursache
|
||||||
|
|
||||||
|
In meinem Fall war das Problem, dass ein Button element in einem anderen Button Element enthalten war. Dies hat dazu geführt, dass der Compiler manchmal die Vollständige Seite nicht gerendert hat, manchmal auch nur vereinzelte Elemente.
|
||||||
|
|
||||||
|
### Lösungsansatz
|
||||||
|
|
||||||
|
Semantisch arbeiten.
|
||||||
|
|
||||||
|
### Warum die Ursache nicht behoben wurde
|
||||||
|
|
||||||
|
In dem fall liegt der Programmcode fehler nicht bei uns, da die Kompillierung von svelte übernommen wird.
|
||||||
|
|
||||||
|
## Probleme mit Variablen werten in #each loops
|
||||||
|
|
||||||
|
### Problemstellung
|
||||||
|
|
||||||
|
Wenn in Svelte in einem each block die länge der liste, über die iteriert wurde, verändert wird, kann es zu fehlern kommen, wenn kein einzigartiger key für jedes element angegeben wurde.
|
||||||
|
|
||||||
|
### Ursache
|
||||||
|
|
||||||
|
Die Ursache ist, dass svelte die liste nicht neu rendert, sondern nur die die properties neu zuordnet. Svelte behandelt keinen key wie den idx als key. Sprich ursprünglich gab es 3 Elemente El1, El2, El3. Wenn nun El1 entfernt wird, wird in der DOM tatsächlich El3 entfernt, da 2 ja nun der key ist, der nicht mehr existiert (idx 2/element 3) und die properties von El3 zu El2 und von El2 zu El1 zugewiesen. Das bedeutet, dass nicht reaktive variablen weiterhin den Wert von der vorherigen Komponente beeinhalten!
|
||||||
|
|
||||||
|
### Lösungsansatz
|
||||||
|
|
||||||
|
Die einfachste Lösung wäre eine Id als key zu haben, die einzigartig für das jeweilige Element ist, da svelte dann in der DOM genau das Element entfernt und nicht das letzte. Hat man das nicht und
|
||||||
|
möchte , dass der inhalt bei Veränderung der Array länge tatsächlich neu gerendert wird, so muss man explizit ein {#key} block drum rum bauen mit den jeweiligen Wert wo es neu gerendert werden soll (key nutzt ebenfalls reactive statements....).
|
||||||
|
|
||||||
|
### Warum die Ursache nicht behoben wurde
|
||||||
|
|
||||||
|
Gibt keine Lösung, da es standard Svelte verhalten ist. Gibt nur den vorgestellten workaround
|
BIN
docs/md/projektkonfig/api-ordner.png
Normal file
BIN
docs/md/projektkonfig/api-ordner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
3
docs/md/projektkonfig/assets.md
Normal file
3
docs/md/projektkonfig/assets.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Folgende Angaben sind in der `assets`-Sektion der [config.yml](./config.yml.md) geführt als Liste möglich:
|
||||||
|
|
||||||
|
!!!include(../api/assets/dist.yml)!!!
|
17
docs/md/projektkonfig/collections.md
Normal file
17
docs/md/projektkonfig/collections.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# collections
|
||||||
|
|
||||||
|
Die Konfiguration einer Kollektion sollte zur besseren Übersicht innerhalb einer gesonderten Datei im Unterorder **api/collections/** erfolgen und via `!include` in die [config.yml](./config.yml.md) eingebunden werden.
|
||||||
|
|
||||||
|
## Grundlegender Aufbau
|
||||||
|
|
||||||
|
Eine solche Datei hat folgenden Aufbau:
|
||||||
|
|
||||||
|
!!!include(../api/collections/medialib.yml)!!!
|
||||||
|
|
||||||
|
### siehe
|
||||||
|
|
||||||
|
- [fields](./collections/fields.md)
|
||||||
|
- [indexes](./collections/indexes.md)
|
||||||
|
- [hooks](./collections/hooks.md)
|
||||||
|
- [imageFilter](./collections/imageFilter.md)
|
||||||
|
- [meta](./collections/meta.md)
|
BIN
docs/md/projektkonfig/collections/dependsOn.webm
Normal file
BIN
docs/md/projektkonfig/collections/dependsOn.webm
Normal file
Binary file not shown.
295
docs/md/projektkonfig/collections/fields.md
Normal file
295
docs/md/projektkonfig/collections/fields.md
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
# fields
|
||||||
|
|
||||||
|
Felder im _tibi-server_ müssen einen bestimmten Datentyp haben. Über den _tibi-admin_ können die Felder über Widgets in unterschiedlichen Ausprägungen dargestellt werden (view-Widgets), bzw. dem Benutzer eine Eingabe abverlangen (input-Widgets).
|
||||||
|
|
||||||
|
Es gibt grundlegende Angaben, die jedes Feld haben muss um vom _tibi-server_ akzeptiert zu werden. Darüber hinaus kann auch jedes Feld ein `meta` Objekt haben, was dem _tibi-admin_ mitteilt, wie er dieses Feld für Ausgabe und Eingabe behandel soll.
|
||||||
|
|
||||||
|
Zunächst folgt der grundlegende Aufbau des Feld-Objektes:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# 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"
|
||||||
|
```
|
||||||
|
|
||||||
|
## validator Objekt
|
||||||
|
|
||||||
|
<video width="100%" controls muted autoplay loop>
|
||||||
|
<source src="validator.webm" type="video/webm">
|
||||||
|
</video>
|
||||||
|
|
||||||
|
Wie im Beispiel von **fields/date.yml** unter `validator` zu sehen ist, wird dort ein Datum nach dem aktuellen erwartet. Wie der Validator sich auf die UI auswirkt, ist im obigen Video zu sehen.
|
||||||
|
|
||||||
|
Das `validator` Objekt wird _tibi-server_ seitig genutzt um die Daten zu validieren. Da das `validator` Objekt dem _tibi-admin_ ebenso zur Verfügung steht, kann vorab eine client-seitige Validierung zusätzlich durchgeführt werden.
|
||||||
|
|
||||||
|
Attribute des Objektes:
|
||||||
|
|
||||||
|
| Attribut | Datentyp | Beschreibung |
|
||||||
|
| ----------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `required` | boolean | wenn `true`, dann ist zwingend eine Eingabe zu diesem Feld nötig |
|
||||||
|
| `allowZero` | boolean | in Kombination mit `required: true`, wenn `true`, dann ist der jeweilige "Null"-Wert des Datentyps erlaubt<br><br>z.B. `type: string` erlaubt den leeren String und `type: number` erlaubt `0` |
|
||||||
|
| `eval` | string | Javascript-Code der zu true evaluieren muss um den Wert des Feldes als gültig zu definieren |
|
||||||
|
|
||||||
|
### eval-Attribut
|
||||||
|
|
||||||
|
Der Javascript-Code in diesem Attribut kann folgende Rückgabe-Werte haben:
|
||||||
|
|
||||||
|
| Wert | Bedeutung |
|
||||||
|
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| `true` | Der Wert des Feldes ist gültig |
|
||||||
|
| `false` | Der Wert des Feldes ist ungültig |
|
||||||
|
| `"Text"` | Wird ein String zurückgegeben ist, wird der Wert es Feldes ebenso als ungültig erachtet und der String selbst ist eine benutzerdefinierte Fehlermeldung, die in der Serverantwort gelesen werden kann. |
|
||||||
|
|
||||||
|
Da der `eval` Code serverseitig immer ausgeführt wird und ein Fehlschlag zwangsläufig zum Abbruch der Serveraktion führt, ist es wichtig, dass der Validator berücksichtigt wird.
|
||||||
|
|
||||||
|
Optional kann der Code auch zusätzlich über eine Lauffähigkeit ohne Fehler (z.B. keine Verwendung nicht vorhandender Kontext-Variablen oder Verwendung von `try ... catch`) im _tibi-admin_ verfügen. Das hat den Vorteil, dass eine Vorab-Validierung stattfindet, bevor der Datensatz an der Server gesendet wird.
|
||||||
|
|
||||||
|
Sollte der `eval` Code im _tibi-admin_ nicht lauffähig sein (nicht abgefangene Exception), wird der Validator clientseitig ingoriert und nur die serverseitige Prüfung beeinflusst die Aktion.
|
||||||
|
|
||||||
|
#### siehe
|
||||||
|
|
||||||
|
- [Server Javascript Kontext](./../../server-javascript-kontext/allgemeines.md)
|
||||||
|
|
||||||
|
## dependsOn
|
||||||
|
|
||||||
|
<video width="100%" controls muted autoplay loop>
|
||||||
|
<source src="dependsOn.webm" type="video/webm">
|
||||||
|
</video>
|
||||||
|
|
||||||
|
Obige Darstellung wie im Video wird beispielsweise durch folgende Feld-Konfiguration erreicht:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# in einer Kollektions-Konfiguration
|
||||||
|
fields:
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- name: title
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: Title
|
||||||
|
|
||||||
|
- name: date
|
||||||
|
type: date
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: title
|
||||||
|
widget: date
|
||||||
|
defaultValue:
|
||||||
|
eval: new Date()
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent?.type == "news"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
`meta.dependsOn` kann als Objekt mit `eval`-Attribut für Javascript oder als `string` mit dem Feldnamen (Punktschreibweise, z.B. `"additionalData.author"`) angegeben werden.
|
||||||
|
|
||||||
|
Wird der Feldname verwendet wird nur geprüft, ob das Feld belegt ist. TODO
|
||||||
|
|
||||||
|
Die `eval` Variante verwendet als Javascript-Kontext Variablen die auf folgenden Seite beschrieben werden:
|
||||||
|
|
||||||
|
- [Admin Javascript Kontext](./../../admin-javascript-kontext/allgemeines.md)
|
||||||
|
- [collection.meta..eval](./../../admin-javascript-kontext/collection.meta..eval.md)
|
||||||
|
- [field.meta..eval](./../../admin-javascript-kontext/field.meta..eval.md)
|
||||||
|
|
||||||
|
Die Rückgabe des Javascript-Codes beeinflusst die Einblendung des betroffenen Feldes in folgender Weise:
|
||||||
|
|
||||||
|
| Rückgabe | Bedeutung |
|
||||||
|
| -------- | -------------------------- |
|
||||||
|
| `true` | Das Feld wird angezeigt |
|
||||||
|
| `false` | Das Feld wird ausgeblendet |
|
||||||
|
|
||||||
|
## defaultValue
|
||||||
|
|
||||||
|
Für die Vorlegung neu anzulegender Datensätze kann in `field.meta.defaultValue` direkt der Standardwert hinterlegt werden, oder über `field.meta.defaultValue.eval` ein Javascript-Code angegeben werden, der den Wert ermittelt. Die Rückgabe des Javascript-Codes, sowie auch die direkte Vergabe des Wertes muss dem Datentyp des Feldes entsprechen.
|
||||||
|
|
||||||
|
Der Javascript-Kontext ist der gleiche wie bei `field.meta.dependsOn.eval`.
|
||||||
|
|
||||||
|
## containerProps
|
||||||
|
|
||||||
|
Um Felder auf breiten Bildschirmen eine schmalere Breite zu geben, wird das containerProps Attribut empfohlen. Es hat ein class Attribut, welches klassen ins HTML injiziert. Es gibt außerdem noch das Layout attribut mit breakBefore und breakAfter, welche dafür sorgen, dass vorher bzw. nachher keine weiteren HTML Elemente platz finden. Hier ist des weiteren das size Objekt drin, welches 3 attribute hat. Die attribute sollten col-1 bis col-12 beeinhalten, diese klassen werden ins html injiziert, können also dem zufolge auch misbraucht werden. Die klassen bei den attributen werden bei unterschiedlichen Bildschirmbreiten aktiv.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: false
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
```
|
||||||
|
|
||||||
|
## inputProps
|
||||||
|
|
||||||
|
Wenn man das Input element direkt bearbeiten möchte (Bspw. readonly oder ähnliches), so kann man diese hier als Objekt übergeben:
|
||||||
|
|
||||||
|
## hide
|
||||||
|
|
||||||
|
möchte man, dass ein bestimmtes Feld nicht im TibiAdmin sichtbar ist, so muss man die property hide auf true setzen.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
inputProps: { readonly: true, placeholder: { de: "Wert wird automatisch gesetzt", en: "Value is set automatically" } }
|
||||||
|
```
|
||||||
|
|
||||||
|
## direction
|
||||||
|
|
||||||
|
Für type Object[] gibt es im Meta objekt das direction attribut, dies kann entweder:
|
||||||
|
|
||||||
|
- `horizontal`: flex-direction: row
|
||||||
|
oder
|
||||||
|
- `vertical`: flex-direction: column
|
||||||
|
annehmen.
|
||||||
|
|
||||||
|
## metaElements
|
||||||
|
|
||||||
|
Möchte man bestimmte Elemente über das Zahnrad greifbar machen (bei type: Object[]), so kann man dies über dieses Attribut tun. Es ist entweder über eine Liste, oder über tablist möglich.
|
||||||
|
!!!include(../api/collections/fields/info.yml)!!!
|
||||||
|
|
||||||
|
## folding
|
||||||
|
|
||||||
|
Das folding Objekt ist ebenfalls ein Teil im Meta object und dient dazu, type ObjectArray einen Wert in den Header im HTML einzuschreiben (von den einzelnen Objekten). Es wird vorallem dazu genutzt, die Rows bzw. Columns der Website rein zu rendern, um praktisch ein direktes Prview zu haben. Ebenfalls gibt es das force attribut, welches dafür sorgt, dass die objekte IMMER geöffnet sind und man sie nicht schließen kann. Sinnvoll für Rows. die Generelle struktur verdeutlicht folgendes Code Beispiel:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
folding:
|
||||||
|
force: false
|
||||||
|
previewUnfolded:
|
||||||
|
raw: true
|
||||||
|
eval: |
|
||||||
|
//js
|
||||||
|
(() => {
|
||||||
|
return $this?.title ? "<h2 style=\"\">" + $this.title + "</h2>" : ""
|
||||||
|
})()
|
||||||
|
//!js
|
||||||
|
previewFolded:
|
||||||
|
eval: |
|
||||||
|
//js
|
||||||
|
(async () => {
|
||||||
|
const { getRenderedElement, Row } = await import($projectBase + "_/assets/dist/admin.mjs")
|
||||||
|
|
||||||
|
const container = getRenderedElement(Row, {
|
||||||
|
props: {
|
||||||
|
row: Object.assign({}, $this),
|
||||||
|
contentId: $?.id,
|
||||||
|
apiBaseURL: $projectBase,
|
||||||
|
},
|
||||||
|
addCss: [
|
||||||
|
$projectBase + "_/assets/dist/index.css",
|
||||||
|
$projectBase + "_/assets/dist/admin.css",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
let style = "max-width: 1220px;"
|
||||||
|
container.style = style
|
||||||
|
return container
|
||||||
|
})()
|
||||||
|
//!js
|
||||||
|
```
|
||||||
|
|
||||||
|
Hierbei ist raw dafür da, das ganze als HTML direkt zu rendern, wenn es true ist. Der prefiewFolded bereich rendert letzten endes die Seite selbst, für diese Funktionallität ist mehreres notwendig.
|
||||||
|
|
||||||
|
- `Row und Column Komponenten`: Dies sind letzenendes jene komponenten die gerendert werden, daher muss man sie natürlich auch bereits programmiert haben.
|
||||||
|
- `admin.ts file`: Dieses file wird im src Folder platziert und durch ES-Build über den oben genutzen Pfad verfügbar gemacht. Hier ist ein Beispiel:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import Row from "./components/Row.svelte"
|
||||||
|
import Col from "./components/Col.svelte"
|
||||||
|
|
||||||
|
function getRenderedElement(component, options?: { props: { [key: string]: any }; addCss?: string[] }) {
|
||||||
|
const el = document.createElement("div")
|
||||||
|
el.attachShadow({ mode: "open" })
|
||||||
|
|
||||||
|
const target = document.createElement("body")
|
||||||
|
el.shadowRoot.appendChild(target)
|
||||||
|
|
||||||
|
options?.addCss?.forEach((css) => {
|
||||||
|
const link = document.createElement("link")
|
||||||
|
link.rel = "stylesheet"
|
||||||
|
link.href = css
|
||||||
|
link.type = "text/css"
|
||||||
|
el.shadowRoot.appendChild(link)
|
||||||
|
})
|
||||||
|
|
||||||
|
new component({
|
||||||
|
target: target,
|
||||||
|
props: options?.props,
|
||||||
|
})
|
||||||
|
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getRenderedElement, Row, Col }
|
||||||
|
```
|
||||||
|
|
||||||
|
Das props Attribut nimmt ein Objekt entgegen, welches als keys die namen hat, wie in der svelte Komponente über export exportiert wurde. Die Komponenten werden in eine Shadow Dom geladen, um sie seperat vom restlichen code halten zu können.
|
43
docs/md/projektkonfig/collections/fields/datentypen.md
Normal file
43
docs/md/projektkonfig/collections/fields/datentypen.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Datentypen
|
||||||
|
|
||||||
|
Via `type` wird der Datentyp des Feldes definiert. Diese Angaben sind für den Tibi Server relevant. Folgende Datentypen sind möglich:
|
||||||
|
|
||||||
|
## string
|
||||||
|
|
||||||
|
String wird für Zeichenketten verwendet. Das Standardwidget ohne weitere Angabe ist bei der Ausgabe die direkte Textausgabe und bei der Eingabe ein HTML `<input ...>` Element mit dem Attribut `type="text"`.
|
||||||
|
|
||||||
|
## number
|
||||||
|
|
||||||
|
Number wird sowohl für ganze Zahlen, wie auch für Gleitkommawerte definiert. Auch hier ist das Standard-Widget für die Eingabe ein HTML `<input ...>` Element, allerdings mit dem Attribut `type="number"`.
|
||||||
|
|
||||||
|
## boolean
|
||||||
|
|
||||||
|
Ein boolcher Wert, also `true` oder `false`, wird über den Typ `"boolean"` definiert und standardmäßig als Checkbox dargestellt.
|
||||||
|
|
||||||
|
## date
|
||||||
|
|
||||||
|
`"date"` als Datentyp kann sowohl Datumsangabe mit, als auch ohne Uhrzeit aufnehmen. Das Standardwidget ist die einfache Datumseingabe ohne Uhrzeit.
|
||||||
|
|
||||||
|
## file
|
||||||
|
|
||||||
|
Der Datentyp `"file"` ist für Dateiuploads vorgesehen. Es daher standardmäßig ein Datei-Auswahl-Dialog als Widget für die Eingabe angeboten.
|
||||||
|
|
||||||
|
## string[]
|
||||||
|
|
||||||
|
Für `"string[]` Arrays ist die Angabe des Widgets zwingend notwendig.
|
||||||
|
|
||||||
|
## number[]
|
||||||
|
|
||||||
|
Auch für `"number[]"` Arrays wird die Widget-Angabe erwartet.
|
||||||
|
|
||||||
|
## object
|
||||||
|
|
||||||
|
`"object"` ist ein spezieller Datentyp der zur Strukturierung der API und der Eingabe dient. Dieser Datentyp fasst `subFields` zusammen.
|
||||||
|
|
||||||
|
## object[]
|
||||||
|
|
||||||
|
Wie `"object"` fasst auch das `"object[]"` Array `subFields` zusammen. Diese allerdings als Liste von Objekten, anstatt als Einzelobjekt.
|
||||||
|
|
||||||
|
## any
|
||||||
|
|
||||||
|
Felder vom Typ `"any"` können beliebige Daten aufnehmen. Die Validierung schlägt auf Basis der Typ-Validierung hier nie fehl.
|
BIN
docs/md/projektkonfig/collections/fields/defaultArray.png
Normal file
BIN
docs/md/projektkonfig/collections/fields/defaultArray.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
docs/md/projektkonfig/collections/fields/foreign.png
Normal file
BIN
docs/md/projektkonfig/collections/fields/foreign.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
131
docs/md/projektkonfig/collections/fields/widgets.md
Normal file
131
docs/md/projektkonfig/collections/fields/widgets.md
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# Widgets
|
||||||
|
|
||||||
|
Die Verwendung von Widgets innerhalb der Anwendung tibi-admin dient zur Handhabung von Dateninputs und -outputs. Das genutzte Widget wird über das meta.widget Feld in der Konfiguration spezifiziert. Dabei wird der Name des Widgets als Textzeichenkette (String) angegeben.
|
||||||
|
|
||||||
|
Es ist zu beachten, dass nicht jedes Widget für jeden Datentyp geeignet ist. Im Weiteren werden die kompatiblen Datentypen für jedes Widget aufgeführt. Zusätzlich werden spezielle Konfigurationsmöglichkeiten für jedes Widget erläutert.
|
||||||
|
|
||||||
|
## Texteingabefeld-Widgets: string / text / input
|
||||||
|
|
||||||
|
Diese Bezeichnungen stehen alle für dasselbe Widget. Es handelt sich hierbei um ein Texteingabefeld. Dieses Widget wird für den Datentyp String verwendet. Sollte ein größeres Textfeld (Textarea) anstatt eines einfachen Eingabefeldes (Input) gewünscht sein, so kann dies erreicht werden, indem das Attribut multiline im inputProps Objekt auf true gesetzt wird.
|
||||||
|
!!!include(../api/collections/fields/pageTitle.yml)!!!
|
||||||
|
|
||||||
|
## Numerische Eingabefeld-Widgets: number / int / integer / float / double
|
||||||
|
|
||||||
|
Diese unterschiedlichen Bezeichnungen stehen alle für dasselbe Widget. Hierbei handelt es sich um ein Eingabefeld für Zahlen. Es wird für den Datentyp Number verwendet.
|
||||||
|
!!!include(../api/collections/fields/manualSort.yml)!!!
|
||||||
|
|
||||||
|
## Auswahl-Widgets: boolean / bool / check / switch / checkbox
|
||||||
|
|
||||||
|
Diese verschiedenen Bezeichnungen repräsentieren dasselbe Widget. Dieses Widget wird in Form einer Auswahlbox (Checkbox) dargestellt und wird für den Datentyp Boolean verwendet.
|
||||||
|
!!!include(../api/collections/fields/active.yml)!!!
|
||||||
|
|
||||||
|
## Auswahl-Widgets für mehrere Optionen: select / selectArray
|
||||||
|
|
||||||
|
Diese beiden Widgets sind im Prinzip das Gleiche, nur mit unterschiedlichen Namen. Intern wird die Unterscheidung zwischen Mehrfachauswahl und einfacher Auswahl anhand des Datentyps getroffen. Bei Datentypen mit einem "[]" am Ende wird die Mehrfachauswahl verwendet. Der Einsatz von selectArray ist für String-Arrays vorgesehen, select für einzelne Strings. Aktuell sind nur Strings möglich, da das Element alle Werte zu Strings konvertiert. Anpassungen sind jedoch bei Bedarf möglich. Es ist wichtig zu beachten, dass das name-Attribut den visuell dargestellten Wert darstellt, während die id den gespeicherten Wert repräsentiert. Wenn choices als Objekt angegeben wird, wird eine Anfrage an den spezifizierten Endpunkt mit den angegebenen Parametern gesendet und das gemappte name-Attribut davon angezeigt. Die id der ausgewählten Elemente wird intern als String gespeichert. Weiterhin ist die Angabe von chipStyle: (style) möglich. Dieser wird als Stil in das Element gerendert und ermöglicht zum Beispiel die visuelle Darstellung von Flaggen.
|
||||||
|
!!!include(../api/collections/fields/contentType.yml)!!!
|
||||||
|
|
||||||
|
## Bezug zu anderen Datenbankeinträgen: foreignKey
|
||||||
|
|
||||||
|
Dieses Widget wird verwendet, um eine Referenz zu einem anderen Datenbankeintrag herzustellen. Neben der Angabe von widget: foreignKey gibt es das foreign Attribut, welches die referenzierte Sammlung (collection) angibt. Zudem gibt es ein id Feld, welches die spezifische id für die Sicherheitsüberprüfung angibt. Wird hier "id" angegeben, wird es automatisch auf \_id gemappt, da dies der Name des ID-Feldes in MongoDB ist. Des Weiteren gibt es eine subNavigation, die die Struktur des Modals spezifiziert und neben dem Üblichen a) modal heißen sollte (Konvention) und b) einen defaultCallback haben sollte, der ausgelöst wird, wenn auf den Eintrag geklickt wird. Für die Auswahl gibt es auf dem Fensterobjekt (window Objekt) eine selectEntry Methode, die den ForeignEntry auswählt. Es gibt auch ein sort Attribut, falls die Auswahlmöglichkeiten sortiert werden sollen. Dieses wird einfach an die Anfrage angehängt. Wenn die zurückgegebenen Felder eingeschränkt werden sollen, kann eine Projektion (projection) für die Sammlung spezifiziert werden. Schließlich gibt es das render Attribut, welches ein Objekt ist und ein eval Feld enthält. Hier kann man unter anderem auf $foreignEntry und somit auf alle Werte der ausgewählten Projektion zugreifen. Der zurückgegebene Wert wird schließlich gerendert. Wenn das HTML roh gerendert werden soll, kann das raw Attribut auf true gesetzt werden.
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/images.yml)!!!
|
||||||
|
|
||||||
|
```yml
|
||||||
|
meta: #... in medialib collection
|
||||||
|
subNavigation:
|
||||||
|
- name: modalForeign # Name des Eingabefelds oder der Ansicht.
|
||||||
|
defaultSort: # Standard-Sortierkriterien, die angewendet werden, wenn keine anderen Sortierkriterien spezifiziert sind.
|
||||||
|
field: "path" # Standardmäßig wird nach dem "path"-Feld sortiert.
|
||||||
|
order: "ASC" # Standardmäßig wird in aufsteigender Reihenfolge (ASC) sortiert.
|
||||||
|
views: # Liste der Ansichten, die in diesem Feld angezeigt werden können.
|
||||||
|
- 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.
|
||||||
|
- source: file
|
||||||
|
|
||||||
|
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
|
||||||
|
eval: | # Der Code wird als JavaScript evaluiert.
|
||||||
|
//js
|
||||||
|
(entry) => {
|
||||||
|
parent.selectEntry(entry)
|
||||||
|
}
|
||||||
|
//!js
|
||||||
|
```
|
||||||
|
|
||||||
|
Setzt man defaultCollectionViews auf true, so könnte das ergebnis wie folgt aussehen:
|
||||||
|
![defaultCollectionViews auf ture](foreign.png)
|
||||||
|
|
||||||
|
## Datums-Widgets: date / dateTime
|
||||||
|
|
||||||
|
Diese beiden Widgets können für den Typ "date" verwendet werden. date erzeugt ein Widget (nur das Datum), während dateTime ein Widget erzeugt (Datum und Uhrzeit).
|
||||||
|
!!!include(../api/collections/fields/from.yml)!!!
|
||||||
|
|
||||||
|
## Textbearbeitungs-Widgets: richtext / html
|
||||||
|
|
||||||
|
Diese beiden Bezeichnungen stehen für dasselbe Widget. Es handelt sich um ein Textfeld (Textarea) mit erweiterten Bearbeitungsmöglichkeiten (ähnlich wie in Word), wobei die Eingabe als HTML in einen String geladen wird. Das HTML kann auch manuell angepasst werden, indem die "source" Checkbox aktiviert wird.
|
||||||
|
!!!include(../api/collections/fields/text.yml)!!!
|
||||||
|
|
||||||
|
## Datei-Upload-Widgets: file / image / mediaLibraryFile
|
||||||
|
|
||||||
|
Diese verschiedenen Bezeichnungen stehen alle für das gleiche Widget. Es wird für den Datentyp File verwendet.
|
||||||
|
!!!include(../api/collections/fields/file.yml)!!!
|
||||||
|
|
||||||
|
## Mehrfachauswahl-Widgets: checkboxArray
|
||||||
|
|
||||||
|
Hierbei handelt es sich um eine Reihe von Auswahlboxen (Checkboxen). Jede einzelne Auswahlbox spiegelt das Array choices wider. Dies entspricht genau dem, was auch im selectArray geschieht, nur dass es hier anders dargestellt wird.
|
||||||
|
!!!include(../api/collections/fields/excludedDays.yml)!!!
|
||||||
|
|
||||||
|
## Eingabe mit Vorschlägen: chipArray
|
||||||
|
|
||||||
|
Dieses Widget hat eine ähnliche Funktion wie select, wird jedoch visuell anders dargestellt. Es bietet ein Eingabefeld, in dem nur Elemente akzeptiert werden, wenn ein Objekt im choices Array den gleichen name Wert wie das Eingabeelement hat. Darüber hinaus kann man im meta Objekt autocomplete auf true setzen, um die Autovervollständigung zu aktivieren. Dadurch werden dem Benutzer die möglichen Einträge angezeigt und können direkt ausgewählt werden, was die Benutzerfreundlichkeit erhöht.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
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.
|
||||||
|
```
|
||||||
|
|
||||||
|
## object / objectArray / object[] / containerLessObjectArray / containerLessObject
|
||||||
|
|
||||||
|
Dieses Widget erfordert die weitere Angabe von subFields, die außerhalb des meta Objekts spezifiziert werden müssen. Hier werden die Felder angegeben, die in diesem Objekt enthalten sein sollen. containerLess bedeutet, dass das Objekt in der UI nicht dargestellt wird, und nur der Inhalt ausgegeben. Dadurch wird übermäßiges verschachteln unterbunden.
|
||||||
|
!!!include(../api/collections/fieldLists/formular/checkboxGroup.yml)!!!
|
||||||
|
|
||||||
|
## grid
|
||||||
|
|
||||||
|
Für Datentyp object[], dient als übersichtliche object[] alternative, speziell für pagebuilder entwickelt.
|
||||||
|
!!!include(../api/collections/fields/rows.yml)!!!
|
||||||
|
|
||||||
|
## jsonField
|
||||||
|
|
||||||
|
Wird für Daten genutzt, wo man die Struktur nicht absehen kann.
|
||||||
|
!!!include(../api/collections/fields/form.yml)!!!
|
||||||
|
|
||||||
|
## tabs
|
||||||
|
|
||||||
|
Dieses Widget hat im Prinzip die gleiche Funktion wie dasjenige in der Collection Meta-Konfiguration, ist jedoch etwas anders strukturiert. Ähnlich wie beim object Widget werden subFields verwendet, wobei das label von jedem subField der jeweilige Tab-Name ist. Würde man type auf number setzen, so hätte man in diesem Fall einfach einen Tab mit dem Namen "xyz" und ein number Feld im Tab mit dem gleichen Namen. Sinnvoller ist es natürlich, type auf object zu setzen, um mehrere Felder in einen Tab zu packen.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
type: object
|
||||||
|
name: formular
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Formular
|
||||||
|
en: Form
|
||||||
|
widget: jsonField
|
||||||
|
```
|
||||||
|
|
||||||
|
# useDefaultArray
|
||||||
|
|
||||||
|
Wenn ein belibiger Datentyp in einem Array gefordert ist, so kann man jedes beliebige Widget dafür nutzten, indem man useDefaultArray: true benutzt. Damit kann jedes widget in das defaultArray widget gepackt werden. Wird Object[] in kombination mit useDefaultArray verwendet, so wird die einfache Objektdarstellung in diese darstellung implementiert.
|
||||||
|
|
||||||
|
![useDefaultArray auf true](defaultArray.png)
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/emailCC.yml)!!!
|
112
docs/md/projektkonfig/collections/hooks.md
Normal file
112
docs/md/projektkonfig/collections/hooks.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# hooks
|
||||||
|
|
||||||
|
Hooks in Tibi sind spezielle Funktionen, die bestimmte Teile der HTTP-Anfragen und -Antworten manipulieren können. Sie erlauben Ihnen, den Datenfluss und die Abläufe zu bestimmten Zeitpunkten im Lebenszyklus einer HTTP-Anfrage zu beeinflussen.
|
||||||
|
|
||||||
|
Jeder Hook ist einer bestimmten HTTP-Methode (z.B. GET, POST, PUT, DELETE) und einem bestimmten Schritt in diesem Prozess zugeordnet. Die verfügbaren Schritte variieren je nach Methode und können beinhalten:
|
||||||
|
|
||||||
|
- read (GET)
|
||||||
|
- return (GET, POST, PUT, DELETE)
|
||||||
|
- bind (POST, PUT)
|
||||||
|
- validate (POST, PUT)
|
||||||
|
- create (POST)
|
||||||
|
- update (PUT)
|
||||||
|
- delete (DELETE)
|
||||||
|
|
||||||
|
Jeder dieser Schritte wird an einem spezifischen Punkt während der Verarbeitung einer HTTP-Anfrage oder -Antwort ausgeführt. Die genaue Reihenfolge und das Verhalten der Hooks ist in dem betrag zur Collection definiert.
|
||||||
|
|
||||||
|
## Hook Implementierung
|
||||||
|
|
||||||
|
Jeder Hook ist in einer separaten JavaScript-Datei implementiert, die im hooks-Ordner Ihres Projekts gespeichert ist. Der Pfad zu dieser Datei wird in der jeweiligen collection yml Datei angegeben.
|
||||||
|
|
||||||
|
Ein Hook ist eine Funktion, die eine context-Variable zur Verfügung hat, welche Informationen und Methoden für die aktuelle Anfrage bereitstellt. Der Rückgabewert dieser Funktion wird verwendet, um die Verarbeitung der Anfrage oder Antwort zu beeinflussen.
|
||||||
|
|
||||||
|
Zwei spezielle Typen, `HookResponse` und `HookException`, werden in Hooks verwendet, um Daten zu manipulieren und Fehler zu signalisieren.
|
||||||
|
|
||||||
|
### HookResponse
|
||||||
|
|
||||||
|
Die HookResponse ist das Objekt, das von einem Hook zurückgegeben wird. Es kann verwendet werden, um Daten zu manipulieren, die in die Datenbank geschrieben oder an den Benutzer zurückgegeben werden.
|
||||||
|
|
||||||
|
Es beinhaltet:
|
||||||
|
|
||||||
|
- `data`: Daten, die in die Datenbank geschrieben werden. Sie können diese Daten im Hook ändern, bevor sie in die Datenbank geschrieben werden.
|
||||||
|
- `results`: Daten, die an den Benutzer zurückgegeben werden. Sie können diese Daten im Hook ändern, bevor sie an den Benutzer zurückgegeben werden. (return hook)
|
||||||
|
|
||||||
|
### HookException
|
||||||
|
|
||||||
|
Eine HookException ist ein Fehler, der in einem Hook geworfen werden kann. Sie können eine HookException verwenden, um einen Fehler zu signalisieren und die Verarbeitung der Anfrage oder Antwort zu stoppen. Er kann aber auch verwendet werden, um einen 200er zu werfen und zu verhindern, dass irgendetwas in die Datenbank geschrieben wird. Dies ist bei einer "actions" collection vom vorteil.
|
||||||
|
|
||||||
|
Eine HookException kann folgende Eigenschaften haben:
|
||||||
|
|
||||||
|
- `status`:
|
||||||
|
HTTP-Statuscode des Fehlers.
|
||||||
|
- `html`:
|
||||||
|
HTML-Nachricht des Fehlers.
|
||||||
|
- `message`:
|
||||||
|
Textnachricht des Fehlers.
|
||||||
|
- `bytes`:
|
||||||
|
Binäre Daten des Fehlers.
|
||||||
|
- `json`:
|
||||||
|
JSON-Daten des Fehlers.
|
||||||
|
- `file`:
|
||||||
|
Dateipfad der Fehlermeldung.
|
||||||
|
- `log`:
|
||||||
|
Wenn true, wird der Fehler im Serverprotokoll aufgezeichnet.
|
||||||
|
|
||||||
|
### Hook Beispiel
|
||||||
|
|
||||||
|
Hier ist ein Beispiel für einen Hook, der die GET-Methode bearbeitet:
|
||||||
|
|
||||||
|
```js
|
||||||
|
;(function () {
|
||||||
|
/** @type {HookResponse}*/ // @ts-ignore
|
||||||
|
let hookResponse
|
||||||
|
let request = context.request()
|
||||||
|
if (request.query("rateIt")) {
|
||||||
|
let orderNumber
|
||||||
|
orderNumber = Number(request.query("orderNumber"))
|
||||||
|
|
||||||
|
if (isNaN(orderNumber))
|
||||||
|
throw {
|
||||||
|
status: 400,
|
||||||
|
message: "Invalid order number.",
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Order} */ // @ts-ignore
|
||||||
|
let order = context.db.find("order", {
|
||||||
|
filter: {
|
||||||
|
sequence: orderNumber,
|
||||||
|
},
|
||||||
|
})[0]
|
||||||
|
|
||||||
|
if (!order)
|
||||||
|
throw {
|
||||||
|
status: 400,
|
||||||
|
message: "No entry with this order number.",
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order.deliveryAddress.postcode != request.query("postalcode"))
|
||||||
|
throw {
|
||||||
|
status: 403,
|
||||||
|
message: "Error",
|
||||||
|
}
|
||||||
|
|
||||||
|
hookResponse = {
|
||||||
|
filter: {
|
||||||
|
orderId: order.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return hookResponse
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
In diesem Beispiel wird zuerst die Anfrage analysiert und eine Bedingung überprüft. Wenn die Bedingung erfüllt ist, wird ein bestimmtes Element in der Datenbank gesucht. Wenn das Element gefunden wird und bestimmte Kriterien erfüllt, wird ein HookResponse-Objekt erstellt und zurückgegeben. Wenn während des Prozesses Fehler auftreten, werden entsprechende HookException-Objekte geworfen.
|
||||||
|
|
||||||
|
Hier ist ein beispiel für einen Posthook, welcher ein dynamisches formular validiert (Post create):
|
||||||
|
|
||||||
|
!!!include(../api/hooks/forms/post_create.js)!!!
|
||||||
|
|
||||||
|
Hier ist ein beispiel für einen Posthook, welcher ein dynamisches formular abschickt (Post return):
|
||||||
|
|
||||||
|
!!!include(../api/hooks/forms/post_return.js)!!!
|
29
docs/md/projektkonfig/collections/imageFilter.md
Normal file
29
docs/md/projektkonfig/collections/imageFilter.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# imageFilter Objekt
|
||||||
|
|
||||||
|
Die Bildmanipulation von hochgeladen Bildern zu einer Kollektion kann über das `imageFilter` Objekt definiert werden.
|
||||||
|
Der Filter wird angewandt, wenn an die Bild-URL der Parameter `filter=...` angehangen wird.
|
||||||
|
|
||||||
|
Der Prozess selbst erfolgt beim ersten Abruf des Bildes und wird zwischengespeichert.
|
||||||
|
|
||||||
|
Eine beispielhafte Konfiguration, die die Bilder nur verkleinert sieht so aus:
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/imageFilter.yml)!!!
|
||||||
|
|
||||||
|
Folgende Attribute können Filter-Eintrage haben, wobei `fit` und `fill` exklusiv sind:
|
||||||
|
|
||||||
|
| Attribut | Typ | Beschreibung |
|
||||||
|
| ------------ | ---------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||||
|
| `fit` | boolean | passt das Bild in ein Rechteck ein |
|
||||||
|
| `fill` | boolean | streckt/staucht das Bild, so dass es das Rechteck komplett ausfüllt |
|
||||||
|
| `height` | number | Höhe des Rechtecks |
|
||||||
|
| `width` | number | Breite des Rechtecks |
|
||||||
|
| `blur` | number | Verwischungsgrad |
|
||||||
|
| `brightness` | number | Helligkeit |
|
||||||
|
| `contrast` | number | Konrast |
|
||||||
|
| `gamma` | number | Gamma-Wert |
|
||||||
|
| `saturation` | number | Sättigung |
|
||||||
|
| `sharpen` | number | Schärfe |
|
||||||
|
| `invert` | boolean | Farben invertieren |
|
||||||
|
| `grayscale` | boolean | Schwarz-Weiß |
|
||||||
|
| `resampling` | "lanczos"<br>"nearestNeighbor"<br>"linear"<br>"catmullRom" | Resampling-Algorithmus |
|
||||||
|
| `quality` | number | Ausgabequalität 0..100 |
|
30
docs/md/projektkonfig/collections/indexes.md
Normal file
30
docs/md/projektkonfig/collections/indexes.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# indexes Liste
|
||||||
|
|
||||||
|
Die indexes-Anweisung in der Konfigurationsdatei einer Sammlung (collection.yml) ist ein Array von Indexdefinitionen. Indizes werden in Datenbanken verwendet, um die Suchleistung zu optimieren. Indem Sie die richtigen Indizes definieren, können Sie die Effizienz Ihrer Anwendung verbessern. Es ist NICHT MÖGLICH einen gesetzten Index über die yml Datei wieder zu entfernen, hierfür muss man direkt in die Datenbank gehen.
|
||||||
|
|
||||||
|
Jede Indexdefinition ist ein Objekt mit bestimmten Eigenschaften:
|
||||||
|
|
||||||
|
- `name`:
|
||||||
|
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.
|
||||||
|
|
||||||
|
Zum Beispiel key: ["$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.
|
||||||
|
|
||||||
|
Eine andere mögliche Indexdefinition könnte so aussehen: key: ["file.type"]. Dies würde einen Index auf dem Feld type innerhalb des Unterobjekts file erstellen.
|
||||||
|
|
||||||
|
- `unique`:
|
||||||
|
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 und der Vorgang abgebrochen.
|
||||||
|
|
||||||
|
- `background`:
|
||||||
|
Wenn auf true gesetzt, erstellt die Datenbank den Index im Hintergrund, um die Leistungsauswirkungen auf andere Operationen zu minimieren.
|
||||||
|
|
||||||
|
- `defaultLanguage`:
|
||||||
|
Wird verwendet, um die Sprache für Textindizes festzulegen. Dies ist wichtig für die Volltextsuche, da verschiedene Sprachen unterschiedliche Tokenisierungs- und Stemmungsregeln haben.
|
||||||
|
|
||||||
|
Ein Beispiel für die Verwendung von Indizes in der Sammlungskonfigurationsdatei könnte so aussehen:
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/textIndex.yml)!!!
|
||||||
|
|
||||||
|
In diesem Beispiel wird ein Textindex namens textindex erstellt, der alle Felder der Sammlung abdeckt. Der Index wird im Hintergrund erstellt und verwendet Deutsch als Standardtextsprache.
|
76
docs/md/projektkonfig/collections/meta.md
Normal file
76
docs/md/projektkonfig/collections/meta.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# meta Objekt
|
||||||
|
|
||||||
|
Wie bereits an anderer Stelle beschrieben, dient das `meta` Objekt zur Definition von Merkmalen, die im _tibi-admin_ finden. Zum Anlegen der Struktur in der Datenbank und Definition der API haben diese Angaben keine Relevanz.
|
||||||
|
|
||||||
|
Folgende Angaben sind möglich:
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol/meta.yml)!!!
|
||||||
|
|
||||||
|
## views Liste
|
||||||
|
|
||||||
|
`views` werden für die Darstellung der Kollektion-Daten im _tibi-admin_ benötigt. Die Auswahl des passenden View erfolgt über CSS Media-Queries.
|
||||||
|
|
||||||
|
Optionale Unternavigationen können eigene `views` haben.
|
||||||
|
Möchte man, dass in der view selection Navbar vor den View namen bestimme Icons angezeigt werden, so kann man diese einfach per muiIcon im jeweiligen View Objekt angeben.
|
||||||
|
|
||||||
|
Folgende möglche Einträge für `views` gibt es derzeit:
|
||||||
|
|
||||||
|
### simpleList
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/medialibSimpleList.yml)!!!
|
||||||
|
|
||||||
|
### table
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/medialibTable.yml)!!!
|
||||||
|
|
||||||
|
### cardList
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/medialibCardList.yml)!!!
|
||||||
|
|
||||||
|
## quickEdit
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/quickEditMedialib.yml)!!!
|
||||||
|
|
||||||
|
### dashboardSimpleList
|
||||||
|
|
||||||
|
Fürs dashboard type: table
|
||||||
|
|
||||||
|
```yml
|
||||||
|
type: dashboardSimpleList
|
||||||
|
mediaQuery: "(max-width: 600px)"
|
||||||
|
primaryText: email
|
||||||
|
secondaryText: subject
|
||||||
|
```
|
||||||
|
|
||||||
|
### dashboardTable
|
||||||
|
|
||||||
|
Fürs dashboard type: table
|
||||||
|
|
||||||
|
```yml
|
||||||
|
type: dashboardTable
|
||||||
|
mediaQuery: "(min-width: 600px)"
|
||||||
|
columns:
|
||||||
|
- subject
|
||||||
|
- file
|
||||||
|
- file
|
||||||
|
- subject
|
||||||
|
- file
|
||||||
|
```
|
||||||
|
|
||||||
|
## tablist
|
||||||
|
|
||||||
|
Wird die `tablist` verwendet, ist sicher zu stellen, dass alle Felder in der Definition aufgenommen werden. Werden Felder nicht in die `tablist` aufgenommen, sind diese weiterhin in einer Gesamtliste unterhalb der Tabs und bringen das Layout durcheinander.
|
||||||
|
|
||||||
|
## multiupload
|
||||||
|
|
||||||
|
Der mutliupload kann bei jedem view type verwendet werden. Über $file kann man in eval auf das aktuelle file Objekt zugreifen. Hier ist eine Beispielscollection, welchen diesen verwendet.
|
||||||
|
|
||||||
|
!!!include(../api/collections/medialib.yml)!!!
|
||||||
|
|
||||||
|
## backups
|
||||||
|
|
||||||
|
im meta Objekt einer collection können backups für diese collection konfiguriert werden. Die backups werden in der Datenbank gespeichert und können über das tibi-admin in der selben collection angewandt werden. Wird ein collectoneintrag gelöscht, kann man diesen über den gelöschte einträge checkbox wiederherstellen.
|
||||||
|
folgende collection ist ein beispiel für eine backup collection sowie die aktvierung der backupfunktion in einer "normalen" collection (Im Meta objekt...).
|
||||||
|
!!!include(../api/collections/fields/backup.yml)!!!
|
||||||
|
|
||||||
|
!!!include(../api/collections/backups.yml)!!!
|
BIN
docs/md/projektkonfig/collections/validator.webm
Normal file
BIN
docs/md/projektkonfig/collections/validator.webm
Normal file
Binary file not shown.
34
docs/md/projektkonfig/config.yml.md
Normal file
34
docs/md/projektkonfig/config.yml.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# config.yml
|
||||||
|
|
||||||
|
Die Datei **config.yml** ist der Einstieg in die API-Konfiguration eines Projekts. Die Datei kann sich an einem beliebigen Ort befinden. Die einzige Bedingung ist, dass sie durch den tibi-server lesbar ist.
|
||||||
|
|
||||||
|
Es hat sich jedoch als günstig erwiesen bei Webprojekten die Datei und alle anderen Datein, die zur API-Konfiguration gehören, im ordner [api/](./ordnerstruktur.md) unterhalb des eigentlichen Webprojektes anzuordnen. Die Quellen des Frontends und der API können somit in ein Mono-Repo eingecheckt werden.
|
||||||
|
|
||||||
|
## Aufbau
|
||||||
|
|
||||||
|
!!!include(../api/config.yml)!!!
|
||||||
|
Der Namespace legt die eigentliche Projektbezeichnung und den Datenbankkontext fest.
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Das imageUrl objekt definiert den Pfad zu einer Bilddatei die als Projektbild im tibi-admin verwendet wird
|
||||||
|
|
||||||
|
"collections" ist eine Auflistung von Kollektions-Konfigurationen.
|
||||||
|
Hier bietet sich eine Auslagerung und Einbindung via YAML-Tag "!include" an.
|
||||||
|
|
||||||
|
Unter "jobs" können Jobs definiert werden, die regelmäßig ausgeführt werden sollen.
|
||||||
|
Werden Dateien innerhalb vom tibi-admin benötigt, bietet es sich an diese über
|
||||||
|
"assets"-Pfade erreichbar zu machen
|
||||||
|
|
||||||
|
### siehe
|
||||||
|
|
||||||
|
- [dashboard](./dashboard.md)
|
||||||
|
- [collections](./collections.md)
|
||||||
|
- [jobs](./jobs.md)
|
||||||
|
- [assets](./assets.md)
|
511
docs/md/projektkonfig/dashboard.md
Normal file
511
docs/md/projektkonfig/dashboard.md
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
# dashboard
|
||||||
|
|
||||||
|
# Übersicht
|
||||||
|
|
||||||
|
Die bereitgestellte Konfiguration ist eine Spezifikation für ein Dashboard-Layout und seine Komponenten. Dieses Layout bestimmt die Anzeige und Interaktion von verschiedenen Datenvisualisierungen, vor allem in Form von Diagrammen (Graphen). Die Konfiguration ist in zwei Hauptabschnitte unterteilt: "majorItems" und "minorItems". Die "majorItems" sind größere, prominentere Darstellungen von Daten, während die "minorItems" kleinere, weniger prominente Datenelemente repräsentieren. Jedes Element innerhalb dieser Abschnitte ist ein einzelnes Modul oder eine Komponente auf dem Dashboard und kann verschiedene Arten von Datenvisualisierungen darstellen, einschließlich Linien-, Balken-, Kreis- (donut) und Flächendiagramme. Generell ist zu sagen, dass bei jeder string angabe auch I18n verwendet werden kann und bei nahezu jeder String angabe ist ebenfalls die eval angabe möglich. Sollten Nutzer keinen Zugriff auf die Daten haben dürfen, so wird das bestimmte Diagramm nicht gerendert und stattdessen ein Placeholder mit Zugriff verweigert angezeigt.
|
||||||
|
|
||||||
|
# Elementbeschreibungen
|
||||||
|
|
||||||
|
## type
|
||||||
|
|
||||||
|
Der Typ des Dashboard-Elements ist ein entscheidendes Attribut.
|
||||||
|
|
||||||
|
- ˋgraphˋ:
|
||||||
|
Wenn der Typ "graph" ist, wird das Element als Diagramm dargestellt. Dies ermöglicht eine Vielzahl von Visualisierungen wie Linien-, Balken-, Kuchen-, Donut- oder Flächendiagramme, abhängig vom graphType.
|
||||||
|
|
||||||
|
- ˋswiperˋ:
|
||||||
|
Der Typ "swiper" erstellt ein Karussell-ähnliches Element, das eine Reihe von anderen Elementen enthält, die durchgeblättert werden können. Jedes Element innerhalb des "swiper"-Typs wird genauso konfiguriert wie ein normales Dashboard-Element, was bedeutet, dass sie jeweils ihren eigenen type, title, etc. haben können.
|
||||||
|
|
||||||
|
- ˋreferenceˋ:
|
||||||
|
Die "reference"-Typ Elemente sind Verweise auf Collections.
|
||||||
|
|
||||||
|
- ˋcomparisonˋ:
|
||||||
|
Außerdem gibt es den type "comparison", wobei man ein timespan auswählt und dieser timespan und der timespan davor mit einander auf einen bestimmten Wert verglichen werden.
|
||||||
|
|
||||||
|
- ˋtableˋ:
|
||||||
|
Desweiteren gibt es einen type "table" wobei über das additionalApiParams Objekt mit dem limit attribut gesetzt wird wie viele Einträge von der ausgewählten collection Angezeigt werden sollen. Per Default sind es 5
|
||||||
|
|
||||||
|
- ˋsectionTitleˋ
|
||||||
|
Der "sectionTitle" type ist wie der name schon sagt, ein Titel für einen Abschnitt vom dashboard
|
||||||
|
|
||||||
|
## title
|
||||||
|
|
||||||
|
Der Titel eines Elements ist ein Objekt, das einen eval, value, contentBefore und contentAfter haben kann. value repräsentiert den Hauptteil des Titels, während contentBefore und contentAfter optionale Textstücke sind, die vor bzw. nach dem Haupttitel platziert werden. Eval kann als ersatz für value verwendet werden. Auch ist eine normale String angabe möchglich. Diese wird hier, sowie überall anders auch in die genutzte sprache konvertiert, daher ist die angabe über das {de:”xyz”, en:”xyz”} sinnvoll.
|
||||||
|
|
||||||
|
## subTitle
|
||||||
|
|
||||||
|
Dies ist ein Untertitel für das Dashboard-Element.
|
||||||
|
|
||||||
|
## additionalApiParams
|
||||||
|
|
||||||
|
Dies ist ein Objekt und kann folgende Parameter haben:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface APIParams {
|
||||||
|
offset?: number
|
||||||
|
limit?: number
|
||||||
|
sort?: string
|
||||||
|
filter?: {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
projection?: string
|
||||||
|
count?: 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Sollte es komntextabhängig bereits automatisch genertierte Filter Objekt attirbute geben, so werden, wenn man welche angibt, seine eigenen über Object.assign zu diesen hinzu gefügt.
|
||||||
|
|
||||||
|
## subNavigation
|
||||||
|
|
||||||
|
Das Attrbiut bei type: reference dient dazu, den Link zu einer bestimmten subKategorie zu machen. Nimmt den index der gewüpnschten subNavigation als Wert.
|
||||||
|
|
||||||
|
## graphType
|
||||||
|
|
||||||
|
Das Attribut graphType bestimmt die spezifische Art der Datenvisualisierung für ein Element vom Typ "graph". Die möglichen Werte sind "line" (Linien-Diagramm), "bar" (Balkendiagramm), "donut" (Kreisdiagramm), “pie” (Kuchendiagramm) und "area" (Flächendiagramm).
|
||||||
|
|
||||||
|
## xAxis und yAxis
|
||||||
|
|
||||||
|
Diese Attribute definieren die Daten, die auf den Achsen des Diagramms angezeigt werden. xAxis immer "timeline", was bedeutet, dass die Daten über die Zeit dargestellt werden. yAxis kann “sum” oder “amount” sein. Sum summiert die Werte des angegebenen feldes im time interval, wohingegen amount die Menge des angegebenen Feldes im time interval aufsummiert und angibt. Möchte man die menge von den Kollektionen angeben, so ist kein weiterer schritt nötig. Möchte man angeben, wie oft ein feld in den kollektionen vor kommt, so hat man 2 möglichkeiten. Wenn das feld einmal pro kollektion vor kommt, so gibt man einfach über den field parameter den pfad dorthin an also bspw. wenn im root einfach nur xyz oder xyz.yxz.... Wenn das feld aber in einer object[] struktur ist, so gibt man den pfad dorthin an (über path) und dann ausgehend von dem objekt wird die field angabe genutzt. Bei sum ist das prinzip das selbe.
|
||||||
|
|
||||||
|
## containerProps
|
||||||
|
|
||||||
|
Um Felder auf breiten Bildschirmen eine schmalere Breite zu geben, wird das containerProps Attribut empfohlen. Es hat ein class Attribut, welches klassen ins HTML injiziert. Es gibt außerdem noch das Layout attribut mit breakBefore und breakAfter, welche dafür sorgen, dass vorher bzw. nachher keine weiteren HTML Elemente platz finden. Hier ist des weiteren das size Objekt drin, welches 3 attribute hat. Die attribute sollten col-1 bis col-12 beeinhalten, diese klassen werden ins html injiziert, können also dem zufolge auch misbraucht werden. Die klassen bei den attributen werden bei unterschiedlichen Bildschirmbreiten aktiv.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: false
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
```
|
||||||
|
|
||||||
|
## graphs
|
||||||
|
|
||||||
|
Ein Array von Objekten, wobei jedes Objekt ein einzelnes Diagramm darstellt, das innerhalb des Dashboard-Elements dargestellt wird. Bei meherer Angabe werden auch mehrere graphen im selben chart angezeigt, für unterschiedliche y Achsen im selben Chart ist multipleYAxes auf true zu setzen, hier ist dann auch die YAxisTitle vorgenommen. Jedes dieser Diagrammobjekte hat mehrere Attribute, darunter field,path, dateTimeField, collection und graphName. field gibt an, welches Datenfeld aus der Sammlung zur Erzeugung des Diagramms verwendet werden soll. Path gibt den weg zum feld an, wenn das feld direkt im objekt liegt, so ist “this” oder garkeine angabe valide. dateTimeField bestimmt das Feld, das die Zeitskala für das Diagramm liefert. collection ist der Name der Datenkollektion, aus der die Daten bezogen werden. Schließlich definiert graphName den Namen des Diagramms.
|
||||||
|
|
||||||
|
## style
|
||||||
|
|
||||||
|
Ein Objekt, das CSS-Stilinformationen für das Dashboard-Element enthält. Es ist für die reference elemente gedacht.
|
||||||
|
|
||||||
|
## collection
|
||||||
|
|
||||||
|
Dieses Feld bezieht sich auf die Datenquelle oder Sammlung, auf die das Dashboard-Element zugreifen wird.
|
||||||
|
|
||||||
|
## timeInterval
|
||||||
|
|
||||||
|
Dieses Feld definiert den Zeitraum, der im Diagramm angezeigt wird. Die möglichen Werte können "day", "month", "year" sein, je nachdem, welche Granularität für die Datenvisualisierung gewünscht wird.
|
||||||
|
|
||||||
|
## timespan
|
||||||
|
|
||||||
|
Der Zeitraum für die Vergleichsdaten. Es kann "QTD" für das aktuelle Quartal und das Quartal davor sein, "MTD" für den aktuellen Monat und den Monat davor sein oder YTD für das aktuelle Jahr und das Jahr davor sein. Immer nur bis zum heutigem Tag dieser Zeitspanne, also bspw. vom 1.1.2023 bis zum 28.5.2023 wäre YTD wobei das vergleichs Jahr dann vom 1.1.2022 bis zum 28.5.2022 wäre:
|
||||||
|
|
||||||
|
```js
|
||||||
|
switch (input) {
|
||||||
|
case "YTD": // Year to date
|
||||||
|
begin = new Date(date.getFullYear(), 0, 1)
|
||||||
|
end = currentDate
|
||||||
|
lastBegin = new Date(date.getFullYear() - 1, 0, 1)
|
||||||
|
lastEnd = new Date(date.getFullYear() - 1, date.getMonth(), date.getDate())
|
||||||
|
break
|
||||||
|
case "QTD": // Quarter to date
|
||||||
|
let quarterStartMonth = Math.floor(date.getMonth() / 3) * 3
|
||||||
|
begin = new Date(date.getFullYear(), quarterStartMonth, 1)
|
||||||
|
end = currentDate
|
||||||
|
lastBegin = new Date(date.getFullYear(), quarterStartMonth - 3, 1)
|
||||||
|
lastEnd = new Date(date.getFullYear(), date.getMonth() - 3, date.getDate())
|
||||||
|
break
|
||||||
|
case "MTD": // Month to date
|
||||||
|
begin = new Date(date.getFullYear(), date.getMonth(), 1)
|
||||||
|
end = currentDate
|
||||||
|
lastBegin = new Date(date.getFullYear(), date.getMonth() - 1, 1)
|
||||||
|
lastEnd = new Date(date.getFullYear(), date.getMonth() - 1, date.getDate())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## until
|
||||||
|
|
||||||
|
Dieses Feld definiert den Endpunkt des Zeitintervalls für die Datenvisualisierung. Mögliche Werte sind "lastWeek", “lastMonth”, “lastYear” und "allTime", welches jedoch default ist. Zum Beispiel, wenn until auf "lastMonth" gesetzt ist, wird das Diagramm maximal Daten bis zum letzten Monat anzeigen. Außerdem sind alle Optionen darunter für den Nutzer auswählbar. Um dies zu unterbinden, muss das filter attribut auf false gesetzt werden.
|
||||||
|
|
||||||
|
## defaultUntil
|
||||||
|
|
||||||
|
Dieses Attribut setzt den default Filter. Es ist anzumerken, dass mit jedem Filter change eine Neue Request einhergeht, und immer mit dem aktuellem Filter requested wird, dieser sollte also ggf. für perfomance per default niedrig gesetzt werden.
|
||||||
|
|
||||||
|
## filter
|
||||||
|
|
||||||
|
Wird filter auf false gesetzt, so ist der Filter nicht länger sichtbar.
|
||||||
|
|
||||||
|
## multipleYAxes
|
||||||
|
|
||||||
|
Dieses Boolean-Feld gibt an, ob das Diagramm mehrere Y-Achsen haben soll. Wenn auf true gesetzt, hat jedes Diagramm im graphs Array eine eigene Y-Achse haben. Hierfür ist dann eine Achsenbeschriftung sinnvoll. Diese wird dann mit yAxisTitle im jeweiligen Graphs objekt angegeben.
|
||||||
|
|
||||||
|
## graphBaseColor
|
||||||
|
|
||||||
|
Dies definiert die Basisfarbe des Diagramms. Die Farbe muss in einem gültigen CSS-Farbformat angegeben werden.
|
||||||
|
|
||||||
|
## value
|
||||||
|
|
||||||
|
Im Kontext des title-Feldes repräsentiert value den Hauptteil des Titels. In Bezug auf Diagramme, insbesondere bei Donut- und Kuchendiagrammen, repräsentiert value den numerischen Wert, der im Diagramm dargestellt wird. Hier sind mögliche werte: “total”, welches die Summe vom ausgewählten feld bis zu until ausgibt, “amount”, welches das gleiche macht, nur nicht summiert sondern zählt und “count” wobei die Einträge selbst gezählt werden.
|
||||||
|
|
||||||
|
## valueType
|
||||||
|
|
||||||
|
Wird bei "comparison" verwendet, um den vergleich relativ oder absolut vorzunehmen. Valide angaben sind: "relative" und "absolute".
|
||||||
|
|
||||||
|
## path
|
||||||
|
|
||||||
|
Dieses Feld kann verwendet werden, um den genauen Pfad zu der spezifischen Datenstruktur zu definieren, welches in der Sammlung für die Datenvisualisierung als referenz Array für den field parameter verwendet wird. Dies ist also sinvoll, wenn das Feld in einem Object[] ist, andernfalls ist bei field die angabe über xyz.yxz.zyx erwünscht. Ist das feld im root oder über den field parameter erreichbar, so kann man path leeer lassen oder "this" angeben.
|
||||||
|
|
||||||
|
## dateTimeField
|
||||||
|
|
||||||
|
Dies ist das Feld, das den Zeitstempel in der Datensammlung repräsentiert. Es wird verwendet, um die Zeitskala für das Diagramm zu liefern. Hier ist das erwünschte Datumsfeld in der collection auszuwählen.
|
||||||
|
|
||||||
|
## limit
|
||||||
|
|
||||||
|
gibt an wie viele Elemente maximal returned werden sollen.
|
||||||
|
|
||||||
|
## newPageRef
|
||||||
|
|
||||||
|
boolean, wenn explizit auf false, dann wird bei type reference kein Neue Seite hinzufügen button angezeigt.
|
||||||
|
|
||||||
|
# Code Beispiel
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dashboard:
|
||||||
|
majorItems: # Liste der Hauptelemente des Dashboards
|
||||||
|
- type: sectionTitle
|
||||||
|
title: "Overview" #i18n or eval
|
||||||
|
|
||||||
|
- type: swiper
|
||||||
|
containerProps:
|
||||||
|
class: "random-class"
|
||||||
|
layout:
|
||||||
|
breakBefore: false # no html elements before
|
||||||
|
breakAfter: false #no html elmenets after
|
||||||
|
size: #different classes depending on innerWidth
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
elements:
|
||||||
|
- type: comparison
|
||||||
|
collection: contact_form
|
||||||
|
timespan: "QTD" #QTD & MTD with last quarter, month or year
|
||||||
|
value: total
|
||||||
|
valueType: absolute #oder relative (prozentual)
|
||||||
|
path: paymentValues
|
||||||
|
additionalApiParams: #Nimmt APIParams entgegen und fügt sie zusätzlich ein, filter Objekt Parameter wird ggf. zum automatisch generierten Assigned, also vorsicht!
|
||||||
|
limit: 3
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
title: toller titel #string or eval
|
||||||
|
subTitle: { de: "YTD Vergleich zum Vorjahr", en: "YTD comparison with last year" }
|
||||||
|
|
||||||
|
- type: comparison
|
||||||
|
collection: contact_form
|
||||||
|
timespan: "QTD" #QTD & MTD with last quarter, month or year
|
||||||
|
value: total
|
||||||
|
valueType: absolute #oder relative (prozentual)
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
title: toller titel #i18n or eval
|
||||||
|
subTitle: { de: "YTD Vergleich zum Vorjahr", en: "YTD comparison with last year" }
|
||||||
|
|
||||||
|
- type: swiper
|
||||||
|
css:
|
||||||
|
graph:
|
||||||
|
wrapper:
|
||||||
|
eval: |
|
||||||
|
`
|
||||||
|
background-color: green ;
|
||||||
|
`
|
||||||
|
containerProps:
|
||||||
|
class: "random-class"
|
||||||
|
layout:
|
||||||
|
breakBefore: false # no html elements before
|
||||||
|
breakAfter: true #no html elmenets after
|
||||||
|
size: #different classes depending on innerWidth
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
elements:
|
||||||
|
- type: comparison
|
||||||
|
collection: contact_form
|
||||||
|
timespan: "QTD" #QTD & MTD with last quarter, month or year
|
||||||
|
value: total
|
||||||
|
valueType: relative #oder relative (prozentual)
|
||||||
|
path: paymentValues
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
title: toller titel #string or eval
|
||||||
|
subTitle: { de: "YTD Vergleich zum Vorjahr", en: "YTD comparison with last year" }
|
||||||
|
|
||||||
|
- type: comparison
|
||||||
|
collection: contact_form
|
||||||
|
timespan: "QTD" #QTD & MTD with last quarter, month or year
|
||||||
|
value: total
|
||||||
|
valueType: relative #oder relative (prozentual)
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
title: toller titel #string or eval
|
||||||
|
subTitle: { de: "YTD Vergleich zum Vorjahr", en: "YTD comparison with last year" }
|
||||||
|
|
||||||
|
- type: sectionTitle
|
||||||
|
title: "Details"
|
||||||
|
|
||||||
|
- type: graph # Art des Elements, hier ein Graph
|
||||||
|
css:
|
||||||
|
graph:
|
||||||
|
wrapper:
|
||||||
|
eval: |
|
||||||
|
`
|
||||||
|
background-color: yellow ;
|
||||||
|
`
|
||||||
|
title: # Titel des Graphen
|
||||||
|
#eval anstelle von value möglich
|
||||||
|
value: total #o. amount Haupttitel des Graphen
|
||||||
|
contentAfter: "€" # Nach dem Haupttitel hinzugefügte Inhalte
|
||||||
|
contentBefore: "xyz" # Vor dem Haupttitel hinzugefügte Inhalte
|
||||||
|
timeInterval: "day" # Zeitintervall der Daten im Graphen
|
||||||
|
until: "lastMonth" # Ende des Zeitintervalls (Ab dem aktuellen Datum)
|
||||||
|
graphType: "line" # Art des Graphen, hier ein Liniendiagramm
|
||||||
|
graphBaseColor: "#ff0000" # Basisfarbe des Graphen
|
||||||
|
subTitle: { de: "Umsatz", en: "sales volume" } # Untertitel des Graphen, mehrsprachig
|
||||||
|
xAxis: timeline # Art der x-Achse, hier eine Zeitachse
|
||||||
|
class: "random-class" #Class added
|
||||||
|
additionalApiParams:
|
||||||
|
limit: 2
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: false
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
|
||||||
|
graphs: # Liste der Graphen in diesem Element
|
||||||
|
- yAxis: sum # Art der y-Achse, hier eine Summe
|
||||||
|
field: paymentValue # Feld der Daten für den Graphen
|
||||||
|
dateTimeField: Date # Feld für den Zeitstempel der Daten
|
||||||
|
yAxisTitle: Graph titel # Titel der y-Achse
|
||||||
|
collection: contact_form # Sammlung, aus der die Daten stammen
|
||||||
|
graphName: { de: "Umsatz", en: "sales volume" } # Name des Graphen, mehrsprachig
|
||||||
|
- graphName: { de: "Umsatz anderes feldes", en: "Sum of other values" }
|
||||||
|
path: paymentValues # Pfad zu den Daten im Feld
|
||||||
|
yAxis: sum
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
collection: contact_form
|
||||||
|
- type: graph
|
||||||
|
title:
|
||||||
|
value: total
|
||||||
|
contentAfter: "€"
|
||||||
|
contentBefore: "xyz"
|
||||||
|
timeInterval: "day"
|
||||||
|
until: "lastMonth"
|
||||||
|
graphType: "line"
|
||||||
|
graphBaseColor: "#ff0000"
|
||||||
|
subTitle: { de: "Umsatz", en: "sales volume" }
|
||||||
|
xAxis: timeline
|
||||||
|
multipleYAxes: true # Option für mehrere y-Achsen
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: false
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
|
||||||
|
graphs:
|
||||||
|
- yAxis: sum
|
||||||
|
yAxisTitle: Summe nr 1
|
||||||
|
graphType: "bar" # Art des Graphen, hier ein Balkendiagramm
|
||||||
|
field: paymentValue
|
||||||
|
dateTimeField: Date
|
||||||
|
collection: contact_form
|
||||||
|
graphName: { de: "Umsatz", en: "sales volume" }
|
||||||
|
|
||||||
|
- graphName: { de: "Umsatz anderes feldes", en: "Sum of other values" }
|
||||||
|
path: paymentValues
|
||||||
|
yAxisTitle: Summe nr 2
|
||||||
|
yAxis: sum
|
||||||
|
graphType: "line"
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
collection: contact_form
|
||||||
|
- type: swiper # Art des Elements, hier ein Swiper
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: false
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
|
||||||
|
elements: # Liste der Elemente in diesem Swiper
|
||||||
|
- type: graph
|
||||||
|
title:
|
||||||
|
value: total
|
||||||
|
contentAfter: "€"
|
||||||
|
contentBefore: "xyz"
|
||||||
|
until: "lastMonth"
|
||||||
|
graphType: "donut" # Art des Graphen, hier ein Donut-Diagramm
|
||||||
|
value: total # Summe aller werte in spezifiziertem Feld, welche dann im Diagramm dargestellt werden
|
||||||
|
graphBaseColor: "#ff0000"
|
||||||
|
subTitle: { de: "Umsatz", en: "sales volume" }
|
||||||
|
graphs:
|
||||||
|
- field: paymentValue
|
||||||
|
dateTimeField: Date
|
||||||
|
collection: contact_form
|
||||||
|
graphName: { de: "Umsatz", en: "sales volume" }
|
||||||
|
- graphName: { de: "Umsatz anderes feldes", en: "Sum of other values" }
|
||||||
|
path: paymentValues
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
collection: contact_form
|
||||||
|
- type: graph
|
||||||
|
title:
|
||||||
|
value: total
|
||||||
|
contentAfter: "€"
|
||||||
|
contentBefore: "xyz"
|
||||||
|
until: "lastMonth"
|
||||||
|
graphType: "pie" # Art des Graphen, hier ein Kuchendiagramm
|
||||||
|
value: total
|
||||||
|
graphBaseColor: "#ff0000"
|
||||||
|
subTitle: { de: "Umsatz", en: "sales volume" }
|
||||||
|
graphs:
|
||||||
|
- field: paymentValue
|
||||||
|
dateTimeField: Date
|
||||||
|
collection: contact_form
|
||||||
|
graphName: { de: "Umsatz", en: "sales volume" }
|
||||||
|
- graphName: { de: "Umsatz anderes feldes", en: "Sum of other values" }
|
||||||
|
path: paymentValues
|
||||||
|
dateTimeField: Date
|
||||||
|
field: paymentValue
|
||||||
|
collection: contact_form
|
||||||
|
|
||||||
|
- containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: false
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
type: graph
|
||||||
|
title:
|
||||||
|
value: total
|
||||||
|
contentAfter: "€"
|
||||||
|
subTitle: { de: "Umsatz", en: "sales volume" }
|
||||||
|
xAxis: timeline
|
||||||
|
timeInterval: "day"
|
||||||
|
graphType: "area" # Art des Graphen, hier ein Flächendiagramm
|
||||||
|
graphs:
|
||||||
|
- field: paymentValue
|
||||||
|
dateTimeField: Date
|
||||||
|
yAxis: sum
|
||||||
|
collection: contact_form
|
||||||
|
path: "this" # Pfad zu den Daten im Feld, hier das aktuelle Objekt, keine Angabe hat den gleichen Wert
|
||||||
|
graphName: { de: "Umsatz", en: "sales volume" }
|
||||||
|
- type: swiper
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: true
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-4"
|
||||||
|
elements:
|
||||||
|
- class: col-6
|
||||||
|
type: graph
|
||||||
|
subTitle: { de: "Produktmenge", en: "Amount of products" }
|
||||||
|
xAxis: timeline
|
||||||
|
timeInterval: "day"
|
||||||
|
filter: false #deaktiviert die Filter möglichkeit für den Nutzer beim diagramm, normalerweise aktiviert. Hierbei sind alle kombinationen x >= until möglich
|
||||||
|
dateTimeField: Date
|
||||||
|
until: "lastMonth"
|
||||||
|
graphType: "bar"
|
||||||
|
graphs:
|
||||||
|
- graphName: { de: "Menge", en: "Amount" }
|
||||||
|
yAxis: amount # Art der y-Achse, hier die Anzahl von allen Feldern im spezifiziertem intervall
|
||||||
|
dateTimeField: Date
|
||||||
|
collection: contact_form
|
||||||
|
- class: col-8
|
||||||
|
type: graph
|
||||||
|
filter: false
|
||||||
|
title:
|
||||||
|
value: total
|
||||||
|
contentAfter: "€"
|
||||||
|
subTitle: { de: "Umsatz", en: "sales volume" }
|
||||||
|
xAxis: timeline
|
||||||
|
timeInterval: "day"
|
||||||
|
dateTimeField: Date
|
||||||
|
graphType: "line"
|
||||||
|
until: "lastMonth"
|
||||||
|
graphs:
|
||||||
|
- field: paymentValue
|
||||||
|
yAxis: sum # Art der y-Achse, hier eine Summe
|
||||||
|
collection: contact_form # Sammlung, aus der die Daten stammen
|
||||||
|
dateTimeField: Date # Feld für den Zeitstempel der Daten
|
||||||
|
path: "this" # Pfad zu den Daten im Feld, hier das aktuelle Objekt
|
||||||
|
graphName: { de: "Umsatz", en: "sales volume" } # Name des Graphen, mehrsprachig
|
||||||
|
- type: table #shows entries from specified collection
|
||||||
|
containerProps:
|
||||||
|
#optional class prop
|
||||||
|
layout:
|
||||||
|
breakBefore: false
|
||||||
|
breakAfter: true
|
||||||
|
size:
|
||||||
|
default: "col-8"
|
||||||
|
small: "col-12"
|
||||||
|
large: "col-7"
|
||||||
|
collection: contact_form
|
||||||
|
title: Konaktformular Titel
|
||||||
|
subTitle: subtitel oder so
|
||||||
|
additionalApiParams:
|
||||||
|
limit: 3
|
||||||
|
|
||||||
|
- collection: content # Sammlung, aus der die Daten für das nächste Element stammen
|
||||||
|
type: reference # Art des Elements, hier ein Referenz-Element
|
||||||
|
style: # Stil des Elements
|
||||||
|
upper: rgba(3, 50, 59, 0.7) # Farbe des oberen Teils
|
||||||
|
lower: rgba(3, 50, 59) # Farbe des unteren Teils
|
||||||
|
- collection: content # Wiederholung der vorherigen Elemente
|
||||||
|
type: reference
|
||||||
|
style:
|
||||||
|
upper: rgba(3, 50, 59, 0.7)
|
||||||
|
lower: rgba(3, 50, 59)
|
||||||
|
- collection: contact_form
|
||||||
|
subNavigation: 1
|
||||||
|
type: reference
|
||||||
|
style:
|
||||||
|
upper: rgba(3, 50, 59, 0.7)
|
||||||
|
lower: rgba(3, 50, 59)
|
||||||
|
|
||||||
|
minorItems: # Liste der Nebenelemente des Dashboards
|
||||||
|
- collection: contact_form # Referenz auf collections
|
||||||
|
subNavigation: 0
|
||||||
|
- collection: contact_form # Wiederholung der vorherigen Nebenelemente
|
||||||
|
subNavigation: 0
|
||||||
|
- collection: contact_form
|
||||||
|
subNavigation: 0
|
||||||
|
- collection: contact_form
|
||||||
|
subNavigation: 0
|
||||||
|
- collection: contact_form
|
||||||
|
subNavigation: 0
|
||||||
|
- collection: contact_form
|
||||||
|
newPageRef: false
|
||||||
|
```
|
||||||
|
|
||||||
|
![Resultierende Dashboard](./dashboard.png)
|
BIN
docs/md/projektkonfig/dashboard.png
Normal file
BIN
docs/md/projektkonfig/dashboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
13
docs/md/projektkonfig/jobs.md
Normal file
13
docs/md/projektkonfig/jobs.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# jobs
|
||||||
|
|
||||||
|
In dem ein oder anderen Projekt werden sicherlich Jobs im Hintergrund benötigt, die zu bestimmten Zeiten oder Intervallweise ausgeführt werden müssen (z.B. Datenbereinigung). Diese Jobs können innerhalb der [config.yml](./config.yml.md) definiert werden.
|
||||||
|
|
||||||
|
Wie in allen YAML-Definitionen können auch die Jobs via `!include` ausgelagert werden.
|
||||||
|
|
||||||
|
Der Aufbau eines Jobs ausgelagert in einer Datei sieht beispielsweise folgendermaßen aus:
|
||||||
|
|
||||||
|
!!!include(../api/jobs/lighthouse.yml)!!!
|
||||||
|
|
||||||
|
Die Möglichkeiten innerhalb der Javascript-Datei werden im Kapitel [Javascript Kontext](./../server-javascript-kontext/allgemeines.md) beschrieben. Ein Beispiel für eine solche Datei wäre die folgende:
|
||||||
|
|
||||||
|
!!!include(../api/jobs/lighthouse.js)!!!
|
65
docs/md/projektkonfig/ordnerstruktur.md
Normal file
65
docs/md/projektkonfig/ordnerstruktur.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Ordnerstruktur
|
||||||
|
|
||||||
|
Als Konvention für neue Projekte hat sich folgende Ordnerstruktur etabliert:
|
||||||
|
|
||||||
|
![Ordnerstruktur](api-ordner.png)
|
||||||
|
|
||||||
|
Die Aufteilung der YAML-Konfiguration ist durch den YAML-Tag `!include` möglich. Genaueres dazu wird auf den nachfolgenden Seiten beschrieben.
|
||||||
|
|
||||||
|
## /api
|
||||||
|
|
||||||
|
Der Einstiegsordner in die Konfiguration ist frei wählbar. "/api" innerhalb des Projektrepositories hat sich jedoch bewährt.
|
||||||
|
|
||||||
|
Die Einstiegsdatei in die Gesamt-Konfiguration liegt hier und heißt [config.yml](./config.yml.md). In dieser können Umgebungsvariablen erstetzt werden, welche in [config.yml.env](./config.yml.md) definiert sind.
|
||||||
|
|
||||||
|
Ebenso sind alle nachfolgenden Unterordner beliebig zu benennen. Da aber ein JSON-Schema und VSCode-Konfiguration zur Validierung der YAML Dateien existiert, ist folgende Struktur hilfreich.
|
||||||
|
|
||||||
|
### JSON-Schema
|
||||||
|
|
||||||
|
Das JSON-Schema ist in die package.json einzubinden via:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"devDependencies": {
|
||||||
|
...,
|
||||||
|
"tibi-types": "https://gitbase.de/cms/tibi-types.git"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Die im Projekt liegende VSCode-Konfig sollte dementsprechend ergänzt werden:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"yaml.schemas": {
|
||||||
|
"node_modules/tibi-types/schemas/api-config/config.json": "api/config.y*ml",
|
||||||
|
"node_modules/tibi-types/schemas/api-config/collection.json": "api/collections/*.y*ml",
|
||||||
|
"node_modules/tibi-types/schemas/api-config/field.json": "api/collections/fields/*.y*ml",
|
||||||
|
"node_modules/tibi-types/schemas/api-config/fieldArray.json": "api/collections/fieldLists/*.y*ml"
|
||||||
|
},
|
||||||
|
"yaml.customTags": ["!include scalar"],
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Sollte Yarn2 verwendet werden ist die Verlinkung von **node_modules** nötig. Dazu ist folgendes in der **.yarnrc.yml** einzutragen:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
...
|
||||||
|
nodeLinker: node-modules
|
||||||
|
```
|
||||||
|
|
||||||
|
## /api/collections
|
||||||
|
|
||||||
|
Bei Aufteilung der Kollektionskonfigurationen in einzelne Dateien, sollten diese in diesem Ordner gespeichert werden. Für jede Kollektion sollte eine eigene Datei verwendet werden, hier im Beispiel [api/collections/democol.yml](./collections.md).
|
||||||
|
|
||||||
|
### /api/collections/fields
|
||||||
|
|
||||||
|
Sollten Feldkonfigurationen wieder verwendet werden, können diese im [api/collections/fields/](./collections/fields.md) Unterordner gepeichert werden. Diese sind pro Feldkonfiguration als einzelne Datei aufzuführen.
|
||||||
|
|
||||||
|
### /api/hooks
|
||||||
|
|
||||||
|
Jede Javascript-Datei, die einen Hook bedient sollte im Unterordner benannt nach der Kollektion im Ordner [api/hooks/](./collections/hooks.md) sein. Der Name der Datei sollte sich nach den Hook richten. Z.B. **get_return.js** ist zustängig für den GET-Hook nach dem Lesen der Daten, bevor diese zurück gegeben werden. Mehr dazu unter [Hooks](./collections/hooks.md).
|
||||||
|
|
||||||
|
### /api/templates
|
||||||
|
|
||||||
|
Ist es nötig im Projekt Templates zu rendern (z.B. für den Email-Versand), sind diese im Ordner **templates** gut aufgehoben.
|
27
docs/md/restapi/assets.md
Normal file
27
docs/md/restapi/assets.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# /assets
|
||||||
|
|
||||||
|
Die /assets-API ist dazu gedacht, den Zugriff auf bestimmte Ordnerpfade zu ermöglichen, die direkt über den Tibi-Server erreichbar sind. Diese Pfade werden in der Konfigurationsdatei (config.yml) definiert und relativ zu dieser Datei interpretiert. Jeder dieser Pfade wird durch einen eindeutigen Namen identifiziert, der in der URL verwendet wird.
|
||||||
|
|
||||||
|
## URL-Struktur
|
||||||
|
|
||||||
|
Die Struktur der URL für den Zugriff auf die Assets ist wie folgt:
|
||||||
|
|
||||||
|
- TIBI-SERVER-URL/api/v1/_/NAMESPACE/_/assets/NAME/
|
||||||
|
|
||||||
|
Hierbei steht NAME für den in der Konfigurationsdatei festgelegten Namen für den Pfad. Wenn beispielsweise ein Pfad mit dem Namen _dist_ definiert ist, der auf den Ordner ../frontend/_dist_ relativ zur config.yml zeigt, würde die entsprechende URL so aussehen:
|
||||||
|
|
||||||
|
- TIBI-SERVER-URL/api/v1/_/NAMESPACE/_/assets/_dist_/
|
||||||
|
|
||||||
|
## Zugriffsmethode
|
||||||
|
|
||||||
|
Über die /assets-API ist ausschließlich ein unbeschränkter Lesezugriff (GET-Methode) möglich. Dies bedeutet, dass Sie über diese API Dateien aus den definierten Pfaden abrufen können, aber keine Änderungen vornehmen oder Dateien hochladen können.
|
||||||
|
Konfigurationsbeispiel
|
||||||
|
|
||||||
|
In der config.yml könnten Sie einen Asset-Pfad wie folgt definieren:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: _dist_
|
||||||
|
path: ../frontend/_dist_
|
||||||
|
```
|
||||||
|
|
||||||
|
Dies würde den Zugriff auf Dateien im Ordner ../frontend/_dist_ relativ zur config.yml über die URL TIBI-SERVER-URL/api/v1/_/NAMESPACE/_/assets/_dist_/ ermöglichen.
|
239
docs/md/restapi/collection.md
Normal file
239
docs/md/restapi/collection.md
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
# `/_/NAMESPACE/COLLECTION`
|
||||||
|
|
||||||
|
Dieser Endpoint ermöglicht Interaktionen mit den Collectionen, die flexible Strukturen zur Organisation und Kategorisierung von Daten darstellen. Sie können einen Collectioneintrag abrufen, aktualisieren, erstellen und löschen. Jede Collection wird durch einen eindeutigen Namespace und Namen identifiziert.
|
||||||
|
|
||||||
|
## GET /{namespace}/{collection}
|
||||||
|
|
||||||
|
Diese Anforderung ruft alle Einträge einer bestimmten Collection ab. Sie nimmt den Namespace und den Namen der Collection sowie optionale API-Parameter für die Anpassung der Anfrage als Parameter an.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein Objekt mit folgenden Eigenschaften:
|
||||||
|
|
||||||
|
- `data`: Ein Array von CollectionEntry Objekten.
|
||||||
|
|
||||||
|
- `count`: Die Gesamtzahl der Einträge.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface Collection {
|
||||||
|
name: string
|
||||||
|
meta?: CollectionMeta
|
||||||
|
permissions?: {
|
||||||
|
public?: CollectionPermission
|
||||||
|
user?: CollectionPermission
|
||||||
|
[token: string]: CollectionPermission
|
||||||
|
}
|
||||||
|
projections?: {
|
||||||
|
[projectionName: string]: {
|
||||||
|
select: {
|
||||||
|
[field: string]: 1 | 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fields: CollectionField[]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET /{namespace}/{collection}/{id}
|
||||||
|
|
||||||
|
Diese Anforderung ruft einen bestimmten Eintrag in einer Collection ab. Sie nimmt den Namespace und Namen der Collection sowie die ID des abzurufenden Eintrags als Parameter an.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
- `id`: Die ID des abzurufenden Eintrags.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist das entsprechende CollectionEntry Objekt.
|
||||||
|
|
||||||
|
## PUT /{namespace}/{collection}/{id}
|
||||||
|
|
||||||
|
Diese Anforderung aktualisiert die Daten eines vorhandenen Eintrags in einer Collection. Sie nimmt den Namespace und den Namen der Collection, die ID des zu aktualisierenden Eintrags und ein Änderungssatz-Objekt, das die zu aktualisierenden Daten enthält, als Parameter an.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
id: Die ID des zu aktualisierenden Eintrags.
|
||||||
|
|
||||||
|
data: Ein Änderungssatz-Objekt, das die zu aktualisierenden Daten enthält.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist das aktualisierte CollectionEntry Objekt.
|
||||||
|
|
||||||
|
## POST /{namespace}/{collection}
|
||||||
|
|
||||||
|
Diese Anforderung erstellt einen neuen Eintrag in einer Collection. Sie nimmt den Namespace und den Namen der Collection und ein Datenobjekt, das die Informationen des neuen Eintrags enthält, als Parameter an. Optional kann eine Funktion für den Fortschritt des Uploads übergeben werden.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
- `data`: Ein Datenobjekt, das die Informationen des neuen Eintrags enthält.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist das neu erstellte CollectionEntry Objekt.
|
||||||
|
|
||||||
|
## DELETE /{namespace}/{collection}/{id}
|
||||||
|
|
||||||
|
Diese Anforderung löscht einen vorhandenen Eintrag in einer Collection. Sie nimmt den Namespace und den Namen der Collection und die ID des zu löschenden Eintrags als Parameter an.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
- `id`: Die ID des zu löschenden Eintrags.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein boolean, das true zurückgibt, wenn das Löschen erfolgreich war.
|
||||||
|
|
||||||
|
Jede Collection besteht aus mehreren Feldern (CollectionField), die verschiedene Datenpunkte repräsentieren. Jedes Feld hat einen Namen, einen Typ und ggf. eine Reihe von Subfeldern. Die Metadaten eines Feldes (CollectionFieldMeta) können zusätzliche Informationen über das Feld enthalten, wie z.B. ein Label, Hilfstexte, Widget-Typen, InputProps und mehr.
|
||||||
|
|
||||||
|
Eine Collection kann auch Metadaten (CollectionMeta) enthalten, die Informationen über die Collection selbst enthalten.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface CollectionNavigation {
|
||||||
|
label?: I18Text
|
||||||
|
muiIcon?: string
|
||||||
|
defaultSort?: {
|
||||||
|
field: string
|
||||||
|
order?: "ASC" | "DESC" | "MANUALLY"
|
||||||
|
}
|
||||||
|
defaultImageFilter?: string
|
||||||
|
views?: View[]
|
||||||
|
filter?: { [key: string]: any }
|
||||||
|
defaultCallback?:
|
||||||
|
| "edit"
|
||||||
|
| "view"
|
||||||
|
| {
|
||||||
|
eval: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectionMeta extends CollectionNavigation {
|
||||||
|
singleton: boolean
|
||||||
|
rowIdentTpl?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
twig: string
|
||||||
|
}
|
||||||
|
|
||||||
|
subNavigation?: CollectionNavigation[]
|
||||||
|
|
||||||
|
tablist?: {
|
||||||
|
activeTab?: string
|
||||||
|
tabs: CollectionMetaTab[]
|
||||||
|
}
|
||||||
|
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectionMetaTab {
|
||||||
|
name: string
|
||||||
|
label: I18Text
|
||||||
|
dependsOn?: DependsOn
|
||||||
|
subFields: {
|
||||||
|
source: string
|
||||||
|
name?: string
|
||||||
|
}[]
|
||||||
|
_resolvedSubFields?: CollectionField[]
|
||||||
|
_hide?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EntryViewTab {
|
||||||
|
name: string
|
||||||
|
meta: {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectionPermission {
|
||||||
|
methods?: MethodPermission
|
||||||
|
filter?: any
|
||||||
|
validProjections?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectionField {
|
||||||
|
name: string
|
||||||
|
type?: string
|
||||||
|
index?: ("single" | "unique")[]
|
||||||
|
meta?: CollectionFieldMeta
|
||||||
|
subFields?: CollectionField[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type CssWithEval = string | { [key: string]: string | number } | { eval: string }
|
||||||
|
|
||||||
|
interface ContainerProps {
|
||||||
|
class?: string
|
||||||
|
style?: string
|
||||||
|
layout?: {
|
||||||
|
breakBefore: boolean
|
||||||
|
breakAfter: boolean
|
||||||
|
size: {
|
||||||
|
default: string
|
||||||
|
small: string
|
||||||
|
large: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectionFieldMeta {
|
||||||
|
source?: string
|
||||||
|
label?: I18Text
|
||||||
|
helperText?: I18Text
|
||||||
|
widget?: string
|
||||||
|
valueMap?: {
|
||||||
|
[value: "string" | number]: {
|
||||||
|
name?: I18Text
|
||||||
|
muiIcon?: string
|
||||||
|
style?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerProps?: ContainerProps
|
||||||
|
choices?: ArrayFieldChoice[] | EndpointOptions
|
||||||
|
filter?: boolean | FilterConfig
|
||||||
|
defaultValue?: DefaultValue
|
||||||
|
addAllowed?: boolean
|
||||||
|
props?: {
|
||||||
|
step?: string | number
|
||||||
|
[key: string]: string | number | boolean
|
||||||
|
}
|
||||||
|
inputProps?: {
|
||||||
|
step?: string | number
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
dependsOn?: DependsOn
|
||||||
|
|
||||||
|
css?: {
|
||||||
|
input?: {
|
||||||
|
wrapper?: CssWithEval
|
||||||
|
element?: CssWithEval
|
||||||
|
foreignEntry?: CssWithEval
|
||||||
|
}
|
||||||
|
view?: {
|
||||||
|
wrapper?: CssWithEval
|
||||||
|
element?: CssWithEval
|
||||||
|
foreignEntry?: CssWithEval
|
||||||
|
}
|
||||||
|
filter?: {
|
||||||
|
wrapper?: CssWithEval
|
||||||
|
element?: CssWithEval
|
||||||
|
foreignEntry?: CssWithEval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
folding?: {
|
||||||
|
unfolded?: boolean
|
||||||
|
previewFolded?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
eval: string
|
||||||
|
raw?: boolean
|
||||||
|
}
|
||||||
|
previewUnfolded?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
eval: string
|
||||||
|
raw?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
```
|
63
docs/md/restapi/login.md
Normal file
63
docs/md/restapi/login.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# `/login`
|
||||||
|
|
||||||
|
## POST /login
|
||||||
|
|
||||||
|
Dieser Endpoint ermöglicht es Benutzern, sich in das System einzuloggen. Dabei wird eine Authentifizierung durchgeführt und bei erfolgreicher Authentifizierung ein Token zurückgegeben, der für nachfolgende API-Aufrufe verwendet wird.
|
||||||
|
|
||||||
|
## Anforderungsparameter
|
||||||
|
|
||||||
|
Der /login Endpoint erwartet folgende Daten im Body:
|
||||||
|
|
||||||
|
- `username`: Der Benutzername des Benutzers, der sich anmelden möchte. Typ: String.
|
||||||
|
|
||||||
|
- `password`: Das Passwort des Benutzers, der sich anmelden möchte. Typ: String.
|
||||||
|
|
||||||
|
Die Daten müssen als LoginData Objekt übergeben werden.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const loginData: LoginData = {
|
||||||
|
username: "IhrBenutzername",
|
||||||
|
password: "IhrPasswort",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Antwort
|
||||||
|
|
||||||
|
Bei erfolgreicher Anmeldung gibt der /login Endpoint ein LoginResponse Objekt zurück. Dieses Objekt enthält:
|
||||||
|
|
||||||
|
- `token`: Ein Authentifizierungstoken, das für nachfolgende API-Aufrufe verwendet wird. Typ: String.
|
||||||
|
|
||||||
|
- `user`: Ein User Objekt, das Informationen über den eingeloggten Benutzer enthält.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface User {
|
||||||
|
id: string // Eindeutige ID des Benutzers
|
||||||
|
insertTime: string // Zeitpunkt der Erstellung des Benutzerkontos
|
||||||
|
updateTime: string // Letzter Zeitpunkt der Aktualisierung des Benutzerkontos
|
||||||
|
username: string // Benutzername des Benutzers
|
||||||
|
role: number // Rolle des Benutzers im System (0=admin, 1 = editor, 2 = user)
|
||||||
|
permissions: any[] // Berechtigungen des Benutzers
|
||||||
|
meta: {
|
||||||
|
// Weitere optionale Benutzerinformationen
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Beispielaufruf
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const loginData: LoginData = {
|
||||||
|
username: "IhrBenutzername",
|
||||||
|
password: "IhrPasswort",
|
||||||
|
}
|
||||||
|
|
||||||
|
postLogin(loginData)
|
||||||
|
.then((response) => {
|
||||||
|
console.log("Erfolgreiche Anmeldung! Token: ", response.token)
|
||||||
|
console.log("Benutzerinformationen: ", response.user)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Fehler beim Login: ", error)
|
||||||
|
})
|
||||||
|
```
|
99
docs/md/restapi/project.md
Normal file
99
docs/md/restapi/project.md
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# `/project`
|
||||||
|
|
||||||
|
Dieser Endpoint bietet eine Schnittstelle für den Zugriff und die Manipulation von Projektdaten. Benutzer können Projekte erstellen, abrufen, aktualisieren und löschen.
|
||||||
|
|
||||||
|
## GET /project
|
||||||
|
|
||||||
|
Mit dieser Funktion können Sie eine Liste aller Projekte abrufen. Diese Funktion nimmt optionale Parameter an, die verwendet werden können, um die abgerufenen Projekte zu sortieren oder zu filtern.
|
||||||
|
|
||||||
|
Diese request ruft eine Liste aller Projekte ab. Sie kann optionale Parameter verwenden, um die abgerufenen Projekte zu sortieren oder zu filtern.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort auf diese request ist ein Objekt mit zwei Eigenschaften:
|
||||||
|
|
||||||
|
- `data`: Ein Array von Projekt-Objekten.
|
||||||
|
- `count`: Die Gesamtzahl der Projekte die es gibt.
|
||||||
|
|
||||||
|
Jedes Projekt-Objekt hat die folgenden Eigenschaften:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface Project {
|
||||||
|
id?: string // Eindeutiger Identifikator für das Projekt
|
||||||
|
insertTime?: string // Zeitpunkt der Erstellung des Projekts
|
||||||
|
updateTime?: string // Letzter Zeitpunkt der Aktualisierung des Projekts
|
||||||
|
configFile: string // Pfad zur config.yml des Projekts
|
||||||
|
name: string // Name des Projekts
|
||||||
|
description: string // Beschreibung des Projekts
|
||||||
|
users?: string[] // Array von Benutzer-IDs mit Zugriff auf das Projekt
|
||||||
|
api?: ProjectAPI // Zusätzliche Projektinformationen
|
||||||
|
yourPermissions?: {
|
||||||
|
// Berechtigungen des aktuellen Benutzers für das Projekt
|
||||||
|
[collectionName: string]: MethodPermission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## PUT /project/{id}
|
||||||
|
|
||||||
|
Diese Anforderung aktualisiert ein vorhandenes Projekt. Sie nimmt die ID des zu aktualisierenden Projekts und ein Änderungsset als Parameter an. Das Änderungsset ist ein Objekt, das die zu ändernden Eigenschaften und ihre neuen Werte enthält.
|
||||||
|
Anforderungsparameter
|
||||||
|
|
||||||
|
- `id`: Die ID des zu aktualisierenden Projekts.
|
||||||
|
|
||||||
|
- `data`: Ein Objekt, das die zu ändernden Eigenschaften und ihre neuen Werte enthält.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist das aktualisierte Project Objekt.
|
||||||
|
|
||||||
|
## DELETE /project/{id}
|
||||||
|
|
||||||
|
Diese Anforderung löscht ein vorhandenes Projekt. Sie nimmt die ID des zu löschenden Projekts als Parameter an.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
- `id`: Die ID des zu löschenden Projekts.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein Objekt mit einer message Eigenschaft, die eine Bestätigungsnachricht enthält.
|
||||||
|
|
||||||
|
## POST /project
|
||||||
|
|
||||||
|
Diese Anforderung erstellt ein neues Projekt. Sie nimmt ein Objekt als Parameter an, das die Eigenschaften des zu erstellenden Projekts enthält.
|
||||||
|
Anforderungsparameter
|
||||||
|
|
||||||
|
- `data`: Ein Objekt vom typ Project.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein Objekt mit einer message Eigenschaft, die eine Bestätigungsnachricht enthält.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface MethodPermission {
|
||||||
|
get: boolean
|
||||||
|
post: boolean
|
||||||
|
put: boolean
|
||||||
|
delete: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProjectPermission {
|
||||||
|
name: string
|
||||||
|
label: I18Text
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectImageUrl = string | EvalObject
|
||||||
|
|
||||||
|
interface ProjectAPI {
|
||||||
|
isOnline: boolean
|
||||||
|
namespace: string
|
||||||
|
meta?: {
|
||||||
|
imageUrl?: ProjectImageUrl
|
||||||
|
permissions?: ProjectPermission[]
|
||||||
|
dashboard?: Dashboard
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
collections: Collection[]
|
||||||
|
}
|
||||||
|
```
|
81
docs/md/restapi/user.md
Normal file
81
docs/md/restapi/user.md
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# `/user`
|
||||||
|
|
||||||
|
Dieser Endpoint bietet eine Schnittstelle für den Zugriff und die Manipulation von Benutzerdaten. Sie können Benutzerinformationen abrufen, aktualisieren, erstellen und löschen. Jeder Benutzer wird durch eine eindeutige Benutzer-ID identifiziert.
|
||||||
|
|
||||||
|
## GET /user
|
||||||
|
|
||||||
|
Diese Anforderung ruft eine Liste aller Benutzer ab. Sie kann optionale Parameter verwenden, um die abgerufenen Benutzerdaten zu sortieren oder zu filtern.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort auf diese Anforderung ist ein Users Objekt mit folgenden Eigenschaften:
|
||||||
|
|
||||||
|
- `data`: Ein Array von User Objekten.
|
||||||
|
|
||||||
|
- `count`: Die Gesamtzahl der Benutzer.
|
||||||
|
|
||||||
|
Jedes User Objekt hat die folgenden Eigenschaften:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface User {
|
||||||
|
id: string // Eindeutiger Identifikator des Benutzers
|
||||||
|
insertTime: string // Zeitpunkt der Erstellung des Benutzers
|
||||||
|
updateTime: string // Letzter Zeitpunkt der Aktualisierung des Benutzers
|
||||||
|
username: string // Benutzername des Benutzers
|
||||||
|
role: number // Rolle des Benutzers, repräsentiert durch eine Zahl
|
||||||
|
permissions: any[] // Array von Berechtigungen des Benutzers
|
||||||
|
meta: {
|
||||||
|
// Zusätzliche Informationen über den Benutzer
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET /user/{id}
|
||||||
|
|
||||||
|
Diese Anforderung ruft einen bestimmten Benutzer ab. Sie nimmt die ID des abzurufenden Benutzers als Parameter an.
|
||||||
|
Anforderungsparameter
|
||||||
|
|
||||||
|
- `id`: Die ID des abzurufenden Benutzers.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist das entsprechende User Objekt.
|
||||||
|
|
||||||
|
## POST /user
|
||||||
|
|
||||||
|
Diese Anforderung erstellt einen neuen Benutzer. Sie nimmt ein Objekt als Parameter an, das die Eigenschaften des zu erstellenden Benutzers enthält.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
- `data`: Ein Objekt, das die Eigenschaften des zu erstellenden Benutzers enthält.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein Objekt, das das neu erstellte User Objekt enthält.
|
||||||
|
|
||||||
|
## PUT /user/{id}
|
||||||
|
|
||||||
|
Diese Anforderung aktualisiert die Daten eines vorhandenen Benutzers. Sie nimmt die ID des zu aktualisierenden Benutzers und ein Objekt, das die zu aktualisierenden Daten enthält, als Parameter an.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
- `id`: Die ID des zu aktualisierenden Benutzers.
|
||||||
|
|
||||||
|
- `data`: Ein Objekt, das die zu aktualisierenden Daten enthält.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein Objekt, das das aktualisierte User Objekt enthält.
|
||||||
|
|
||||||
|
## DELETE /user/{id}
|
||||||
|
|
||||||
|
Diese Anforderung löscht einen vorhandenen Benutzer. Sie nimmt die ID des zu löschenden Benutzers als Parameter an.
|
||||||
|
|
||||||
|
### Anforderungsparameter
|
||||||
|
|
||||||
|
`id`: Die ID des zu löschenden Benutzers.
|
||||||
|
|
||||||
|
### Antwort
|
||||||
|
|
||||||
|
Die Antwort ist ein boolean, das true zurückgibt, wenn das Löschen erfolgreich war.
|
71
docs/md/server-javascript-kontext/allgemeines.md
Normal file
71
docs/md/server-javascript-kontext/allgemeines.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
Das HookContext-Interface bietet ein zentrales Objekt, um Zugang zu verschiedenen Attributen und Paketen zu erhalten. Es wird als context in den Hooks des tibi-server genutzt und stellt wichtige Funktionalitäten zur Verfügung, die zur Manipulation der Daten und Abläufe in den HTTP-Methoden und Schritten der API benötigt werden.
|
||||||
|
|
||||||
|
Das HookContext-Interface setzt sich aus mehreren Schnittstellen zusammen, darunter GetHookData, GetHookGetOnlyData, PostHookData, JobData, request und mehrere third-party Pakete. Hierbei sind mit ausnahme von den request und den third-party-paketen attributen alle attribute direkt auf dem context Objekt vorhanden. Request ist eine funktion die ihre Objekte zurückgibt und ist somit rechenaufwendig. Daher ist es ratsam bei mehrfacher nutzung des request attributs, sich den Wert in einer variable zwischen zu speichern. Die Attribute auf den paketen werden über context.paketname.attribut aufgerufen.
|
||||||
|
|
||||||
|
## GetHookData
|
||||||
|
|
||||||
|
Das GetHookData-Interface enthält Attribute, die spezifisch für die Manipulation von GET-Anfragen in den Hooks sind:
|
||||||
|
|
||||||
|
- `filter`: Ein Filter-Objekt, das die Anfragebedingungen für die zu abrufenden Dokumente enthält.
|
||||||
|
- `selector`: Ein Selektor-Objekt, das festlegt, welche Felder in den zurückgegebenen Dokumenten enthalten sein sollten.
|
||||||
|
- `offset`: Ein numerischer Wert, der den Startpunkt für die Rückgabe von Dokumenten festlegt.
|
||||||
|
- `limit` Ein numerischer Wert, der die maximale Anzahl von Dokumenten festlegt, die zurückgegeben werden sollen.
|
||||||
|
- `sort`: Ein String oder ein Array von Strings, der die Sortierreihenfolge der zurückgegebenen Dokumente bestimmt.
|
||||||
|
- `pipelineMod`: Eine Funktion, die es ermöglicht, die MongoDB-Abfragepipeline zu modifizieren.
|
||||||
|
|
||||||
|
## PostHookData Interface
|
||||||
|
|
||||||
|
Das PostHookData-Interface enthält ein Attribut, das speziell für POST- und PUT-Hooks relevant ist:
|
||||||
|
|
||||||
|
`data`: Das Dokument oder die Daten, die gesendet wurden. Dies ist ein CollectionDocument-Objekt und wird in die Datenbank geschrieben. Will man den Datenbankeinträge im hook also modifizieren, so muss dieses Objekt modifiziert werden. Mann muss dieses Objekt idealerweise also einfach modifiziert in dem HookResponse data attribut abspeichern, dies wird nämlich zwischen allen Hooks immer ausgetauscht. Demzufolge ist das veränderte data Objekt dann auch so im nächsten Hook verfügbar.
|
||||||
|
|
||||||
|
## JobConfig und JobData Interfaces
|
||||||
|
|
||||||
|
Das JobConfig-Interface definiert die Konfiguration für einen Cron-Job, diese ist jene Konfig die im zugehörigen yaml definiert wurde:
|
||||||
|
|
||||||
|
- `meta`: Ein Metadatenobjekt.
|
||||||
|
- `cron`: Ein String, der die Cron-Job-Intervallspezifikation enthält.
|
||||||
|
- `type`: Der Typ des Jobprogramms. Derzeit wird nur "javascript" unterstützt.
|
||||||
|
- `file`: Der Pfad zur Datei des Jobprogramms.
|
||||||
|
|
||||||
|
Das JobData-Interface enthält ein job-Attribut, das ein JobConfig-Objekt ist und die Konfiguration des aktuellen Jobs repräsentiert.
|
||||||
|
|
||||||
|
## request
|
||||||
|
|
||||||
|
Die request Funktion liefert ein Objekt zurück, das Informationen über die HTTP-Anfrage enthält:
|
||||||
|
|
||||||
|
- `method`: Die HTTP-Methode der Anfrage (GET, POST, PUT, DELETE etc.).
|
||||||
|
- `remoteAddr`: Die remote IP-Adresse der Anfrage.
|
||||||
|
- `clientIp()`: Funktion zum Abrufen der Client-IP-Adresse der Anfrage.
|
||||||
|
- `host`: Der Host der Anfrage.
|
||||||
|
- `url`: Die vole URL der Anfrage.
|
||||||
|
- `path`: Der Pfad der Anfrage.
|
||||||
|
- `param(p: string)`: Funktion zum Abrufen von URL-Parametern.
|
||||||
|
- `query(q: string`: Funktion zum Abrufen von URL-Abfrageparametern.
|
||||||
|
- `header(h: string)`: Funktion zum Abrufen von HTTP-Headern.
|
||||||
|
- `body()`: Funktion zum Abrufen des HTTP-Body.
|
||||||
|
- `bodyBytes()`: Funktion zum Abrufen des HTTP-Body als byte array. Wird z.B. für die Umwandlung von iso8859 zu utf8 genutzt.
|
||||||
|
|
||||||
|
## Pakete
|
||||||
|
|
||||||
|
Jedes der folgenden Attribute ist ein Paket, das spezifische Funktionen bereitstellt:
|
||||||
|
|
||||||
|
- `db`: Stellt Funktionen zur Interaktion mit der Datenbank zur Verfügung (DbPackage).
|
||||||
|
- `smtp`: Bietet Funktionen zum Senden von E-Mails (SmtpPackage).
|
||||||
|
- `fs`: Bietet Funktionen zum Interagieren mit dem Dateisystem (FsPackage).
|
||||||
|
- `tpl`: Stellt Funktionen zum Arbeiten mit Templates zur Verfügung (TplPackage).
|
||||||
|
- `http`: Bietet Funktionen zum Senden von HTTP-Anfragen (HttpPackage).
|
||||||
|
- `debug`: Stellt Funktionen zum Debuggen zur Verfügung (DebugPackage).
|
||||||
|
- `response`: Bietet Funktionen zur Manipulation der HTTP-Antwort (ResponsePackage).
|
||||||
|
- `user`: Bietet Funktionen zum Arbeiten mit Benutzern (UserPackage).
|
||||||
|
- `bcrypt`: Stellt Funktionen zum Hashen und Überprüfen von Passwörtern zur Verfügung (BcryptPackage)`
|
||||||
|
- `jwt`: Bietet Funktionen zum Arbeiten mit JSON Web Tokens (JwtPackage).
|
||||||
|
- `charset`: Bietet Funktionen zur Arbeit mit Zeichensätzen (CharsetPackage).
|
||||||
|
- `image`: Bietet Funktionen zur Arbeit mit Bildern (ImagePackage).
|
||||||
|
- `xml`: Stellt Funktionen zum Arbeiten mit XML-Daten zur Verfügung (XmlPackage).
|
||||||
|
- `cookie`: Bietet Funktionen zum Arbeiten mit Cookies (CookiePackage).
|
||||||
|
- `pdf`: Bietet Funktionen zum Arbeiten mit PDF-Dokumenten (PdfPackage).
|
||||||
|
- `crypt`: Bietet Funktionen für Kryptografie (CryptoPackage).
|
||||||
|
- `json`: Bietet Funktionen zum Arbeiten mit JSON-Daten (JsonPackage).
|
||||||
|
|
||||||
|
Diese Pakete erweitern die Möglichkeiten des Context Objektes und ermöglichen es, eine Vielzahl von Aufgaben auszuführen. Für detaillierte Informationen zu jedem Paket, siehe die spezifische Dokumentation des jeweiligen Pakets.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user