Skip to content

Latest commit

 

History

History
401 lines (335 loc) · 11.6 KB

doc.md

File metadata and controls

401 lines (335 loc) · 11.6 KB

Documentation

How to use this framework

Core

Types

Name Description
Keyvalue Key/Value store
User
UserRole There are different user roles like administrator or subscriber with different privileges

Extensions

Name Description
Media Media Handling / Image conversion and uploading
Cms Content management system

Types

A type is basically a collection in mongodb or a table in relational databases.

A Type can be define in the build.json of an extension. Types can also have references to other types.

Type properties

  • name = Name of the type
  • fields = An array of the fields
  • collectionClonable = If true the whole collection of the type is cloneable
  • entryClonable = If true a single data record is cloneable
  • genResolver = If set to false the resolver is not generated automatically
  • mutationResult = The type that is returned after a mutation (default is {TypeName}Status)
  • access = Control who has access -> Object {create: 'anonymous'}
  • noUserRelation = if true the createdBy field won't be created

Field properties

  • name = Name of the field
  • label = The label that is show in the frontend editor
  • required = If set to true the filed must have a value
  • default = Default value if no value is provided (TODO)
  • multi = If true multiple values can be selected
  • type = The type of the field. It can be String (default), Boolean, Float or the name of another type
  • index = Creates a database index. For FTS the value can be text
  • hidden = If true the field is not visible in the type editor nor it is included in the search. It is as if it is non-existent
  • searchable = If true the field is included in the search also if it is hidden
  • uitype = It can be datetime, number, editor, jseditor. If the value is set you can force the type editor to use a certain ui element
  • readOnly = The value is read only. It is not defined whether the field exist in the database or is only dynamic
  • pickerField = When the type is a reference you can define which field you want to show in the frontend for type picking
  • alwaysUpdate = always sends the data even if there was no change
  • dynamic = the value of the field is calculated dynamically

An example of a type definition

 {"types": [
    {
      "name": "Product",
      "fields": [
        {
          "name": "name",
          "required": true
        },
        {
          "name": "description"
        },
        {
          "name": "price",
          "uitype": "numeric"
        },
        {
          "name": "image",
          "type": "Media"
        },
        {
          "name": "categories",
          "type": "ProductCategory",
          "multi": true
        }
      ]
    },
    {
      "name": "ProductCategory",
      "fields": [
        {
          "name": "name",
          "required": true
        }
      ]
    }
  ]
}

Hooks

Who to use a hook?

Hook.on('Routes', ({routes}) => {
    routes.push({exact: true, path: ADMIN_BASE_URL+'/post/:id*', component: PostContainer})
})

// use with key (after .) so if it executed multiple times the function is only called once
Hook.on('Routes.myroute', ({routes}) => {
    routes.push({exact: true, path: ADMIN_BASE_URL+'/post/:id*', component: PostContainer})
})

Client hooks

Hook Params Description
ApiResponse data Exposes the response after an api request. Here you can modify or populate values
Routes routes Where custom routes can be added
TypeTable type, dataSource, data, fields Before the types table is rendered
TypeTableColumns type, columns After the creation of the columns for the type table
Types types Add or remove a type from the type list
TypeCreateEdit type, props Here you can change the behavior of the dialog which is shown when you create or edit data of type
TypeCreateEditBeforeSave type, props Is called before data are saved
ExtensionSystemInfo extension Here you can add extension info which are shown in the system menu

Server hooks

Hook Params Description
appready db, app Is called as soon as connection and db is ready
appexit Is called on precess exit
typeUpdated type,data, db Is called when any type gets updated
typeUpdated_{typeName} result, db Is called when a type gets updated
typeDeleted_{typeName} _id, db Is called when a type gets deleted
typeBeforeCreate type, _version, data, db, context Is called before data gets inserted into type collection

Content Management

Data Resolver

It is a simple json structure to select data on the server. The json is never exposed to the client. Only the resolved data are sent to the client.

  • f = filter for the query
  • t = type
  • d = the data / fields you want to access
  • l = limit of results
  • o = offset
  • p = page (if no offset is defined, offset is limit * (page -1) )
  • g = group

you can subcribe to data changes with $ character placed in front of the type.

[
  {
    "t": "$ProductCategory",
    "f": [
      "name"
    ],
    "l": 100
  }
]                    

Template

Here are some useful helper methods that can be used with in the template

this.escape can be use to make sure the json doesn't break after inserting the value.

"data": "$.x{this.escape(body)}"       

Util.tryCatch to eval a string and return result. errors are ignored and in case of an error an empty string is returned

"c": "Category ${Util.tryCatch('this.filter.parts.categories[0]')}"   

or use the short form

"c": "Category ${_i('this.filter.parts.categories[0]')}"   

define a click event in template

{
    "t": "button",
    "c": "send",
    "p": {
      "onClick":{"action":"send"}
    }
}

Extending a type

In this example the type FileDrop is extended under the name ImageDrop. Now the type ImageDrop can be referenced anywhere within the template.

{
  "x": {
    "t": "FileDrop",
    "n": "ImageDrop",
    "p": {
      "label": "Add image",
      "multi": false
    }
  }
}

