diff --git a/.wappler/migrations/ERTDB/20241103201444_catchup.js b/.wappler/migrations/ERTDB/20241103201444_catchup.js new file mode 100644 index 0000000..6f659c9 --- /dev/null +++ b/.wappler/migrations/ERTDB/20241103201444_catchup.js @@ -0,0 +1,13 @@ + +exports.up = function (knex) { + return knex.schema + .renameTable('tblSection', 'tSection') + .renameTable('tSection', 'tSectionOld') + +}; + +exports.down = function (knex) { + return knex.schema + .renameTable('tSectionOld', 'tSection') + .renameTable('tSection', 'tblSection') +}; diff --git a/.wappler/targets/Development/app/modules/connections/DB.json b/.wappler/targets/Development/app/modules/connections/DB.json index ceb67ac..c40ddd0 100644 --- a/.wappler/targets/Development/app/modules/connections/DB.json +++ b/.wappler/targets/Development/app/modules/connections/DB.json @@ -7,6 +7,10 @@ "connection": { "filename": "/public/ERTSQlite.db" }, - "tz": "utc" - } + "tz": "utc", + "meta": {} + }, + "fileName": "DB.json", + "actionFilePath": "file:///Z:/temp/ERTFastFiller/app/modules/connections/DB.json", + "serverType": "node" } \ No newline at end of file diff --git a/.wappler/targets/Development/app/modules/connections/ERTDB.json b/.wappler/targets/Development/app/modules/connections/ERTDB.json new file mode 100644 index 0000000..ba0837b --- /dev/null +++ b/.wappler/targets/Development/app/modules/connections/ERTDB.json @@ -0,0 +1,13 @@ +{ + "name": "ERTDB", + "module": "dbconnector", + "action": "connect", + "options": { + "client": "sqlite3", + "connection": { + "filename": "/public/ERTSQlite.db" + }, + "tz": "utc" + }, + "fileName": "ERTDB.json" +} \ No newline at end of file diff --git a/.wappler/targets/Development/databases/DB.json b/.wappler/targets/Development/databases/DB.json index a60288a..5b56c6a 100644 --- a/.wappler/targets/Development/databases/DB.json +++ b/.wappler/targets/Development/databases/DB.json @@ -61,6 +61,52 @@ } } } + }, + "_tSections_old_20241031": { + "db": {} + }, + "_tSection_old_20241031": { + "db": {} + }, + "_tPoint_old_20241031": { + "db": {} + }, + "tPoint": { + "db": {} + }, + "tSection": { + "db": {} + }, + "tblSection": { + "db": {}, + "columns": { + "isSection": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "numSection": { + "db": { + "type": "text", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true + } + }, + "txtSection": { + "db": { + "type": "text", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true + } + } + } } }, "views": {} diff --git a/.wappler/targets/Development/databases/ERTDB.json b/.wappler/targets/Development/databases/ERTDB.json new file mode 100644 index 0000000..03eafe1 --- /dev/null +++ b/.wappler/targets/Development/databases/ERTDB.json @@ -0,0 +1,263 @@ +{ + "type": "sqlite3", + "connection": { + "filename": "/public/ERTSQlite.db" + }, + "direct": true, + "schema": { + "tables": { + "_da_old_20241029": { + "db": {}, + "columns": { + "ID": { + "db": { + "type": "integer", + "primary": true, + "unique": false, + "nullable": false + } + }, + "db_fullName": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "db_licenseNumber": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "db_stateIssue": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "db_employeeID": { + "db": { + "type": "integer", + "primary": false, + "unique": false, + "nullable": true + } + }, + "owner": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + } + } + }, + "da": { + "db": {}, + "columns": { + "ID": { + "db": { + "type": "increments", + "primary": true, + "unique": false, + "nullable": false + } + }, + "db_fullName": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "db_licenseNumber": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "db_stateIssue": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "db_employeeID": { + "db": { + "type": "integer", + "primary": false, + "unique": false, + "nullable": true + } + }, + "owner": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + } + } + }, + "_tSections_old_20241031": { + "db": {}, + "columns": { + "id": { + "db": { + "type": "increments", + "primary": true, + "unique": false, + "nullable": false + } + } + }, + "status": { + "deleted": true + } + }, + "_tSection_old_20241031": { + "db": {}, + "columns": { + "id": { + "db": { + "type": "increments", + "primary": true, + "unique": false, + "nullable": false + } + }, + "description": { + "db": { + "type": "string", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true + } + } + }, + "status": { + "deleted": true + } + }, + "_tPoint_old_20241031": { + "db": {}, + "columns": { + "id": { + "db": { + "type": "increments", + "primary": true, + "unique": false, + "nullable": false + } + }, + "fText": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + } + }, + "status": { + "deleted": true + } + }, + "tPoint": { + "db": {}, + "columns": { + "id": { + "db": { + "type": "increments", + "primary": true, + "unique": false, + "nullable": false + } + } + } + }, + "tSection": { + "db": {}, + "columns": { + "id": { + "db": { + "type": "increments", + "primary": true, + "unique": false, + "nullable": false + } + }, + "fText": { + "db": { + "type": "string", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true + } + } + }, + "db_edits": { + "name": "tSectionOld" + }, + "status": { + "modified": true + } + }, + "tblSection": { + "db": {}, + "columns": { + "isSection": { + "db": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true + } + }, + "numSection": { + "db": { + "type": "text", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true + } + }, + "txtSection": { + "db": { + "type": "text", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true + } + } + }, + "db_edits": { + "name": "tSection" + }, + "status": { + "modified": true, + "data_modified": true + }, + "db_changes": [] + } + }, + "views": {} + } +} diff --git a/ERTSQlite.db b/_DNU_ERTSQlite.db similarity index 55% rename from ERTSQlite.db rename to _DNU_ERTSQlite.db index 954eec7..880e476 100644 Binary files a/ERTSQlite.db and b/_DNU_ERTSQlite.db differ diff --git a/app/api/qSection.json b/app/api/qSection.json new file mode 100644 index 0000000..d569f56 --- /dev/null +++ b/app/api/qSection.json @@ -0,0 +1,97 @@ +{ + "meta": { + "options": { + "linkedFile": "/views/observationPage.ejs", + "linkedForm": "form1" + }, + "$_GET": [ + { + "type": "text", + "name": "sort" + }, + { + "type": "text", + "name": "dir" + } + ], + "$_POST": [ + { + "type": "text", + "fieldName": "text1", + "name": "text1" + } + ] + }, + "exec": { + "steps": { + "name": "query", + "module": "dbconnector", + "action": "select", + "options": { + "connection": "DB", + "sql": { + "type": "SELECT", + "distinct": false, + "columns": [ + { + "table": "tblSection", + "column": "*", + "field": "*" + } + ], + "table": { + "name": "tblSection" + }, + "joins": [], + "orders": [], + "params": [], + "query": "select * from `tblSection` where `tblSection`.`isSection` = ?", + "wheres": { + "condition": "AND", + "rules": [ + { + "id": "tblSection.isSection", + "field": "tblSection.isSection", + "type": "string", + "operator": "equal", + "value": "1", + "data": { + "table": "tblSection", + "column": "isSection", + "type": "text", + "columnObj": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true, + "name": "isSection" + } + }, + "operation": "=" + } + ], + "conditional": null, + "valid": true + } + } + }, + "output": true, + "meta": [ + { + "type": "text", + "name": "isSection" + }, + { + "type": "text", + "name": "numSection" + }, + { + "type": "text", + "name": "txtSection" + } + ], + "type": "dbconnector_select", + "outputType": "array" + } + } +} \ No newline at end of file diff --git a/app/api/qSubSection.json b/app/api/qSubSection.json new file mode 100644 index 0000000..cd0b742 --- /dev/null +++ b/app/api/qSubSection.json @@ -0,0 +1,119 @@ +{ + "meta": { + "$_GET": [ + { + "type": "text", + "name": "sort" + }, + { + "type": "text", + "name": "dir" + }, + { + "type": "text", + "name": "subid" + } + ] + }, + "exec": { + "steps": { + "name": "query", + "module": "dbconnector", + "action": "select", + "options": { + "connection": "DB", + "sql": { + "type": "SELECT", + "distinct": false, + "columns": [ + { + "table": "tblSection", + "column": "*", + "field": "*" + } + ], + "table": { + "name": "tblSection" + }, + "joins": [], + "orders": [], + "params": [ + { + "operator": "begins_with", + "type": "expression", + "name": ":P1", + "value": "{{$_GET.subid}}", + "test": "" + } + ], + "query": "select * from `tblSection` where `tblSection`.`numSection` like ? and `tblSection`.`isSection` = ?", + "wheres": { + "condition": "AND", + "rules": [ + { + "id": "tblSection.numSection", + "field": "tblSection.numSection", + "type": "string", + "operator": "begins_with", + "value": "{{$_GET.subid}}", + "data": { + "table": "tblSection", + "column": "numSection", + "type": "text", + "columnObj": { + "type": "text", + "maxLength": 255, + "primary": false, + "unique": false, + "nullable": true, + "name": "numSection" + } + }, + "operation": "LIKE" + }, + { + "id": "tblSection.isSection", + "field": "tblSection.isSection", + "type": "string", + "operator": "equal", + "value": "0", + "data": { + "table": "tblSection", + "column": "isSection", + "type": "text", + "columnObj": { + "type": "text", + "primary": false, + "unique": false, + "nullable": true, + "name": "isSection" + } + }, + "operation": "=" + } + ], + "conditional": null, + "valid": true + } + } + }, + "output": true, + "meta": [ + { + "type": "text", + "name": "isSection" + }, + { + "type": "text", + "name": "numSection" + }, + { + "type": "text", + "name": "txtSection" + } + ], + "type": "dbconnector_select", + "outputType": "array" + } + } +} \ No newline at end of file diff --git a/app/api/q_sub_section.json b/app/api/q_sub_section.json new file mode 100644 index 0000000..18cca0a --- /dev/null +++ b/app/api/q_sub_section.json @@ -0,0 +1,3 @@ +{ + "exec": {} +} \ No newline at end of file diff --git a/app/config/routes.json b/app/config/routes.json index ef7425a..6d7f55a 100644 --- a/app/config/routes.json +++ b/app/config/routes.json @@ -10,6 +10,11 @@ "path": "/DAPage1", "page": "DAPage1", "layout": "main" + }, + { + "path": "/observationPage", + "page": "observationPage", + "layout": "main" } ] } \ No newline at end of file diff --git a/app/modules/connections/DB.json b/app/modules/connections/DB.json index ceb67ac..c40ddd0 100644 --- a/app/modules/connections/DB.json +++ b/app/modules/connections/DB.json @@ -7,6 +7,10 @@ "connection": { "filename": "/public/ERTSQlite.db" }, - "tz": "utc" - } + "tz": "utc", + "meta": {} + }, + "fileName": "DB.json", + "actionFilePath": "file:///Z:/temp/ERTFastFiller/app/modules/connections/DB.json", + "serverType": "node" } \ No newline at end of file diff --git a/app/modules/connections/ERTDB.json b/app/modules/connections/ERTDB.json new file mode 100644 index 0000000..ba0837b --- /dev/null +++ b/app/modules/connections/ERTDB.json @@ -0,0 +1,13 @@ +{ + "name": "ERTDB", + "module": "dbconnector", + "action": "connect", + "options": { + "client": "sqlite3", + "connection": { + "filename": "/public/ERTSQlite.db" + }, + "tz": "utc" + }, + "fileName": "ERTDB.json" +} \ No newline at end of file diff --git a/app/modules/global.json b/app/modules/global.json new file mode 100644 index 0000000..18cca0a --- /dev/null +++ b/app/modules/global.json @@ -0,0 +1,3 @@ +{ + "exec": {} +} \ No newline at end of file diff --git a/lib/modules/api.js b/lib/modules/api.js index 8d24541..76bffa3 100644 --- a/lib/modules/api.js +++ b/lib/modules/api.js @@ -113,6 +113,22 @@ module.exports = { }); }); + req.on('timeout', () => { + req.destroy(new Error(`Request timed out after ${timeout}ms`)); + + if (throwErrors) { + reject(new Error(`Request timed out after ${timeout}ms`)); + } else if (passErrors) { + this.res.status(504).send(`Request timed out after ${timeout}ms`); + resolve(); + } else { + resolve({ + status: 504, + data: `Request timed out after ${timeout}ms` + }); + } + }); + req.on('error', reject); req.write(data); req.end(); diff --git a/public/ERT.json b/public/ERT.json new file mode 100644 index 0000000..cf0ee39 --- /dev/null +++ b/public/ERT.json @@ -0,0 +1,39 @@ +{ + "section": [ + { + "id": "1", + "text": "Locate & Adjust Vehicle Controls (as needed)", + "1.1": "Emergency/Parking Brake (applicable to all vehicles except Rivian)", + "1.2": "Parking controls/gear shift", + "1.3": "Vehicle Height", + "1.4": "Mirrors", + "1.5": "Lights: hazards, interior, headlights, turn signals, and auxiliary (fog)", + "1.6": "Horn", + "1.7": "Windshield wipers", + "1.8": "Window Defroster" + }, + { + "id": "2", + "text": "Vehicle Handling and Braking", + "2.1": "*Secures seat belt correctly prior to starting vehicle’s drive system*", + "2.2": "*Eliminates use of cell phone when vehicle is in motion*", + "2.3": "Steers smoothly with minimal adjustments", + "2.4": "*Stays centered on lane of travel*", + "2.5": "Avoids curbs when turning", + "2.6": "Both hands remain on the steering wheel at 9 & 3", + "2.7": "Engages turn signals and checks blind spots prior to making turns", + "2.8": "Checks mirrors every 5-8 seconds", + "2.9": "*Obeys all traffic signs*" + }, + { + "id": "3", + "text": "Braking, Slowing and Stopping", + "3.1": "Checks mirrors every 5-8 seconds", + "3.2": "Tests brakes before descending grades", + "3.3": "Stops behind crosswalks when stop lines or stop signs are present", + "3.4": "Maintains appropriate eye-lead time (looking ahead for hazards)", + "3.5": "*Safely controls vehicle by utilizing vehicle’s brake pedals*", + "3.6": "Safely utilizes regenerative braking as primary method of operation (EDV Only)" + } + ] +} \ No newline at end of file diff --git a/public/ERTSQlite - Copy.db b/public/ERTSQlite - Copy.db new file mode 100644 index 0000000..1d946d9 Binary files /dev/null and b/public/ERTSQlite - Copy.db differ diff --git a/public/ERTSQlite.db b/public/ERTSQlite.db index 44049ac..1d946d9 100644 Binary files a/public/ERTSQlite.db and b/public/ERTSQlite.db differ diff --git a/public/dmxAppConnect/config.js b/public/dmxAppConnect/config.js index c9a5e5a..1c90a40 100644 --- a/public/dmxAppConnect/config.js +++ b/public/dmxAppConnect/config.js @@ -1,115 +1,14 @@ dmx.config({ - "index": { - "delConfirm": { - "meta": [ - { - "sub": [ - { - "sub": [ - { - "name": "data", - "type": "object", - "sub": [ - { - "name": "delete", - "type": "text", - "sub": [ - { - "name": "affected", - "type": "number" - } - ] - } - ] - }, - { - "name": "state", - "type": "object", - "sub": [ - { - "name": "executing", - "type": "boolean" - }, - { - "name": "uploading", - "type": "boolean" - }, - { - "name": "processing", - "type": "boolean" - }, - { - "name": "downloading", - "type": "boolean" - } - ] - }, - { - "name": "uploadProgress", - "type": "object", - "sub": [ - { - "name": "position", - "type": "number" - }, - { - "name": "total", - "type": "number" - }, - { - "name": "percent", - "type": "number" - } - ] - }, - { - "name": "downloadProgress", - "type": "object", - "sub": [ - { - "name": "position", - "type": "number" - }, - { - "name": "total", - "type": "number" - }, - { - "name": "percent", - "type": "number" - } - ] - }, - { - "name": "lastError", - "type": "object", - "sub": [ - { - "name": "status", - "type": "number" - }, - { - "name": "message", - "type": "text" - }, - { - "name": "response", - "type": "text" - } - ] - }, - { - "name": "status", - "type": "number" - } - ], - "name": "pageFlowSC1", - "type": "object" - } - ] - } - ], - "local": {} - } + "observationPage": { + "datastore1": [ + { + "type": "number", + "name": "numSection" + }, + { + "type": "number", + "name": "Points" + } + ] } }); diff --git a/public/dmxAppConnect/dmxBootstrap5Popovers/dmxBootstrap5Popovers.js b/public/dmxAppConnect/dmxBootstrap5Popovers/dmxBootstrap5Popovers.js new file mode 100644 index 0000000..6d7358c --- /dev/null +++ b/public/dmxAppConnect/dmxBootstrap5Popovers/dmxBootstrap5Popovers.js @@ -0,0 +1,21 @@ +dmx.Attribute('bs-popover', 'mounted', function(node, attr) { + let popover = bootstrap.Popover.getInstance(node); + + this.$watch(attr.value, function(value) { + node.setAttribute('data-bs-content', value || ''); + }); + + if (!popover) { + popover = new bootstrap.Popover(node, { + placement: () => node.getAttribute('data-bs-placement') || 'auto', + title: () => node.getAttribute('popover-title') || node.getAttribute('data-bs-title') || '', + content: () => node.getAttribute('data-bs-content') || '', + }); + } + + return () => { + if (popover) { + popover.dispose(); + } + }; +}); diff --git a/public/dmxAppConnect/dmxDataTraversal/dmxDataTraversal.js b/public/dmxAppConnect/dmxDataTraversal/dmxDataTraversal.js new file mode 100644 index 0000000..7271588 --- /dev/null +++ b/public/dmxAppConnect/dmxDataTraversal/dmxDataTraversal.js @@ -0,0 +1,8 @@ +/*! + App Connect Data Traversal + Version: 2.0.2 + (c) 2024 Wappler.io + @build 2024-08-13 15:22:09 + */ +dmx.versions.dmxDataTraversal="2.0.2",dmx.Component("data-view",{initialData:{data:[],page:1,pages:1,items:0,sort:{on:"",dir:"asc"},has:{first:!1,prev:!1,next:!1,last:!1}},attributes:{data:{type:[Array,Object],default:null},filter:{type:String,default:""},page:{type:Number,default:1},pagesize:{type:Number,default:0},sorton:{type:String,default:""},sortdir:{type:String,default:"asc",enum:["asc","desc"]}},methods:{select(t){this._updatePage(+t)},first(){this._updatePage(1)},prev(){this._updatePage(this.data.page-1)},next(){this._updatePage(this.data.page+1)},last(){this._updatePage(this.data.pages)},sort(t,e){this.props.sorton=t,this.props.sortdir=e&&"desc"==e.toLowerCase()?"desc":"asc"}},init(){this._data=[],this._items=[],this.props.data&&this._updateData(),this.props.filter?this._updateFilter():this._updateItems()},destroy(){this._filterEffect&&(this._filterEffect(),delete this._filterEffect)},performUpdate(t){t.has("filter")?this._updateFilter():t.has("data")?(this._updateData(),this._updateFilter()):t.has("sorton")||t.has("sortdir")?this._updateFilter():t.has("page")?this._updatePage(this.props.page):t.has("pagesize")&&this._updatePage(this.data.page)},_updateFilter(){this.destroy(),this.props.filter?this._filterEffect=dmx.effect((()=>{dmx.parse(this.props.filter,this),this._updateItems()})):this._updateItems()},_updateData(){this._data=dmx.repeatItems(this.props.data).map((t=>(delete(t=dmx.clone(t)).$value,delete t.$index,delete t.$key,t)))},_updateItems(){if(this._items=this._data.slice(0),this.props.filter&&(this._items=this._items.filter((t=>dmx.parse(this.props.filter,dmx.DataScope(t,this))))),this.props.sorton){const t=this.props.sorton,e=this.props.sortdir,a="desc"===e;this._items.sort(((e,s)=>a?"string"==typeof e[t]&&"string"==typeof s[t]?s[t].localeCompare(e[t]):e[t]>s[t]?-1:e[t]s[t]?1:0)),this.set("sort",{on:t,dir:e})}this.props.pagesize;const t=this._items.length;this.set({items:t}),this._updatePage(this.data.page)},_updatePage(t){const e=this.props.pagesize,a=e?Math.max(1,Math.ceil(this._items.length/e)):1,s=((t=t<1?1:t>a?a:t)-1)*e;this.set({page:t,pages:a,data:e?this._items.slice(s,s+e):this._items,has:{first:t>1,prev:t>1,next:t"object"==typeof t?t:{$value:t})):this._data=Object.entries(this.props.data).map((([t,e])=>({$key:t,$value:e})))),this._updateSelection()},_updateSelection(t){this.set("data",this._data.find((t=>t[this.props.key]===this.props.value))||null),t&&requestAnimationFrame((()=>{this.$node.querySelectorAll("form").forEach((t=>t.reset()))}))}}),dmx.Component("data-iterator",{initialData:{index:-1,value:null,has:{first:!1,prev:!1,next:!1,last:!1}},attributes:{data:{type:Array,default:null},index:{type:Number,default:0},loop:{type:Boolean,default:!1}},methods:{first(){this._data.length&&this._select(0)},prev(){this._data.length&&this._select(this.data.index-1)},next(){this._data.length&&this._select(this.data.index+1)},last(){this._data.length&&this._select(this._data.length-1)},random(){this._data.length&&this._select(Math.floor(this._data.length*Math.random()))},select(t){this._data.length&&this._select(t)}},init(){this._updateData()},performUpdate(t){t.has("data")?this._updateData():t.has("index")&&this._select(this.props.index)},_updateData(){this._data=[],this.props.data&&(Array.isArray(this.props.data)?this._data=this.props.data:console.warn(`Iterator ${this.name} expects an array as data but got ${typeof this.props.data}`),this._select(this.props.index))},_select(t){if(t=parseInt(t,10),this._data.length){const e=this._data.length-1;t<0&&(t=this.props.loop?e:0),t>e&&(t=this.props.loop?0:e),this.set({index:t,value:this._data[t],has:{first:t>0,prev:t>0,next:t {\r\n dmx.parse(this.props.filter, this);\r\n this._updateItems();\r\n });\r\n } else {\r\n this._updateItems();\r\n }\r\n },\r\n\r\n _updateData () {\r\n this._data = dmx.repeatItems(this.props.data).map(item => {\r\n item = dmx.clone(item);\r\n delete item.$value;\r\n delete item.$index;\r\n delete item.$key;\r\n return item;\r\n });\r\n },\r\n\r\n _updateItems () {\r\n this._items = this._data.slice(0);\r\n\r\n if (this.props.filter) {\r\n this._items = this._items.filter(item => dmx.parse(this.props.filter, dmx.DataScope(item, this)));\r\n }\r\n\r\n if (this.props.sorton) {\r\n const on = this.props.sorton;\r\n const dir = this.props.sortdir;\r\n const rev = dir === 'desc';\r\n\r\n this._items.sort((a, b) => {\r\n if (rev) {\r\n if (typeof a[on] == 'string' && typeof b[on] == 'string') return b[on].localeCompare(a[on]);\r\n return a[on] > b[on] ? -1 : a[on] < b[on] ? 1 : 0;\r\n } else {\r\n if (typeof a[on] == 'string' && typeof b[on] == 'string') return a[on].localeCompare(b[on]);\r\n return a[on] < b[on] ? -1 : a[on] > b[on] ? 1 : 0;\r\n }\r\n });\r\n\r\n this.set('sort', { on, dir });\r\n }\r\n\r\n const size = this.props.pagesize;\r\n const items = this._items.length;\r\n\r\n this.set({\r\n //pages: size ? Math.max(1, Math.ceil(items / size)) : 1,\r\n items: items,\r\n });\r\n\r\n this._updatePage(this.data.page);\r\n },\r\n\r\n _updatePage (page) {\r\n const size = this.props.pagesize;\r\n const pages = size ? Math.max(1, Math.ceil(this._items.length / size)) : 1;\r\n\r\n page = page < 1 ? 1 : page > pages ? pages : page;\r\n\r\n const offset = (page - 1) * size;\r\n\r\n this.set({\r\n page: page,\r\n pages: pages,\r\n data: size ? this._items.slice(offset, offset + size) : this._items,\r\n has: {\r\n first: page > 1,\r\n prev: page > 1,\r\n next: page < pages,\r\n last: page < pages,\r\n },\r\n });\r\n },\r\n\r\n});\r\n","dmx.Component('data-detail', {\r\n\r\n initialData: {\r\n data: [],\r\n },\r\n\r\n attributes: {\r\n data: {\r\n type: Array,\r\n default: null,\r\n },\r\n\r\n key: {\r\n type: String,\r\n default: null,\r\n },\r\n\r\n value: {\r\n type: [String, Number],\r\n default: null,\r\n },\r\n },\r\n\r\n methods: {\r\n select (value) {\r\n this.props.value = value;\r\n this._updateSelection();\r\n },\r\n },\r\n\r\n init () {\r\n this._updateData();\r\n },\r\n\r\n performUpdate (updatedProps) {\r\n if (updatedProps.has('data')) {\r\n this._updateData();\r\n } else if (updatedProps.has('value')) {\r\n this._updateSelection(true);\r\n }\r\n },\r\n\r\n _updateData () {\r\n this._data = [];\r\n\r\n if (this.props.data && typeof this.props.data == 'object') {\r\n if (Array.isArray(this.props.data)) {\r\n this._data = this.props.data.map(item => typeof item == 'object' ? item : { $value: item });\r\n } else {\r\n this._data = Object.entries(this.props.data).map(([$key, $value]) => ({ $key, $value }));\r\n }\r\n }\r\n\r\n this._updateSelection();\r\n },\r\n\r\n _updateSelection (reset) {\r\n this.set('data', this._data.find(item => item[this.props.key] === this.props.value) || null);\r\n\r\n if (reset) {\r\n requestAnimationFrame(() => {\r\n this.$node.querySelectorAll('form').forEach(form => form.reset());\r\n });\r\n }\r\n },\r\n\r\n});\r\n","dmx.Component('data-iterator', {\r\n\r\n initialData: {\r\n index: -1,\r\n value: null,\r\n has: { first: false, prev: false, next: false, last: false },\r\n },\r\n\r\n attributes: {\r\n data: {\r\n type: Array,\r\n default: null,\r\n },\r\n\r\n index: {\r\n type: Number,\r\n default: 0\r\n },\r\n\r\n loop: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n },\r\n\r\n methods: {\r\n first () {\r\n if (this._data.length) {\r\n this._select(0);\r\n }\r\n },\r\n\r\n prev () {\r\n if (this._data.length) {\r\n this._select(this.data.index - 1);\r\n }\r\n },\r\n\r\n next () {\r\n if (this._data.length) {\r\n this._select(this.data.index + 1);\r\n }\r\n },\r\n\r\n last () {\r\n if (this._data.length) {\r\n this._select(this._data.length - 1);\r\n }\r\n },\r\n\r\n random () {\r\n if (this._data.length) {\r\n this._select(Math.floor(this._data.length * Math.random()));\r\n }\r\n },\r\n\r\n select (index) {\r\n if (this._data.length) {\r\n this._select(index);\r\n }\r\n },\r\n },\r\n\r\n init () {\r\n this._updateData();\r\n },\r\n\r\n performUpdate (updatedProps) {\r\n if (updatedProps.has('data')) {\r\n this._updateData();\r\n } else if (updatedProps.has('index')) {\r\n this._select(this.props.index);\r\n }\r\n },\r\n\r\n _updateData () {\r\n this._data = [];\r\n \r\n if (this.props.data) {\r\n if (Array.isArray(this.props.data)) {\r\n this._data = this.props.data;\r\n } else {\r\n console.warn(`Iterator ${this.name} expects an array as data but got ${typeof this.props.data}`);\r\n }\r\n\r\n this._select(this.props.index);\r\n }\r\n },\r\n\r\n _select (index) {\r\n index = parseInt(index, 10);\r\n\r\n if (this._data.length) {\r\n const last = this._data.length - 1;\r\n \r\n if (index < 0) index = this.props.loop ? last : 0;\r\n if (index > last) index = this.props.loop ? 0 : last;\r\n \r\n this.set({\r\n index: index,\r\n value: this._data[index],\r\n has: {\r\n first: index > 0,\r\n prev: index > 0,\r\n next: index < last,\r\n last: index < last,\r\n },\r\n });\r\n } else {\r\n this.set({\r\n index: -1,\r\n value: null,\r\n has: { first: false, prev: false, next: false, last: false },\r\n });\r\n }\r\n },\r\n\r\n});\r\n"]} \ No newline at end of file diff --git a/public/dmxAppConnect/dmxMasonry/dmxMasonry.js b/public/dmxAppConnect/dmxMasonry/dmxMasonry.js new file mode 100644 index 0000000..1c1a552 --- /dev/null +++ b/public/dmxAppConnect/dmxMasonry/dmxMasonry.js @@ -0,0 +1,8 @@ +/*! + App Connect Masonry + Version: 2.0.2 + (c) 2024 Wappler.io + @build 2024-06-19 16:06:31 + */ +dmx.Component("masonry",{extends:"repeat",attributes:{breakpoints:{type:Object,default:{}},columns:{type:Number,default:4},columnsSm:{type:Number,default:null},columnsMd:{type:Number,default:null},columnsLg:{type:Number,default:null},columnsXl:{type:Number,default:null},columnsXxl:{type:Number,default:null},gutter:{type:Number,default:15},gutterSm:{type:Number,default:null},gutterMd:{type:Number,default:null},gutterLg:{type:Number,default:null},gutterXl:{type:Number,default:null},gutterXxl:{type:Number,default:null},preserveOrder:{type:Boolean,default:!1},animated:{type:Boolean,default:!1},animationDuration:{type:Number,default:400}},methods:{reflow(){this._reflow()}},init(e){this._breakpoints={sm:480,md:768,lg:992,xl:1200,xxl:1400},this._reflow=dmx.debounce(this._reflow.bind(this)),this._resizeObserver=new ResizeObserver(this._reflow),this._resizeObserver.observe(e),window.addEventListener("resize",this._reflow),dmx.Component("repeat").prototype.init.call(this,e)},render(e){e.style.setProperty("position","relative"),this._reflow()},performUpdate(e){(e.has("repeat")||e.has("key"))&&dmx.Component("repeat").prototype.performUpdate.call(this,e),this._reflow()},destroy(){this._resizeObserver.disconnect(),window.removeEventListener("resize",this._reflow)},_reflow(e){if(e&&e.dmxMasonry)return;if(!this.children.length)return;this.$node.querySelectorAll("img").forEach((e=>{e.dmxMasonry||(e.addEventListener("load",this._reflow,{once:!0}),e.src&&(e.src=e.src),e.dmxMasonry=!0)}));let{breakpoints:t,columns:r,gutter:s}=this.props;t=Object.assign({},this._breakpoints,t),["sm","md","lg","xl","xxl"].forEach((e=>{if(window.innerWidth>=t[e]){const t=e[0].toUpperCase()+e.slice(1);r=this.props["columns"+t]||r,s=this.props["gutter"+t]||s}}));const o=Array.from(this.$node.children),n=window.getComputedStyle(this.$node),i=parseInt(n.paddingLeft)||0,l=parseInt(n.paddingRight)||0,a=Math.floor((this.$node.clientWidth-i-l-(r-1)*s)/r);for(const e of o)e.style.setProperty("box-sizing","border-box"),e.style.setProperty("width",a+"px");const p=new Event("resize");p.dmxMasonry=!0,window.dispatchEvent(p);const d=Array(r).fill(0),u=o.map((e=>e.clientHeight));o.forEach(((e,t)=>{const o=this.props.preserveOrder?t%r:d.indexOf(Math.min.apply(Math,d)),n=o*a+o*s,i=d[o];e.style.setProperty("transform",`translate3d(${n}px, ${i}px, 0px)`),u[t]&&(e.dmxMasonryInit||(e.style.setProperty("position","absolute"),this.props.animated&&e.style.setProperty("transition",`transform ${this.props.animationDuration}ms`),requestAnimationFrame((()=>e.style.setProperty("visibility","visible"))),e.dmxMasonryInit=!0,this._resizeObserver.observe(e)),d[o]+=u[t]+s)})),this.$node.style.setProperty("height",Math.max.apply(Math,d)-s+"px")}}); +//# sourceMappingURL=dmxMasonry.js.map diff --git a/public/dmxAppConnect/dmxMasonry/dmxMasonry.js.map b/public/dmxAppConnect/dmxMasonry/dmxMasonry.js.map new file mode 100644 index 0000000..489ab0d --- /dev/null +++ b/public/dmxAppConnect/dmxMasonry/dmxMasonry.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["components/masonry.js"],"names":["dmx","Component","extends","attributes","breakpoints","type","Object","default","columns","Number","columnsSm","columnsMd","columnsLg","columnsXl","columnsXxl","gutter","gutterSm","gutterMd","gutterLg","gutterXl","gutterXxl","preserveOrder","Boolean","animated","animationDuration","methods","reflow","this","_reflow","init","node","_breakpoints","sm","md","lg","xl","xxl","debounce","bind","_resizeObserver","ResizeObserver","observe","window","addEventListener","prototype","call","render","style","setProperty","performUpdate","updatedProps","has","destroy","disconnect","removeEventListener","e","dmxMasonry","children","length","$node","querySelectorAll","forEach","img","once","src","props","assign","breakpoint","innerWidth","suffix","toUpperCase","slice","nodes","Array","from","getComputedStyle","padding","parseInt","paddingLeft","paddingRight","columnWidth","Math","floor","clientWidth","event","Event","dispatchEvent","columnHeights","fill","nodesHeights","map","clientHeight","index","i","indexOf","min","apply","x","y","dmxMasonryInit","requestAnimationFrame","max"],"mappings":"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","file":"dmxMasonry.js","sourcesContent":["dmx.Component('masonry', {\r\n\r\n extends: 'repeat',\r\n\r\n attributes: {\r\n breakpoints: {\r\n type: Object,\r\n default: {},\r\n },\r\n\r\n columns: {\r\n type: Number,\r\n default: 4,\r\n },\r\n\r\n columnsSm: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n columnsMd: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n columnsLg: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n columnsXl: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n columnsXxl: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n gutter: {\r\n type: Number,\r\n default: 15,\r\n },\r\n\r\n gutterSm: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n gutterMd: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n gutterLg: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n gutterXl: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n gutterXxl: {\r\n type: Number,\r\n default: null,\r\n },\r\n\r\n preserveOrder: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n\r\n animated: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n\r\n animationDuration: {\r\n type: Number,\r\n default: 400,\r\n },\r\n },\r\n\r\n methods: {\r\n reflow () {\r\n this._reflow();\r\n },\r\n },\r\n\r\n init (node) {\r\n this._breakpoints = { sm: 480, md: 768, lg: 992, xl: 1200, xxl: 1400 };\r\n this._reflow = dmx.debounce(this._reflow.bind(this));\r\n this._resizeObserver = new ResizeObserver(this._reflow);\r\n this._resizeObserver.observe(node);\r\n\r\n window.addEventListener('resize', this._reflow);\r\n\r\n dmx.Component('repeat').prototype.init.call(this, node);\r\n },\r\n\r\n render (node) {\r\n node.style.setProperty('position', 'relative');\r\n this._reflow();\r\n },\r\n\r\n performUpdate (updatedProps) {\r\n if (updatedProps.has('repeat') || updatedProps.has('key')) {\r\n dmx.Component('repeat').prototype.performUpdate.call(this, updatedProps);\r\n }\r\n\r\n this._reflow();\r\n },\r\n\r\n destroy () {\r\n this._resizeObserver.disconnect();\r\n window.removeEventListener('resize', this._reflow);\r\n },\r\n\r\n _reflow (e) {\r\n if (e && e.dmxMasonry) return;\r\n if (!this.children.length) return;\r\n\r\n this.$node.querySelectorAll('img').forEach(img => {\r\n if (!img.dmxMasonry) {\r\n img.addEventListener('load', this._reflow, { once: true });\r\n if (img.src) img.src = img.src;\r\n img.dmxMasonry = true;\r\n }\r\n });\r\n\r\n let { breakpoints, columns, gutter } = this.props;\r\n breakpoints = Object.assign({}, this._breakpoints, breakpoints);\r\n\r\n ['sm', 'md', 'lg', 'xl', 'xxl'].forEach(breakpoint => {\r\n if (window.innerWidth >= breakpoints[breakpoint]) {\r\n const suffix = breakpoint[0].toUpperCase() + breakpoint.slice(1);\r\n columns = this.props['columns' + suffix] || columns;\r\n gutter = this.props['gutter' + suffix] || gutter;\r\n }\r\n });\r\n\r\n const nodes = Array.from(this.$node.children);\r\n const style = window.getComputedStyle(this.$node);\r\n const padding = {\r\n left: parseInt(style.paddingLeft) || 0,\r\n right: parseInt(style.paddingRight) || 0,\r\n };\r\n const columnWidth = Math.floor((this.$node.clientWidth - padding.left - padding.right - ((columns - 1) * gutter)) / columns);\r\n\r\n for (const node of nodes) {\r\n node.style.setProperty('box-sizing', 'border-box');\r\n node.style.setProperty('width', columnWidth + 'px');\r\n }\r\n\r\n // dispatch resize event for components that still listen to that for updating\r\n const event = new Event('resize');\r\n event.dmxMasonry = true;\r\n window.dispatchEvent(event);\r\n\r\n const columnHeights = Array(columns).fill(0);\r\n const nodesHeights = nodes.map(node => node.clientHeight);\r\n\r\n nodes.forEach((node, index) => {\r\n const i = this.props.preserveOrder ? index % columns : columnHeights.indexOf(Math.min.apply(Math, columnHeights));\r\n const x = (i * columnWidth) + (i * gutter);\r\n const y = columnHeights[i];\r\n\r\n node.style.setProperty('transform', `translate3d(${x}px, ${y}px, 0px)`);\r\n\r\n if (nodesHeights[index]) {\r\n if (!node.dmxMasonryInit) {\r\n node.style.setProperty('position', 'absolute');\r\n\r\n if (this.props.animated) {\r\n node.style.setProperty('transition', `transform ${this.props.animationDuration}ms`);\r\n }\r\n\r\n requestAnimationFrame(() => node.style.setProperty('visibility', 'visible'));\r\n\r\n node.dmxMasonryInit = true;\r\n\r\n this._resizeObserver.observe(node);\r\n }\r\n\r\n columnHeights[i] += nodesHeights[index] + gutter;\r\n }\r\n });\r\n\r\n this.$node.style.setProperty('height', (Math.max.apply(Math, columnHeights) - gutter) + 'px');\r\n },\r\n\r\n});\r\n"]} \ No newline at end of file diff --git a/public/js/connections/PDb.js b/public/js/connections/PDb.js new file mode 100644 index 0000000..f62935b --- /dev/null +++ b/public/js/connections/PDb.js @@ -0,0 +1,2 @@ +dmx.databases = dmx.databases || {}; +dmx.databases['PDb'] = {type: "pouchdb"} \ No newline at end of file diff --git a/views/.wappler_folder.json b/views/.wappler_folder.json index a601f06..f6af151 100644 --- a/views/.wappler_folder.json +++ b/views/.wappler_folder.json @@ -2,5 +2,9 @@ "DAPage1.ejs": { "layoutPage": "main", "description": "Initalization page for Delivery Associate" + }, + "observationPage.ejs": { + "layoutPage": "main", + "description": "Observation Page for DT" } } \ No newline at end of file diff --git a/views/index.ejs b/views/index.ejs index 7483bd0..050c2e3 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -26,18 +26,6 @@
- diff --git a/views/layouts/main.ejs b/views/layouts/main.ejs index 7234343..9c326e5 100644 --- a/views/layouts/main.ejs +++ b/views/layouts/main.ejs @@ -23,6 +23,9 @@ + + + @@ -39,6 +42,7 @@ File Edit About + Observation diff --git a/views/observationPage.ejs b/views/observationPage.ejs new file mode 100644 index 0000000..4f5fe8c --- /dev/null +++ b/views/observationPage.ejs @@ -0,0 +1,85 @@ + + + +
+ + + + + +
+
+
+
+ + +
+ +
+
+
+
+ + + + + + + + + + + + + + +
Num sectionTxt section
+
+ +
+ + + + + + + + + + + + + + + + + + +
PointsIs sectionNum sectionTxt section
+ + +
+
+
+ + + + + + + + + + + + + + + +
$idNum sectionPoints
+
\ No newline at end of file