More work on integrating the script-task.

Ylian Saint-Hilaire committed Aug 18, 2022 at 18:03 UTC 1b67b8436954f00abee27e802dd2dc87050f1780
10 files changed +2120 -14
MeshCentralServer.njsproj
+1
@@ -238,6 +238,7 @@
238 <Compile Include="public\scripts\common-0.0.1.js" />
239 <Compile Include="public\scripts\meshcentral.js" />
240 <Compile Include="redirserver.js" />
241 + <Compile Include="taskmanager.js" />
242 <Compile Include="translate\translate.js" />
243 <Compile Include="ua-parser.js" />
244 <Compile Include="webauthn.js" />
meshagent.js
+1 -14
@@ -1740,20 +1740,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1740 }
1741 case 'script-task': {
1742 // These command are for running regular batch jobs on the remote device
1743 - switch (command.subaction) {
1744 - case 'getScript': {
1745 - console.log('getScript');
1746 - break;
1747 - }
1748 - case 'clearAllPendingTasks': {
1749 - console.log('clearAllPendingTasks');
1750 - break;
1751 - }
1752 - case 'taskComplete': {
1753 - console.log('taskComplete');
1754 - break;
1755 - }
1756 - }
1743 + if (parent.parent.taskManager != null) { parent.parent.taskManager.agentAction(command, obj); }
1744 break;
1745 }
1746 default: {
meshcentral.js
+6
@@ -33,6 +33,7 @@ function CreateMeshCentralServer(config, args) {
33 obj.amtScanner = null;
34 obj.amtManager = null;
35 obj.meshScanner = null;
36 + obj.taskManager = null;
37 obj.letsencrypt = null;
38 obj.eventsDispatch = {};
39 obj.fs = require('fs');
@@ -1497,6 +1498,11 @@ function CreateMeshCentralServer(config, args) {
1498 return;
1499 }
1500
1501 + // Setup the task manager
1502 + if ((obj.config) && (obj.config.settings) && (obj.config.settings.taskmanager == true)) {
1503 + obj.taskManager = require('./taskmanager').createTaskManager(obj);
1504 + }
1505 +
1506 // Start plugin manager if configuration allows this.
1507 if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null) && (obj.config.settings.plugins != false) && ((typeof obj.config.settings.plugins != 'object') || (obj.config.settings.plugins.enabled != false))) {
1508 obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj);
public/tail.datetime/tail.datetime-default-blue.min.css new
+3
@@ -0,0 +1,3 @@
1 +@charset "UTF-8"; /* pytesNET/tail.DateTime v.0.4.14 */
2 +/* @author SamBrishes, pytesNET <sam@pytes.net> | @license MIT */
3 +.tail-datetime-calendar,.tail-datetime-calendar *,.tail-datetime-calendar :after,.tail-datetime-calendar :before{box-sizing:border-box;-webkit-box-sizing:border-box}.tail-datetime-calendar{top:0;left:0;width:275px;height:auto;margin:15px;padding:0;z-index:3000;display:block;position:absolute;visibility:hidden;direction:ltr;border-collapse:separate;font-family:"Open Sans",Calibri,Arial,sans-serif;background-color:#fff;border-width:0;border-style:solid;border-color:transparent;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.3125);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3125)}.tail-datetime-calendar:after{clear:both;content:"";display:block;font-size:0;visibility:hidden}.tail-datetime-calendar.calendar-static{top:auto;left:auto;margin-left:auto;margin-right:auto;position:static;visibility:visible}.tail-datetime-calendar button.calendar-close{top:100%;right:15px;color:#303438;width:35px;height:25px;margin:1px 0 0 0;padding:5px 10px;opacity:.5;outline:0;display:inline-block;position:absolute;font-size:14px;line-height:1.125em;text-shadow:none;background-color:#fff;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjMzAzNDM4IiBkPSJNNy40OCA4bDMuNzUgMy43NS0xLjQ4IDEuNDhMNiA5LjQ4bC0zLjc1IDMuNzUtMS40OC0xLjQ4TDQuNTIgOCAuNzcgNC4yNWwxLjQ4LTEuNDhMNiA2LjUybDMuNzUtMy43NSAxLjQ4IDEuNDhMNy40OCA4eiIvPjwvc3ZnPg==");background-repeat:no-repeat;background-position:center center;border-width:0;border-style:solid;border-color:transparent;border-radius:0 0 3px 3px;box-shadow:0 1px 3px rgba(0,0,0,.3125);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3125);transition:opacity 142ms linear;-webkit-transition:opacity 142ms linear}.tail-datetime-calendar button.calendar-close:hover{opacity:1}.tail-datetime-calendar .calendar-tooltip{color:#fff;width:auto;margin:0;padding:0;display:block;position:absolute;background-color:#202428;border-radius:3px}.tail-datetime-calendar .calendar-tooltip:before{top:-7px;left:50%;width:0;height:0;margin:0 0 0 -6px;content:"";display:block;position:absolute;border-width:0 7px 7px 7px;border-style:solid;border-color:transparent transparent #202428 transparent}.tail-datetime-calendar .calendar-tooltip .tooltip-inner{width:auto;margin:0;padding:4px 7px;display:block;font-size:12px;line-height:14px}.tail-datetime-calendar .calendar-actions{color:#fff;width:100%;height:36px;margin:0;padding:0;display:table;overflow:hidden;border-spacing:0;border-collapse:separate;background-color:#149be6;border-width:0;border-style:solid;border-color:transparent;border-radius:3px 3px 0 0}.tail-datetime-calendar .calendar-actions span{margin:0;padding:0;display:table-cell;position:relative;text-align:center;line-height:36px;text-shadow:-1px -1px 0 #0e6ca0;background-repeat:no-repeat;background-position:center center}.tail-datetime-calendar .calendar-actions span[data-action]{cursor:pointer}.tail-datetime-calendar .calendar-actions span.action{width:36px;font-size:22px}.tail-datetime-calendar .calendar-actions span.label{width:auto}.tail-datetime-calendar .calendar-actions span:first-child:before,.tail-datetime-calendar .calendar-actions span:last-child:before{top:5px;bottom:5px;width:1px;height:auto;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#107bb7}.tail-datetime-calendar .calendar-actions span:first-child:before{right:-1px}.tail-datetime-calendar .calendar-actions span:last-child:before{left:-1px}.tail-datetime-calendar .calendar-actions span:first-child:hover:before,.tail-datetime-calendar .calendar-actions span:last-child:hover:before{display:none}.tail-datetime-calendar .calendar-actions span[data-action]:hover{background-color:#107bb7}.tail-datetime-calendar .calendar-actions span.action-prev{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgNiAxNiI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTYgMkwwIDhsNiA2VjJ6Ii8+PC9zdmc+")}.tail-datetime-calendar .calendar-actions span.action-next{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgNiAxNiI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTAgMTRsNi02LTYtNnYxMnoiLz48L3N2Zz4=")}.tail-datetime-calendar .calendar-actions span.action-submit{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNMTIgNWwtOCA4LTQtNCAxLjUtMS41TDQgMTBsNi41LTYuNUwxMiA1eiIvPjwvc3ZnPg==")}.tail-datetime-calendar .calendar-actions span.action-cancel{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNy40OCA4bDMuNzUgMy43NS0xLjQ4IDEuNDhMNiA5LjQ4bC0zLjc1IDMuNzUtMS40OC0xLjQ4TDQuNTIgOCAuNzcgNC4yNWwxLjQ4LTEuNDhMNiA2LjUybDMuNzUtMy43NSAxLjQ4IDEuNDhMNy40OCA4eiIvPjwvc3ZnPg==")}.tail-datetime-calendar .calendar-datepicker{width:100%;margin:0;padding:0;display:block;position:relative}.tail-datetime-calendar .calendar-datepicker table{width:100%;margin:0;padding:0;border-spacing:0;border-collapse:separate}.tail-datetime-calendar .calendar-datepicker table tr td,.tail-datetime-calendar .calendar-datepicker table tr th{color:#303438;height:30px;padding:0;position:relative;font-size:13px;text-align:center;font-weight:400;text-shadow:none;line-height:30px;background-color:transparent;border-width:0;border-style:solid;border-color:transparent;border-radius:0}.tail-datetime-calendar .calendar-datepicker table tr th{color:#fff;background-color:#303438}.tail-datetime-calendar .calendar-datepicker table tr td{cursor:pointer}.tail-datetime-calendar .calendar-datepicker table tr td span.inner{margin:0;padding:0;display:inline-block}.tail-datetime-calendar .calendar-datepicker table tr td.date-disabled{cursor:not-allowed;color:#909498;background-color:#f0f0f0}.tail-datetime-calendar .calendar-datepicker table tr td.date-disabled:after{left:3px;bottom:3px;width:35px;height:1px;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#bfbfbf;transform-origin:2px -5px;transform:rotate(-45deg);-moz-transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.tail-datetime-calendar .calendar-datepicker table tr td.date-next,.tail-datetime-calendar .calendar-datepicker table tr td.date-previous{color:#909498;background-color:#f0f0f0}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick,.tail-datetime-calendar .calendar-datepicker table tr td.date-today:before{top:5px;width:5px;height:5px;margin:0;padding:0;z-index:20;content:"";display:inline-block;position:absolute;border-width:0;border-style:solid;border-color:transparent;border-radius:50%}.tail-datetime-calendar .calendar-datepicker table tr td.date-today:before{left:5px;background-color:#32b93c}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick{right:5px;background-color:#202428}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick:after,.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick:before{display:none}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week{width:14.28571429%;height:35px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week span.inner{width:31px;height:31px;line-height:29px;border-width:1px;border-style:solid;border-color:transparent;border-radius:50%}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week:hover span.inner{border-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-disabled span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-disabled:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-disabled span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-disabled:hover span.inner{border-color:transparent}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-select span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-select:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-select span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-select:hover span.inner{color:#32b93c;border-color:#32b93c}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year{width:33.33333333%;height:40px;transition:color 142ms linear;-webkit-transition:color 142ms linear}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade.date-today:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month.date-today:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year.date-today:before{left:50%;margin-left:-2.5px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner{width:auto;height:31px;line-height:29px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:before{width:20px;height:20px;content:"";z-index:15;display:inline-block;position:absolute;border-width:1px;border-style:solid;border-color:transparent;transition:all 142ms linear;-webkit-transition:all 142ms linear}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:before{top:0;left:0}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade:hover span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month:hover span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year:hover span.inner:before{top:6px;left:6px;border-top-color:#ccc;border-left-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:after{right:0;bottom:0}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade:hover span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month:hover span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year:hover span.inner:after{right:6px;bottom:6px;border-right-color:#ccc;border-bottom-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year{width:25%}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner{height:54px;padding:7px 15px;text-align:left;line-height:20px}.tail-datetime-calendar .calendar-timepicker{width:100%;margin:0;padding:0;display:block;text-align:center;border-width:1px 0 0 0;border-style:solid;border-color:#d9d9d9}.tail-datetime-calendar .calendar-timepicker .timepicker-field{width:28%;margin:0;padding:15px 0 7px 0;display:inline-block;position:relative;text-align:center}.tail-datetime-calendar .calendar-timepicker .timepicker-field:first-of-type{text-align:right}.tail-datetime-calendar .calendar-timepicker .timepicker-field:last-of-type{text-align:left}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]{color:#303438;width:100%;height:29px;margin:0;z-index:4;padding:3px 20px 3px 5px;outline:0;display:inline-block;position:relative;font-size:12px;text-align:center;line-height:23px;appearance:textfield;-moz-appearance:textfield;-webkit-appearance:textfield;background-color:#f0f0f0;border-width:0;border-style:solid;border-color:transparent;border-radius:3px;box-shadow:none;-webkit-box-shadow:none;transition:color 142ms linear,border 142ms linear,background 142ms linear;-webkit-transition:color 142ms linear,border 142ms linear,background 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:hover{color:#303438;background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:focus{color:#fff;background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:disabled{cursor:not-allowed;color:#a0a4a8;background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step{width:20px;height:15px;right:0;margin:0;padding:0;z-index:15;display:inline-block;position:absolute;background-color:#f0f0f0;box-shadow:none;-webkit-box-shadow:none;transition:border 142ms linear,background 142ms linear;-webkit-transition:border 142ms linear,background 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step:before{top:4px;left:50%;width:0;height:0;margin:0 0 0 -4px;padding:0;content:"";display:inline-block;position:absolute;transition:border 142ms linear;-webkit-transition:border 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up{top:15px;border-width:0 0 1px 1px;border-style:solid;border-color:#fff;border-radius:0 2px 0 0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up:hover{background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up:before{border-width:0 4px 5px 4px;border-style:solid;border-color:transparent transparent #303438 transparent}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down{top:29px;border-width:1px 0 0 1px;border-style:solid;border-color:#fff;border-radius:0 0 2px 0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down:hover{background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down:before{border-width:5px 4px 0 4px;border-style:solid;border-color:#303438 transparent transparent transparent}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up{border-color:rgba(255,255,255,.8);background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up:hover{background-color:#27912f}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up:before{border-bottom-color:#fff}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down{border-color:rgba(255,255,255,.8);background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down:hover{background-color:#27912f}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down:before{border-top-color:#fff}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up{cursor:not-allowed;border-color:rgba(255,255,255,.8);background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up:hover{background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up:before{border-bottom-color:#a0a4a8}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down{cursor:not-allowed;border-color:rgba(255,255,255,.8);background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down:hover{background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down:before{border-top-color:#a0a4a8}.tail-datetime-calendar .calendar-timepicker .timepicker-field label{color:#303438;margin:0;padding:0;display:block;font-size:12px;text-align:center}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch{cursor:pointer;margin:15px 0 -5px 0;display:block;text-align:center;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:after,.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:before{width:auto;margin:0;padding:0 5px;font-size:12px;line-height:16px;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:before{content:attr(data-am)}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:after{content:attr(data-pm)}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]{display:none}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span{display:inline-block;position:relative;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span:before{width:50px;height:16px;content:"";display:inline-block;vertical-align:top;border-width:1px;border-style:solid;border-color:#149be6;border-radius:14px;transition:border 284ms linear;-webkit-transition:border 284ms linear}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span:after{top:3px;left:4px;right:30px;width:auto;height:10px;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#149be6;border-radius:15px;vertical-align:top;transition:left 284ms linear,right 284ms linear 284ms,background 284ms linear;-webkit-transition:left 284ms linear,right 284ms linear 284ms,background 284ms linear}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]:checked+span:before{border-color:#32b93c}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]:checked+span:after{left:30px;right:4px;background-color:#32b93c;transition:right 284ms linear,left 284ms linear 284ms,background 284ms linear;-webkit-transition:right 284ms linear,left 284ms linear 284ms,background 284ms linear}.tail-datetime-calendar .calendar-actions+.calendar-timepicker{border-width:0}.tail-datetime-calendar.rtl{direction:rtl}.tail-datetime-calendar.rtl .calendar-actions span.action-next,.tail-datetime-calendar.rtl .calendar-actions span.action-prev{transform:rotate(180deg);-moz-transform:rotate(180deg);-webkit-transform:rotate(180deg)}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.date-disabled:after{right:3px;transform:rotate(45deg);-moz-transform:rotate(45deg);-webkit-transform:rotate(45deg)}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.date-today:before{right:5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td .tooltip-tick{left:5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade.date-today:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month.date-today:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year.date-today:before{right:50%;margin-right:-2.5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade:hover span.inner:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month:hover span.inner:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year:hover span.inner:before{right:6px;border-right-color:#ccc}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year span.inner:after{left:0}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade:hover span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month:hover span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year:hover span.inner:after{left:6px;border-left-color:#ccc}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade span.inner{text-align:right}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:first-child{text-align:left;padding-left:0;padding-right:25px}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:last-child{text-align:right;padding-left:25px;padding-right:0}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:first-child input[type=text]{margin-left:-1px;margin-right:0;border-radius:0 3px 3px 0}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:last-child input[type=text]{margin-left:0;margin-right:-1px;border-radius:3px 0 0 3px}
\ No newline at end of file
public/tail.datetime/tail.datetime-default-blue.min.map new
+1
@@ -0,0 +1 @@
1 +{"version":3,"sources":["$stdin"],"names":[],"mappings":"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"}
\ No newline at end of file
public/tail.datetime/tail.datetime.min.js new
+2
@@ -0,0 +1,2 @@
1 +/* pytesNET/tail.DateTime v.0.4.14 | Basic Version | @author SamBrishes, pytesNET <sam@pytes.net> | @license MIT */
2 +!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof module&&module.exports?module.exports=e(t,t.document):(void 0===t.tail&&(t.tail={}),t.tail.DateTime=t.tail.datetime=e(t,t.document),"undefined"!=typeof jQuery&&(jQuery.fn.DateTime=jQuery.fn.datetime=function(t){var e,i=[];return this.each(function(){!1!==(e=tail.DateTime(this,t))&&i.push(e)}),1===i.length?i[0]:0!==i.length&&i}),"undefined"!=typeof MooTools&&(Element.implement({DateTime:function(t){return new tail.DateTime(this,t)}}),Element.implement({datetime:function(t){return new tail.DateTime(this,t)}})))}(window,function(h,d){"use strict";function u(t,e){return!!(t&&"classList"in t)&&t.classList.contains(e)}function a(t,e){return t&&"classList"in t?t.classList.add(e):void 0}function n(t,e){return t&&"classList"in t?t.classList.remove(e):void 0}function s(t,e,i){if(CustomEvent&&CustomEvent.name)var a=new CustomEvent(e,i);else(a=d.createEvent("CustomEvent")).initCustomEvent(e,!!i.bubbles,!!i.cancelable,i.detail);return t.dispatchEvent(a)}function o(t,e){if("function"==typeof Object.assign)return Object.assign({},t,e||{});var i=Object.constructor();for(var a in t)i[a]=a in e?e[a]:t[a];return i}function p(t,e){var i=d.createElement(t);return i.className=e&&e.join?e.join(" "):e||"",i}function r(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t,e,i){var a=t instanceof Date?t:!!t&&new Date(t);return a instanceof Date&&!isNaN(a.getDate())&&(i&&a.setHours(0,0,0,0),!0===e?a.getTime():a)}d.forms.inputmode=!0;var l=function(t,e){if((t="string"==typeof t?d.querySelectorAll(t):t)instanceof NodeList||t instanceof HTMLCollection||t instanceof Array){for(var i=[],a=t.length,n=0;n<a;n++)i.push(new l(t[n],e));return 1===i.length?i[0]:0!==i.length&&i}if(!(t instanceof Element))return!1;if(!(this instanceof l))return new l(t,e);if(l.inst[t.getAttribute("data-tail-datetime")])return l.inst[t.getAttribute("data-tail-datetime")];if(t.getAttribute("data-datetime")){var s=JSON.parse(t.getAttribute("data-datetime").replace(/\'/g,'"'));s instanceof Object&&(e=o(e,s))}return this.e=t,this.id=++l.count,this.con=o(l.defaults,e),(l.inst["tail-"+this.id]=this).e.setAttribute("data-tail-datetime","tail-"+this.id),this.init()};return l.version="0.4.14",l.status="beta",l.count=0,l.inst={},l.defaults={animate:!0,classNames:!1,closeButton:!0,dateFormat:"YYYY-mm-dd",dateStart:!1,dateRanges:[],dateBlacklist:!0,dateEnd:!1,locale:"en",position:"bottom",rtl:"auto",startOpen:!1,stayOpen:!1,time12h:!1,timeFormat:"HH:ii:ss",timeHours:!0,timeMinutes:!0,timeSeconds:0,timeIncrement:!0,timeStepHours:1,timeStepMinutes:5,timeStepSeconds:5,today:!0,tooltips:[],viewDefault:"days",viewDecades:!0,viewYears:!0,viewMonths:!0,viewDays:!0,weekStart:0},l.strings={en:{months:["January","February","March","April","May","June","July","August","September","October","November","December"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shorts:["SUN","MON","TUE","WED","THU","FRI","SAT"],time:["Hours","Minutes","Seconds"],header:["Select a Month","Select a Year","Select a Decade","Select a Time"]},modify:function(t,e,i){if(!(t in this))return!1;if(e instanceof Object)for(var a in e)this.modify(t,a,e[a]);else this[t][e]="string"==typeof i?i:this[t][e];return!0},register:function(t,e){return"string"==typeof t&&e instanceof Object&&(this[t]=e,!0)}},l.prototype={init:function(){this.prepare();var t=this.__.shorts.slice(this.con.weekStart).concat(this.__.shorts.slice(0,this.con.weekStart));this.weekdays="<thead>\n<tr>\n";for(var e=0;e<7;e++)this.weekdays+='<th class="calendar-week">'+t[e]+"</th>";this.weekdays+="\n</tr>\n</thead>",this.select=c(this.e.getAttribute("data-value")||this.e.value),(!this.select||this.select<this.con.dateStart||this.select>this.con.dateEnd)&&(this.select=null),null==this.view&&(this.view={type:this.con.viewDefault,date:this.select||new Date});var i=["Hours","Minutes","Seconds"];for(e=0;e<3;e++)if("number"==typeof this.con["time"+i[e]])this.view.date["set"+i[e]](this.con["time"+i[e]]);else for(;this.view.date["get"+i[e]]()%this.con["timeStep"+i[e]]!=0;)this.view.date["set"+i[e]](this.view.date["get"+i[e]]()+1);return this.ampm=!!this.con.time12h&&12<this.view.date.getHours(),this.events={},this.dt=this.renderCalendar(),this.con.startOpen&&this.open(),this.select&&this.selectDate(this.select),this.bind()},prepare:function(){if(this.__=o(l.strings.en,l.strings[this.con.locale]||{}),this.con.dateStart=c(this.con.dateStart,!0,!0)||-9999999999999,this.con.dateEnd=c(this.con.dateEnd,!0,!0)||9999999999999,this.con.viewDefault=this.con.dateFormat?this.con.viewDefault:"time","string"==typeof this.con.weekStart&&(this.con.weekStart=l.strings.en.shorts.indexOf(this.con.weekStart)),this.con.weekStart<0&&6<this.con.weekStart&&(this.con.weekStart=0),0<this.con.dateRanges.length){for(var t=[],e=(n=this.con.dateRanges).length,i=0;i<e;i++)n[i]instanceof Object&&(n[i].start||n[i].days)&&(!1===(n[i].start=c(n[i].start||!1,!0,!0))?n[i].start=n[i].end=1/0:(!1===(n[i].end=c(n[i].end||!1,!0,!0))&&(n[i].end=n[i].start),n[i].start=n[i].start>n[i].end?[n[i].end,n[i].end=n[i].start][0]:n[i].start),n[i].days=!("days"in n[i])||n[i].days,n[i].days="boolean"!=typeof n[i].days?function(t){for(var e=[],i=t.length,a=0;a<i;a++)"string"==typeof t[a]&&(t[a]=l.strings.en.shorts.indexOf(t[a])),0<=t[a]&&t[a]<=6&&e.push(t[a]);return e}(n[i].days instanceof Array?n[i].days:[n[i].days]):[0,1,2,3,4,5,6],t.push({start:n[i].start,end:n[i].end,days:n[i].days}));this.con.dateRanges=t}if(0<this.con.tooltips.length){t=[];var a,n,s=this.con.tooltips;for(e=s.length,i=0;i<e;i++)s[i]instanceof Object&&s[i].date&&(s[i].date instanceof Array?(a=c(s[i].date[0]||!1,!0,!0),n=c(s[i].date[1]||!1,!0,!0)||a):a=n=c(s[i].date||!1,!0,!0),a&&t.push({date:a!==n?[a,n]:a,text:s[i].text||"Tooltip",color:s[i].color||"inherit",element:s[i].element||(r=d.createElement("DIV"),r.className="calendar-tooltip",r.innerHTML='<div class="tooltip-inner">'+s[i].text||"Tooltip</div>",r)}));this.con.tooltips=t}var r;return this},bind:function(){var e=this;return void 0===this._bind&&(this.e.addEventListener("focusin",function(t){e.open.call(e)}),this.e.addEventListener("keyup",function(t){e.callback.call(e,t)}),d.addEventListener("keyup",function(t){e.dt.contains(t.target)&&e.callback.call(e,t)}),d.addEventListener("click",function(t){e.dt.contains(t.target)?e.callback.call(e,t):!e.e.contains(t.target)&&u(e.dt,"calendar-open")&&(t.target==e.dt||t.target==e.e||e.con.stayOpen||e.close.call(e))}),d.addEventListener("mouseover",function(t){e.dt.contains(t.target)&&e.callback.call(e,t)}),this._bind=!0),this},callback:function(t){var e,i=t.target,a="getAttribute",n="data-action",s=i[a](n)?i:i.parentElement[a](n)?i.parentElement:i,r="data-tooltip";if("mouseover"==t.type&&(!1!==(e=i[a](r)?i:!!s[a](r)&&s)?this.dt.querySelector("#tooltip-"+e[a](r)+"-"+e[a](r+"-time"))||this.showTooltip(e[a](r),e,e[a](r+"-time")):this.dt.querySelector(".calendar-tooltip:not(.remove)")&&this.hideTooltip(this.dt.querySelector(".calendar-tooltip").id.slice(8))),"click"==t.type){if(!s||1!=t.buttons&&1!=(t.which||t.button))return;if(s.hasAttribute("data-disabled"))return;switch(s[a](n)){case"prev":case"next":return this.browseView(s[a](n));case"cancel":this.con.stayOpen||this.close();break;case"submit":return this.con.stayOpen||this.close(),this.selectDate(this.fetchDate(parseInt(s[a]("data-date"))));case"view":return this.switchDate(s[a]("data-year")||null,s[a]("data-month")||null,s[a]("data-day")||null),this.switchView(s[a]("data-view"))}}if("keyup"==t.type){if("INPUT"!=t.target.tagName&&t.target!==this.e&&/calendar-(static|close)/i.test(this.dt.className))return!1;13==(t.keyCode||t.which)&&(this.selectDate(this.fetchDate(this.select)),t.stopPropagation(),this.con.stayOpen||this.close()),27==(t.keyCode||t.which)&&(this.con.stayOpen||this.close())}},trigger:function(t){var e={bubbles:!1,cancelable:!0,detail:{args:arguments,self:this}};"change"==t&&(s(this.e,"input",e),s(this.e,"change",e)),s(this.dt,"tail::"+t,e);for(var i=(this.events[t]||[]).length,a=0;a<i;a++)this.events[t][a].cb.apply(this,function(t,e,i){for(var a=e.length,n=0;n<a;++n)t[n-1]=e[n];return t[n]=i,t}(new Array(arguments.length),arguments,this.events[t][a].args));return!0},calcPosition:function(){var t=this.dt.style,e=h.getComputedStyle(this.dt),i=parseInt(e.marginLeft)+parseInt(e.marginRight),a=parseInt(e.marginTop)+parseInt(e.marginBottom),n=this.e.getBoundingClientRect().top+h.scrollY,s=this.e.getBoundingClientRect().left-h.scrollX,r=this.e.offsetWidth||0,o=this.e.offsetHeight||0;switch(t.visibility="hidden",this.con.position){case"top":var c=n-(this.dt.offsetHeight+a),l=s+r/2-(this.dt.offsetWidth/2+i/2);break;case"left":c=n+o/2-(this.dt.offsetHeight/2+a),l=s-(this.dt.offsetWidth+i);break;case"right":c=n+o/2-(this.dt.offsetHeight/2+a),l=s+r;break;default:c=n+o,l=s+r/2-(this.dt.offsetWidth/2+i/2)}return t.top=(0<=c?c:this.e.offsetTop)+"px",t.left=(0<=l?l:0)+"px",t.visibility="visible",this},convertDate:function(t,e){var i,a={H:String("00"+t.getHours()).toString().slice(-2),G:(i=t.getHours(),i%12?i%12:12),A:12<=t.getHours()?"PM":"AM",a:12<=t.getHours()?"pm":"am",i:String("00"+t.getMinutes()).toString().slice(-2),s:String("00"+t.getSeconds()).toString().slice(-2),Y:t.getFullYear(),y:parseInt(t.getFullYear().toString().slice(2)),m:String("00"+(t.getMonth()+1)).toString().slice(-2),M:this.__.months[t.getMonth()].slice(0,3),F:this.__.months[t.getMonth()],d:String("00"+t.getDate()).toString().slice(-2),D:this.__.days[t.getDay()],l:this.__.shorts[t.getDay()].toLowerCase()};return e.replace(/([HGismd]{1,2}|[Y]{2,4}|y{2})/g,function(t){return 4==t.length||2==t.length?a[t.slice(-1)].toString().slice(-Math.abs(t.length)):1==t.length&&"0"==t[0]?a[t.slice(-1)].toString().slice(-1):a[t.slice(-1)].toString()}).replace(/(A|a|M|F|D|l)/g,function(t){return a[t]})},renderCalendar:function(){var t=["tail-datetime-calendar","calendar-close"],e=!0===this.con.classNames?this.e.className.split(" "):this.con.classNames;if(["top","left","right","bottom"].indexOf(this.con.position)<0){var i=d.querySelector(this.con.position);t.push("calendar-static")}(!0===this.con.rtl||0<=["ar","he","mdr","sam","syr"].indexOf(this.con.rtl))&&t.push("rtl"),this.con.stayOpen&&t.push("calendar-stay"),(e="function"==typeof e.split?e.split(" "):e)instanceof Array&&(t=t.concat(e));var a=p("DIV",t),n=!1;if(a.id="tail-datetime-"+this.id,this.con.dateFormat?n='<span class="action action-prev" data-action="prev"></span><span class="label" data-action="view" data-view="up"></span><span class="action action-next" data-action="next"></span>':this.con.timeFormat&&(n='<span class="action action-submit" data-action="submit"></span><span class="label"></span><span class="action action-cancel" data-action="cancel"></span>'),a.innerHTML=n?'<div class="calendar-actions">'+n+"</div>":"",this.con.dateFormat&&this.renderDatePicker(a,this.con.viewDefault),this.con.timeFormat&&this.renderTimePicker(a),this.con.closeButton&&!i){var s=p("BUTTON","calendar-close"),r=this;s.addEventListener("click",function(t){t.preventDefault(),r.close()}),a.appendChild(s)}return(i||d.body).appendChild(a),a},renderDatePicker:function(t,e){if((!e||["decades","years","months","days"].indexOf(e)<0)&&(e=this.con.viewDays?"days":this.con.viewMonths?"months":this.con.viewYears?"years":!!this.con.viewDecades&&"decades"),!e||!this.con["view"+r(e)]||!this.con.dateFormat)return!1;var i=d.createElement("DIV");return i.className="calendar-datepicker calendar-view-"+e,i.innerHTML=this["view"+r(e)](),t.querySelector(".calendar-datepicker")?t.replaceChild(i,t.querySelector(".calendar-datepicker")):t.appendChild(i),this.view.type=e,this.handleLabel(t)},renderTimePicker:function(t){if(!this.con.timeFormat)return!1;var e,i,a=[],n=0;if(this.con.time12h){var s=12<this.view.date.getHours()?'checked="checked" ':"";a.push('<label class="timepicker-switch" data-am="AM" data-pm="PM"><input type="checkbox" value="1" data-input="PM" '+s+"/><span></span></label>")}for(var r in{Hours:0,Minutes:0,Seconds:0})!1!==this.con["time"+r]?((e=d.createElement("INPUT")).type="text",e.disabled=null===this.con["time"+r],e.setAttribute("min","Hours"===r&&this.con.time12h?"01":"00"),e.setAttribute("max","Hours"!==r?"60":this.con.time12h?"13":"24"),e.setAttribute("step",this.con["timeStep"+r]),e.setAttribute("value",(i=this.view.date["get"+r]())<10?"0"+i:i),e.setAttribute("pattern","d*"),e.setAttribute("inputmode","numeric"),e.setAttribute("data-input",r.toLowerCase()),a.push('<div class="timepicker-field timepicker-'+r.toLowerCase()+'">'+e.outerHTML+'<button class="picker-step step-up"></button><button class="picker-step step-down"></button><label>'+this.__.time[n++]+"</label></div>")):a.push((n++,null));var o=p("DIV","calendar-timepicker"),c=this;o.innerHTML=a.join("\n");var l=o.querySelectorAll("input");for(n=0;n<l.length;n++)"checkbox"!==l[n].type?(l[n].addEventListener("input",function(t){c.handleTime.call(c,this)}),l[n].addEventListener("keydown",function(t){var e=event.keyCode||event.which||0;if(38===e||40===e)return t.preventDefault(),c.handleStep.call(c,this,38===e?"up":"down"),!1})):l[n].addEventListener("change",function(t){c.handleTime.call(c,this)});for(l=o.querySelectorAll("button"),n=0;n<l.length;n++)l[n].addEventListener("mousedown",function(t){t.preventDefault();var e=this.parentElement.querySelector("input");return c.handleStep.call(c,e,u(this,"step-up")?"up":"down"),!1});var h=t.querySelector(".calendar-timepicker");return t[h?"replaceChild":"appendChild"](o,h),this.handleLabel(t)},handleTime:function(t){this.con.time12h&&"checkbox"===t.type&&(this.ampm=t.checked);var e=t.parentElement.parentElement;e=[e.querySelector("input[data-input=hours]")||{value:0},e.querySelector("input[data-input=minutes]")||{value:0},e.querySelector("input[data-input=seconds]")||{value:0}],this.selectTime(parseInt(e[0].value)+(this.ampm?12:0),parseInt(e[1].value),parseInt(e[2].value)),e[2].value=this.view.date.getSeconds(),e[1].value=this.view.date.getMinutes(),this.con.time12h?e[0].value=12<this.view.date.getHours()?this.view.date.getHours()-12:this.view.date.getHours():e[0].value=this.view.date.getHours()},handleStep:function(t,e,i){var a=null,n=parseInt(t.value),s=parseInt(t.getAttribute("min")),r=parseInt(t.getAttribute("max")),o=t.getAttribute("data-input"),c=parseInt(t.getAttribute("step"));if("up"===e?(a=r<=n+c||null,t.value=r<=n+c?13===r?1:0:n+c,this.ampm=!!this.con.time12h&&12<=this.view.date.getHours()+1):"down"===e&&(a=!(n-c<s)&&null,t.value=n-c<s?r-c:n-c,this.ampm=!!this.con.time12h&&this.view.date.getHours()-1<=0),t.value<10&&(t.value="0"+t.value),this.con.timeIncrement&&null!==a){var l=t.parentElement.previousElementSibling;l&&!1===l.disabled?this.handleStep(l.querySelector("input"),a?"up":"down",!0):"hours"==o&&this.view.date.setDate(this.view.date.getDate()+(a?1:-1))}if(void 0!==i&&!0===i)return!1;var h=t.parentElement.parentElement;if(this.selectTime(parseInt((h.querySelector("input[data-input=hours]")||{value:0}).value)+(this.ampm?12:0),parseInt((h.querySelector("input[data-input=minutes]")||{value:0}).value),parseInt((h.querySelector("input[data-input=seconds]")||{value:0}).value)),this.con.time12h){var d=t.parentElement.parentElement.querySelector("input[type=checkbox]");d&&d.checked!==12<this.view.date.getHours()&&(d.checked=12<this.view.date.getHours())}return!0},handleLabel:function(t){var e,i,a=t.querySelector(".label");switch(this.view.type){case"days":e=this.__.months[this.view.date.getMonth()]+", "+this.view.date.getFullYear();break;case"months":e=this.view.date.getFullYear();break;case"years":e=(i=parseInt(this.view.date.getFullYear().toString().slice(0,3)+"0"))+" - "+(i+10);break;case"decades":e=(i=parseInt(this.view.date.getFullYear().toString().slice(0,2)+"00"))+" - "+(i+100);break;case"time":e=this.__.header[3]}return a.innerText=e,t},viewDecades:function(){var t=this.view.date.getFullYear(),e=new Date(this.view.date.getTime()),i=this.con.today?(new Date).getYear():0;e.setFullYear(t-parseInt(t.toString()[3])-30);for(var a,n,s=[],r=[],o=1;o<=16;o++)a="calendar-decade"+(i>=e.getYear()&&i<=e.getYear()+10?" date-today":""),n='data-action="view" data-view="down" data-year="'+e.getFullYear()+'"',s.push('<td class="'+a+'" '+n+'><span class="inner">'+e.getFullYear()+" - "+(e.getFullYear()+10)+"</span></td>"),4<=o&&o%4==0&&(r.push("<tr>\n"+s.join("\n")+"\n</tr>"),s=[]),e.setFullYear(e.getFullYear()+10);return'<table class="calendar-decades"><thead><tr><th colspan="4">'+this.__.header[2]+"</th></tr></thead><tbody>"+r.join("\n")+"</tbody></table>"},viewYears:function(){var t=this.view.date.getFullYear(),e=new Date(this.view.date.getTime()),i=this.con.today?(new Date).getYear():0;e.setFullYear(t-parseInt(t.toString()[3])-2);for(var a,n,s=[],r=[],o=1;o<=16;o++)a="calendar-year"+(e.getYear()==i?" date-today":""),n='data-action="view" data-view="down" data-year="'+e.getFullYear()+'"',s.push('<td class="'+a+'" '+n+'><span class="inner">'+e.getFullYear()+"</span></td>"),4<=o&&o%4==0&&(r.push("<tr>\n"+s.join("\n")+"\n</tr>"),s=[]),e.setFullYear(e.getFullYear()+1);return'<table class="calendar-years"><thead><tr><th colspan="4">'+this.__.header[1]+"</th></tr></thead><tbody>"+r.join("\n")+"</tbody></table>"},viewMonths:function(){var t=this.__.months,e=this.con.today?(new Date).getMonth():-1;e=this.view.date.getYear()==(new Date).getYear()?e:-1;for(var i,a,n=[],s=[],r=0;r<12;r++)i="calendar-month"+(e==r?" date-today":""),a='data-action="view" data-view="down" data-month="'+r+'"',n.push('<td class="'+i+'" '+a+'><span class="inner">'+t[r]+"</span></td>"),3==n.length&&(s.push("<tr>\n"+n.join("\n")+"\n</tr>"),n=[]);return'<table class="calendar-months"><thead><tr><th colspan="3">'+this.__.header[0]+"</th></tr></thead><tbody>"+s.join("\n")+"</tbody></table>"},viewDays:function(){var i,t,e,a,n,s,r=new Date(this.view.date.getTime()),o=(new Date).toDateString(),c=r.getMonth(),l=[],h=[],d=[0,[]],u=([].concat(this.con.tooltips),[0,0]);for(r.setHours(0,0,0,0),r.setDate(1),r.setDate(1-(r.getDay()-this.con.weekStart));h.length<6;)i=r.getTime(),s=[].concat(this.con.dateRanges),e='data-action="submit" data-date="'+r.getTime()+'"',t="calendar-day date-"+(r.getMonth()>c?"next":r.getMonth()<c?"previous":"current"),this.con.today&&o==r.toDateString()&&(t+=" date-today"),this.con.dateBlacklist&&(i<this.con.dateStart||i>this.con.dateEnd)?d=[i<this.con.dateStart?this.con.dateStart:1/0,[0,1,2,3,4,5,6],!0]:0<this.con.dateRanges.length?s.filter(function(t){return t.start==1/0||i>=t.start&&i<=t.end?!(d=[t.end,t.days]):t.start>i},this):3==d.length&&(d=[0,[0,1,2,3,4,5,6]]),0<this.con.tooltips.length&&this.con.tooltips.filter(function(t,e){t.date instanceof Array?t.date[0]<=i&&t.date[1]>=i&&(u=[t.date[1],e,t.color]):t.date==i&&(u=[t.date,e,t.color])},this),u[0]<i&&(u=[0,0]),(n=d[0]>=i&&0<=d[1].indexOf(r.getDay()))&&this.con.dateBlacklist||!n&&!this.con.dateBlacklist?(t+=" date-disabled",e+=' data-disabled="true"'):0!==d[0]&&d[0]<=i&&(d=[0,[]]),this.select&&this.select.toDateString()==r.toDateString()&&(t+=" date-select"),a='<span class="inner">'+r.getDate()+"</span>",0<u[0]&&(t+=" date-tooltip",e+=' data-tooltip="'+u[1]+'" data-tooltip-time="'+i+'"',"inherit"!==u[2]?a+='<span class="tooltip-tick" style="background:'+u[2]+';"></span>':a+='<span class="tooltip-tick"></span>'),l.push('<td class="'+t+'" '+e+">"+a+"</td>"),7==l.length&&(h.push("<tr>\n"+l.join("\n")+"\n</tr>"),l=[]),r.setDate(r.getDate()+1);return h="<tbody>"+h.join("\n")+"</tbody>",'<table class="calendar-days">'+this.weekdays+h+"</table>"},showTooltip:function(t,e,i){var a,n=this.con.tooltips[t].element,s=n.style,r=this.dt.querySelector(".calendar-datepicker");s.cssText="opacity:0;visibility:hidden;",n.id="tooltip-"+t+"-"+i,r.appendChild(n),a=n.offsetWidth,n.offsetHeight,s.top=e.offsetTop+e.offsetHeight+"px",s.left=e.offsetLeft+e.offsetWidth/2-a/2+"px",s.visibility="visible",this.con.animate?(n.setAttribute("data-top",parseInt(s.top)),s.top=parseInt(s.top)+5+"px",function t(){parseFloat(s.top)>n.getAttribute("data-top")&&(s.top=parseFloat(s.top)-.5+"px"),(s.opacity=parseFloat(s.opacity)+.125)<1&&setTimeout(t,20)}()):s.opacity=1},hideTooltip:function(t){var e=this.dt.querySelector("#tooltip-"+t),i=e.style;this.con.animate?(e.className+=" remove",function t(){if(parseFloat(i.top)<parseInt(e.getAttribute("data-top"))+5&&(i.top=parseFloat(i.top)+.5+"px"),(i.opacity-=.125)<0)return(e.className="calendar-tooltip")?e.parentElement.removeChild(e):"";setTimeout(t,20)}()):e.parentElement.removeChild(e)},switchView:function(t){var e=[null,"days","months","years","decades",null];return-1==e.indexOf(t)&&("up"==t?t=e[(e.indexOf(this.view.type)||5)+1]||null:"down"==t&&(t=e[(e.indexOf(this.view.type)||1)-1]||null),t&&this.con["view"+r(t)]||(t=!1)),!!t&&(this.renderDatePicker(this.dt,t),this.trigger("view",t))},switchDate:function(t,e,i,a){return"auto"===i&&(i=this.view.date.getDate(),(1===this.view.date.getMonth()&&28<=i||30<=i)&&(i=(i=new Date(t,e+1,0)).getDate())),this.view.date.setFullYear(null==t?this.view.date.getFullYear():t,null==e?this.view.date.getMonth():e,i||this.view.date.getDate()),!0===a||this.switchView(this.view.type)},switchMonth:function(t,e){return"string"==typeof t&&(t=0<=["previous","prev"].indexOf(t)?-1:1,t=this.view.date.getMonth()+type),this.switchDate(e||this.getFullYear(),t)},switchYear:function(t){return"string"==typeof t&&(t=0<=["previous","prev"].indexOf(t)?-1:1,t=this.view.date.getFullYear()+type),this.switchDate(t)},browseView:function(t){switch(t=0<=["previous","prev"].indexOf(t)?-1:1,this.view.type){case"days":return this.switchDate(null,this.view.date.getMonth()+t,"auto");case"months":return this.switchDate(this.view.date.getFullYear()+t,null,"auto");case"years":return this.switchDate(this.view.date.getFullYear()+10*t,null,"auto");case"decades":return this.switchDate(this.view.date.getFullYear()+100*t,null,"auto")}return!1},fetchDate:function(t){t=c(t||!1)||this.view.date;var e=this.dt.querySelectorAll("input[type=number]");return e&&3==e.length&&t.setHours(e[0].value||0,e[1].value||0,e[2].value||0,0),t},selectDate:function(t,e,i,a,n,s){var r=new Date,o=[];return this.con.dateFormat&&o.push(this.con.dateFormat),this.con.timeFormat&&o.push(this.con.timeFormat),this.select=t instanceof Date?t:new Date(t||(null==t?this.view.date.getFullYear():r.getFullYear()),e||(null==e?this.view.date.getMonth():r.getMonth()),i||(null==i?this.view.date.getDate():r.getDate()),a||(null==a?this.view.date.getHours():0),n||(null==n?this.view.date.getMinutes():0),s||(null==s?this.view.date.getSeconds():0)),this.view.date=new Date(this.select.getTime()),this.e.value=this.convertDate(this.select,o.join(" ")),this.e.setAttribute("data-value",this.select.getTime()),this.switchView("days"),this.trigger("change")},selectTime:function(t,e,i){return this.selectDate(void 0,void 0,void 0,t,e,i)},open:function(){if(!u(this.dt,"calendar-close"))return this;var e=this,i=this.dt.style;return i.display="block",i.opacity=this.con.animate?0:1,n(this.dt,"calendar-close"),a(this.dt,"calendar-idle"),u(this.dt,"calendar-static")||e.calcPosition(),function t(){if(1<=(i.opacity=parseFloat(i.opacity)+.125))return n(e.dt,"calendar-idle"),a(e.dt,"calendar-open"),e.trigger("open");setTimeout(t,20)}(),this},close:function(){if(!u(this.dt,"calendar-open"))return this;var e=this,i=this.dt.style;return i.display="block",i.opacity=this.con.animate?1:0,n(this.dt,"calendar-open"),a(this.dt,"calendar-idle"),function t(){if((i.opacity-=.125)<=0)return n(e.dt,"calendar-idle"),a(e.dt,"calendar-close"),i.display="none",e.trigger("close");setTimeout(t,20)}(),this},toggle:function(){return u(this.dt,"calendar-open")?this.close():u(this.dt,"calendar-close")?this.open():this},on:function(t,e,i){return!(["open","close","change","view"].indexOf(t)<0||"function"!=typeof e)&&(t in this.events||(this.events[t]=[]),this.events[t].push({cb:e,args:i instanceof Array?i:[]}),this)},remove:function(){return this.e.removeAttribute("data-tail-datetime"),this.e.removeAttribute("data-value"),this.dt.parentElement.removeChild(this.dt),this},reload:function(){return this.remove(),this.init()},config:function(t,e,i){if(t instanceof Object){for(var a in t)this.config(a,t[a],!1);return this.reload(),this.con}return void 0===t?this.con:t in this.con&&(void 0===e?this.con[t]:(this.con[t]=e,!1!==this.rebuild&&this.reload(),this))}},l});
taskmanager.js new
+714
@@ -0,0 +1,714 @@
1 +/**
2 +* @description MeshCentral ScriptTask
3 +* @author Ryan Blenis
4 +* @copyright
5 +* @license Apache-2.0
6 +*/
7 +
8 +'use strict';
9 +
10 +module.exports.createTaskManager = function (parent) {
11 + var obj = {};
12 + obj.parent = parent.webserver;
13 + obj.meshServer = parent;
14 + obj.db = null;
15 + obj.intervalTimer = null;
16 + obj.debug = obj.meshServer.debug;
17 + obj.VIEWS = __dirname + '/views/';
18 + obj.exports = [
19 + 'onDeviceRefreshEnd',
20 + 'resizeContent',
21 + 'historyData',
22 + 'variableData',
23 + 'malix_triggerOption'
24 + ];
25 +
26 + obj.malix_triggerOption = function(selectElem) {
27 + selectElem.options.add(new Option("ScriptTask - Run Script", "scripttask_runscript"));
28 + }
29 + obj.malix_triggerFields_scripttask_runscript = function() {
30 +
31 + }
32 + obj.resetQueueTimer = function() {
33 + clearTimeout(obj.intervalTimer);
34 + obj.intervalTimer = setInterval(obj.queueRun, 1 * 60 * 1000); // every minute
35 + };
36 +
37 + // Start the task manager
38 + obj.server_startup = function() {
39 + obj.meshServer.pluginHandler.scripttask_db = require (__dirname + '/db.js').CreateDB(obj.meshServer);
40 + obj.db = obj.meshServer.pluginHandler.scripttask_db;
41 + obj.resetQueueTimer();
42 + };
43 +
44 + obj.onDeviceRefreshEnd = function() {
45 + pluginHandler.registerPluginTab({ tabTitle: 'ScriptTask', tabId: 'pluginScriptTask' });
46 + QA('pluginScriptTask', '<iframe id="pluginIframeScriptTask" style="width: 100%; height: 800px;" scrolling="no" frameBorder=0 src="/pluginadmin.ashx?pin=scripttask&user=1" />');
47 + };
48 +
49 + /*
50 + // may not be needed, saving for later. Can be called to resize iFrame
51 + obj.resizeContent = function() {
52 + var iFrame = document.getElementById('pluginIframeScriptTask');
53 + var newHeight = 800;
54 + var sHeight = iFrame.contentWindow.document.body.scrollHeight;
55 + if (sHeight > newHeight) newHeight = sHeight;
56 + if (newHeight > 1600) newHeight = 1600;
57 + iFrame.style.height = newHeight + 'px';
58 + };
59 + */
60 +
61 + obj.queueRun = async function() {
62 + var onlineAgents = Object.keys(obj.meshServer.webserver.wsagents);
63 + //obj.debug('ScriptTask', 'Queue Running', Date().toLocaleString(), 'Online agents: ', onlineAgents);
64 +
65 + obj.db.getPendingJobs(onlineAgents)
66 + .then(function(jobs) {
67 + if (jobs.length == 0) return;
68 + //@TODO check for a large number and use taskLimiter to queue the jobs
69 + jobs.forEach(function(job) {
70 + obj.db.get(job.scriptId)
71 + .then(async function(script) {
72 + script = script[0];
73 + var foundVars = script.content.match(/#(.*?)#/g);
74 + var replaceVars = {};
75 + if (foundVars != null && foundVars.length > 0) {
76 + var foundVarNames = [];
77 + foundVars.forEach(function(fv) { foundVarNames.push(fv.replace(/^#+|#+$/g, '')); });
78 +
79 + var limiters = {
80 + scriptId: job.scriptId,
81 + nodeId: job.node,
82 + meshId: obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'],
83 + names: foundVarNames
84 + };
85 + var finvals = await obj.db.getVariables(limiters);
86 + var ordering = { 'global': 0, 'script': 1, 'mesh': 2, 'node': 3 }
87 + finvals.sort(function(a, b) { return (ordering[a.scope] - ordering[b.scope]) || a.name.localeCompare(b.name); });
88 + finvals.forEach(function(fv) { replaceVars[fv.name] = fv.value; });
89 + replaceVars['GBL:meshId'] = obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'];
90 + replaceVars['GBL:nodeId'] = job.node;
91 + //console.log('FV IS', finvals);
92 + //console.log('RV IS', replaceVars);
93 + }
94 + var dispatchTime = Math.floor(new Date() / 1000);
95 + var jObj = {
96 + action: 'task',
97 + subaction: 'triggerJob',
98 + jobId: job._id,
99 + scriptId: job.scriptId,
100 + replaceVars: replaceVars,
101 + scriptHash: script.contentHash,
102 + dispatchTime: dispatchTime
103 + };
104 + //obj.debug('ScriptTask', 'Sending job to agent');
105 + try {
106 + obj.meshServer.webserver.wsagents[job.node].send(JSON.stringify(jObj));
107 + obj.db.update(job._id, { dispatchTime: dispatchTime });
108 + } catch (ex) { }
109 + })
110 + .catch(function (ex) { console.log('task: Could not dispatch job.', ex) });
111 + });
112 + })
113 + .then(function() {
114 + obj.makeJobsFromSchedules();
115 + obj.cleanHistory();
116 + })
117 + .catch(function(ex) { console.log('task: Queue Run Error: ', ex); });
118 + };
119 +
120 + obj.cleanHistory = function() {
121 + if (Math.round(Math.random() * 100) == 99) {
122 + //obj.debug('Task', 'Running history cleanup');
123 + obj.db.deleteOldHistory();
124 + }
125 + };
126 +
127 + obj.downloadFile = function(req, res, user) {
128 + var id = req.query.dl;
129 + obj.db.get(id)
130 + .then(function(found) {
131 + if (found.length != 1) { res.sendStatus(401); return; }
132 + var file = found[0];
133 + res.setHeader('Content-disposition', 'attachment; filename=' + file.name);
134 + res.setHeader('Content-type', 'text/plain');
135 + //var fs = require('fs');
136 + res.send(file.content);
137 + });
138 + };
139 +
140 + obj.updateFrontEnd = async function(ids){
141 + if (ids.scriptId != null) {
142 + var scriptHistory = null;
143 + obj.db.getJobScriptHistory(ids.scriptId)
144 + .then(function(sh) {
145 + scriptHistory = sh;
146 + return obj.db.getJobSchedulesForScript(ids.scriptId);
147 + })
148 + .then(function(scriptSchedule) {
149 + var targets = ['*', 'server-users'];
150 + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'historyData', scriptId: ids.scriptId, nodeId: null, scriptHistory: scriptHistory, nodeHistory: null, scriptSchedule: scriptSchedule });
151 + });
152 + }
153 + if (ids.nodeId != null) {
154 + var nodeHistory = null;
155 + obj.db.getJobNodeHistory(ids.nodeId)
156 + .then(function(nh) {
157 + nodeHistory = nh;
158 + return obj.db.getJobSchedulesForNode(ids.nodeId);
159 + })
160 + .then(function(nodeSchedule) {
161 + var targets = ['*', 'server-users'];
162 + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'historyData', scriptId: null, nodeId: ids.nodeId, scriptHistory: null, nodeHistory: nodeHistory, nodeSchedule: nodeSchedule });
163 + });
164 + }
165 + if (ids.tree === true) {
166 + obj.db.getScriptTree()
167 + .then(function(tree) {
168 + var targets = ['*', 'server-users'];
169 + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'newScriptTree', tree: tree });
170 + });
171 + }
172 + if (ids.variables === true) {
173 + obj.db.getVariables()
174 + .then(function(vars) {
175 + var targets = ['*', 'server-users'];
176 + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'variableData', vars: vars });
177 + });
178 + }
179 + };
180 +
181 + obj.handleAdminReq = function(req, res, user) {
182 + if ((user.siteadmin & 0xFFFFFFFF) == 1 && req.query.admin == 1)
183 + {
184 + // admin wants admin, grant
185 + var vars = {};
186 + res.render(obj.VIEWS + 'admin', vars);
187 + return;
188 + } else if (req.query.admin == 1 && (user.siteadmin & 0xFFFFFFFF) == 0) {
189 + // regular user wants admin
190 + res.sendStatus(401);
191 + return;
192 + } else if (req.query.user == 1) {
193 + // regular user wants regular access, grant
194 + if (req.query.dl != null) return obj.downloadFile(req, res, user);
195 + var vars = {};
196 +
197 + if (req.query.edit == 1) { // edit script
198 + if (req.query.id == null) return res.sendStatus(401);
199 + obj.db.get(req.query.id)
200 + .then(function(scripts) {
201 + if (scripts[0].filetype == 'proc') {
202 + vars.procData = JSON.stringify(scripts[0]);
203 + res.render(obj.VIEWS + 'procedit', vars);
204 + } else {
205 + vars.scriptData = JSON.stringify(scripts[0]);
206 + res.render(obj.VIEWS + 'scriptedit', vars);
207 + }
208 + });
209 + return;
210 + } else if (req.query.schedule == 1) {
211 + var vars = {};
212 + res.render(obj.VIEWS + 'schedule', vars);
213 + return;
214 + }
215 + // default user view (tree)
216 + vars.scriptTree = 'null';
217 + obj.db.getScriptTree()
218 + .then(function(tree) {
219 + vars.scriptTree = JSON.stringify(tree);
220 + res.render(obj.VIEWS + 'user', vars);
221 + });
222 + return;
223 + } else if (req.query.include == 1) {
224 + switch (req.query.path.split('/').pop().split('.').pop()) {
225 + case 'css': res.contentType('text/css'); break;
226 + case 'js': res.contentType('text/javascript'); break;
227 + }
228 + res.sendFile(__dirname + '/includes/' + req.query.path); // don't freak out. Express covers any path issues.
229 + return;
230 + }
231 + res.sendStatus(401);
232 + return;
233 + };
234 +
235 + obj.historyData = function (message) {
236 + if (typeof pluginHandler.scripttask.loadHistory == 'function') pluginHandler.scripttask.loadHistory(message);
237 + if (typeof pluginHandler.scripttask.loadSchedule == 'function') pluginHandler.scripttask.loadSchedule(message);
238 + };
239 +
240 + obj.variableData = function (message) {
241 + if (typeof pluginHandler.scripttask.loadVariables == 'function') pluginHandler.scripttask.loadVariables(message);
242 + };
243 +
244 + obj.determineNextJobTime = function(s) {
245 + var nextTime = null;
246 + var nowTime = Math.floor(new Date() / 1000);
247 +
248 + // special case: we've reached the end of our run
249 + if (s.endAt !== null && s.endAt <= nowTime) {
250 + return nextTime;
251 + }
252 +
253 + switch (s.recur) {
254 + case 'once':
255 + if (s.nextRun == null) nextTime = s.startAt;
256 + else nextTime = null;
257 + break;
258 + case 'minutes':
259 + /*var lRun = s.nextRun || nowTime;
260 + if (lRun == null) lRun = nowTime;
261 + nextTime = lRun + (s.interval * 60);
262 + if (s.startAt > nextTime) nextTime = s.startAt;*/
263 + if (s.nextRun == null) { // hasn't run yet, set to start time
264 + nextTime = s.startAt;
265 + break;
266 + }
267 + nextTime = s.nextRun + (s.interval * 60);
268 + // this prevents "catch-up" tasks being scheduled if an endpoint is offline for a long period of time
269 + // e.g. always make sure the next scheduled time is relevant to the scheduled interval, but in the future
270 + if (nextTime < nowTime) {
271 + // initially I was worried about this causing event loop lockups
272 + // if there was a long enough time gap. Testing over 50 years of backlog for a 3 min interval
273 + // still ran under a fraction of a second. Safe to say this approach is safe! (~8.5 million times)
274 + while (nextTime < nowTime) {
275 + nextTime = nextTime + (s.interval * 60);
276 + }
277 + }
278 + if (s.startAt > nextTime) nextTime = s.startAt;
279 + break;
280 + case 'hourly':
281 + if (s.nextRun == null) { // hasn't run yet, set to start time
282 + nextTime = s.startAt;
283 + break;
284 + }
285 + nextTime = s.nextRun + (s.interval * 60 * 60);
286 + if (nextTime < nowTime) {
287 + while (nextTime < nowTime) {
288 + nextTime = nextTime + (s.interval * 60 * 60);
289 + }
290 + }
291 + if (s.startAt > nextTime) nextTime = s.startAt;
292 + break;
293 + case 'daily':
294 + if (s.nextRun == null) { // hasn't run yet, set to start time
295 + nextTime = s.startAt;
296 + break;
297 + }
298 + nextTime = s.nextRun + (s.interval * 60 * 60 * 24);
299 + if (nextTime < nowTime) {
300 + while (nextTime < nowTime) {
301 + nextTime = nextTime + (s.interval * 60 * 60 * 24);
302 + }
303 + }
304 + if (s.startAt > nextTime) nextTime = s.startAt;
305 + break;
306 + case 'weekly':
307 + var tempDate = new Date();
308 + var nowDate = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate());
309 +
310 + if (s.daysOfWeek.length == 0) {
311 + nextTime = null;
312 + break;
313 + }
314 + s.daysOfWeek = s.daysOfWeek.map(function (el) { Number(el) });
315 + var baseTime = s.startAt;
316 + //console.log('dow is ', s.daysOfWeek);
317 + var lastDayOfWeek = Math.max(...s.daysOfWeek);
318 + var startX = 0;
319 + //console.log('ldow is ', lastDayOfWeek);
320 + if (s.nextRun != null) {
321 + baseTime = s.nextRun;
322 + //console.log('basetime 2: ', baseTime);
323 + if (nowDate.getDay() == lastDayOfWeek) {
324 + baseTime = baseTime + ( s.interval * 604800 ) - (lastDayOfWeek * 86400);
325 + //console.log('basetime 3: ', baseTime);
326 + }
327 + startX = 0;
328 + } else if (s.startAt < nowTime) {
329 + baseTime = Math.floor(nowDate.getTime() / 1000);
330 + //console.log('basetime 4: ', baseTime);
331 + }
332 + //console.log('startX is: ', startX);
333 + //var secondsFromMidnight = nowTimeDate.getSeconds() + (nowTimeDate.getMinutes() * 60) + (nowTimeDate.getHours() * 60 * 60);
334 + //console.log('seconds from midnight: ', secondsFromMidnight);
335 + //var dBaseTime = new Date(0); dBaseTime.setUTCSeconds(baseTime);
336 + //var dMidnight = new Date(dBaseTime.getFullYear(), dBaseTime.getMonth(), dBaseTime.getDate());
337 + //baseTime = Math.floor(dMidnight.getTime() / 1000);
338 + for (var x = startX; x <= 7; x++){
339 + var checkDate = baseTime + (86400 * x);
340 + var d = new Date(0); d.setUTCSeconds(checkDate);
341 + var dm = new Date(d.getFullYear(), d.getMonth(), d.getDate());
342 +
343 + console.log('testing date: ', dm.toLocaleString()); // dMidnight.toLocaleString());
344 + //console.log('if break check :', (s.daysOfWeek.indexOf(d.getDay()) !== -1 && checkDate >= nowTime));
345 + //console.log('checkDate vs nowTime: ', (checkDate - nowTime), ' if positive, nowTime is less than checkDate');
346 + if (s.nextRun == null && s.daysOfWeek.indexOf(dm.getDay()) !== -1 && dm.getTime() >= nowDate.getTime()) break;
347 + if (s.daysOfWeek.indexOf(dm.getDay()) !== -1 && dm.getTime() > nowDate.getTime()) break;
348 + //if (s.daysOfWeek.indexOf(d.getDay()) !== -1 && Math.floor(d.getTime() / 1000) >= nowTime) break;
349 + }
350 + var sa = new Date(0); sa.setUTCSeconds(s.startAt);
351 + var sad = new Date(sa.getFullYear(), sa.getMonth(), sa.getDate());
352 + var diff = (sa.getTime() - sad.getTime()) / 1000;
353 + nextTime = Math.floor(dm.getTime() / 1000) + diff;
354 + //console.log('next schedule is ' + d.toLocaleString());
355 + break;
356 + default:
357 + nextTime = null;
358 + break;
359 + }
360 +
361 + if (s.endAt != null && nextTime > s.endAt) nextTime = null; // if the next time reaches the bound of the endAt time, nullify
362 +
363 + return nextTime;
364 + };
365 +
366 + obj.makeJobsFromSchedules = function(scheduleId) {
367 + //obj.debug('ScriptTask', 'makeJobsFromSchedules starting');
368 + return obj.db.getSchedulesDueForJob(scheduleId)
369 + .then(function(schedules) {
370 + //obj.debug('ScriptTask', 'Found ' + schedules.length + ' schedules to process. Current time is: ' + Math.floor(new Date() / 1000));
371 + if (schedules.length) {
372 + schedules.forEach(function(s) {
373 + var nextJobTime = obj.determineNextJobTime(s);
374 + var nextJobScheduled = false;
375 + if (nextJobTime === null) {
376 + //obj.debug('ScriptTask', 'Removing Job Schedule for', JSON.stringify(s));
377 + obj.db.removeJobSchedule(s._id);
378 + } else {
379 + //obj.debug('ScriptTask', 'Scheduling Job for', JSON.stringify(s));
380 + obj.db.get(s.scriptId)
381 + .then(function(scripts) {
382 + // if a script is scheduled to run, but a previous run hasn't completed,
383 + // don't schedule another job for the same (device probably offline).
384 + // results in the minimum jobs running once an agent comes back online.
385 + return obj.db.getIncompleteJobsForSchedule(s._id)
386 + .then(function(jobs) {
387 + if (jobs.length > 0) { /* obj.debug('Task', 'Skipping job creation'); */ return Promise.resolve(); }
388 + else { /* obj.debug('Task', 'Creating new job'); */ nextJobScheduled = true; return obj.db.addJob( { scriptId: s.scriptId, scriptName: scripts[0].name, node: s.node, runBy: s.scheduledBy, dontQueueUntil: nextJobTime, jobSchedule: s._id } ); }
389 + });
390 + })
391 + .then(function() {
392 + if (nextJobScheduled) { /* obj.debug('Plugin', 'ScriptTask', 'Updating nextRun time'); */ return obj.db.update(s._id, { nextRun: nextJobTime }); }
393 + else { /* obj.debug('Plugin', 'ScriptTask', 'NOT updating nextRun time'); */ return Promise.resolve(); }
394 + })
395 + .then(function() {
396 + obj.updateFrontEnd( { scriptId: s.scriptId, nodeId: s.node } );
397 + })
398 + .catch(function(ex) { console.log('Task: Error managing job schedules: ', ex); });
399 + }
400 + });
401 + }
402 + });
403 + };
404 +
405 + obj.deleteElement = function (command) {
406 + var delObj = null;
407 + obj.db.get(command.id)
408 + .then(function(found) {
409 + var file = found[0];
410 + delObj = {...{}, ...found[0]};
411 + return file;
412 + })
413 + .then(function(file) {
414 + if (file.type == 'folder') return obj.db.deleteByPath(file.path); //@TODO delete schedules for scripts within folders
415 + if (file.type == 'script') return obj.db.deleteSchedulesForScript(file._id);
416 + if (file.type == 'jobSchedule') return obj.db.deletePendingJobsForSchedule(file._id);
417 + })
418 + .then(function() {
419 + return obj.db.delete(command.id)
420 + })
421 + .then(function() {
422 + var updateObj = { tree: true };
423 + if (delObj.type == 'jobSchedule') {
424 + updateObj.scriptId = delObj.scriptId;
425 + updateObj.nodeId = delObj.node;
426 + }
427 + return obj.updateFrontEnd( updateObj );
428 + })
429 + .catch(function(ex) { console.log('Task: Error deleting ', ex.stack); });
430 + };
431 +
432 + // Process 'task' commands received by an agent
433 + obj.agentAction = function (command, agent) {
434 + console.log('task-agentAction', command);
435 + switch (command.subaction) {
436 + case 'getScript':
437 + // TODO
438 + break;
439 + case 'clearAllPendingTasks':
440 + // TODO
441 + break;
442 + case 'taskComplete':
443 + // TODO
444 + break;
445 + }
446 + }
447 +
448 + obj.serveraction = function(command, myparent, grandparent) {
449 + switch (command.subaction) {
450 + case 'addScript':
451 + obj.db.addScript(command.name, command.content, command.path, command.filetype)
452 + .then(function() { obj.updateFrontEnd( { tree: true } ); });
453 + break;
454 + case 'new':
455 + var parent_path = '', new_path = '';
456 + obj.db.get(command.parent_id)
457 + .then(function(found) { if (found.length > 0) { var file = found[0]; parent_path = file.path; } else { parent_path = 'Shared'; } })
458 + .then(function () { obj.db.addScript(command.name, '', parent_path, command.filetype); })
459 + .then(function() { obj.updateFrontEnd( { tree: true } ); });
460 + break;
461 + case 'rename':
462 + obj.db.get(command.id)
463 + .then(function(docs) {
464 + var doc = docs[0];
465 + if (doc.type == 'folder') {
466 + console.log('old', doc.path, 'new', doc.path.replace(doc.path, command.name));
467 + return obj.db.update(command.id, { path: doc.path.replace(doc.name, command.name) })
468 + .then(function() { // update sub-items
469 + return obj.db.getByPath(doc.path)
470 + })
471 + .then(function(found) {
472 + if (found.length > 0) {
473 + var proms = [];
474 + found.forEach(function(f) { proms.push(obj.db.update(f._id, { path: doc.path.replace(doc.name, command.name) } )); })
475 + return Promise.all(proms);
476 + }
477 + })
478 + } else {
479 + return Promise.resolve();
480 + }
481 + })
482 + .then(function() {
483 + obj.db.update(command.id, { name: command.name })
484 + })
485 + .then(function() {
486 + return obj.db.updateScriptJobName(command.id, command.name);
487 + })
488 + .then(function() {
489 + obj.updateFrontEnd( { scriptId: command.id, nodeId: command.currentNodeId, tree: true } );
490 + });
491 + break;
492 + case 'move':
493 + var toPath = null, fromPath = null, parentType = null;
494 + obj.db.get(command.to)
495 + .then(function(found) { // get target data
496 + if (found.length > 0) {
497 + var file = found[0];
498 + toPath = file.path;
499 + } else throw Error('Target destination not found');
500 + })
501 + .then(function() { // get item to be moved
502 + return obj.db.get(command.id);
503 + })
504 + .then(function(found) { // set item to new location
505 + var file = found[0];
506 + if (file.type == 'folder') {
507 + fromPath = file.path;
508 + toPath += '/' + file.name;
509 + parentType = 'folder';
510 + if (file.name == 'Shared' && file.path == 'Shared') throw Error('Cannot move top level directory: Shared');
511 + }
512 + return obj.db.update(command.id, { path: toPath } );
513 + })
514 + .then(function() { // update sub-items
515 + return obj.db.getByPath(fromPath)
516 + })
517 + .then(function(found) {
518 + if (found.length > 0) {
519 + var proms = [];
520 + found.forEach(function(f) {
521 + proms.push(obj.db.update(f._id, { path: toPath } ));
522 + })
523 + return Promise.all(proms);
524 + }
525 + })
526 + .then(function() {
527 + return obj.updateFrontEnd( { tree: true } );
528 + })
529 + .catch(function(ex) { console.log('Task: Error moving ', ex.stack); });
530 + break;
531 + case 'newFolder':
532 + var parent_path = '';
533 + var new_path = '';
534 +
535 + obj.db.get(command.parent_id)
536 + .then(function(found) {
537 + if (found.length > 0) {
538 + var file = found[0];
539 + parent_path = file.path;
540 + } else {
541 + parent_path = 'Shared';
542 + }
543 + })
544 + .then(function() {
545 + new_path = parent_path + '/' + command.name;
546 + })
547 + .then(function() {
548 + return obj.db.addFolder(command.name, new_path);
549 + })
550 + .then(function () {
551 + return obj.updateFrontEnd( { tree: true } );
552 + })
553 + .catch(function(ex) { console.log('Task: Error creating new folder ', ex.stack); });
554 + break;
555 + case 'delete':
556 + obj.deleteElement(command);
557 + break;
558 + case 'addScheduledJob':
559 + /* {
560 + scriptId: scriptId,
561 + node: s,
562 + scheduledBy: myparent.user.name,
563 + recur: command.recur, // [once, minutes, hourly, daily, weekly, monthly]
564 + interval: x,
565 + daysOfWeek: x, // only used for weekly recur val
566 + // onTheXDay: x, // only used for monthly
567 + startAt: x,
568 + endAt: x,
569 + runCountLimit: x,
570 + lastRun: x,
571 + nextRun: x,
572 + type: "scheduledJob"
573 + } */
574 + var sj = command.schedule;
575 +
576 + var sched = {
577 + scriptId: command.scriptId,
578 + node: null,
579 + scheduledBy: myparent.user.name,
580 + recur: sj.recur,
581 + interval: sj.interval,
582 + daysOfWeek: sj.dayVals,
583 + startAt: sj.startAt,
584 + endAt: sj.endAt,
585 + lastRun: null,
586 + nextRun: null,
587 + type: "jobSchedule"
588 + };
589 + var sel = command.nodes;
590 + var proms = [];
591 + if (Array.isArray(sel)) {
592 + sel.forEach(function(s) {
593 + var sObj = {...sched, ...{ node: s }};
594 + proms.push(obj.db.addJobSchedule( sObj ));
595 + });
596 + } else { test.push(sObj);
597 + proms.push(obj.db.addJobSchedule( sObj ));
598 + }
599 + Promise.all(proms)
600 + .then(function() {
601 + obj.makeJobsFromSchedules();
602 + return Promise.resolve();
603 + })
604 + .catch(function(ex) { console.log('Task: Error adding schedules. The error was: ', ex); });
605 + break;
606 + case 'runScript':
607 + var scriptId = command.scriptId;
608 + var sel = command.nodes;
609 + var proms = [];
610 + if (Array.isArray(sel)) {
611 + sel.forEach(function(s) {
612 + proms.push(obj.db.addJob( { scriptId: scriptId, node: s, runBy: myparent.user.name } ));
613 + });
614 + } else {
615 + proms.push(obj.db.addJob( { scriptId: scriptId, node: sel, runBy: myparent.user.name } ));
616 + }
617 + Promise.all(proms)
618 + .then(function() {
619 + return obj.db.get(scriptId);
620 + })
621 + .then(function(scripts) {
622 + return obj.db.updateScriptJobName(scriptId, scripts[0].name);
623 + })
624 + .then(function() {
625 + obj.resetQueueTimer();
626 + obj.queueRun();
627 + obj.updateFrontEnd( { scriptId: scriptId, nodeId: command.currentNodeId } );
628 + });
629 + break;
630 + case 'getScript':
631 + //obj.debug('ScriptTask', 'getScript Triggered', JSON.stringify(command));
632 + obj.db.get(command.scriptId)
633 + .then(function(script) {
634 + myparent.send(JSON.stringify({
635 + action: 'task',
636 + subaction: 'cacheScript',
637 + nodeid: myparent.dbNodeKey,
638 + rights: true,
639 + sessionid: true,
640 + script: script[0]
641 + }));
642 + });
643 + break;
644 + case 'jobComplete':
645 + //obj.debug('ScriptTask', 'jobComplete Triggered', JSON.stringify(command));
646 + var jobNodeHistory = null, scriptHistory = null;
647 + var jobId = command.jobId, retVal = command.retVal, errVal = command.errVal, dispatchTime = command.dispatchTime;
648 + var completeTime = Math.floor(new Date() / 1000);
649 + obj.db.update(jobId, {
650 + completeTime: completeTime,
651 + returnVal: retVal,
652 + errorVal: errVal,
653 + dispatchTime: dispatchTime
654 + })
655 + .then(function() {
656 + return obj.db.get(jobId)
657 + .then(function(jobs) {
658 + return Promise.resolve(jobs[0].jobSchedule);
659 + })
660 + .then(function(sId) {
661 + if (sId == null) return Promise.resolve();
662 + return obj.db.update(sId, { lastRun: completeTime } )
663 + .then(function() {
664 + obj.makeJobsFromSchedules(sId);
665 + });
666 + });
667 + })
668 + .then(function() {
669 + obj.updateFrontEnd( { scriptId: command.scriptId, nodeId: myparent.dbNodeKey } );
670 + })
671 + .catch(function(ex) { console.log('Task: Failed to complete job. ', ex); });
672 + // update front end by eventing
673 + break;
674 + case 'loadNodeHistory':
675 + obj.updateFrontEnd( { nodeId: command.nodeId } );
676 + break;
677 + case 'loadScriptHistory':
678 + obj.updateFrontEnd( { scriptId: command.scriptId } );
679 + break;
680 + case 'editScript':
681 + obj.db.update(command.scriptId, { type: command.scriptType, name: command.scriptName, content: command.scriptContent })
682 + .then(function() { obj.updateFrontEnd( { scriptId: command.scriptId, tree: true } ); });
683 + break;
684 + case 'clearAllPendingJobs':
685 + obj.db.deletePendingJobsForNode(myparent.dbNodeKey);
686 + break;
687 + case 'loadVariables':
688 + obj.updateFrontEnd( { variables: true } );
689 + break;
690 + case 'newVar':
691 + obj.db.addVariable(command.name, command.scope, command.scopeTarget, command.value)
692 + .then(function() { obj.updateFrontEnd( { variables: true } ); })
693 + break;
694 + case 'editVar':
695 + obj.db.update(command.id, {
696 + name: command.name,
697 + scope: command.scope,
698 + scopeTarget: command.scopeTarget,
699 + value: command.value
700 + })
701 + .then(function() { obj.updateFrontEnd( { variables: true } ); })
702 + break;
703 + case 'deleteVar':
704 + obj.db.delete(command.id)
705 + .then(function() { obj.updateFrontEnd( { variables: true } ); })
706 + break;
707 + default:
708 + console.log('Task: unknown action');
709 + break;
710 + }
711 + };
712 +
713 + return obj;
714 +}
\ No newline at end of file
views/task-schedule.handlebars new
+249
@@ -0,0 +1,249 @@
1 +<html>
2 +<head>
3 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
4 + <link rel="stylesheet" type="text/css" href="/public/tail.DateTime/tail.datetime-default-blue.min.css" />
5 + <style>
6 + body {
7 + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
8 + color: white;
9 + }
10 +
11 + #scriptContent {
12 + width: 80%;
13 + height: 80%;
14 + }
15 +
16 + #schedContentC {
17 + padding: 20px;
18 + }
19 +
20 + #controlBar button {
21 + cursor: pointer;
22 + }
23 +
24 + #scriptNameC {
25 + padding: 20px;
26 + }
27 +
28 + #scriptName {
29 + width: 300px;
30 + }
31 +
32 + #controlBar {
33 + padding: 5px;
34 + padding-left: 20px;
35 + }
36 +
37 + #left {
38 + height: 100%;
39 + width: 25%;
40 + float: left;
41 + }
42 +
43 + #right {
44 + height: 100%;
45 + width: 75%;
46 + float: right;
47 + }
48 +
49 + body {
50 + background-color: #036;
51 + }
52 +
53 + #intervalListC {
54 + list-style-type: none;
55 + }
56 +
57 + #daysListC {
58 + list-style-type: none;
59 + }
60 +
61 + .rOpt {
62 + height: 40px;
63 + }
64 +
65 + #daysListC {
66 + display: inline-grid;
67 + }
68 +
69 + li {
70 + padding: 2px;
71 + }
72 + </style>
73 +</head>
74 +<body onload="doOnLoad();">
75 + <script type="text/javascript" src="/public/tail.DateTime/tail.datetime.min.js"></script>
76 + <div id="scriptTaskSchedule">
77 + <div id="controlBar">
78 + <button onclick="goSave();">Schedule</button>
79 + <button onclick="goCancel();">Cancel</button>
80 + </div>
81 + <div id="schedContentC">
82 + <div id="left">
83 + <span class="oTitle">Recurrence</span>
84 + <ul id="intervalListC">
85 + <li><label><input onclick="intervalSelected(this);" type="radio" checked name="recur" value="once">Once</label></li>
86 + <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="minutes">Minutes</label></li>
87 + <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="hourly">Hourly</label></li>
88 + <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="daily">Daily</label></li>
89 + <li><label><input onclick="intervalSelected(this);" type="radio" name="recur" value="weekly">Weekly</label></li>
90 + <!-- li><label><input type="radio" name="recur" value="monthly">Monthly</label></li -->
91 + </ul>
92 + </div>
93 + <div id="right">
94 + <div class="rOpt">
95 + <span class="oTitle">Start: </span>
96 + <input type="text" class="datePick" id="startDate" value="" />
97 + <input type="text" class="timePick" id="startTime" value="" />
98 + </div>
99 + <div class="rOpt" id="intervalC" style="display: none;">
100 + <span class="oTitle">Every: </span>
101 + <input type="text" id="interval" value="1" />&nbsp;<span id="hintText"></span>
102 + </div>
103 + <div class="rOpt" id="endC" style="display: none;">
104 + <span class="oTitle">End: </span>
105 + <input type="text" class="datePick" id="endDate" value="" />
106 + <input type="text" class="timePick" id="endTime" value="" />
107 + <label><input type="checkbox" id="endNever" checked onclick="checkEndNever(this);" /> Never</label>
108 + </div>
109 + <div class="rOpt" id="daysC" style="display: none;">
110 + <span class="oTitle">Days: </span>
111 + <ul id="daysListC">
112 + <li><label><input type="checkbox" name="days[]" value="0"> Sunday</label></li>
113 + <li><label><input type="checkbox" name="days[]" value="1"> Monday</label></li>
114 + <li><label><input type="checkbox" name="days[]" value="2"> Tuesday</label></li>
115 + <li><label><input type="checkbox" name="days[]" value="3"> Wednesday</label></li>
116 + <li><label><input type="checkbox" name="days[]" value="4"> Thursday</label></li>
117 + <li><label><input type="checkbox" name="days[]" value="5"> Friday</label></li>
118 + <li><label><input type="checkbox" name="days[]" value="6"> Saturday</label></li>
119 + </ul>
120 + </div>
121 + </div>
122 + </div>
123 + </div>
124 + <script type="text/javascript">
125 +
126 + function checkEndNever(el) {
127 + if (el.checked) {
128 + Q('endDate').value = '';
129 + Q('endTime').value = '';
130 + }
131 + }
132 + function setTimePick() {
133 + var d = new Date();
134 + document.getElementById("startDate").value = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
135 + document.getElementById("startTime").value = d.getHours() + ':' + d.getMinutes();
136 + tail.DateTime(".datePick", { position: "bottom", dateStart: Date(), timeFormat: false });
137 + tail.DateTime(".timePick", { position: "bottom", dateFormat: false, timeFormat: "HH:ii", timeStepMinutes: 15 });
138 + tail.datetime.inst[document.getElementById('endDate').getAttribute('data-tail-datetime')].on('change', function () {
139 + document.getElementById('endNever').checked = false;
140 + });
141 + tail.datetime.inst[document.getElementById('endTime').getAttribute('data-tail-datetime')].on('change', function () {
142 + document.getElementById('endNever').checked = false;
143 + });
144 + }
145 +
146 + function doOnLoad() {
147 + try {
148 + if (scriptId == null) {
149 + alert('Page reloaded and data lost. Please re-run scheduler from the main window.');
150 + goCancel();
151 + return;
152 + }
153 + } catch (e) {
154 + alert('Page reloaded and data lost. Please re-run scheduler from the main window.');
155 + goCancel();
156 + return;
157 + }
158 + setTimePick();
159 + }
160 +
161 + function intervalSelected(el) {
162 + var v = el.value;
163 + switch (v) {
164 + case 'once':
165 + QV('intervalC', false);
166 + QV('endC', false);
167 + QV('daysC', false);
168 + break;
169 + case 'minutes':
170 + QV('intervalC', true);
171 + QV('endC', true);
172 + QV('daysC', false);
173 + QH('hintText', 'minute(s)');
174 + break;
175 + case 'hourly':
176 + QV('intervalC', true);
177 + QV('endC', true);
178 + QV('daysC', false);
179 + QH('hintText', 'hour(s)');
180 + break;
181 + case 'daily':
182 + QV('intervalC', true);
183 + QV('endC', true);
184 + QV('daysC', false);
185 + QH('hintText', 'day(s)');
186 + break;
187 + case 'weekly':
188 + QV('intervalC', true);
189 + QV('endC', true);
190 + QV('daysC', true);
191 + QH('hintText', 'week(s)');
192 + break;
193 + }
194 + }
195 + function goSave() {
196 + var o = {};
197 + var recurEls = document.getElementsByName("recur");
198 + recurEls.forEach(function (el) {
199 + if (el.checked) o.recur = el.value;
200 + });
201 + switch (o.recur) {
202 + case 'once':
203 + o.startAt = Date.parse(Q('startDate').value + ' ' + Q('startTime').value);
204 + o.startAt = Math.floor(o.startAt / 1000);
205 + break;
206 + case 'minutes':
207 + case 'hourly':
208 + case 'daily':
209 + o.startAt = Date.parse(Q('startDate').value + ' ' + Q('startTime').value);
210 + o.startAt = Math.floor(o.startAt / 1000);
211 + o.interval = Number(Q('interval').value);
212 + if (Q('endNever').checked) o.endAt = null;
213 + else {
214 + o.endAt = Date.parse(Q('endDate').value + ' ' + Q('endTime').value);
215 + o.endAt = Math.floor(o.endAt / 1000);
216 + }
217 + break;
218 + case 'weekly':
219 + o.startAt = Date.parse(Q('startDate').value + ' ' + Q('startTime').value);
220 + o.startAt = Math.floor(o.startAt / 1000);
221 + o.interval = Number(Q('interval').value);
222 + if (Q('endNever').checked) o.endAt = null;
223 + else {
224 + o.endAt = Date.parse(Q('endDate').value + ' ' + Q('endTime').value);
225 + o.endAt = Math.floor(o.endAt / 1000);
226 + }
227 + var dayEls = document.getElementsByName("days[]");
228 + o.dayVals = [];
229 + if (dayEls.length) {
230 + dayEls.forEach(function (de) {
231 + if (de.checked) o.dayVals.push(de.value);
232 + });
233 + }
234 + break;
235 + }
236 + o.scriptId = scriptId;
237 + o.nodes = nodes;
238 +
239 + window.opener.schedCallback(o);
240 + window.close();
241 + }
242 +
243 + function goCancel() {
244 + window.close();
245 + }
246 +
247 + </script>
248 +</body>
249 +</html>
\ No newline at end of file
views/task-scriptedit.handlebars new
+73
@@ -0,0 +1,73 @@
1 +<html>
2 +<head>
3 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
4 + <style>
5 + body {
6 + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
7 + color: white;
8 + }
9 +
10 + #scriptContent {
11 + width: 80%;
12 + height: 80%;
13 + }
14 +
15 + #scriptContentC {
16 + padding: 20px;
17 + }
18 +
19 + #controlBar button {
20 + cursor: pointer;
21 + }
22 +
23 + #scriptNameC {
24 + padding: 20px;
25 + }
26 +
27 + #scriptName {
28 + width: 300px;
29 + }
30 +
31 + #controlBar {
32 + padding: 5px;
33 + padding-left: 20px;
34 + }
35 +
36 + body {
37 + background-color: #036;
38 + }
39 + </style>
40 +</head>
41 +<body onload="doOnLoad();">
42 + <div id="scriptTaskScriptEdit">
43 + <div id="scriptNameC">Script Name: <input type="text" value="" id="scriptName" /></div>
44 + <div id="controlBar">
45 + <button onclick="goSave();">Save</button>
46 + <button onclick="goClose();">Close</button>
47 + </div>
48 + <div id="scriptContentC">
49 + <textarea id="scriptContent"></textarea>
50 + </div>
51 + </div>
52 + <script type="text/javascript">
53 + var scriptData = {{{scriptData}}};
54 +
55 + function doOnLoad() {
56 + //QH('scriptContent', scriptData.content);
57 + Q('scriptContent').value = scriptData.content;
58 + Q('scriptName').value = scriptData.name;
59 + }
60 +
61 + function goSave() {
62 + scriptData.content = Q('scriptContent').value;
63 + scriptData.name = Q('scriptName').value;
64 + window.opener.callback(scriptData);
65 + //goClose();
66 + }
67 +
68 + function goClose() {
69 + window.close();
70 + }
71 + </script>
72 +</body>
73 +</html>
\ No newline at end of file
views/task-user.handlebars new
+1070
@@ -0,0 +1,1070 @@
1 +<html>
2 +<head>
3 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
4 + <style>
5 + body {
6 + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
7 + }
8 +
9 + #dropBlock {
10 + /*background-color: gray;
11 + text-align: center;
12 + height: 100%;
13 + width: 100%;
14 + position: absolute;
15 + float:left;*/
16 + width: 100%;
17 + overflow: hidden;
18 + position: absolute;
19 + right: 437px;
20 + padding-top: 100px;
21 + text-align: center;
22 + font-size: 1600%;
23 + color: #AAA;
24 + }
25 +
26 + #scripts_endpoints {
27 + width: 100%;
28 + height: 100%;
29 + }
30 +
31 + #scriptContainer {
32 + width: 35%;
33 + height: 100%;
34 + float: left;
35 + }
36 +
37 + #infoContainer {
38 + width: 65%;
39 + height: 100%;
40 + float: right;
41 + border-left: 1px;
42 + }
43 +
44 + .lifolder {
45 + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAM2xV/Xur+XPgP///yH5BAEAAAMALAAAAAAQABAAAAJD3ISZIGHWUGihznesYDYATFVM+D2hJ4lgN1olxALAtAlmPCJvuMmJd6PJckDYwicrHhTD5o7plJmg0Uc0asNMkphHAQA7) no-repeat 16px;
46 + padding-left: 35px;
47 + cursor: pointer;
48 + border: none;
49 + margin-top: 1px;
50 + }
51 +
52 + .liscript {
53 + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb19IGBgbq6uv///yH5BAEAAAMALAAAAAAQABAAAAIy3ISpxgcPH2ouQgFEw1YmxnUXKEaaEZZnVWZk66JwzKpvuwZzwOgwb/C1gIOA8Yg8DgoAOw==) no-repeat 16px;
54 + padding-left: 35px;
55 + cursor: pointer;
56 + border: none;
57 + margin-top: 1px;
58 + }
59 +
60 + .liselected {
61 + background-color: lightgray;
62 + }
63 +
64 + #controlBar {
65 + width: 100%;
66 + height: 20px;
67 + border-bottom: 1px solid black;
68 + font-size: smaller;
69 + margin-bottom: 7px;
70 + }
71 +
72 + #controlBar span {
73 + cursor: pointer;
74 + padding-left: 4px;
75 + padding-right: 4px;
76 + }
77 +
78 + #controlBar > span:nth-child(n+2) {
79 + border-left: 1px solid black;
80 + }
81 +
82 + .infoBar {
83 + background-color: #777;
84 + color: white;
85 + cursor: pointer;
86 + padding: 10px;
87 + width: 100%;
88 + border: none;
89 + text-align: left;
90 + outline: none;
91 + font-size: 15px;
92 + }
93 +
94 + .infoBar.active, .infoBar:hover {
95 + background-color: #555;
96 + }
97 +
98 + .infoContent {
99 + display: none;
100 + }
101 +
102 + #nHistTbl, #sHistTbl, #nSchTbl, #sSchTbl, #varTbl {
103 + font-size: smaller;
104 + width: 100%;
105 + }
106 +
107 + #nHistTbl td, #sHistTbl td, #nSchTbl td, #sSchTbl td, #varTbl td {
108 + padding-left: 5px;
109 + padding-right: 5px;
110 + }
111 +
112 + .stNHRow, .stSHRow, .stNSRow, .stSSRow {
113 + height: 36px;
114 + max-height: 40px;
115 + width: 100%;
116 + }
117 +
118 + .stNHRow:nth-child(odd) {
119 + background-color: #CCC;
120 + }
121 +
122 + .stSHRow:nth-child(odd) {
123 + background-color: #CCC;
124 + }
125 +
126 + .stNSRow:nth-child(odd) {
127 + background-color: #CCC;
128 + }
129 +
130 + .stSSRow:nth-child(odd) {
131 + background-color: #CCC;
132 + }
133 +
134 + .stVRow:nth-child(odd) {
135 + background-color: #CCC;
136 + }
137 +
138 + .delSched {
139 + cursor: pointer;
140 + }
141 +
142 + .nIcon {
143 + width: 16px;
144 + margin-top: 1px;
145 + margin-left: 2px;
146 + height: 16px;
147 + display: inline-block;
148 + margin-right: 10px;
149 + }
150 +
151 + .j1 {
152 + background: url(../images/icons16.png) 0px 0px;
153 + height: 16px;
154 + width: 16px;
155 + border: none;
156 + }
157 +
158 + .j2 {
159 + background: url(../images/icons16.png) -16px 0px;
160 + height: 16px;
161 + width: 16px;
162 + border: none;
163 + }
164 +
165 + .j3 {
166 + background: url(../images/icons16.png) -32px 0px;
167 + height: 16px;
168 + width: 16px;
169 + border: none;
170 + }
171 +
172 + .j4 {
173 + background: url(../images/icons16.png) -48px 0px;
174 + height: 16px;
175 + width: 16px;
176 + border: none;
177 + }
178 +
179 + .j5 {
180 + background: url(../images/icons16.png) -64px 0px;
181 + height: 16px;
182 + width: 16px;
183 + border: none;
184 + }
185 +
186 + .j6 {
187 + background: url(../images/icons16.png) -80px 0px;
188 + height: 16px;
189 + width: 16px;
190 + border: none;
191 + }
192 +
193 + .ftype {
194 + font-size: small;
195 + }
196 +
197 + .tblFloat {
198 + float: left;
199 + width: 33%;
200 + }
201 +
202 + .flink {
203 + cursor: pointer;
204 + }
205 + </style>
206 +</head>
207 +<body onload="doOnLoad();">
208 + <div id="scriptTaskUser">
209 + <div id="dropBlock" style="display:none;"><b>&checkmark;</b></div>
210 + Upload: <input type="file" id="files" name="files[]" multiple onchange="fileUpload();" />
211 + <hr />
212 + <div id="controlBar">
213 + <span onclick="goNew();">New</span>
214 + <span onclick="goRename();">Rename</span>
215 + <span onclick="goEdit();">Edit</span>
216 + <span onclick="goDelete();">Delete</span>
217 + <span onclick="goNewFolder();">New Folder</span>
218 + <span onclick="goDownload();">Download</span>
219 + <span onclick="goRun();">Run</span>
220 + </div>
221 + <div id="scripts_endpoints">
222 + <div id="scriptContainer">
223 + </div>
224 + <div id="infoContainer">
225 + <div id="history">
226 + <div class="infoBar">Advanced Run</div>
227 + <div id="multiRun" class="infoContent">
228 + <div style="padding-top: 15px;"><button onclick="goAdvancedRun();">Schedule on Selected</button></div>
229 + <div class="tblFloat">
230 + <table id="mRunTbl" cellspacing="0" cellpadding="0">
231 + <tr><td><label><input type="checkbox" onclick="selAllNodes(this);"> Select All</label></td></tr>
232 + </table>
233 + </div>
234 + <div class="tblFloat">
235 + <table id="mRunTblMesh" cellspacing="0" cellpadding="0">
236 + <tr><td>Meshes</td></tr>
237 + </table>
238 + </div>
239 + <div class="tblFloat">
240 + <table id="mRunTblTag" cellspacing="0" cellpadding="0">
241 + <tr><td>Tags</td></tr>
242 + </table>
243 + </div>
244 + </div>
245 + <div class="infoBar">Node Schedules</div>
246 + <div id="nSch" class="infoContent">
247 + <table id="nSchTbl" cellspacing="0" cellpadding="0">
248 + <th>Script</th>
249 + <th>Author</th>
250 + <th>Every</th>
251 + <th>Starting</th>
252 + <th>Ending</th>
253 + <th>Last Run</th>
254 + <th>Next Run</th>
255 + <th>Action</th>
256 + </table>
257 + </div>
258 + <div class="infoBar">Script Schedules</div>
259 + <div id="sSch" class="infoContent">
260 + <table id="sSchTbl" cellspacing="0" cellpadding="0">
261 + <th>Node</th>
262 + <th>Author</th>
263 + <th>Every</th>
264 + <th>Starting</th>
265 + <th>Ending</th>
266 + <th>Last Run</th>
267 + <th>Next Run</th>
268 + <th>Action</th>
269 + </table>
270 + </div>
271 + <div class="infoBar">Node History</div>
272 + <div id="nodeHistory" class="infoContent">
273 + <table id="nHistTbl" cellspacing="0" cellpadding="0">
274 + <th>Time</th>
275 + <th>Run By</th>
276 + <th>Script</th>
277 + <th>Status</th>
278 + <th>Return Value</th>
279 + </table>
280 + </div>
281 + <div class="infoBar">Script History</div>
282 + <div id="scriptHistory" class="infoContent">
283 + <table id="sHistTbl" cellspacing="0" cellpadding="0">
284 + <th>Time</th>
285 + <th>Run By</th>
286 + <th>Node</th>
287 + <th>Status</th>
288 + <th>Return Value</th>
289 + </table>
290 + </div>
291 + <div class="infoBar">Variables</div>
292 + <div id="variables" class="infoContent">
293 + <table id="varTbl" cellspacing="0" cellpadding="0">
294 + <th>Variable Name</th>
295 + <th>Value</th>
296 + <th>Scope</th>
297 + <th>Scope Target</th>
298 + <th>Action</th>
299 + </table>
300 + <br />
301 + <span class="flink" onclick="newVar();return false;">[+]</span>
302 + </div>
303 + </div>
304 +
305 + </div>
306 + </div>
307 + </div>
308 + <script type="text/javascript">
309 + var scriptTree = {{{scriptTree}}};
310 + var elementDragged = false;
311 + var dragCounter = 0;
312 + var draggedId = null;
313 + var nodesObj = {};
314 + var variables = [];
315 + var varScopes = { global: 'Global', script: 'Script', mesh: 'Mesh', node: 'Node' };
316 +
317 + function onlyUnique(value, index, self) {
318 + return self.indexOf(value) === index;
319 + }
320 + function resizeIframe() {
321 + document.body.style.height = 0;
322 + parent.pluginHandler.scripttask.resizeContent();
323 + }
324 + function updateNodesTable() {
325 + let dRows = document.querySelectorAll('.stNodeRow');
326 + dRows.forEach((r) => {
327 + r.parentNode.removeChild(r);
328 + });
329 + var tagList = [];
330 + var nodeRowIns = document.querySelector('#mRunTbl');
331 + parent.nodes.forEach(function(i) {
332 + var item = {...i, ...{}};
333 + if (item.mtype == 2) {
334 + item.meshName = parent.meshes[item['meshid']].name;
335 + if (item._id == parent.currentNode._id) item.checked = 'checked '; else item.checked = '';
336 + let tpl = `<tr class="stNodeRow"><td><label><input type="checkbox" ${item.checked} name="runOn[]" value="${item._id}"> <div class="nIcon j${item.icon}"></div>${item.name}</label></td></tr>`;
337 + nodeRowIns.insertAdjacentHTML('beforeend', tpl);
338 + if (i.tags && i.tags.length) item.tags.forEach(function(t) { tagList.push(t) });
339 + nodesObj[i._id] = i;
340 + }
341 + });
342 + tagList = tagList.filter(onlyUnique); tagList = tagList.sort();
343 + var nodeRowIns = document.querySelector('#mRunTblMesh');
344 + for (const i in parent.meshes) { // parent.meshes.forEach(function(i) {
345 + var item = {...parent.meshes[i], ...{}};
346 + if (item.mtype == 2) {
347 + let tpl = `<tr class="stNodeRow"><td><label><input type="checkbox" onclick="selNodesByMesh(this);" value="${item._id}"> ${item.name}</label></td></tr>`;
348 + nodeRowIns.insertAdjacentHTML('beforeend', tpl);
349 + }
350 + }
351 + var nodeRowIns = document.querySelector('#mRunTblTag');
352 + tagList.forEach(function(i) {
353 + let tpl = `<tr class="stNodeRow"><td><label><input type="checkbox" onclick="selNodesByTag(this)" value="${i}"> ${i}</label></td></tr>`;
354 + nodeRowIns.insertAdjacentHTML('beforeend', tpl);
355 + });
356 + }
357 +
358 + function selNodesByTag(el) {
359 + var t = el.value;
360 + var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
361 + var checked = false;
362 + if (el.checked) checked = true;
363 + allNodes.forEach(function(n) {
364 + if (nodesObj[n.value].tags && nodesObj[n.value].tags.indexOf(t) > -1) n.checked = checked;
365 + });
366 + return true;
367 + }
368 + function selNodesByMesh(el) {
369 + var mid = el.value;
370 + var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
371 + var checked = false;
372 + if (el.checked) checked = true;
373 + allNodes.forEach(function(n) {
374 + if (nodesObj[n.value].meshid == mid) n.checked = checked;
375 + });
376 + return true;
377 + }
378 + function selAllNodes(el) {
379 + var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
380 + var checked = false;
381 + if (el.checked) checked = true;
382 + allNodes.forEach(function(n) {
383 + n.checked = checked;
384 + });
385 + return true;
386 + }
387 +
388 + function doOnLoad() {
389 + redrawScriptTree();
390 + selectPreviouslySelectedScript();
391 + updateNodesTable();
392 + parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadNodeHistory', 'nodeId': parent.currentNode._id });
393 + parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadVariables', 'nodeId': parent.currentNode._id });
394 + }
395 +
396 + function selectPreviouslySelectedScript() {
397 + var sel_item = parent.getstore('_scripttask_sel_item', null)
398 + if (sel_item != null) {
399 + var s = document.getElementById(sel_item);
400 + if (s != null) {
401 + s.classList.toggle('liselected');
402 + goScript(s);
403 + }
404 + }
405 + if (sel_item != null) parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadScriptHistory', 'scriptId': sel_item });
406 + }
407 +
408 + function goRun() {
409 + var selScript = document.querySelectorAll('.liselected');
410 + if (selScript.length) {
411 + var scriptId = selScript[0].getAttribute('x-data-id');
412 + if (scriptId == selScript[0].getAttribute('x-folder-id'))
413 + {
414 + parent.setDialogMode(2, "Oops!", 1, null, 'Please select a script. A folder is currently selected.');
415 + }
416 + else {
417 + parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'runScript', 'scriptId': scriptId, 'nodes': [ parent.currentNode._id ], 'currentNodeId': parent.currentNode._id });
418 + }
419 + } else {
420 + parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
421 + }
422 + }
423 +
424 + function goEdit() {
425 + var selScript = document.querySelectorAll('.liselected');
426 + if (selScript.length && (selScript[0].getAttribute('x-data-id') != selScript[0].getAttribute('x-data-folder'))) {
427 + var scriptId = selScript[0].getAttribute('x-data-id');
428 + window.open('/pluginadmin.ashx?pin=scripttask&user=1&edit=1&id=' + scriptId, '_blank');
429 + window.callback = function(sd) {
430 + parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'editScript', 'scriptId': sd._id, 'scriptType': sd.type, 'scriptName': sd.name, 'scriptContent': sd.content, 'currentNodeId': parent.currentNode._id });
431 + };
432 + } else {
433 + parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to edit.');
434 + }
435 + }
436 +
437 + function goAdvancedRun() {
438 + var cboxes = document.getElementsByName("runOn[]");
439 + var sel = [];
440 +
441 + cboxes.forEach((n) => {
442 + if (n.checked) sel.push(n.value);
443 + });
444 + if (sel.length == 0) {
445 + parent.setDialogMode(2, "Oops!", 1, null, 'No machines have been selected.');
446 + return;
447 + }
448 + var selScript = document.querySelectorAll('.liselected');
449 + if (selScript.length) {
450 + var scriptId = selScript[0].getAttribute('x-data-id');
451 + var sWin = window.open('/pluginadmin.ashx?pin=scripttask&user=1&schedule=1', 'schedule', "width=800,height=600");
452 + sWin.scriptId = scriptId;
453 + sWin.nodes = sel;
454 + window.schedCallback = function(opts) {
455 + parent.meshserver.send({
456 + 'action': 'plugin',
457 + 'plugin': 'scripttask',
458 + 'pluginaction': 'addScheduledJob',
459 + 'scriptId': opts.scriptId,
460 + 'nodes': opts.nodes,
461 + 'currentNodeId': parent.currentNode._id,
462 + 'schedule': opts
463 + });
464 + };
465 + } else {
466 + parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
467 + }
468 + }
469 +
470 + var coll = document.getElementsByClassName("infoBar");
471 + for (var i = 0; i < coll.length; i++) {
472 + coll[i].addEventListener("click", function() {
473 + this.classList.toggle("active");
474 + var content = this.nextElementSibling;
475 + if (content.style.display === "block") {
476 + content.style.display = "none";
477 + } else {
478 + content.style.display = "block";
479 + }
480 + content.style.maxHeight = '300px';
481 + content.style.overflowY = 'scroll';
482 + resizeIframe();
483 + });
484 + }
485 +
486 + function goDownload() {
487 + var isSelected = document.querySelectorAll('.liselected');
488 + if (isSelected.length == 0) return;
489 + var sel = isSelected[0];
490 + var id = sel.getAttribute('x-data-id');
491 + if (id == sel.getAttribute('x-data-folder')) return;
492 + window.location = '/pluginadmin.ashx?pin=scripttask&user=1&dl='+id;
493 + }
494 + function addScript(name, content, path) {
495 + // file type testing
496 + var n = name.split('.').pop().toLowerCase();
497 + if (content.split('\n')[0][0] == '#' && content.split('\n')[0][1] == '!') n = 'bash';
498 + if (['ps1', 'bat', 'bash'].indexOf(n) !== -1) {
499 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'addScript', name: name, content: content, path: path, filetype: n });
500 + }
501 + else {
502 + parent.setDialogMode(2, "Oops!", 1, null, 'Currently accepted filetypes are .ps1, .bat, and bash scripts.');
503 + }
504 + }
505 + function redrawScriptTree() {
506 + var lastpath = null;
507 + var str = '';
508 + var indent = 0;
509 + var folder_id = null;
510 + scriptTree.forEach(function(f) {
511 + if (f.path != lastpath && f.type == 'folder') {
512 + indent = (f.path.match(/\//g) || []).length + 1;
513 + var name = f.path.match(/[^\/]+$/);
514 + folder_id = f._id;
515 + str += '<div draggable="true" x-data-path="' + f.path + '" x-data-id="' + f._id + '" x-data-folder="' + folder_id + '" style="margin-left: ' + indent + 'em;" class="lifolder" onclick="toggleCollapse(this);"><span class="fname">' + name + '</span></div>';
516 + lastpath = f.path;
517 + indent += 1;
518 + }
519 + if (f.type != 'folder') {
520 + str += '<div id="' + f._id + '" draggable="true" x-data-path="' + f.path + '" x-data-id="' + f._id + '" x-data-folder="' + folder_id + '" style="margin-left: ' + indent + 'em;" class="liscript" onclick="goScript(this);"><span class="fname">' + f.name + '</span> [<span class="ftype">' + f.filetype + '</span>]</div>';
521 + }
522 + document.getElementById('scriptContainer').innerHTML = str;
523 + });
524 +
525 + var liScripts = document.querySelectorAll('.liscript');
526 + var liFolders = document.querySelectorAll('.lifolder');
527 + liScripts.forEach(function(el) {
528 + el.addEventListener('mousedown', function() { elementDragged = true; });
529 + el.addEventListener('mouseup', function() { elementDragged = false; });
530 + el.addEventListener('dragstart', function(evt) { evt.dataTransfer.setData('text/plain', evt.target.getAttribute('x-data-id')); });
531 + });
532 + liFolders.forEach(function(el) {
533 + el.addEventListener('drop', dropMove);
534 + el.addEventListener('dragover', function(e) { e.preventDefault(); });
535 + el.addEventListener('mousedown', function() { elementDragged = true; });
536 + el.addEventListener('mouseup', function() { elementDragged = false; });
537 + el.addEventListener('dragstart', function(evt) { evt.dataTransfer.setData('text/plain', evt.target.getAttribute('x-data-id')); });
538 + });
539 + resizeIframe();
540 + selectPreviouslySelectedScript();
541 + }
542 + parent.pluginHandler.scripttask.newScriptTree = function(message) {
543 + scriptTree = message.event.tree;
544 + redrawScriptTree();
545 + }
546 + parent.pluginHandler.scripttask.loadHistory = function(message) {
547 + // cache script names
548 + var nNames = {};
549 + parent.nodes.forEach(function(n){
550 + nNames[n._id] = n.name;
551 + });
552 + if (message.event.nodeHistory != null && message.event.nodeId == parent.currentNode._id) {
553 + var nHistTbl = document.getElementById('nHistTbl');
554 + var rows = nHistTbl.querySelectorAll('.stNHRow');
555 + if (rows.length) {
556 + rows.forEach(function(r) {
557 + r.parentNode.removeChild(r);
558 + });
559 + }
560 + if (message.event.nodeHistory.length) {
561 + message.event.nodeHistory.forEach(function(nh) {
562 + nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
563 + });
564 + message.event.nodeHistory.sort((a, b) => (a.latestTime < b.latestTime) ? 1 : -1);
565 + message.event.nodeHistory.forEach(function(nh) {
566 + nh = prepHistory(nh);
567 + let tpl = '<td>' + nh.timeStr + '</td> \
568 + <td>' + nh.runBy + '</td> \
569 + <td>' + nh.scriptName + '</td> \
570 + <td>' + nh.statusTxt + '</td> \
571 + <td>' + nh.returnTxt + '</td>';
572 + let tr = nHistTbl.insertRow(-1);
573 + tr.innerHTML = tpl;
574 + tr.classList.add('stNHRow');
575 + });
576 + }
577 + }
578 + var currentScript = document.getElementById('scriptHistory');
579 + var currentScriptId = currentScript.getAttribute('x-data-id');
580 + if (message.event.scriptHistory != null && message.event.scriptId == currentScriptId) {
581 + var sHistTbl = document.getElementById('sHistTbl');
582 + var rows = sHistTbl.querySelectorAll('.stSHRow');
583 + if (rows.length) {
584 + rows.forEach(function(r) {
585 + r.parentNode.removeChild(r);
586 + });
587 + }
588 + if (message.event.scriptHistory.length) {
589 + message.event.scriptHistory.forEach(function(nh) {
590 + nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
591 + });
592 + message.event.scriptHistory.sort((a, b) => (a.latestTime < b.latestTime) ? 1 : -1);
593 + message.event.scriptHistory.forEach(function(nh) {
594 + nh = prepHistory(nh);
595 + let tpl = '<td>' + nh.timeStr + '</td> \
596 + <td>' + nh.runBy + '</td> \
597 + <td>' + nNames[nh.node] + '</td> \
598 + <td>' + nh.statusTxt + '</td> \
599 + <td>' + nh.returnTxt + '</td>';
600 + let tr = sHistTbl.insertRow(-1);
601 + tr.innerHTML = tpl;
602 + tr.classList.add('stSHRow');
603 + });
604 + }
605 + }
606 + resizeIframe();
607 + }
608 + function prepHistory(nh) {
609 + var nowTime = Math.floor(new Date() / 1000);
610 + var d = new Date(0);
611 + d.setUTCSeconds(nh.latestTime);
612 + nh.timeStr = d.toLocaleString();
613 + if (nh.errorVal != null) { nh.returnTxt = nh.errorVal; } else { nh.returnTxt = nh.returnVal; }
614 + nh.statusTxt = 'Queued';
615 + if (nh.dispatchTime != null) nh.statusTxt = 'Running';
616 + if (nh.errorVal != null) nh.statusTxt = 'Error';
617 + if (nh.returnVal != null) nh.statusTxt = 'Completed';
618 + if (nh.dontQueueUntil > nowTime) nh.statusTxt = 'Scheduled';
619 + if (nh.returnTxt == null) nh.returnTxt = '&nbsp;';
620 + if (nh.statusTxt == 'Completed') {
621 + nh.statusTxt = '<span title="Completed ' + secondsToHms((nh.completeTime - nh.dispatchTime)) + '">' + nh.statusTxt + '</span>';
622 + }
623 + if (isJsonString(nh.returnTxt)) {
624 + try {
625 + nh.returnObj = JSON.parse(nh.returnTxt);
626 + nh.returnTxt = 'Object: ';
627 + nh.returnTxt += '' + JSON.stringify(nh.returnObj, null, 2);
628 + nh.returnTxt = nh.returnTxt.replace(/\n\s*\n/g, '\n');
629 + nh.returnTxt = nh.returnTxt.replace(/(?:\r\n|\r|\n)/g, '<br />');
630 + } catch(e) { }
631 + } else {
632 + if (typeof nh.returnTxt == 'string') {
633 + nh.returnTxt = nh.returnTxt.replace(/\n\s*\n/g, '\n');
634 + nh.returnTxt = nh.returnTxt.replace(/(?:\r\n|\r|\n)/g, '<br />');
635 + }
636 + }
637 + return nh;
638 + }
639 + parent.pluginHandler.scripttask.loadVariables = function(message) {
640 + if (message.event.vars.length) {
641 + var vars = message.event.vars;
642 + vars.forEach(function(vd) {
643 + switch (vd.scope) {
644 + case 'global':
645 + vd.scopeTargetTxt = vd.scopeTargetHtml = 'N/A';
646 + break;
647 + case 'script':
648 + var s = scriptTree.filter(obj => { return obj._id === vd.scopeTarget })[0]
649 + vd.scopeTargetHtml = '<span title="' + s.path + '">' + s.name + '</span>';
650 + vd.scopeTargetTxt = s.name;
651 + break;
652 + case 'mesh':
653 + vd.scopeTargetTxt = vd.scopeTargetHtml = parent.meshes[vd.scopeTarget].name;
654 + break;
655 + case 'node':
656 + var n = parent.nodes.filter(obj => { return obj._id === vd.scopeTarget })[0]
657 + vd.scopeTargetHtml = '<span title="' + n.meshnamel + '">' + n.name + '</span>';
658 + vd.scopeTargetTxt = n.name;
659 + break;
660 + default:
661 + vd.scopeTargetTxt = vd.scopeTargetHtml = 'N/A';
662 + break;
663 + }
664 + vd.scopeTxt = varScopes[vd.scope];
665 + })
666 + var ordering = { 'global': 0, 'script': 1, 'mesh': 2, 'node': 3 }
667 + vars.sort((a, b) => {
668 + return (ordering[a.scope] - ordering[b.scope])
669 + || a.name.localeCompare(b.name)
670 + || a.scopeTargetTxt.localeCompare(b.scopeTargetTxt);
671 + });
672 + variables = vars;
673 + parseVariables();
674 + }
675 + }
676 + function parseVariables() {
677 + var vTbl = document.getElementById('varTbl');
678 + var rows = vTbl.querySelectorAll('.stVRow');
679 +
680 + if (rows.length) {
681 + rows.forEach(function(r) {
682 + r.parentNode.removeChild(r);
683 + });
684 + }
685 + var scriptEl = document.querySelectorAll('.liselected');
686 + if (scriptEl.length != 1) return;
687 + var el = scriptEl[0];
688 + scopeTargetScriptId = el.getAttribute('x-data-id');
689 + variables.forEach(function(vd) {
690 + if (vd.scope == 'script' && vd.scopeTarget != scopeTargetScriptId) return;
691 + if (vd.scope == 'mesh' && vd.scopeTarget != parent.currentNode.meshid) return;
692 + if (vd.scope == 'node' && vd.scopeTarget != parent.currentNode._id) return;
693 + let actionHtml = '<span class="flink" onclick="editVar(this);">Edit</span> <span class="flink" onclick="delVar(this);">Delete</span>';
694 + let tpl = '<td>' + vd.name + '</td> \
695 + <td>' + vd.value + '</td> \
696 + <td>' + vd.scopeTxt + '</td> \
697 + <td>' + vd.scopeTargetHtml + '</td> \
698 + <td>' + actionHtml + '</td>';
699 + let tr = vTbl.insertRow(-1);
700 + tr.innerHTML = tpl;
701 + tr.classList.add('stVRow');
702 + tr.setAttribute('x-data-id', vd._id);
703 + })
704 + }
705 + parent.pluginHandler.scripttask.loadSchedule = function(message) {
706 + // cache script names
707 + var nNames = {}, sNames = {};
708 + parent.nodes.forEach(function(n){
709 + nNames[n._id] = n.name;
710 + });
711 + scriptTree.forEach(function(s) {
712 + if (s.type == 'script') sNames[s._id] = s.name;
713 + });
714 + if (message.event.nodeSchedule != null && message.event.nodeId == parent.currentNode._id) {
715 + var nTbl = document.getElementById('nSchTbl');
716 + var rows = nTbl.querySelectorAll('.stNSRow');
717 + if (rows.length) {
718 + rows.forEach(function(r) {
719 + r.parentNode.removeChild(r);
720 + });
721 + }
722 + if (message.event.nodeSchedule.length) {
723 + message.event.nodeSchedule.forEach(function(nh) {
724 + nh = prepSchedule(nh);
725 + let tpl = '<td>' + sNames[nh.scriptId] + '</td> \
726 + <td>' + nh.scheduledBy + '</td> \
727 + <td>' + nh.everyTxt + '</td> \
728 + <td>' + nh.startedTxt + '</td> \
729 + <td>' + nh.endingTxt + '</td> \
730 + <td>' + nh.lastRunTxt + '</td> \
731 + <td>' + nh.nextRunTxt + '</td> \
732 + <td>' + nh.actionTxt + '</td>';
733 + let tr = nTbl.insertRow(-1);
734 + tr.innerHTML = tpl;
735 + tr.classList.add('stNSRow');
736 + tr.setAttribute('x-data-id', nh._id);
737 + });
738 + }
739 + }
740 + var currentScript = document.getElementById('scriptHistory');
741 + var currentScriptId = currentScript.getAttribute('x-data-id');
742 + if (message.event.scriptSchedule != null && message.event.scriptId == currentScriptId) {
743 + var sTbl = document.getElementById('sSchTbl');
744 + var rows = sTbl.querySelectorAll('.stSSRow');
745 + if (rows.length) {
746 + rows.forEach(function(r) {
747 + r.parentNode.removeChild(r);
748 + });
749 + }
750 + if (message.event.scriptSchedule.length) {
751 + message.event.scriptSchedule.forEach(function(nh) {
752 + nh = prepSchedule(nh);
753 + let tpl = '<td>' + nNames[nh.node] + '</td> \
754 + <td>' + nh.scheduledBy + '</td> \
755 + <td>' + nh.everyTxt + '</td> \
756 + <td>' + nh.startedTxt + '</td> \
757 + <td>' + nh.endingTxt + '</td> \
758 + <td>' + nh.lastRunTxt + '</td> \
759 + <td>' + nh.nextRunTxt + '</td> \
760 + <td>' + nh.actionTxt + '</td>';
761 + let tr = sTbl.insertRow(-1);
762 + tr.innerHTML = tpl;
763 + tr.classList.add('stSSRow');
764 + tr.setAttribute('x-data-id', nh._id);
765 + });
766 + }
767 + }
768 + resizeIframe();
769 + }
770 + function prepSchedule(nh) {
771 + nh.everyTxt = nh.interval + ' ';
772 + switch (nh.recur) {
773 + case 'once':
774 + nh.everyTxt = 'Once';
775 + break;
776 + case 'minutes':
777 + nh.everyTxt += 'minute';
778 + break;
779 + case 'hourly':
780 + nh.everyTxt += 'hour';
781 + break;
782 + case 'daily':
783 + nh.everyTxt += 'day';
784 + break;
785 + case 'weekly':
786 + nh.everyTxt += 'week';
787 + break;
788 + case 'monthly':
789 + nh.everyTxt += 'month';
790 + break;
791 + }
792 + if (nh.interval > 1) nh.everyTxt += 's';
793 +
794 + if (nh.recur == 'weekly') {
795 + nh.daysOfWeek = nh.daysOfWeek.map(el => Number(el));
796 + nh.everyTxt += ' (';
797 + nh.daysOfWeek.forEach(function(num) {
798 + switch(num) {
799 + case 0: nh.everyTxt += 'S'; break;
800 + case 1: nh.everyTxt += 'M'; break;
801 + case 2: nh.everyTxt += 'T'; break;
802 + case 3: nh.everyTxt += 'W'; break;
803 + case 4: nh.everyTxt += 'R'; break;
804 + case 5: nh.everyTxt += 'F'; break;
805 + case 6: nh.everyTxt += 'S'; break;
806 + }
807 + });
808 + nh.everyTxt += ')';
809 + }
810 +
811 + var d = new Date(0); d.setUTCSeconds(nh.startAt);
812 + nh.startedTxt = d.toLocaleString();
813 + d = new Date(0); d.setUTCSeconds(nh.endAt);
814 + nh.endingTxt = d.toLocaleString();
815 + if (nh.endAt == null) nh.endingTxt = 'Never';
816 + if (nh.recur == 'once') nh.endingTxt = 'After first run';
817 + d = new Date(0); d.setUTCSeconds(nh.lastRun);
818 + nh.lastRunTxt = d.toLocaleString();
819 + if (nh.lastRun == null) nh.lastRunTxt = 'Never';
820 + d = new Date(0); d.setUTCSeconds(nh.nextRun);
821 + nh.nextRunTxt = d.toLocaleString();
822 + if (nh.nextRun == null) nh.nextRunTxt = 'Never';
823 + if (nh.nextRun < nh.lastRun) nh.nextRunTxt = 'Running now';
824 +
825 + nh.actionTxt = '<span class="delSched" onclick="deleteSchedule(this);">Delete</span>';
826 + return nh;
827 + }
828 + function secondsToHms(d) {
829 + d = Number(d);
830 + if (d == 0) return "immediately";
831 + var h = Math.floor(d / 3600);
832 + var m = Math.floor(d % 3600 / 60);
833 + var s = Math.floor(d % 3600 % 60);
834 +
835 + var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
836 + var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
837 + var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
838 + return "in " + hDisplay + mDisplay + sDisplay;
839 + }
840 + function isJsonString(str) {
841 + try {
842 + JSON.parse(str);
843 + } catch (e) {
844 + return false;
845 + }
846 + return true;
847 + }
848 + function newVarEx() {
849 + var name = parent.document.getElementById('stvarname').value;
850 + var scope = parent.document.getElementById('stvarscope').value;
851 + var value = parent.document.getElementById('stvarvalue').value;
852 + var scopeTarget = null;
853 + if (scope == 'script') {
854 + var scriptEl = document.querySelectorAll('.liselected');
855 + if (scriptEl.length != 1) return;
856 + var el = scriptEl[0];
857 + scopeTarget = el.getAttribute('x-data-id');
858 + } else if (scope == 'mesh') {
859 + scopeTarget = parent.currentNode.meshid;
860 + } else if (scope == 'node') {
861 + scopeTarget = parent.currentNode._id;
862 + }
863 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'newVar', name: name, scope: scope, scopeTarget: scopeTarget, value: value, currentNodeId: parent.currentNode._id });
864 +
865 + }
866 + function newVar() {
867 + parent.setDialogMode(2, "New Variable", 3, newVarEx, 'Variable Name: <input type="text" id=stvarname /><br />Scope: <select id=stvarscope><option value="global">Global</option><option value="script">Script</option><option value="mesh">Mesh</option><option value="node">Node</option></select><br />Value: <input id="stvarvalue" type="text" />');
868 + parent.focusTextBox('stvarname');
869 + }
870 + function editVarEx() {
871 + var varid = parent.document.getElementById('stvarid').value;
872 + var name = parent.document.getElementById('stvarname').value;
873 + var scope = parent.document.getElementById('stvarscope').value;
874 + var value = parent.document.getElementById('stvarvalue').value;
875 + var scopeTarget = null;
876 + if (scope == 'script') {
877 + var scriptEl = document.querySelectorAll('.liselected');
878 + if (scriptEl.length != 1) return;
879 + var el = scriptEl[0];
880 + scopeTarget = el.getAttribute('x-data-id');
881 + } else if (scope == 'mesh') {
882 + scopeTarget = parent.currentNode.meshid;
883 + } else if (scope == 'node') {
884 + scopeTarget = parent.currentNode._id;
885 + }
886 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'editVar', id: varid, name: name, scope: scope, scopeTarget: scopeTarget, value: value, currentNodeId: parent.currentNode._id });
887 + }
888 + function editVar(el) {
889 + var vid = el.parentNode.parentNode.getAttribute('x-data-id');
890 + var v = variables.filter(obj => { return obj._id === vid })[0];
891 + var soptHtml = '';
892 + for (const [k, t] of Object.entries(varScopes)) {
893 + soptHtml += '<option value="' + k + '"';
894 + if (v.scope == k) soptHtml += ' selected';
895 + soptHtml += '>' + t + '</option>';
896 + }
897 + parent.setDialogMode(2, "Edit Variable", 3, editVarEx, 'Variable Name: <input type="text" id=stvarname value="' + v.name + '" /><br />Scope: <select id=stvarscope>' + soptHtml + '</select><br />Value: <input id="stvarvalue" type="text" value="' + v.value + '" /><input type="hidden" id="stvarid" value="' + vid + '" />');
898 + parent.focusTextBox('stvarname');
899 + }
900 + function delVarEx() {
901 + var varid = parent.document.getElementById('stvarid').value;
902 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'deleteVar', id: varid, currentNodeId: parent.currentNode._id });
903 +
904 + }
905 + function delVar(el) {
906 + var vid = el.parentNode.parentNode.getAttribute('x-data-id');
907 + var v = variables.filter(obj => { return obj._id === vid })[0];
908 + parent.setDialogMode(2, "Delete Variable", 3, delVarEx, 'Are you sure you want to delete this?<input type="hidden" id="stvarid" value="' + vid + '" /><br />Name: '+ v.name +'<br />Scope: '+ varScopes[v.scope] +'<br />Value: '+ v.value);
909 + }
910 + function renameEx() {
911 + var name = parent.document.getElementById('stfilename').value;
912 + var id = parent.document.getElementById('stid').value;
913 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'rename', name: name, id: id, currentNodeId: parent.currentNode._id });
914 + }
915 + function goRename() {
916 + var scriptEl = document.querySelectorAll('.liselected');
917 + if (scriptEl.length != 1) return;
918 + var el = scriptEl[0];
919 + var name = el.querySelector('.fname').innerHTML;
920 + var id = el.getAttribute('x-data-id');
921 + parent.setDialogMode(2, "Rename " + name, 3, renameEx, '<input type="text" value="' + name + '" id=stfilename style=width:100% /><input type="hidden" id="stid" value="' + id + '" />');
922 + parent.focusTextBox('stfilename');
923 + }
924 + function newEx() {
925 + var name = parent.document.getElementById('stfilename').value;
926 + var parent_id = parent.document.getElementById('stfolderid').value;
927 + var fileType = parent.document.getElementById('stfiletype').value;
928 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'new', name: name, parent_id: parent_id, filetype: fileType, currentNodeId: parent.currentNode._id });
929 + }
930 + function goNew() {
931 + var scriptEl = document.querySelectorAll('.liselected');
932 + var folder_id = null;
933 + if (scriptEl.length > 0) {
934 + var el = scriptEl[0];
935 + folder_id = el.getAttribute('x-data-folder');
936 + }
937 + parent.setDialogMode(2, "New Script", 3, newEx, 'Name: <input type="text" value="' + name + '" id=stfilename style=width:100% /><br />Type:<select id="stfiletype"><option value="bash">Bash</option><option value="bat">BAT</option><option value="ps1">PS1</option></select><input type="hidden" id="stfolderid" value="' + folder_id + '" />');
938 + parent.focusTextBox('stfilename');
939 + }
940 + function newFolderEx() {
941 + var name = parent.document.getElementById('stfoldername').value;
942 + var parent_id = parent.document.getElementById('stfolderid').value;
943 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'newFolder', name: name, parent_id: parent_id });
944 + }
945 + function goNewFolder() {
946 + var scriptEl = document.querySelectorAll('.liselected');
947 + var folder_id = null;
948 + if (scriptEl.length > 0) {
949 + var el = scriptEl[0];
950 + folder_id = el.getAttribute('x-data-folder');
951 + }
952 + parent.setDialogMode(2, "New Folder", 3, newFolderEx, '<input type="text" value="" id=stfoldername style=width:100% /><input type="hidden" id="stfolderid" value="' + folder_id + '" />');
953 + parent.focusTextBox('stfoldername');
954 + }
955 + function goScript(el) {
956 + var xdi = el.getAttribute('x-data-id');
957 + var scriptEls = document.querySelectorAll('.liselected');
958 + parent.putstore('_scripttask_sel_item', xdi);
959 + scriptEls.forEach(function(e) {
960 + e.classList.remove('liselected');
961 + })
962 + el.classList.add('liselected');
963 + Q('scriptHistory').setAttribute('x-data-id', el.getAttribute('x-data-id'));
964 + if (xdi != el.getAttribute('x-data-folder')) {
965 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'loadScriptHistory', scriptId: xdi });
966 + }
967 + parseVariables();
968 + }
969 + function deleteEx() {
970 + var id = parent.document.getElementById('stdelid').value;
971 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id });
972 + }
973 + function goDelete() {
974 + var els = document.querySelectorAll('.liselected');
975 + if (els.length == 0) return;
976 + var el = els[0];
977 + var name = el.innerHTML;
978 + var id = el.getAttribute('x-data-id');
979 + parent.setDialogMode(2, "Delete " + name, 3, deleteEx, 'Are you sure? <input type="hidden" id="stdelid" value="' + id + '" />');
980 + }
981 + function deleteScheduleEx() {
982 + var id = parent.document.getElementById('stdelid').value;
983 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id });
984 + }
985 + function deleteSchedule(el) {
986 + var id = el.parentNode.parentNode.getAttribute('x-data-id');
987 + parent.setDialogMode(2, "Delete Schedule", 3, deleteScheduleEx, 'Are you sure you want to delete this schedule? <input type="hidden" id="stdelid" value="' + id + '" />');
988 + }
989 + function toggleCollapse(el) {
990 + var xdf = el.getAttribute('x-data-path');
991 + var folderEls = document.querySelectorAll('.lifolder, .liscript');
992 + var showHide = null;
993 + folderEls.forEach(function(e){
994 + if (e === el) return;
995 + if (e.getAttribute('x-data-path').indexOf(xdf) !== -1) {
996 + if (e.style.display == 'none') {
997 + if (showHide === null) showHide = '';
998 + } else {
999 + if (showHide === null) showHide = 'none';
1000 + }
1001 + e.style.display = showHide;
1002 + }
1003 + });
1004 + goScript(el);
1005 + }
1006 + function handleFileSelect(evt) {
1007 + evt.preventDefault();
1008 + var files = evt.dataTransfer.files; // FileList object
1009 + // files is a FileList of File objects. List some properties.
1010 + QV('dropBlock', false);
1011 + var output = [];
1012 + fileUpload(files);
1013 + elementDragged = false;
1014 + if (dragTimer != null) dragTimer = null;
1015 + //document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
1016 + }
1017 +
1018 + function fileUpload(files) {
1019 + if (files == null) files = document.getElementById('files').files;
1020 + var path = null;
1021 + var isSelected = document.querySelectorAll('.liselected');
1022 + if (isSelected.length) {
1023 + var sel = isSelected[0];
1024 + path = sel.getAttribute('x-data-path');
1025 + }
1026 + for (var i = 0, f; f = files[i]; i++) {
1027 + var reader = new FileReader();
1028 + reader.fileName = f.name;
1029 + reader.readAsBinaryString(f);
1030 + reader.addEventListener('loadend', function(e, file){
1031 + addScript(e.currentTarget.fileName, e.currentTarget.result, path);
1032 + });
1033 + }
1034 + }
1035 +
1036 + var dropZone = document.getElementById('scriptTaskUser');
1037 + var dropBlock = document.getElementById('dropBlock');
1038 + var dragTimer = null;
1039 + function allowDrag(e) {
1040 + if (!elementDragged) { // Test that the item being dragged is a valid one
1041 + e.dataTransfer.dropEffect = 'copy';
1042 + QV('dropBlock', true);
1043 + e.preventDefault();
1044 + clearTimeout(dragTimer);
1045 + dragTimer = setTimeout(function(){ dragCounter = 0; QV('dropBlock', false); }, 100);
1046 + }
1047 + }
1048 +
1049 + function dropMove(evt) {
1050 + const move_id = evt.dataTransfer.getData('text');
1051 + const container_id = evt.target.parentNode.getAttribute('x-data-id');
1052 + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'move', id: move_id, to: container_id });
1053 + }
1054 + // file upload events
1055 + window.addEventListener('dragenter', function(e) {
1056 + dragCounter++;
1057 + });
1058 + dropZone.addEventListener('dragenter', allowDrag);
1059 + dropZone.addEventListener('dragover', allowDrag);
1060 + dropZone.addEventListener('dragleave', function(e) {
1061 + dragCounter--;
1062 + if (dragCounter == 0) {
1063 + QV('dropBlock', false);
1064 + elementDragged = false;
1065 + }
1066 + });
1067 + dropZone.addEventListener('drop', handleFileSelect);
1068 + </script>
1069 +</body>
1070 +</html>
\ No newline at end of file