The scope

Within a template all scope properties (See the section scope below) are accessible. For example if you want to access the parent scope just write ${parent.scope} or if you want to use data that has been resolved by the Data Resolver just type ${data.ProductCategory.total}

loop

Let's assume there is a property array breadcrumbs on the scope like this:

scope.breadcrumbs = [{name:'Home',url:'/'},{name:'Page 1', url: '/page1'}]

In the template we can iterate through it with the $loop expression:

{
  "$loop": {
    "d": "breadcrumbs",
    "c": {
      "t": "Link",
      "c": "$.loop{name}",
      "p": {
        "to": "$.loop{url}"
      }
    }
  }
}
Properties
  • d = data source (access on the scope)
  • $d = data source as string that gets parsed to an array
  • c = children in loop
  • s = name of scope in loop to access data (default is loop). If s is equal to x for example data can be accessed with $.x{name}
Other
  • Use this.scope to access the main scope within a loop.
  • Use this.loop to access the whole data object
  • If the data is not an object use $.loop{data} to access it
  • Use _index to get the current position in the loop

Script

Reserved keywords

  • this => is the current JsonDom
  • parent => reference to the parent JsonDom
  • root => reference to the root parent JsonDom
  • getComponent(id) => get any JsonDom by its id
  • clientQuery => for communication with the graphql api
  • setStyle => set a css style for this page. Will automatically be removed when page is released
  • scope => Object with properties related to the current template
  • on => Add an event listener function
  • setLocal => put data to the localstorage
  • getLocal => get data from the localstorage
  • forceUpdate(id,refreshScript) => refresh a component
  • history => history obj
  • _t => i18n
  • Util => Utilities
  • setKeyValue => set key value for the user if there is a session otherwise the values are kept in the local storage
  • getKeyValueFromLS => read key value from local storage

Scope

The scope is an object with all relevant properties which is accessible in the script as well as in the template

Here is an example of a scope object:

{
  "page": {
    "slug": "mailer"
  },
  "user": {
    "userData": {
      "username": "admin",
      "email": "axax@gmx.net",
      "_id": "590effdab75b10094f8543b8",
      "role": {
        "_id": "59358a39d56f6b06cc266433",
        "capabilities": [
          "manage_keyvalues",
          "manage_cms_pages",
          "access_admin_panel",
          "view_app",
          "access_admin_page",
          "manage_types",
          "manage_other_users"
        ],
        "__typename": "UserRole"
      },
      "__typename": "User"
    },
    "isAuthenticated": true
  },
  "pathname": "/en/mailer",
  "params": {},
  "hashParams": {},
  "data": {
    "globals": {
      "MailSettings": {
        "smtp": {
          "host": "localhost"
        }
      }
    }
  },
  "_app_": {
    "tr": {
    },
    "lang": "en",
    "config": {
      "DEBUG": true,
      "ADMIN_BASE_URL": "/admin",
      "BACKUP_DIR": "/backups",
      "BACKUP_URL": "/backups",
      "UPLOAD_DIR": "/uploads",
      "UPLOAD_URL": "/uploads",
      "LANGUAGES": [
        "de",
        "en"
      ],
      "DEFAULT_LANGUAGE": "de",
      "DEFAULT_RESULT_LIMIT": 10,
      "DEV_MODE": true
    }
  },
  "bindings": {
    "xx": "1234"
  },
  "parent": [object Object]
  "root": [object Object]
}

Events

  • beforeRender => is called before template is rendered
  • change => input change
  • click => simple click event
  • mount => JsonDom is mounted
  • childmount => A child JsonDom is mounted
  • unmount => JsonDom is unmounted
  • update => Is called after JsonDom is updated
  • resourcesReady => Is called after JsonDom is updated and all resources are loaded
  • urlchanged => is called when the url has changed (it only makes sens if the page is not urlSensitive)
  • subscription => on subscription event
  • beforerunscript => gets called right before the script is executed
on('unmount',()=>{
    console.log('unmount');
})

on('change',(payload, e)=>{
	if( payload.action === 'sortby' ){
  	...
	}
})

on('click',(payload, e)=>{
	if( payload.action === 'speak' ){               
	}
})

Internalization

[local].tr.json

_tr()

Config environment vars

LUNUC_HTTPX --> if true webserver handles http and https request on the same port (default is true) LUNUC_FORCE_HTTPS --> If true reqeust is forced to be https LUNUC_AUTH_EXPIRES_IN --> Expiration of authentication LUNUC_SECRET_KEY --> Secret key for user token LUNUC_MONGO_URL = MONGO_URL --> Connection to mongodb LUNUC_CERT_DIR --> SSL cert location LUNUC_API_PORT = API_PORT --> Graphql API port LUNUC_PORT = PORT --> Webserver port LUNUC_GROUP --> Is used for execution rule AWS_SECRET --> Amason web service secret key GOOGLE_API_KEY --> Google cloud key LUNUC_ALPHA_VANTAGE_API_KEY --> Alpha vantage spi key

Security

This framework uses the local and the session storage to cache data. Be aware of the vulnerability and make sure that sensitiv data never end up in the local storage.