From 52076029490324652dfa0d6d852fc5f0c8e687c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B8=CC=86=20=D0=AE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 21 Sep 2020 17:01:03 +0300 Subject: [PATCH 1/3] Add documentation --- QEWD.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 92 ++++++++++++++-------------------- 2 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 QEWD.md diff --git a/QEWD.md b/QEWD.md new file mode 100644 index 0000000..d1b9ba9 --- /dev/null +++ b/QEWD.md @@ -0,0 +1,147 @@ +# qewd-baseline: Minimal QEWD Set-up on which to start Application Development + +Rob Tweed +4 December 2019, M/Gateway Developments Ltd [http://www.mgateway.com](http://www.mgateway.com) + +Twitter: @rtweed + +Google Group for discussions, support, advice etc: [http://groups.google.co.uk/group/enterprise-web-developer-community](http://groups.google.co.uk/group/enterprise-web-developer-community) + + +# About this Repository + +This repository provides a pre-configured, minimal set-up on which you can begin +developing your APIs and/or back-end logic/message handlers for your interactive applications. + +It supports two modes of operation: + +1) A Dockerised version of QEWD that will run on any Linux system or on a Raspberry Pi + +2) A version that will run on the InterSystems +[AWS Community Edition of IRIS](https://aws.amazon.com/marketplace/pp/B07MSHYLF1?qid=1575041206953&sr=0-1&ref_=srh_res_product_title) + +This repository also contains in-depth tutorials that will teach you how to build QEWD-based: + +- [REST APIs](./REST.md) +- [interactive WebSocket-based applications](./INTERACTIVE.md) + +# What is QEWD? + +QEWD is a 100% Node.js-based, integrated system on which you can build the back-end logic for +both REST APIs and interactive, browser-based or Native applications. The pre-installated +and pre-configured components that constitute QEWD include: + +- the [Express](https://www.npmjs.com/package/express) web server +- the [socket.io](https://www.npmjs.com/package/socket.io) nodule for WebSocket support +- the [ewd-qoper8](https://www.npmjs.com/package/ewd-qoper8) Queue/Worker Pool management system +- [QEWD-jsdb](https://github.com/robtweed/qewd-jsdb): an in-process multi-model database +- the [QEWD-transform-json](https://github.com/robtweed/qewd-transform-json) JSON transformation module + +QEWD provides and supports Session management using either server-side Session storage (using +QEWD-JSdb) or JSON Web Tokens (JWT). + +QEWD can be run either natively or as a [Dockerised version](https://hub.docker.com/repository/docker/rtweed/qewd-server) +and can be configured to support either single monolithic applications or +applications built as MicroServices (each of which will run on its own QEWD instance). + +QEWD also includes [ewd-client](https://github.com/robtweed/ewd-client), a client JavaScript library +which allows browser or Native front-ends to communicate securely over WebSockets with +QEWD's *socket-io* interface. *ewd-client* can be used and easily integrated with any +JavaScript framework. + +# Getting Started + +For the IRIS / AWS Version, see [these instructions](./IRIS.md). + +Otherwise, the simplest way to work with QEWD is to use the pre-built Docker version which will run on +any Linux system or even on a Raspberry Pi. + +Just type these commands in a Linux system or Raspberry Pi: + + cd ~ + git clone https://github.com/robtweed/qewd-baseline + cd qewd-baseline + source install.sh + +Simply answer the questions and within a few minutes you'll have it all ready to run. + +Don't worry if you don't have Docker installed (which is the only dependency) - the installer +will also install Docker if necessary (though you'll need to start a new process and re-run +the installer after it installs Docker). + +When the installer has completed you have two options for starting the QEWD Docker container: + +- without database persistence between Container restarts: + + cd ~/qewd-baseline + ./start + +- with database persistence between Container restarts: + + + cd ~/qewd-baseline + ./start_p + + +To stop the Docker Container, you should always use the command: + + cd ~/qewd-baseline + ./stop + +This cleanly and safely shuts down the database-connected QEWD Worker Processes + + +The QEWD-baseline Folder Structure + +You'll see the following folders in your QEWD-baseline directory: + +- apis: used for your REST API handler logic +- configuration: this is where your QEWD system is configured, and where your REST API routes are defined +- qewd-apps: used for your interactive applications' message handlers +- utils: used for any of your utility modules on which your REST or interactive application handler are +dependent +- www: used as the QEWD Express web Server root path, and therefore the home for the front-end +markup, JavaScript and CSS resources of your applications + +If you're running the Containerised version of QEWD, you'll also see a folder named +*yottadb*. If you run the QEWD Container in persistent mode, this folder contains +the host files for the YottaDB database. They are mapped for use by YottaDB within the +Container. You should not change or move this folder or its contents, but you should back them +up regularly. + +You'll also see a folder named *iris-aws*. This contains versions of key files which +are used if you are running on IRIS + + +# Developing REST APIs + +[Click here](./REST.md) to learn how to create REST APIs on your QEWD system + + +# Developing Interactive Applications + +[Click here](./INTERACTIVE.md) to learn how to create interactive applications, the +back-end of which will run on your QEWD system + + +## License + + Copyright (c) 2019 M/Gateway Developments Ltd, + Redhill, Surrey UK. + All rights reserved. + + http://www.mgateway.com + Email: rtweed@mgateway.com + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index d1b9ba9..e029f36 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,19 @@ -# qewd-baseline: Minimal QEWD Set-up on which to start Application Development +# PTWQ - Open Source Telehealth Solution by the Ripple Foundation + +Open Source Telehealth Solution developed by the the Ripple Foundation - featuring PulseTile, Qewd, YottaDB and Jitsi open source technologies. +For any related code/information/discussion/questions/issues please visit this related discussion forum which is open to all; + +[Visit Discussion](https://gitter.im/Ripple-Foundation/Open-Source-TeleHealth) -Rob Tweed -4 December 2019, M/Gateway Developments Ltd [http://www.mgateway.com](http://www.mgateway.com) +### Contributors -Twitter: @rtweed +[![](https://github.com/tony-shannon.png?size=50)](https://github.com/tony-shannon) [![](https://github.com/yudin-s.png?size=50)](https://github.com/yudin-s) -Google Group for discussions, support, advice etc: [http://groups.google.co.uk/group/enterprise-web-developer-community](http://groups.google.co.uk/group/enterprise-web-developer-community) # About this Repository -This repository provides a pre-configured, minimal set-up on which you can begin -developing your APIs and/or back-end logic/message handlers for your interactive applications. +This repository provides a Open Source Telehealth app based on QEWD framework that allow dynamically extending and modifying It supports two modes of operation: @@ -22,32 +24,10 @@ It supports two modes of operation: This repository also contains in-depth tutorials that will teach you how to build QEWD-based: +- [QEWD](./QEWD.md) - [REST APIs](./REST.md) - [interactive WebSocket-based applications](./INTERACTIVE.md) -# What is QEWD? - -QEWD is a 100% Node.js-based, integrated system on which you can build the back-end logic for -both REST APIs and interactive, browser-based or Native applications. The pre-installated -and pre-configured components that constitute QEWD include: - -- the [Express](https://www.npmjs.com/package/express) web server -- the [socket.io](https://www.npmjs.com/package/socket.io) nodule for WebSocket support -- the [ewd-qoper8](https://www.npmjs.com/package/ewd-qoper8) Queue/Worker Pool management system -- [QEWD-jsdb](https://github.com/robtweed/qewd-jsdb): an in-process multi-model database -- the [QEWD-transform-json](https://github.com/robtweed/qewd-transform-json) JSON transformation module - -QEWD provides and supports Session management using either server-side Session storage (using -QEWD-JSdb) or JSON Web Tokens (JWT). - -QEWD can be run either natively or as a [Dockerised version](https://hub.docker.com/repository/docker/rtweed/qewd-server) -and can be configured to support either single monolithic applications or -applications built as MicroServices (each of which will run on its own QEWD instance). - -QEWD also includes [ewd-client](https://github.com/robtweed/ewd-client), a client JavaScript library -which allows browser or Native front-ends to communicate securely over WebSockets with -QEWD's *socket-io* interface. *ewd-client* can be used and easily integrated with any -JavaScript framework. # Getting Started @@ -59,8 +39,8 @@ any Linux system or even on a Raspberry Pi. Just type these commands in a Linux system or Raspberry Pi: cd ~ - git clone https://github.com/robtweed/qewd-baseline - cd qewd-baseline + git clone https://github.com/RippleOSI/OS-TeleHealth + cd OS-TeleHealth source install.sh Simply answer the questions and within a few minutes you'll have it all ready to run. @@ -73,13 +53,13 @@ When the installer has completed you have two options for starting the QEWD Dock - without database persistence between Container restarts: - cd ~/qewd-baseline + cd ~/OS-TeleHealth ./start - with database persistence between Container restarts: - cd ~/qewd-baseline + cd ~/OS-TeleHealth ./start_p @@ -91,38 +71,39 @@ To stop the Docker Container, you should always use the command: This cleanly and safely shuts down the database-connected QEWD Worker Processes -The QEWD-baseline Folder Structure +## The OS-TeleHealth Folder and File Structure -You'll see the following folders in your QEWD-baseline directory: +Website Structure -- apis: used for your REST API handler logic -- configuration: this is where your QEWD system is configured, and where your REST API routes are defined -- qewd-apps: used for your interactive applications' message handlers -- utils: used for any of your utility modules on which your REST or interactive application handler are -dependent -- www: used as the QEWD Express web Server root path, and therefore the home for the front-end -markup, JavaScript and CSS resources of your applications +- www/pt-wc-q/ : Main Folder with website pages and components structure. +- www/pt-wc-q/app.js : Entity point of project building and execution +- www/pt-wc-q/css : Global Stylesheet files. We are using https://startbootstrap.com/themes/sb-admin-2/ as main template. -If you're running the Containerised version of QEWD, you'll also see a folder named -*yottadb*. If you run the QEWD Container in persistent mode, this folder contains -the host files for the YottaDB database. They are mapped for use by YottaDB within the -Container. You should not change or move this folder or its contents, but you should back them -up regularly. +#### Inside www/pt-wc-q/js -You'll also see a folder named *iris-aws*. This contains versions of key files which -are used if you are running on IRIS +- utils - Helper functions and classes +- researching - Examples and samples of the component building processes +- pages - static pages mgWebComponents object + +#### File naming rules +`[page name]-page.js ` File with custom mgWebComponents page structure +`[page name]_page_state.js ` File with schema for CRUD page builder (see adminui/components/adminui-crud.js to understand how building is happens) +`[page name]_modal.js ` File that is uses adminui-modal.js from adminui component section -# Developing REST APIs -[Click here](./REST.md) to learn how to create REST APIs on your QEWD system +### About core framework +[Click Here](QEWD.md) to learn about QEWD -# Developing Interactive Applications +### Developing REST APIs -[Click here](./INTERACTIVE.md) to learn how to create interactive applications, the -back-end of which will run on your QEWD system +[Click here](./REST.md) to learn how to create REST APIs on your QEWD system + +### Developing Interactive Applications +[Click here](./INTERACTIVE.md) to learn how to create interactive applications, the +back-end of which will run on your QEWD system for got better understanding how project was builded. ## License @@ -145,3 +126,4 @@ back-end of which will run on your QEWD system WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + From 78f517cf46610d2cb377c753be8db7030c5bdeb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B8=CC=86=20=D0=AE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Thu, 24 Sep 2020 17:56:39 +0300 Subject: [PATCH 2/3] Working under docs --- .../ptwq/assembly/ptwq-calendar-assembly.js | 10 ++++++ .../ptwq/assembly/ptwq-chart-assembly.js | 35 +++++++++++-------- .../ptwq/assembly/ptwq-summary-assembly.js | 10 ++++-- www/components/ptwq/components/ptwq-jitsu.js | 4 ++- www/components/ptwq/components/ptwq-root.js | 28 ++++++++++++++- 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/www/components/ptwq/assembly/ptwq-calendar-assembly.js b/www/components/ptwq/assembly/ptwq-calendar-assembly.js index 99a8aa9..3e29490 100644 --- a/www/components/ptwq/assembly/ptwq-calendar-assembly.js +++ b/www/components/ptwq/assembly/ptwq-calendar-assembly.js @@ -1,3 +1,12 @@ +/** + * Assembly function for page with calendar data + * This assembly uses component fullcalendar from www/components/fullcalendar/components/fullcalendar-root.js + * @see fullcalendar.js library (https://fullcalendar.io) for figure out more options and + * @param QEWD required - Main object from QEWD framework + * @param state default crud options (@see www/pt-wc-q/js/events_page_state.js) + * @returns + * + */ export function ptwq_calendar_assembly(QEWD,state){ state = state || {}; @@ -357,6 +366,7 @@ export function ptwq_calendar_assembly(QEWD,state){ } ] }; + let calendarObj; let getFullCalendarData = async function(_this, context){ diff --git a/www/components/ptwq/assembly/ptwq-chart-assembly.js b/www/components/ptwq/assembly/ptwq-chart-assembly.js index f44a86a..7ec4ced 100644 --- a/www/components/ptwq/assembly/ptwq-chart-assembly.js +++ b/www/components/ptwq/assembly/ptwq-chart-assembly.js @@ -1,3 +1,10 @@ +/** + * Assembly with chart support + * Uses chart.js (https://www.chartjs.org) lib and chart component as swap targets + * @param QEWD required - Main object from QEWD framework + * @param state default crud options (@see www/pt-wc-q/js/events_page_state.js) + * @returns {{component: {assemblyName: *, children: [{componentName: string, state: {name: string}}, {componentName: string, state: {name: string, currentPage: *}}, {componentName: string, state: {title: *}}, {children: [{children: [{children: [{componentName: string, state: {disableButton: *, title_colour: *, icon: *, tooltip, buttonColour: *, title: *}, hooks: [string]}], componentName: string}, {children: [{componentName: string, state: {name: *}, hooks: [string]}], componentName: string, state: {name: string}}, {children: [{componentName: string, state: {colour, text, cls: string}, hooks: [string]}], componentName: string, state: {hidden: boolean}}], componentName: string, state: {hide: boolean, name: string}, hooks: [string]}, {children: [{children: [{children: [{componentName: string, state: {title_colour: *, name: string, icon: string, tooltip: *, buttonColour: *, title: string, hideButton: boolean}, hooks: [string]}, {componentName: string, state: {title_colour: *, name: string, icon: string, tooltip: *, buttonColour: *, title: string, hideButton: boolean}, hooks: [string]}, {componentName: string, state: {title_colour: *, icon: *, tooltip: *, buttonColour: *, title: string, hideButton: *}, hooks: [string]}], componentName: string, state: {title_colour: *, title: *}}], componentName: string}, {children: [{componentName: string, state: {name: *}, hooks: [string]}], componentName: string}], componentName: string, state: {name: string}, hooks: [string]}, {children: [{children: [{children: [{componentName: string, state: {title_colour: *, name: string, icon: string, tooltip: *, buttonColour: *, title: string, hideButton: boolean}, hooks: [string]}, {componentName: string, state: {title_colour: *, name: string, icon: string, tooltip: *, buttonColour: *, title: string, hideButton: boolean}, hooks: [string]}, {componentName: string, state: {title_colour: *, icon: *, tooltip: *, buttonColour: *, title: string, hideButton: *}, hooks: [string]}], componentName: string, state: {title_colour: *, title: *}}], componentName: string}, {children: [{name: string, componentName: string, hooks: [string]}], componentName: string}], componentName: string, state: {name: string}, hooks: [string]}], componentName: string}], componentName: string, state: {name: *}}, hooks: {"adminui-chart": {getChartData: hooks.adminui-chart.getChartData}, "adminui-form": {addFormFields: hooks.adminui-form.addFormFields}, "adminui-content-card": {detailsHook: hooks.adminui-content-card.detailsHook, chartBlockHook: hooks.adminui-content-card.chartBlockHook, summaryHook: hooks.adminui-content-card.summaryHook}, "adminui-content-card-button-title": {updateRecord: hooks.adminui-content-card-button-title.updateRecord}, "adminui-form-select-multiple": {displayOptions: hooks.adminui-form-select-multiple.displayOptions}, "ptwq-content-page": {loadModal: hooks.ptwq-content-page.loadModal}, "adminui-form-select": {displayOptions: hooks.adminui-form-select.displayOptions}, "adminui-datatables": {retrieveRecordSummary: (function(): Promise)}, "adminui-button": {showVitals: hooks.adminui-button.showVitals, getDetail: hooks.adminui-button.getDetail, save: hooks.adminui-button.save, showChart: hooks.adminui-button.showChart, delete: hooks.adminui-button.delete, createNewRecord: hooks.adminui-button.createNewRecord, confirmDelete: hooks.adminui-button.confirmDelete, fullScreen: hooks.adminui-button.fullScreen}}}} + */ export function ptwq_chart_assembly(QEWD, state) { state = state || {}; @@ -41,20 +48,18 @@ export function ptwq_chart_assembly(QEWD, state) { } + /** + * Callback async function that is refresh data by action happening - create, update, delete + * @param id + * @param _this + * @returns {Promise} + */ let getDetailsActions = async function(id, _this) { let card = _this.getComponentByName('adminui-content-card', state.name + '-details-card'); let form = _this.getComponentByName('adminui-form', state.name); form.recordId = id; - /* - QEWD.send({ - type: state.summary.qewd.getDetail, - params: { - id: id - } - }, function(responseObj) { - */ let responseObj = await QEWD.reply({ type: state.summary.qewd.getDetail, params: { @@ -108,9 +113,14 @@ export function ptwq_chart_assembly(QEWD, state) { } } } - //}); }; + /** + * Function that is prepare data to place inside chart.js + * @param context object with global user options by repository pattern @see QEWD.context + * @returns {Promise} + * TODO: Move process of prepare patient lifetime health state out of assembly function + */ let chartConfigGenerator = async function(context){ return new Promise((resolve, reject)=> { QEWD.reply({ @@ -218,6 +228,7 @@ export function ptwq_chart_assembly(QEWD, state) { }); }); } + let component = { componentName: 'ptwq-content-page', assemblyName: state.assemblyName, @@ -687,12 +698,6 @@ export function ptwq_chart_assembly(QEWD, state) { } }, function (responseObj) { - /*let responseObj = await QEWD.reply({ - type: state.summary.qewd.getSummary, - params: { - properties: state.summary.data_properties - } - });*/ if (!responseObj.message.error) { table.data = {}; let data = []; diff --git a/www/components/ptwq/assembly/ptwq-summary-assembly.js b/www/components/ptwq/assembly/ptwq-summary-assembly.js index 52cf39a..54e2b2e 100644 --- a/www/components/ptwq/assembly/ptwq-summary-assembly.js +++ b/www/components/ptwq/assembly/ptwq-summary-assembly.js @@ -1,3 +1,9 @@ +/** + * Sub-assembly function that is prepare card-object for dashboard based on global State object data. + * @param state CRUD object definition. + * @see www/pt-wc-q/js/events_page_state.js to got detailed information about state information contains + * @returns {{componentName: string, state: {patientIdDepends: boolean, data_properties: *, name: string, summaryLoader: *, icon: string, page: *, title: *}, hooks: [string]}} + */ function build_summary_card(state) { if(typeof state.patientIdDepends === 'undefined'){ @@ -25,7 +31,7 @@ function build_summary_card(state) { } /*** - * + * Assembly function that is used for prepare dashboard page schema * @param QEWD * @param state_array array of default CRUD state (adminui_crud) what need to be shown at crud * @returns {{component: {assemblyName: *, children: [{componentName: string, state: {title: *}}, {children: [], componentName: string}], componentName: string, state: {name: *}, hooks: [string]}, hooks: {}}} @@ -85,7 +91,7 @@ export function summary_assembly(QEWD, state_array) { }, 'ptwq-summary-element':{ - 'summaryAssemblyHook': async function () { + summaryAssemblyHook: async function () { let sE = this; return new Promise(((resolve, reject) => { diff --git a/www/components/ptwq/components/ptwq-jitsu.js b/www/components/ptwq/components/ptwq-jitsu.js index 166d6b1..9d2a15c 100644 --- a/www/components/ptwq/components/ptwq-jitsu.js +++ b/www/components/ptwq/components/ptwq-jitsu.js @@ -1,4 +1,6 @@ - +/** + * Component that is integrated Jitsu Meet ( https://jitsi.org ) with QEWD + */ export function load() { let componentName = 'ptwq-jitsu'; diff --git a/www/components/ptwq/components/ptwq-root.js b/www/components/ptwq/components/ptwq-root.js index 08b1161..7c56d03 100644 --- a/www/components/ptwq/components/ptwq-root.js +++ b/www/components/ptwq/components/ptwq-root.js @@ -1,4 +1,4 @@ -/* +/** ---------------------------------------------------------------------------- | admin-ui: SB2-Admin UI Theme WebComponents Library | @@ -26,6 +26,26 @@ 17 April 2020 +_________ + +More about ptwq-root + +This component used as main page schema with four areas of content placement +Basically it's works as adminui-root (www/components/adminui/components/adminui-root.js) with special additionals +such as: + +- Middleware processing by simple callbacks +- More areas that you can use + +## Areas of content: + + - rootElement: main DIV element + - sidebarTarget: left sidebar area (menu is placed here) + - topbarTarget: top area where is search, notification and logout button placed. + - contentTarget: area where is main content placed including CRUD containers and datatables. + - footerTarget: not used for now, copyright area where you can place anything. + - loader: full size and overflow element that is used for show loader. + */ export function load() { @@ -111,7 +131,13 @@ export function load() { page.setState({show: true}); } + /** + * Core and main routing function for swap pages by + * navbar item click or by other reasons + * @param pageName route to switch + */ switchToPage(pageName) { + if(this.middlewareArray['WHOLE_WEBSITE']){ for (const [key, callback] of Object.entries(this.middlewareArray['WHOLE_WEBSITE'])) { From f2d78a7d275a729f9cebbf23726af64e78e5ff92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B8=CC=86=20=D0=AE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 28 Sep 2020 21:58:08 +0300 Subject: [PATCH 3/3] Add Readme Add comments Remove unused code --- README.md | 8 + docs/components.md | 465 ++++++++++++++++++++++ docs/how-to.md | 297 ++++++++++++++ docs/installation.md | 0 docs/ui-kit.md | 18 + qewd-apps/pt-wc-q/getMedications/index.js | 244 ------------ 6 files changed, 788 insertions(+), 244 deletions(-) create mode 100644 docs/components.md create mode 100644 docs/how-to.md create mode 100644 docs/installation.md create mode 100644 docs/ui-kit.md diff --git a/README.md b/README.md index df80bf9..485c6e1 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,14 @@ For any related code/information/discussion/questions/issues please visit this r ======= # Open Source Telehealth Solution +## Global Table of Contents + +- [Quick Readme](/README.md) +- [Installation Guide](/docs/installation.md) +- [PT-WC-Q Components](/docs/components.md) +- [How To / Recipe](/docs/how-to.md) +- [QEWD Main Documentation](/QEWD.md) +- [REST scope](/REST.md) Building on open source technologies; diff --git a/docs/components.md b/docs/components.md new file mode 100644 index 0000000..62e8ffa --- /dev/null +++ b/docs/components.md @@ -0,0 +1,465 @@ +#Components Guide + +This document contains explanation what components is included inside PT-WC-Q +build + +All Components placed in `www/components/` folder + +## Global Table of Contents + +- [Quick Readme](/README.md) +- [Installation Guide](/docs/installation.md) +- [PT-WC-Q Components](/docs/components.md) +- [How To / Recipe](/docs/how-to.md) +- [CRUD Quickstart](/docs/crud-structure.md) +- [QEWD Main Documentation](/QEWD.md) +- [REST scope](/REST.md) + +## Main Components + +- [Conference](#conference-component) +- [DataTable](#data-table-component) +- [Calendar](#calendar-component) +- [Chart component](#chart-component) + +### Layout Components + +#### Root Template component + +Placed in `www/components/ptwq/components/ptwq-root.js` + +Component is used for provide two column HTML structure based on adminui-root with important changes. + +First one change is page switching main logic that is supports middlewares. Middleware is callback that check +user page permissions. More details of middleware can be readed at comments of middleware function` www/components/ptwq/components/ptwq-root.js line 291` + +___ + +#### Data table Component + +Placed in `www/components/ptwq/components/ptwq-datatables.js` + +Data table component uses js table component from https://datatables.net + +This is main CRUD component that uses for manage records from YottaDB backend + +#### How to init DataTable? + +Example schema for initialization crud component are written above. +This schema used assembly (route) name - contacts with store data in 'contacts' QEWD route. + + let contactsPageState = { + assemblyName: 'contacts', + name: 'contacts', + title: 'Contacts', + icon: 'phone', + summary: { + title: 'Contacts:', + titleColour: 'info', + btnIcon: 'user-plus', + btnColour: 'success', + btnTooltip: 'Add a New Contact', + headers: ['Name', 'Relationship', 'NextOfKin'], + data_properties: ['name', 'relationship', 'nextOfKin'], + qewd: { + getSummary: 'getContacts', + getDetail: 'getContactInfo', + delete: 'deleteContact' + }, + rowBtnIcon: 'user-edit', + rowBtnColour: 'info', + enableDelete: true, + deleteConfirmDisplayColumn: 0 + }, + detail: { + cardWidth: '500px', + newRecordTitle: 'Enter New Contact', + titleColour: 'info', + btnIcon: 'user-cog', + btnColour: 'success', + btnTooltip: 'Edit Contact Details', + title_data_property: 'name', + fields: [ + { + name: 'name', + data_property: 'name', + label: 'Name', + type: 'text', + labelWidth: 4 + }, + { + name: 'email', + data_property: 'email', + label: 'Email', + type: 'text', + labelWidth: 4 + }, + { + name: 'phone', + data_property: 'phone', + label: 'Telephone', + type: 'text', + labelWidth: 4 + }, + { + name: 'relationship', + data_property: 'relationship', + label: 'Relationship', + type: 'select', + labelWidth: 4, + options: [ + {text: 'Brother', value: 'Brother'}, + {text: 'Sister', value: 'Sister'}, + {text: 'Not Specified', value: 'N/A'} + ] + }, + { + name: 'relationship_type', + data_property: 'relationship_type', + label: 'Relationship Type', + type: 'select', + labelWidth: 4, + options: [ + {text: 'Family', value: 'f'}, + {text: 'Professional', value: 'p'}, + {text: 'Not Specified', value: 'x'} + ] + }, + { + name: 'nextOfKin', + data_property: 'nextOfKin', + label: 'Next Of Kin', + type: 'radios', + radios: [ + {text: 'Yes', value: true}, + {text: 'No', value: false} + ] + } , + { + name: 'contact_info', + data_property: 'contact_info', + label: 'Contact Info', + type: 'textarea', + labelWidth: 4, + height: 2 + }, + + { + name: 'note', + data_property: 'note', + label: 'Note', + type: 'textarea', + labelWidth: 4, + height: 2 + }, + { + name: 'author', + data_property: 'author', + label: 'Author', + type: 'text', + labelWidth: 4 + }, + ] + }, + update: { + btnText: 'Save', + btnColour: 'warning', + qewd: { + save: 'updateContact' + } + } + }; + + export {contactsPageState}; + +After this schema is exported you need to call and import function `crud_assembly` from QEWD and use them. + +More information and samples of usage DataTable component you can check out in [HowTo](./how-to.md) + +____ + +### Calendar Component + +Sources placed in `www/components/fullcalendar/components/fullcalendar-root.js` + +Assembly for Calendar CRUD placed in `www/components/ptwq/assembly/ptwq-calendar-assembly.js` + +Calendar component used for pull date time data in calendar-look page with supporting switch between regular datatable & calendar view. +As supportive component we are using [FullCalendar](https://fullcalendar.io) + +#### How To init Calendar Component? + +For initiate full calendar render just add this lines in page JSON Schema + + { + componentName: 'fullcalendar-root', + state: { + height: '300px' + }, + hooks: ['getFullcalendar'] + } + +#### Hook example + +This sample code demonstrates process of sending data inside of FullCalendar.io PT-WC-Q component with async waiting +of background rendering results that is presented in QEWD + + 'fullcalendar-root': { + getFullcalendar: function () { + let _this = this; + let context = this.context; + + getFullCalendarData(_this, context).then((events)=>{ + _this.renderFullcalendar(events).then((res)=>{ + let calendar = _this.getComponentByName('adminui-content-card', state.name + '-events-card') + calendar.classList.add('d-none'); + _this.addEventHandler(function(info){ + console.log(info); + //let id = info.event.id; + getDetailsActions.call(_this, info.event.id, _this); + + console.log('event Clicked'); + },'eventClick'); + }); + }) + } + }, + +____ + + +### Chart Component + +Sources placed in `www/components/adminui/components/adminui-chart.js` + +Assembly for CRUD-based pages with Chart.js pages placed in` www/components/ptwq/assembly/ptwq-chart-assembly.js ` + +This component are included in `adminui` components list from mgWebComponents sample and uses Chart.js as main library + +Base JS Component: https://www.chartjs.org + +#### How use this component? + +For initiate chart.js page render just add this lines in page JSON Schema + + { + componentName: 'adminui-chart', + name: state.name + '-chart', + hooks: ['getChartData'] + } + +##### Hook sample + + getChartData: function() { + let _this = this; + let chartData = store.get('chartX'); + + let config = { + type: 'doughnut', + data: { + //labels: ["Direct", "Referral", "Social"], + labels: chartData.labels, + datasets: [{ + //data: [55, 30, 15], + data: chartData.counts, + backgroundColor: ['#4e73df', '#1cc88a', '#36b9cc'], + hoverBackgroundColor: ['#2e59d9', '#17a673', '#2c9faf'], + hoverBorderColor: "rgba(234, 236, 244, 1)", + }], + }, + options: { + maintainAspectRatio: false, + tooltips: { + backgroundColor: "rgb(255,255,255)", + bodyFontColor: "#858796", + borderColor: '#dddfeb', + borderWidth: 1, + xPadding: 15, + yPadding: 15, + displayColors: false, + caretPadding: 10, + }, + legend: { + display: false + }, + cutoutPercentage: 80, + + onClick: (evt, item) => { // this is standard syntax for ChartJS events + console.log("evt is " + evt + " & item is: " + item ); // both of these are objects + + // as difficult to stringify item (circular object) found this replacer function which helps via cache + // https://stackoverflow.com/questions/11616630/how-can-i-print-a-circular-structure-in-a-json-like-format + var cache = []; + JSON.stringify(item, (key, value) => { + if (typeof value === 'object' && value !== null) { + // Duplicate reference found, discard key + if (cache.includes(value)) return; + + // Store value in our collection + cache.push(value); + } + return null; + //return value; + }); + console.log(cache); // we can inspect the cached object from here + cache = null; // + + // we have used the cache view to inspect the chart object to log these ... + console.log("Chart Type = " + item[0]._chart.config.type); + let ix = item[0]._index; + console.log("ChartIndex = " + ix); + //console.log("Labels = " + item[0]._chart.config.data.labels); + console.log("Label = " + item[0]._chart.config.data.labels[ix]); + console.log("Data = " + item[0]._chart.config.data.datasets[0].data[ix]); + let div = _this.getComponentByName('adminui-div', 'chart-detail'); + //div.setState({text: 'added by event - from click from ' + cell.data()}); + div.setState({text: 'Label :' + item[0]._chart.config.data.labels[ix] + " & Data :" + item[0]._chart.config.data.datasets[0].data[ix]}); + + + } + }, + }; + + this.draw(config); + } + +____ + +### Conference Component + +Placed in `www/components/ptwq/components/ptwq-jitsu.js` + +This component uses Jitsu library as basics and allow includes conference webRTC app inside of custom page with +custom parameters. + +Main library are placed in: https://jitsi.org + +#### How to init Jitsu Component + + { + componentName: 'ptwq-jitsu', + state: { + height: '300px' + }, + hooks: ['getJitsu'] + } + +##### Hook Sample + + 'ptwq-jitsu': { + getJitsu: function() { + let user = this.context.user; + let event = this.context.conference; + + console.log(event); + this.renderJitsuMeet({}).then((res)=>{ + console.group(); + console.log('console back'); + console.log(event) + console.groupEnd(); + let randomID; + if(!event) { + randomID = + Math.random() + .toString(36) + .substring(2, 8) + + "-" + + Math.random() + .toString(36) + .substring(2, 8); + }else{ + randomID = btoa(event.id + event.date + event.comments + event.service) + } + console.log("randomID =" + randomID); + let block = document.querySelector("#jitsu-meet-window"); + block.innerHTML = ''; + const domain = "meet.jit.si"; + const options = { + roomName: "OS-Clinic-Care-SessionID-" + randomID, + width: 500, + height: 500, + parentNode: block, + interfaceConfigOverwrite: { + HIDE_INVITE_MORE_HEADER: true, + TOOLBAR_BUTTONS: [ + "microphone", + "camera", + "fodeviceselection", + "hangup", + "profile", + "invite", + "chat", + "security", + "help" + ] + }, + //interfaceConfigOverwrite: { filmStripOnly: true }, + userInfo: { + email: "email@jitsiexamplemail.com", + displayName: "Dr John Doe" + } + }; + const api = new JitsiMeetExternalAPI(domain, options); + api.executeCommand('displayName', user.name); + + api.executeCommand("subject", "Private Telehealth Session"); + + //api.executeCommand("password", "ABC234"); + //api.executeCommand("toggleFilmStrip"); + + console.log(api.getIFrame()); + + api.addEventListener("participantJoined", function(event) { + console.log("id " + id + "nameX " + displayName); + }); + + var pass = "ABC2"; + api.addEventListener("participantRoleChanged", function(event) { + // when host has joined the video conference + if (event.role == "moderator") { + console.log("this person is a Mod"); + //api.executeCommand("password", pass); + } else { + setTimeout(() => { + // why timeout: I got some trouble calling event listeners without setting a timeout :) + + // when local user is trying to enter in a locked room + api.addEventListener("passwordRequired", () => { + // api.executeCommand("password", pass); + }); + + // when local user has joined the video conference + api.addEventListener("videoConferenceJoined", response => { + setTimeout(function() { + // api.executeCommand("password", pass); + }, 300); + }); + }, 10); + } + }); + $("#jitsu-meet-configure").click(function() { + //$("p").slideToggle(); + api.executeCommand("toggleFilmStrip"); + console.log( + "Meeting Link is https://" + domain + "/" + options.roomName + ); + console.log( + Math.random() + .toString(36) + .substring(2, 8) + + "-" + + Math.random() + .toString(36) + .substring(2, 8) + ); + }); + + $("#jitsu-meet-start").click(function() { + //$("p").slideToggle(); + // console.log("Setting Password"); + // api.executeCommand("password", "BBC2"); + }); + }); + } + } + diff --git a/docs/how-to.md b/docs/how-to.md new file mode 100644 index 0000000..d94bd74 --- /dev/null +++ b/docs/how-to.md @@ -0,0 +1,297 @@ +# How To Create New Entity Page inside PT-WC-Q in few steps + +This guide demonstrates how CRUD assembly functions is working and how new entity store can be implemented using store +of "medications" that user must use as sample. + +Our task of this guide is make "Medications" page that is supports dividing by patient_id by using `ptwc-datatable` component and `crud_assembly` function. + +## Our steps are + +- [Create store in DB](#create-store-in-database) +- [Define schema of page settings](#definition-schema-of-page-settings) +- [Register page in entity point](#register-page-in-main-entity-point-appjs) + +See also... + +## Global Table of Contents + +- [Quick Readme](/README.md) +- [Installation Guide](/docs/installation.md) +- [PT-WC-Q Components](/docs/components.md) +- [How To / Recipe](/docs/how-to.md) +- [QEWD Main Documentation](/QEWD.md) +- [REST scope](/REST.md) + + +## Create Store in Database + +First part of any CRUD development processes is populate CRUD methods on API side. + +All methods of QEWD framework API are placed in qewd-apps/[app name]. Until our app named PT-WC-Q all methods must be defined in All methods of QEWD framework API are placed in qewd-apps/[app name]. +Until our app named PT-WC-Q all methods must be defined in `qewd-apps/pt-wc-q` + +What crud methods are we needed? + +- (C)reate +- (R)ead +- (U)pdate +- (D)elete + +Let's see each of them. + +#### Create / Update Method + +> **IMPORTANT NOTE!** Difference between update and create only in one thing: when we create new one entity we are leave 'id' field are empty. + +For create method API for populate our data just make folder named update%EntityName% and place index.js file inside of them with contents: + + module.exports = function(messageObj, session, send, finished) { + + if (!session.authenticated) { + return finished({error: 'Unauthenticated'}); + } + + let error = ''; + let delim = ''; + for (let name in messageObj.params) { + if (messageObj.params[name] === '') { + error = error + delim + name + ': Missing value'; + delim = '; '; + } + } + if (error !== '') { + return finished({error: error}); + } + + let id = messageObj.params.id; + if (!id || id === '') { + return finished({error: 'Missing or empty user id'}); + } + + let doc = this.db.use('demoMedication'); + + if (id === 'new-record') { + id = doc.$('id_counter').increment(); + messageObj.params.id = id; + } + doc.$(['by_id', id]).setDocument(messageObj.params); + + finished({ok: true}); + + + }; + +You can compare results in `qewd-apps/pt-wc-q/updateMedication` + +___ + +#### Read Method + +To create method that is load data from the database you need to pass two parameters: id and that field is needed from frontend to backend. +Or do not pass anything. Main idea that we have meaning using NoSQL database as data storage. That is allow us to make pretty simple read route. + +For make method of API for read our data just make folder named get%EntityName% and place index.js file inside of them. + +Example of code for reading data of medications: + + module.exports = function(messageObj, session, send, finished) { + + if (!session.authenticated) { + return finished({error: 'unauthenticated'}); + } + + let doc = this.db.use('demoMedications'); + + + let userDoc = doc.$('by_id'); + let results = []; + let properties = messageObj.params.properties; + userDoc.forEachChild(function(ix, node) { + let result = {}; + result.id = node.$('id').value; + properties.forEach(function(property) { + if (property !== 'id') { + result[property] = node.$(property).value; + } + }); + results.push(result); + }); + + finished({summary: results}); + }; + + +You can compare results in `qewd-apps/pt-wc-q/getMedications` + +____ + +#### Delete action + +For create method API for populate our data just make folder named delete%EntityName% and place index.js file inside of them with contents: + + module.exports = function(messageObj, session, send, finished) { + + if (!session.authenticated) { + return finished({error: 'Unauthenticated'}); + } + + let id = messageObj.params.id; + if (!id || id === '') { + return finished({error: 'Missing or empty user id'}); + } + + this.db.use('demoMedications', 'by_id', id).delete(); + + finished({ok: true}); + + }; + + +... and that all! Our API Is ready for integration! + +## Definition schema of page settings + +For the purpose of placing simplicity logic of CRUD pages definition has been developed JSON schema of the CRUD page populations. + +And this how it looks like: + + let medicationsPageState = { + // System name + assemblyName: 'medications', + // Name of route in route system + name: 'medications', + // Title that will be used in HTML heading + title: 'Medications', + // Icon for Summary View, Menu and page + icon: 'prescription-bottle-alt', + summary: { + title: 'Current Meds', + titleColour: 'info', + btnIcon: 'user-plus', + btnColour: 'success', + btnTooltip: 'Add a New Med', + headers: ['Name', 'Dose'], + data_properties: ['name', 'dose'], + qewd: { + // Name of folder for C(R)UD all data in short list + getSummary: 'getMedications', + // Name of folder for C(R)UD all data in long list + getDetail: 'getMedicationInfo', + // Name of folder for CRU(D) all data in any places + delete: 'deleteMedication' + }, + rowBtnIcon: 'user-edit', + rowBtnColour: 'info', + enableDelete: true, + deleteConfirmDisplayColumn: 0 + }, + detail: { + cardWidth: '500px', + newRecordTitle: 'Enter New User', + titleColour: 'info', + btnIcon: 'user-cog', + btnColour: 'success', + btnTooltip: 'Edit User Details', + title_data_property: 'name', + fields: [ + { + name: 'name', + data_property: 'name', + label: 'Name', + type: 'text', + labelWidth: 4 + }, + { + name: 'route', + data_property: 'route', + label: 'Route', + type: 'text', + labelWidth: 4 + }, + { + name: 'dose', + data_property: 'dose', + label: 'Dose', + type: 'text', + labelWidth: 4 + }, + { + name: 'timing', + data_property: 'timing', + label: 'Timing', + type: 'text', + labelWidth: 4 + }, + + { + name: 'description', + data_property: 'description', + label: 'Description', + type: 'textarea', + labelWidth: 4, + height: 2 + }, + { + name: 'date_start', + data_property: 'date_start', + label: 'Start Date', + type: 'date', + labelWidth: 4 + }, + { + name: 'author', + data_property: 'author', + label: 'Author', + type: 'text', + labelWidth: 4 + }, + { + name: 'date_of_entry', + data_property: 'date_of_entry', + label: 'Date of Entry', + type: 'date', + labelWidth: 4 + }, + + ] + }, + update: { + btnText: 'Save', + btnColour: 'warning', + qewd: { + // Name of folder for CR(U)D medication + save: 'updateMedication' + } + } + }; + + export {medicationsPageState}; + +This schema has define columns that will be used for output in heading list and in detail view for the `ptwq-datatable` component and also defines form for edit contents. + +Whole files with schema in PT-WC-Q app must be placed in `www/pt-wc-q/js/medications_page_state.js` + +After all files are placed only register this page with components are left. + +## Register page in main entity point (app.js) + +Let's see how co include our medications schema file (`www/pt-wc-q/js/medications_page_state.js`) + +#### Include schema file + +At start of entity point file (app.js) place this one lines for load JSON schema as object + + import {medicationsPageState} from './medications_page_state.js'; + +#### Register path of the contents + +Next thing is register path of the schema. + +Inside of DOMContentLoaded event place this line + + webComponents.addComponent('medications', crud_assembly(QEWD, medicationsPageState)); + +Where crud_assembly is assembly that convert our CRUD schema to JSON global page schema + + +Congratulations! Now you can store patient medications inside PT-WC-Q website diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/ui-kit.md b/docs/ui-kit.md new file mode 100644 index 0000000..97e8215 --- /dev/null +++ b/docs/ui-kit.md @@ -0,0 +1,18 @@ +#### Root Template component + +Source Code: + +Description: + +How to use: + +___ + +## Global Table of Contents + +- [Quick Readme](/README.md) +- [Installation Guide](/docs/installation.md) +- [PT-WC-Q Components](/docs/components.md) +- [How To / Recipe](/docs/how-to.md) +- [QEWD Main Documentation](/QEWD.md) +- [REST scope](/REST.md) diff --git a/qewd-apps/pt-wc-q/getMedications/index.js b/qewd-apps/pt-wc-q/getMedications/index.js index 23d55d3..e161f66 100644 --- a/qewd-apps/pt-wc-q/getMedications/index.js +++ b/qewd-apps/pt-wc-q/getMedications/index.js @@ -5,250 +5,6 @@ module.exports = function(messageObj, session, send, finished) { } let doc = this.db.use('demoMedications'); - if (!doc.exists) { - -/* -let users = [ - { - "id": 1, - "name": "Leanne Graham", - "username": "Bret", - "email": "Sincere@april.biz", - "address": { - "street": "Kulas Light", - "suite": "Apt. 556", - "city": "Gwenborough", - "zipcode": "92998-3874", - "geo": { - "lat": "-37.3159", - "lng": "81.1496" - } - }, - "phone": "1-770-736-8031 x56442", - "website": "hildegard.org", - "company": { - "name": "Romaguera-Crona", - "catchPhrase": "Multi-layered client-server neural-net", - "bs": "harness real-time e-markets" - } - }, - { - "id": 2, - "name": "Ervin Howell", - "username": "Antonette", - "email": "Shanna@melissa.tv", - "address": { - "street": "Victor Plains", - "suite": "Suite 879", - "city": "Wisokyburgh", - "zipcode": "90566-7771", - "geo": { - "lat": "-43.9509", - "lng": "-34.4618" - } - }, - "phone": "010-692-6593 x09125", - "website": "anastasia.net", - "company": { - "name": "Deckow-Crist", - "catchPhrase": "Proactive didactic contingency", - "bs": "synergize scalable supply-chains" - } - }, - { - "id": 3, - "name": "Clementine Bauch", - "username": "Samantha", - "email": "Nathan@yesenia.net", - "address": { - "street": "Douglas Extension", - "suite": "Suite 847", - "city": "McKenziehaven", - "zipcode": "59590-4157", - "geo": { - "lat": "-68.6102", - "lng": "-47.0653" - } - }, - "phone": "1-463-123-4447", - "website": "ramiro.info", - "company": { - "name": "Romaguera-Jacobson", - "catchPhrase": "Face to face bifurcated interface", - "bs": "e-enable strategic applications" - } - }, - { - "id": 4, - "name": "Patricia Lebsack", - "username": "Karianne", - "email": "Julianne.OConner@kory.org", - "address": { - "street": "Hoeger Mall", - "suite": "Apt. 692", - "city": "South Elvis", - "zipcode": "53919-4257", - "geo": { - "lat": "29.4572", - "lng": "-164.2990" - } - }, - "phone": "493-170-9623 x156", - "website": "kale.biz", - "company": { - "name": "Robel-Corkery", - "catchPhrase": "Multi-tiered zero tolerance productivity", - "bs": "transition cutting-edge web services" - } - }, - { - "id": 5, - "name": "Chelsey Dietrich", - "username": "Kamren", - "email": "Lucio_Hettinger@annie.ca", - "address": { - "street": "Skiles Walks", - "suite": "Suite 351", - "city": "Roscoeview", - "zipcode": "33263", - "geo": { - "lat": "-31.8129", - "lng": "62.5342" - } - }, - "phone": "(254)954-1289", - "website": "demarco.info", - "company": { - "name": "Keebler LLC", - "catchPhrase": "User-centric fault-tolerant solution", - "bs": "revolutionize end-to-end systems" - } - }, - { - "id": 6, - "name": "Mrs. Dennis Schulist", - "username": "Leopoldo_Corkery", - "email": "Karley_Dach@jasper.info", - "address": { - "street": "Norberto Crossing", - "suite": "Apt. 950", - "city": "South Christy", - "zipcode": "23505-1337", - "geo": { - "lat": "-71.4197", - "lng": "71.7478" - } - }, - "phone": "1-477-935-8478 x6430", - "website": "ola.org", - "company": { - "name": "Considine-Lockman", - "catchPhrase": "Synchronised bottom-line interface", - "bs": "e-enable innovative applications" - } - }, - { - "id": 7, - "name": "Kurtis Weissnat", - "username": "Elwyn.Skiles", - "email": "Telly.Hoeger@billy.biz", - "address": { - "street": "Rex Trail", - "suite": "Suite 280", - "city": "Howemouth", - "zipcode": "58804-1099", - "geo": { - "lat": "24.8918", - "lng": "21.8984" - } - }, - "phone": "210.067.6132", - "website": "elvis.io", - "company": { - "name": "Johns Group", - "catchPhrase": "Configurable multimedia task-force", - "bs": "generate enterprise e-tailers" - } - }, - { - "id": 8, - "name": "Nicholas Runolfsdottir V", - "username": "Maxime_Nienow", - "email": "Sherwood@rosamond.me", - "address": { - "street": "Ellsworth Summit", - "suite": "Suite 729", - "city": "Aliyaview", - "zipcode": "45169", - "geo": { - "lat": "-14.3990", - "lng": "-120.7677" - } - }, - "phone": "586.493.6943 x140", - "website": "jacynthe.com", - "company": { - "name": "Abernathy Group", - "catchPhrase": "Implemented secondary concept", - "bs": "e-enable extensible e-tailers" - } - }, - { - "id": 9, - "name": "Glenna Reichert", - "username": "Delphine", - "email": "Chaim_McDermott@dana.io", - "address": { - "street": "Dayna Park", - "suite": "Suite 449", - "city": "Bartholomebury", - "zipcode": "76495-3109", - "geo": { - "lat": "24.6463", - "lng": "-168.8889" - } - }, - "phone": "(775)976-6794 x41206", - "website": "conrad.com", - "company": { - "name": "Yost and Sons", - "catchPhrase": "Switchable contextually-based project", - "bs": "aggregate real-time technologies" - } - }, - { - "id": 10, - "name": "Clementina DuBuque", - "username": "Moriah.Stanton", - "email": "Rey.Padberg@karina.biz", - "address": { - "street": "Kattie Turnpike", - "suite": "Suite 198", - "city": "Lebsackbury", - "zipcode": "31428-2261", - "geo": { - "lat": "-38.2386", - "lng": "57.2232" - } - }, - "phone": "024-648-3804", - "website": "ambrose.net", - "company": { - "name": "Hoeger LLC", - "catchPhrase": "Centralized empowering task-force", - "bs": "target end-to-end models" - } - } -]; - - - let data = doc.$('by_id'); - users.forEach(function(user) { - data.$(user.id).setDocument(user); - doc.$('id_counter').value = user.id; - }); - */ - } let userDoc = doc.$('by_id');