JavaScript is disabled on your browser.
# flow-task-logic.psm1
<#
The logic to run the workflow engine
History:
EC2619 - logic from previous versions & restructured
#>
<##.mod-doc
flow-task-logic.psm1
================
_PSEC version 0.0.9_
#### Workflow bootstrap ####
This script module contains the routines that handle the the Workflow implementation
It does this by extending the Form object to add the additional fields it requires for managing
the Workflow.
#### Workflow Architecture ####
A workflow consists of one or more steps.
These steps are controlled from a Workflow Control Panel that is rendered by the @@GUI. The @@Workflow i s created with the @@GuiConfig.
The Workflow Control Panel is used to prepare each step, execute each step and inspect the results of each execution.
Each step is expected to produce a @@Brief (simple json format) that is used to represent a summary of the step execution.
The execution of each step can result in a GOOD status or FAIL status as recorded in the @@Brief.
Failure to produce the @@Brief is treated as a failure.
Any standard output is stored in a @@RunLog which can be easily viewed from the control panel.
Dependencies can be specified which ensures a subsequent step only runs when the dependant step successfully executes (status is GOOD).
In addition, steps can be specified that only show if the previous step fails and are used to take corrective action (such as updating a database).
#>
using namespace System.Collections;
using namespace System.Management.Automation;
using module .\gui-classes.psm1
#using module .\gui-utils.psm1
using module .\flow-classes.psm1
set-strictmode -version 2.0
<#.md
.desc
desc tbd
.details
details tbd
#>
class TaskExec : Task {
TaskExec([string]$name, [string]$type, [string]$title, [string]$desc): base($name, $type, $title, $desc) {
}
[void]statGood([string]$statMsg) {
if ($this.statElem -ne $null) {
$this.statElem.peer.text = $statMsg;
$this.statElem.foreColor("good");
}
}
[void]statWarn([string]$statMsg) {
if ($this.statElem -ne $null) {
$this.statElem.peer.text = $statMsg;
$this.statElem.foreColor("warn");
}
}
[void]statFlag([string]$statMsg) {
if ($this.statElem -ne $null) {
$this.statElem.peer.text = $statMsg;
$this.statElem.foreColor("flag");
}
}
[void]statFlag([string]$statMsg, [boolean]$bBroken) {
if ($bBroken) {
if ($this.optFind("task-icon") -ne $null) {
$this.markBroken()
} else {
$this.bBroken = $true;
}
}
$this.statFlag($statMsg);
if ($this.optFind("Run Task") -ne $null) {
[void]$this.find("Run Task").disableLink();
}
}
[void]runGenericTask([PSMethod]$runner) {
hlog("runGenericTask for $this invoked");
if ($this.prevLogDlg -ne $null) { # EC9B29
$logchk = $this.form.findElemOpt("log-view-keep");
hlog("$logchk $($logchk.isChecked())")
if (($logchk -eq $null) -or !($logchk.isChecked())) {
$this.prevLogDlg.peer.close();
$this.prevLogDlg = $null;
}
}
if (exists $this.methods stopApplicationProgram) {
$this.commObj = $this.custobj.stopApplicationProgram($this,$this.commObj);
}
try {
$this.runTaskMain($runner);
} catch {
$e = $_
hLogErr("$($e.exception.message)")
hLogErr("$($e.ScriptStackTrace)")
}
}
[void]log([string]$msg) {
$this.form.log($msg);
}
<#.md
.desc
This runs the Task using the runner passed in.
.details
This is the guts of the whole system. It executes the task depending on the task type.
All output is directed to a string for creation of the log file and the status for the task is
updated (Brief file).
.notes
For cyclic tasks (whenCycle ne null) previous cycle are merged into the results. Cyclic tasks are not fully implemented.
#>
[string]runTaskMain([PSMethod]$runner) {
hlogBoth("runTaskMain $runner");
$outstr = "";
runlog("workflow-runtask $($this.execlocn) $($this.name) $($this.type)")
[void]$this.find("Run Task").disableLink();
$this.find("stat-time").setText("busy")
$this.find("stat-why").setText("busy");
$this.form.logGood("======= Run for $($this.name) starting $([DateTime]::now)");
$prevHT = @{}
if (test-path $this.statlocn) {
remove-item -path $this.statlocn
$this.form.log("deleted $($this.statlocn)");
$this.brief = $null;
$this.briefTS = 0;
}
$runDone = $runner.invoke(@([RunDone]::new($this)));
$parmsHT = $runDone.parmsHT;
$outstr = $runDone.outstr;
<#
if ($this.type -eq 'java') {
hlog("Running java code for $($this.name)");
$parmsHT = $this.fetchParams();
if ($parmsHT -eq $null) {$this.statFlag("no parameters returned for run",$true); return $null;}
$parms = formatParms($parmsHT);
$outstr = $this.runJavaPgm($parms,$parmsHT);
hlog("Run completed $(maxStr $outstr 120)");
} elseif ($this.type -eq 'nodejs') {
$parmsHT = $this.fetchParams();
if ($parmsHT -eq $null) {$this.statFlag("no parameters returned for run",$true); return $null;}
$parms = formatParms($parmsHT);
$outstr = $this.runNodejsPgm($parms);
hlog("Nodejs run completed $(maxStr $outstr 120)");
} elseif ($this.type -eq 'script') {
hlog("Running script code for $($this.name)");
$parmsHT = [hashTable]$this.fetchParams();
if ($parmsHT -eq $null) {$this.statFlag("no parameters returned for run",$true); return $null;}
if (!(exists $this.methods runScript)) {throw "expected method 'runScript' for script type task $this"}
$statHT = [hashTable]@{sCondCode = "GOOD"};
try {
##see $this.custObj
$outstr = $this.custobj.runScript($this,$parmsHT,$statHT);
$this.stowBriefFile($statHT);
} catch {
$e = $_
hLogErr("$($e.exception.message) $($e.getType())")
hLogErr("$($e.ScriptStackTrace)")
$statHT.sCondCode = 'FAIL';
$statHT.sReason = "TRAPPED $($e.exception.message)";
$this.stowBriefFile($statHT);
$outStr = $statHT.sReason;
}
} else {
throw "Task run of $($this.type) not implemented";
}
#>
[void]$this.find("Run Task").enableLink();
$this.find("stat-time").setText("")
$this.find("stat-why").setText("");
$this.form.logGood("Run completed for $($this.name) at $([DateTime]::now)");
$outstr | Out-File -FilePath $this.loglocn -encoding ascii
[void]$this.find("View Log").enableLink();
if (test-path $this.statlocn) {
$next = $null
$this.populateBriefGrid($false);
$curHT = $this.getBriefFile(); # EC8C18
if (($curHT -ne $null) -and (exists $curHT sCondCode) -and ($curHT.sCondCode -eq "GOOD")) {
if (($this.startAppOpts -ne $null) -and (exists $this.startAppOpts exec) -and ($this.autoStartFlag.peer.checked)) {
$this.runTaskOptionProgram($this.startAppOpts.exec);
}
}
} else {
$this.find("stat-time").setText("")
$this.find("stat-why").setText("");
$this.statFlag("No brief file produced");
#$this.find("task-icon").peer.image = $this.form.icons.iconX;
$this.find("brf-grid").hidePeer($true);
}
$this.updateDependencyTree($false);
return $outstr;
}
[RunDone]runJavaTask([RunDone]$runDone) {
hlogBoth("doing runJavaTask $($runDone.task)");
$runDone.parmsHT = $parmsHT = $this.fetchTaskParams();
if ($parmsHT -eq $null) {$this.statFlag("no parameters returned for run",$true); return $runDone;}
$parms = formatParms($parmsHT);
$runDone.outstr = $outstr = $this.runJavaPgm($parms,$parmsHT);
hlog("Run completed $(maxStr $outstr 120)");
return $runDone;
}
[RunDone]runScriptTask([RunDone]$runDone) {
hlogBoth("doing runScriptTask $($runDone.task)");
$runDone.parmsHT = $parmsHT = $this.fetchTaskParams();
if ($parmsHT -eq $null) {$this.statFlag("no parameters returned for run",$true); return $runDone;}
if (!(exists $this.methods runScript)) {throw "expected method 'runScript' for script type task $this"}
$statHT = [hashTable]@{sCondCode = "GOOD"};
try {
##see $this.custObj
$runDone.outstr = $this.custobj.runScript($this,$parmsHT,$statHT);
$this.stowBriefFile($statHT);
} catch {
$e = $_
hLogErr("$($e.exception.message) $($e.getType())")
hLogErr("$($e.ScriptStackTrace)")
$statHT.sCondCode = 'FAIL';
$statHT.sReason = "TRAPPED $($e.exception.message)";
$this.stowBriefFile($statHT);
$runDone.outstr = $statHT.sReason;
}
#$parms = formatParms($parmsHT);
#$runDone.outstr = $outstr = $this.runJavaPgm($parms,$parmsHT);
#hlog("Run completed $(maxStr $outstr 120)");
return $runDone;
}
[Object[]]formatParms([hashTable]$runParms) {
$parms = @();
forEach($key in $runParms.Keys) {
hlog("format parm $key value $($runParms[$key])")
if ($key.substring($key.length-1,1) -eq "=") { # property
$parms += $("-def");
$parms += $($key+$($runParms[$key]))
} else {
$parms += $("-"+$key);
if ($runParms[$key] -ne $null) {$parms += $runParms[$key]}; # else boolean
}
}
hlog("formatParms $parms")
return $parms
}
[string]runJavaPgm([Object[]]$parms,[hashtable]$parmsHT) {
$main = [string]$this.custObj.fetchJavaMain($this,$parmsHT);
hlogBoth("======= Invoke java $parms main=$main");
$pathStr = [string]$this.custObj.fetchJavaClassStr($this,$parmsHT);
hlog("formatJavaClassViewViewGrid $pathStr");
$resolveStr = (& resolveClassPath $pathStr);
$cmdOutStr = . java -cp $resolveStr $main $($parms) 2>&1
#hFlag("cmdOutput $($cmdOutStr.getType())");
$asStr = [string]::join("`r`n",$cmdOutStr);
return $asStr
}
<#.md
.desc
Updates the PriorTask which requires inspection of the whenFail flag.
.notes
The wrapper object varies on context (CfgFlow and Flow). As long as the wrapper has the requited fields, Powershell can handle it.
#>
[void]updatePriorTask([object]$wrap) {
$task = $this;
if (($task.whenFail -ne $null) -or (exists $task.methods showWhen)) {
if ($wrap.minorPriorTask -eq $null) {
$task.priorTask = $wrap.priorTask;
} else {
$task.priorTask = $wrap.minorPriorTask;
}
$wrap.minorStepSeq += 1;
$task.stepLabel = "Step $( $wrap.majorStepSeq )$(".abcdefghijklmnopq".substring($wrap.minorStepSeq, 1) )";
$wrap.minorPriorTask = $task;
} else {
$wrap.majorStepSeq += 1;
$wrap.minorStepSeq = 0;
$wrap.minorPriorTask = $null;
$task.priorTask = $wrap.priorTask;
$wrap.priorTask = $task;
$task.stepLabel = "Step $( $wrap.majorStepSeq ) ";
}
}
[void]populateBriefGrid([boolean]$bInitial) {
##hlog("populateBriefGrid $this $bInitial")
$file = $(Get-Item $this.statlocn)
#$this.find("stat-time").setText("Completion Date: $($file.LastWriteTime)")
#$this.find("stat-why").setText("");
$brf = $this.getBriefFile()
if ($this.type -eq [TaskType]::Manual) {
return
}
$this.statGood("Run completed");
[Grid]$grid = $this.find("brf-grid");
[Windows.Forms.DataGridView]$dgv = $grid.peer;
$dgv.rows.clear();
[Grid]::addCols($dgv,"Property/150,Value/800");
$dgv.ReadOnly = 'true';
$dgv.AllowUserToAddRows = $false
$dgv.RowHeadersVisible = $false;
$this.updateStatusLine($brf);
forEach($k in (& sortedKeys($brf))) {
$v = $brf[$k];
if ($v -as [hashtable] -ne $null) {
$hint = ConvertTo-Json -InputObject $v -depth 5 -compress
$ht = $v
$v = "hashtable"
if ($ht.fmt -eq "cycle") {
$hint = $hint -replace '(,"[^"]+":)',("`r`n"+'$1')
if (exists $ht TS) {$hint += "`r`n strTS=$(fromUnixTime $ht.TS)"}
$v = "sCondCode:$($ht.sCondCode),ix=$($ht.ix)";
}
[Grid]::addRow($dgv,$k,$v,$hint);
} elseif ("$($v.getType())" -eq "System.Object[]") {
if ($this.parseBriefObject -ne $null) {
[void](& $this.parseBriefObject $this $v $dgv)
} else {
if ($v -as [string[]] -ne $null) {
##hlog("format as string[]");
$six = -1;
forEach($str in $v) {
$six += 1;
[Grid]::addRow($dgv,"$($k).$six",$str);
}
}
}
} else {
[Grid]::addRow($dgv,$k,$v);
}
}
if (exists $brf statMsg) {$this.statGood($brf.statMsg);}
$size = [Grid]::calcGridSize($dgv,15);
$dgv.size = $size;
$grid.hidePeer($false);
$dgv.add_RowPostPaint({
#hlog("post-paint-row $this");
$this.ClearSelection();
});
}
<#.md
.desc
Creates the initial right hand panel.
.notes
This sets marker fields used elsewhere and should be run early in the work flow creation.
#>
[void]createRgtPanel([Flow]$flow, [Panel]$panLft, [Panel]$panRgt) {
[TaskExec]$task = $this;
hlog("createRgtPanel $($task.toString() )")
$pan = ([Panel]::createPanel($panRgt, $task.name)).setMar(10, 10).backColor("actionBG");
$pan.tied = $task;
$hdr = ([Div]::createDiv($pan, "hdr")).setHorz().setAbs(0, 1);
$task.hdrDiv = $hdr;
$lab = ([Label]::createLabel($hdr, "task-head-title")).setFont('taskHead').hook($task).setText("Task:$($task.title)(temp)")
$lab.form.toolTip.SetToolTip($lab.peer, "$( $task.name ) $( $task.type )"); #show mapping to definition
$ancs = ([Div]::createDiv($hdr, "anchors")).setHorz().setAbs(1, 0).setGap(50, 0).dock('right');
[ViewTaskExec]$vt = createViewTask $flow $task $panLft $panRgt $ancs;
hlog("createRgtPanel $vt")
if ($task.type -eq [TaskType]::Manual) {
#[void](createHdrLink $ancs 'Reset TODO Steps' $task $task.markManualTaskNotDone).disableLink().hook($task);
# $vt.createWflHdrLink('Reset TODO Steps',$vt.markManualTaskNotDone).disableLink().hook($task);
if (!(exists $task.methods fetchManualSteps)) {
$task.type = [TaskType]::CfgErr;
$task.desc = "Manual type requires fetchManualSteps method";
} else {
$task.type = [TaskType]::Manual;
[void]$vt.createWflHdrLink('Reset TODO Steps',$vt.markManualTaskNotDone).disableLink().hook($task);
}
} elseif ($task.type -eq [TaskType]::Java) {
if (!(exists $task.methods fetchJavaClassStr)) {
$task.type = [TaskType]::CfgErr;
$task.desc = "Java type requires fetchJavaClassStr method";
} else {
[void]$vt.createWflHdrLink('View Log', $vt.viewRunTaskLog).disableLink().hook($task);
[void]$vt.createWflHdrLink('Run Task', $vt.RunJavaTask).hook($task);
}
} elseif ($task.type -eq [TaskType]::Script) {
if (!(exists $task.methods runScript)) {
$task.type = [TaskType]::CfgErr;
$task.desc = "Script type requires runScript method";
} else {
[void]$vt.createWflHdrLink('View Log', $vt.viewRunTaskLog).disableLink().hook($task);
[void]$vt.createWflHdrLink('Run Task', $vt.RunScriptTask).hook($task);
}
} else {
#$vt.createWflHdrLink('View Log',$vt.viewRunTaskLog).disableLink().hook($task);
#$taskLink = $vt.createWflHdrLink('Run Task',$vt.RunTask).hook($task);
}
#$vt.createWflHdrLink('View Task',$vt.viewTaskSetup).hook($task);
$vt.createWflHdrLink('Task Help', $vt.viewTaskHelp).hook($task);
$labSettings = $vt.createWflHdrSettings("$( [char]0x2261 )").hook($task);
[void](& createActionMenu $flow $task $labSettings);
$body = ([Div]::createDiv($pan, "body"));
$task.bodyDiv = $body;
$body.bUseVScr = $true;
#$task.origWinSize = "$($body.form.peer.size.width),$($body.form.peer.size.height)"; # for task switches
$DescArea = ([Div]::createDiv($body, "desc-area")).setHorz().hook($task)
#$DescArea.bHidden = $true; #reserve position
[void]([Label]::createLabel($DescArea, "Description:", "145,40")).setFont('bodyLabel').setAbs(1, 1)
$descLines = ([Label]::createLabel($DescArea,"desc-lines")).setAbs(300, 0).hook($task).maxWidth(700).setText("desc not refreshed");
$StatLine = ([Div]::createDiv($body, "stat-line")).setHorz().setAbs(0, 1);
[void]([Label]::createLabel($StatLine, "Status:", "145,40")).setFont('bodyLabel').setAbs(1, 1)
$task.statElem = ([Label]::createLabel($StatLine, "to-be-loaded", "450,30")).setFont('bodyLabel').setText("desc not refreshed");
if ($task.type -eq [TaskType]::CfgErr) {
$null = $task.statElem.setText("config err").foreColor("red");
$null = $descLines.setText($task.desc).foreColor("red");
$descArea.bHidden = $false;
} else {
}
[void]([Label]::createLabel($StatLine, "stat-why", "450,30")).hook($task).setText('')
[void]([Label]::createLabel($StatLine, "stat-time")).hook($task).setText('');
if (exists $task.methods options) {
$OptArea = ([Div]::createDiv($body, "opt-area")).setHorz().hook($task)
#$OptArea.bHidden = $true; #reserve position
[void]([Label]::createLabel($OptArea, "Options:", "145,40")).setFont('bodyLabel').setAbs(1, 1)
[void]([Div]::createDiv($OptArea, "opt-lines")).hook($task);
[void](buildOptionLine $task $task.find("opt-lines"));
}
#importTaskDefn $flow $tht $task
if ($task.type -ne [TaskType]::Manual) {
$BrfArea = ([Div]::createDiv($body,"stat-line")).setHorz();
[void]([Label]::createLabel($BrfArea,"Brief:","145,40")).setFont('bodyLabel').setAbs(1,1)
$GridArea = ([Div]::createDiv($BrfArea,"grid-area")).setAbs(800,400);
$GridArea.peer.AutoScroll = $false;
$GridArea.peer.HorizontalScroll.Enabled = $false;
$GridArea.peer.HorizontalScroll.Visible = $false;
$GridArea.peer.HorizontalScroll.Maximum = 0;
$GridArea.peer.AutoScroll = $true;
[void]([Grid]::createGrid($GridArea,$null,$null,$null,$task)).setName("brf-grid").hook($task).hidePeer($true);
$task.find("brf-grid").peer.size = "880,100";
} else {
$bUpdateBrf = $false;
if ($task.type -eq [TaskType]::Manual) {
$StepDiv = ([Div]::createDiv($body,"step-line")).setHorz();
[void]([Label]::createLabel($StepDiv,"Steps:","145,40")).setFont('bodyLabel').setAbs(1,1)
$StepArea = ([Div]::createDiv($StepDiv,"step-area")).setAbs(800,400);
$ix = -1
[string[]]$steps = $task.custObj.fetchManualSteps($task);
$task.manSteps = New-Object ManStep[] $steps.count
[void]$task.getBriefFile()
if ($task.brief -eq $null) {$task.brief = @{sCondCode='FAIL';sReason='Step(s) not performed'}}
forEach($step in $steps) {
hlog("add manualStep $step");
$ix += 1
$manStep = [ManStep]::new()
$manStep.task = $task;
$manStep.name = $step;
$manStep.line = $ix + 1;
$StepLine = ([Div]::createDiv($StepArea,"step-line")).setAbs(1,1).setHorz();
$click = {
param($evt)
$elem = $evt.tag;
$manStep = $elem.tied;
hlog("checkbox clicked $evt $($evt.getType()) $($manStep.name) checked=($evt.checked)");
if (!$manStep.bIgnore) {
[void]$manStep.task.getBriefFile();
$manStep.task.brief["step-$($manStep.line)"] = $evt.checked;
$manStep.task.stowBriefFile($manStep.task.brief);
$manStep.task.markManualTaskStatus($true);
}
}
$chkLine = ([CheckBox]::createCheckBox($StepLine,"50,30",$null,""))
$manStep.chkBox = $chkLine;
$chkLine.tied = $manStep;
$labName = "step-$($manStep.line)"
if (exists $task.brief $labName) {
$chkLine.peer.checked = $task.brief[$labName];
} else {
$task.brief[$labName] = $false;
$bUpdateBrf = $true;
}
[void]([Label]::createLabel($StepLine,"$($manStep.line). $($manStep.name)","600,40")).setFont('bodyLabel').setAbs(1,1)
$task.manSteps[$ix] = $manStep;
$chkLine.peer.add_CheckedChanged($click);
}
}
if ($bUpdateBrf) {$task.stowBriefFile($task.brief)};
}
#if (exists $task.methods primeTask) {[void]$task.custobj.primeTask($task,$cfg)};
if ((test-path $task.loglocn) -and ($task.optFind("View Log") -ne $null)) {
[void]$task.find("View Log").enableLink();
}
if (test-path $task.statlocn) {
$task.populateBriefGrid($true);
}
$task.tabPan = $panRgt;
$panRgt.addTabPanel($pan);
}
[void]refreshRgtPanel(){
hlog("refreshRgtPanel $($this.toString())");
[Flow]$flow = $this.flow;
if ((exists $flow flowSetup) -and (exists $flow.flowSetup.PsObject.methods customTitle)) {
$this.find("task-head-title").setText("Task:$($flow.flowSetup.customTitle($flow,$this,$($this.title)))");
} else {
$this.find("task-head-title").setText("Task:$($this.title)");
}
$desc = "getTaskDesc not defined";
if (exists $this.methods getTaskDesc) {
$desc = $this.custObj.getTaskDesc($this);
}
$this.find("desc-lines").setText($desc);
if ($this.optFind("Run Task") -ne $null) {
if ($this.bRunLocked) {
[void]$this.find("Run Task").disableLink();
} else {
[void]$this.find("Run Task").enableLink();
}
}
}
<#.md
.desc
The method updates the dependency tree.
#>
[void]updateDependencyTree([boolean]$bInitial) {
hlogBoth("updateDependencyTree $bInitial $this");
$bDirtyLayout = $false;
[int64]$maxTS = 0;
forEach($task in $this.flow.tasks) {
$task.setPrimaryFlags();
if ($task.name -eq $this.name) {$task.bIsCurrent = $true;}
$maxTS = $task.setDerivedFlags($maxTS);
if ($task.whenFail -ne $null) {
if ($task.menuDiv.bHidden -ne !$task.bWhenShow) {
$task.menuDiv.setHidden(!$task.bWhenShow);
$bDirtyLayout = $true;
}
}
if (exists $task.methods showWhen) { # show in menu when task indicates to be shown
hlog("showWhen $($task.toString()) $($task.name)");
$bShow = [boolean]$task.custObj.showWhen($task);
if ($task.menuDiv.bHidden -ne !$bShow) {
$task.menuDiv.setHidden(!$bShow);
$bDirtyLayout = $true;
}
}
$img = $task.form.icons.iconQ;
if ($task.bRunGood -and !$task.bRunStale) {$img = $task.form.icons.iconOK;}
if ($task.bRunGood -and $task.bRunStale) {$img = $task.form.icons.iconWOK;}
if ($task.bRunFail) {$img = $task.form.icons.iconWX;}
if ($task.bRunLocked) {$img = $task.form.icons.iconWX;}
if ($task.bRunLapsed) {$img = $task.form.icons.iconWX;}
if ($task.bBroken) {$img = $task.form.icons.iconX;}
if ($task.bIsCurrent -and !$task.bRunLocked -and !$task.bBroken) {
if ($task.bRunFail) {
$img = $task.form.icons.iconX;
} else {
if ($task.bRunGood -and !$task.bRunStale -and !$task.bRunLapsed) {
$img = $task.form.icons.iconOK;
} else {
$img = $task.form.icons.iconQ;
}
}
}
$icon = $task.find("task-icon");
$icon.peer.image = $img;
$str = "";
if ($task.bRunGood) {$str += "good ";}
if ($task.bRunFail) {$str += "fail ";}
if ($task.bRunStale) {$str += "stale ";}
if ($task.bRunLocked) {$str += "locked ";}
if ($task.bRunLapsed) {$str += "lapsed ";}
if ($task.bisCurrent) {$str += "current ";}
if ($task.bBroken) {$str += "broken ";}
$icon.form.toolTip.SetToolTip($icon.peer,"$str".trim());
}
# update status line
$this.refreshRgtPanel();
$brf = $this.getBriefFile();
$this.updateStatusLine($brf);
if ($bInitial) {$this.form.bNoJam = $true};
if ($bDirtyLayout) {
hlog("Update menu layout");
$elem = $this.form.findElem("menu-panel");
$elem.form.bLayDirty = $true;
$elem.layout();
}
}
<#.md
.desc
First pass at setting the Run status flags.
.notes
Earlier versions had the notion of Cycles. This has been removed from this version. Some Task flags exist which never get set.
#>
#bRunGood and $bRunFail, runTS, cycTS
[void]setPrimaryFlags() {
$this.bRunFail = $false;
$this.bRunGood = $false;
$this.bRunStale = $false;
$this.bRunLocked = $false;
$this.bRunLapsed = $false;
$this.bIsCurrent = $false;
$this.runTS = 0;
$Brfht = $this.getBriefFile();
if ($Brfht -ne $null) {
$this.runTS = $this.briefTS;
if ($BrfHT.sCondCode -eq "GOOD") {
$this.bRunGood = $true;
} else {
$this.bRunFail = $true;
}
}
if ($this.bBroken) {
$this.bRunLocked = $true;
$this.bRunFail = $true;
}
if (test-path $this.statlocn) {
$file = $(Get-Item $this.statlocn)
$this.runTS = (fileUnixWriteTime $this.statlocn);
}
if (test-path $this.loglocn) {
if ($this.runTS -eq 0) {
$this.bRunFail = $true; # run must have aborted
}
$fileTS = (fileUnixWriteTime $this.loglocn)
if ($fileTS -gt $this.runTS) { #usually later
$this.runTS = $fileTS;
}
}
}
[void]markManualTaskStatus([boolean]$updateTree) {
if (!(test-path $this.statlocn)) {throw "lost manual brief file $this"}
$brfHT = $this.getBriefFile();
$bHaveNotDone = $false;
forEach($manStep in $this.manSteps) {
$labName = "step-$($manStep.line)"
if ((!(exists $brfHT $labName)) -or (!($brfHT[$labName]))) {
$bHaveNotDone = $true;
}
}
hlog("markManualTaskStatus $bHaveNotDone $($brfHT.sCondCode) $updateTree")
if ($bHaveNotDone) {
if ($brfHT.sCondCode -ne 'FAIL') {
$brfHT.sCondCode = 'FAIL';
$brfHT.sReason = "All manual steps not completed";
$this.stowBriefFile($brfHT);
}
} else {
if ($brfHT.sCondCode -ne 'GOOD') {
$brfHT.sCondCode = 'GOOD';
$brfHT.sReason = "All manual steps completed";
$this.stowBriefFile($brfHT);
}
}
if ($brfHT.sCondCode -eq 'GOOD') {
$this.statGood("Manual Step(s) completed");
[void]$this.find('Reset TODO Steps').enableLink();
#$this.find("task-icon").peer.image = $this.form.icons.iconOK;
$this.populateBriefGrid($false);
} else {
$this.statWarn("Manual step(s) not performed");
[void]$this.find('Reset TODO Steps').enableLink();
#$this.find("task-icon").peer.image = $this.form.icons.iconQ;
}
if ($updateTree) {$this.updateDependencyTree($false)}
}
#bRunStale and $bRunnable
<#.md
.desc
Second look at setting the Run status flags with consideration for prior task flags.
#>
[int64]setDerivedFlags([int64]$maxTS) {
if ($this.whenFail -ne $null) {
$show = $false;
forEach($prevTask in $this.whenFail) {
if ($this.whenFail.bRunFail) {$show = $true;}
}
$this.bWhenShow = $show;
}
if ($this.bBroken) {$this.bRunLocked = $true;}
if ($this.dependsOn -ne $null) {
[boolean]$bOK = $true;
forEach($dt in $this.dependsOn) {
if ($dt.runTS -eq 0) {$bOK = $false;}
if ($dt.bRunFail) {$bOK = $false;}
if ($dt.bRunLocked) {$bOK = $false;}
if ($dt.bRunStale) {$bOK = $false;}
if ($dt.runTS -gt $this.runTS) {$this.bRunLapsed = $true;}
}
if (!$bOK) {$this.bRunLocked = $true;}
}
if ($this.runTS -gt $maxTS) {$maxTS = $this.runTS};
if ($this.runTS -lt $maxTS) {$this.bRunStale = $true;}
return $maxTS;
}
[hashtable]loadBriefFile() {
if (test-path $this.statlocn) {
$json = Get-Content -path $this.statlocn -encoding ascii
[hashtable]$ht = jsonAsHashTable $json
$this.brief = $ht;
$this.briefTS = (fileUnixWriteTime $this.statlocn)
if ($ht.sCondCode -eq 'GOOD') {
$this.bRunFail = $false;
} else {
$this.bRunFail = $true;
}
return $ht;
} else {
$this.brief = $null;
$this.briefTS = 0;
return $null
}
}
#get cached version
[hashtable]getBriefFile() {
if ($this.brief -eq $null) {return $this.loadBriefFile();}
return $this.brief;
}
[void]stowBriefFile([hashtable]$statHT) {
$statText = ConvertTo-Json -InputObject $statHT -depth 5
[void]($statText | Out-File -FilePath $this.statlocn -encoding ascii)
hlog("Brief file $($this.statlocn) written");
$this.brief = $null;
$this.briefTS = 0;
}
<#.md
.desc
Update status line in right hand panel
.notes
This has to be run after the status fields of the Task are set.
#>
[void]updateStatusLine([hashtable]$brf) {
if (!(test-path $this.statlocn)) {return;}
$file = $(Get-Item $this.statlocn)
hlog("updateStatusLine $($this.statlocn) lwt=$(exists $file lastWriteTime) cls=$($file.getType().FullName) $($file.lastWriteTime)")
#if (exists $file lastWriteTime)#>{$this.find("stat-time").setText("Completion Date: $($file.lastWriteTime)")}
$this.find("stat-time").setText("Completion Date: $($file.lastWriteTime)")
forEach($k in (& sortedKeys($brf))) {
$v = $brf[$k];
#hilite -yellow "$k is $v"
if ($k -eq "sCondCode") {
if ($v -eq "GOOD") {
if ($this.bRunStale) {
$this.statWarn("Run completed: $v");
$this.find("stat-why").setText("Results are Stale").foreColor("warn");
#$this.find("task-icon").peer.image = $this.form.icons.iconQ;
} else {
$this.statGood("Run completed: $v");
if (exists $brf sReason) {
$this.find("stat-why").setText("$($brf.sReason)").foreColor("good");
}
#$this.find("task-icon").peer.image = $this.form.icons.iconOK;
}
} elseif ($v -eq "FAIL") {
$this.statWarn("Run completed: $v");
#$this.find("task-icon").peer.image = $this.form.icons.iconX;
if (exists $brf sReason) {
$this.find("stat-why").setText("$($brf.sReason)").foreColor("warn");
}
} else {
$this.statFlag("Run completed: $v");
if (exists $brf sReason) {
$this.find("stat-why").setText("$($brf.sReason)").foreColor("flag");
}
}
}
}
}
[void]viewRunTaskLog() {
hlog("viewRunTaskLog for $this invoked");
runlog("workflow-viewlog $($this.execlocn) $($this.name) $($this.type)")
if ($this.prevLogDlg -ne $null) { # EC9B29
$logchk = $this.form.findElemOpt("log-view-keep");
hlog("$logchk $($logchk.isChecked())")
if (($logchk -eq $null) -or !($logchk.isChecked())) {
$this.prevLogDlg.peer.close();
$this.prevLogDlg = $null;
}
}
if (test-path $this.loglocn) {
$logData = (Get-Content -path $this.loglocn -encoding ascii)
if ($logData -eq $null) {$logData = "no log data produced by $($this.name)"}
[dialog]$dlg = [Dialog]::makeCommonDialog($this.menuDiv.form,230,500,'att',"Log View: $($this.loglocn)",$false)
$this.prevLogDlg =$dlg;
$wid = $this.defLogWid;
$hgt = $this.defLogHgt;
forEach($line in ($logdata -split "\r\n")) {
#hlog("Line length $($line.length)")
if ($line.length * 8 -gt $wid) {$wid = $line.length * 8}
}
if ($wid -gt 2200) {$wid = 2200}
hlog("dims $wid $hgt")
$pan = ([Panel]::createPanel($dlg,'wrap')).setMar(1,1)
[TextBox]$box = [TextBox]::createTextBox($pan,"$wid,$hgt",$null,$false);
$box.peer.MultiLine = $true;
$box.peer.ScrollBars = 'Vertical'
$box.peer.Font = $this.form.getFixedFont(8);
$box.peer.text = [string]::join([environment]::newline, $logData)
$dlg.layout();
$dlg.peer.show();
$box.peer.DeselectAll();
} else {
[void](emitTrouble $this.menuDiv.form "Log File $($this.loglocn) lost")
}
}
#---- formatter methods ----
[hashtable] formatTaskViewGrid([Flow]$flow, [Object]$ctx, [Windows.Forms.DataGridView]$dgv, [Area]$par) {
hlog("formatGrid called $this $dgv");
$dgv.ReadOnly = 'true';
#$dgv.AutoSizeColumnsMode = 'none';
$dgv.AllowUserToAddRows = $false
$dgv.RowHeadersVisible = $false;
[Grid]::addCols($dgv, "Field/150,Value/500");
[Grid]::addRow($dgv, "Seq", $this.seq, "Execution Sequence");
[Grid]::addRow($dgv, "Name", $this.name);
[Grid]::addRow($dgv, "Type", $this.type);
if ($this.flow.flowSetup -ne $null) {
[Grid]::addRow($dgv, "flowSetup", $this.flow.flowSetup);
}
if ($this.libLocn -ne $null) {
[Grid]::addRow($dgv, "libLocn", $this.libLocn);
}
[Grid]::addRow($dgv, "execLocn", $this.execLocn);
[Grid]::addRow($dgv, "execDef", $this.execDef);
[Grid]::addRow($dgv, "helpLocn", $this.helpLocn);
if ($this.taskCfg -ne $null) {
[Grid]::addRow($dgv,"**CFG**","--- task CFG ---");
forEach($vbl in $this.taskCfg.keys) {
[Grid]::addRow($dgv,$vbl,$this.taskCfg[$vbl]);
}
}
##[Grid]::addRow($dgv,"StatLocn",$this.statlocn);
##[Grid]::addRow($dgv,"DataLocn",$this.datalocn);
<#
if ($this.bLibTask) {
[Grid]::addRow($dgv,"LibTask",$this.execDef); ##EC0516
[Grid]::addRow($dgv,"LibBase",$this.libBase);
[Grid]::addRow($dgv,"LibLocn",$this.libLocn);
[Grid]::addRow($dgv,"ExecOvrDef",$this.execOvrDef);
} else {
[Grid]::addRow($dgv,"ExecDef",$this.execDef); ##EC0516
}
if ($this.custObj -ne $null) {[Grid]::addRow($dgv,"CustObj","$($this.custObj)");} ##EC1B13
if ($this.overObj -ne $null) {[Grid]::addRow($dgv,"OverObj","$($this.overObj)");} ##EC1B13
$flags = "";
if ($this.bBroken) {$flags += " broken=T"};
if ($this.bRunFail) {$flags += " fail=T"};
if ($this.bRunGood) {$flags += " good=T"};
if ($this.bRunStale) {$flags += " stale=T"};
if ($this.bRunLapsed) {$flags += " lapse=T"};
if ($this.bRunLocked) {$flags += " locked=T"};
#if ($this.bRunnable) {$flags += " rable=T"};
#if ($this.bRunLater) {$flags += " later=T"};
[Grid]::addRow($dgv,"Flags","$($flags.trim())");
$CRLF = "`r`n"
if ($this.form.appGbl.count -gt 0) {
$hint = ($this.form.appGbl | ConvertTo-Json -depth 5 -compress)
$hint = $hint -replace '(,"[^"]+":)',("`r`n"+'$1')
[Grid]::addRow($dgv,"AppGbl","count=$($this.form.appGbl.count)",$hint);
}
if ($this.runTS -ne 0) {[Grid]::addRow($dgv,"RunTS","$($this.runTS)","$(fromUnixTime $this.runTS)");}
if ($this.cycTS -ne 0) {[Grid]::addRow($dgv,"cycTS","$($this.cycTS) ix=$($this.maxCycIX)","$(fromUnixTime $this.cycTS)");}
if ($this.briefTS -ne 0) {[Grid]::addRow($dgv,"BriefTS","$($this.briefTS)","$(fromUnixTime $this.briefTS)");}
if ($this.whenCycle -ne $null) {
[Grid]::addRow($dgv,"WhenCycle",$this.whenCycle);
[Grid]::addRow($dgv,"CurCycIX","$($this.curCycIX)");
[Grid]::addRow($dgv,"CurCycle","$($this.getcurCycle())");
[Grid]::addRow($dgv,"GoodRuns","$($this.goodRuns)");
[Grid]::addRow($dgv,"ArrIX","$($this.arrIX -join ',')");
}
if ($this.priorTask -ne $null) {[Grid]::addRow($dgv,"PriorTask","$($this.priorTask.name)");}
if ($this.whenFail -ne $null) {[Grid]::addRow($dgv,"WhenFail","$($this.whenFail.name)");}
if ($this.depTasks -ne $null) {[Grid]::addRow($dgv,"DepTasks","Count=$($this.depTasks.count)","$($this.depTasks -join $CRLF)");}
if ($this.dependsOn -ne $null) {[Grid]::addRow($dgv,"DependsOn","Count=$($this.dependsOn.count)","$($this.dependsOn -join $CRLF)");}
if ($this.type -eq 'cycle') {
$cycHT = $this.form.cycle.clone();
[void]$cycHT.remove('links')
$hint = ($cycHT | ConvertTo-Json -depth 5 -compress)
$hint = $hint -replace '(,"[^"]+":)',("`r`n"+'$1')
[Grid]::addRow($dgv,"FormCycle","year=$($cycHT.year) cats$($cycHT.cats))",$hint);
}
if ($this.startAppOpts -ne $null) {[Grid]::addRow($dgv,"startAppOpts","Count=$($this.startAppOpts.count) exec=$($this.startAppOpts.exec)","");}
if ($flow.cfb -ne $null) {
[boolean]$hdr = $false;
$flow.cfb.PsObject.methods | ForEach {
$name = $_.name
$type = $_.getType()
if("$type" -eq "psscriptmethod") {
if (!$hdr) {
$hdr = $true;
[Grid]::addRow($dgv,"**SETUP**","--- implemented methods ---");
}
$val = $_.value
[Grid]::addRow($dgv,$name,$val,$null);
}
}
[boolean]$hdr = $false;
$flow.cfb.PsObject.properties | ForEach {
if (!$hdr) {
$hdr = $true;
[Grid]::addRow($dgv,"**SETUP**","--- property values ---");
}
$name = $_.name
$type = $_.getType()
$val = $_.value
[Grid]::addRow($dgv,$name,$val,"type=$type");
}
}
if ($this.methods -ne $null) {
[Grid]::addRow($dgv,"**METHODS**","--- implemented methods ---");
forEach($meth in $this.methods.keys) {
[Grid]::addRow($dgv,$meth,"");
}
}
if ($this.vbls -ne $null) {
[Grid]::addRow($dgv,"**VBLS**","--- populated variables ---");
forEach($vbl in $this.vbls.keys) {
$hint = $this.vbls[$vbl];
if (($vbl -eq "cp") -and ($hint.length -gt 100)) {
$hint = $hint -replace ';',";`r`n"
}
[Grid]::addRow($dgv,$vbl,$this.vbls[$vbl],$hint);
}
}
#>
if ($this.type -eq [TaskType]::Java) {
$parmsHT = $this.fetchTaskParams();
[string]$main = [string]$this.custObj.fetchJavaMain($this,$parmsHT);
[Grid]::addRow($dgv, "JavaMain", $main);
}
if ($this.methods -ne $null) {
[Grid]::addRow($dgv, "**METHODS**", "--- implemented methods ---");
forEach ($meth in $this.methods.keys) {
[Grid]::addRow($dgv, $meth, "");
}
}
if ($this.vbls -ne $null) {
[Grid]::addRow($dgv, "**VBLS**", "--- populated variables ---");
forEach ($vbl in $this.vbls.keys) {
$hint = $this.vbls[$vbl];
if (($vbl -eq "cp") -and ($hint.length -gt 100)) {
$hint = $hint -replace ';', ";`r`n"
}
[Grid]::addRow($dgv, $vbl, $this.vbls[$vbl], $hint);
}
}
[void][Grid]::calcGridSize($dgv);
return @{ }; #indicate we are good
}
# build params from user supplied script
[Object[]]fetchOptions() {
<#if (exists $this.methods ovrOptions) {
hlog("========= $this fetchOptions ========= $($this.methods.ovrOptions)");
} else {
hlog("========= $this fetchOptions ========= $($this.name))");
}#>
[Object[]]$opts = [Object[]]$this.custObj.options($this);
if (($this.overObj -ne $null) -and (exists $this.methods ovrOptions)) {
$opts = [Object[]]$this.overObj.ovrOptions($this, $opts);
}
return $opts;
}
[hashtable] formatParamViewGrid([Flow]$flow, [Object]$ctx, [Windows.Forms.DataGridView]$dgv, [Area]$par) {
$task = $this;
hlog("formatParamViewGrid called $task $dgv");
$dgv.ReadOnly = 'true';
#$dgv.AutoSizeColumnsMode = 'none';
$dgv.AllowUserToAddRows = $false
$dgv.RowHeadersVisible = $false;
$ht = @{}
if ($task.type -eq [TaskType]::Java) {
##$runparms = $task.populateJavaParms($dgv)
$ht = $this.fetchTaskParams();
} elseif ($task.type -eq [TaskType]::NodeJS) {
#$runparms = $task.populateNodejsParms($dgv)
} elseif ($task.type -eq [TaskType]::Script) {
#$runparms = $task.populateScriptParms($dgv)
} else {
return $null;
}
if ($ht.count -eq 0) {
[Grid]::addCols($dgv, "No params are passed/300");
} else {
[Grid]::addCols($dgv, "Param/150,Value/500");
forEach ($vbl in $ht.keys) {
[Grid]::addRow($dgv, "-$($vbl)", "$($ht[$vbl])");
}
}
return $ht;
}
[hashtable]fetchTaskParams() {
$ht = @{ }
if ($this.methods -eq $null) {
hlogBoth("no methods");
return $ht;
}
if (exists $this.methods options) {
$opts = $this.fetchOptions();
forEach ($opt in $opts) {
hlog("process option $($opt.parm) $($opt.type)")
[Elem]$elem = $this.optFind("opt-$( $opt.parm )");
if ((exists $opt local) -and ($opt.local)) {
continue;
} #EC9B30
if (($opt.type -eq "input") -or ($opt.type -eq "file") -or ($opt.type -eq "dir")) {
if ($elem -eq $null) {throw "elem expected for $($opt.type)"}
if (($elem.peer.text -ne "") -and (exists $opt place) -and ($elem.peer.text -ne $opt.place)) {
if (!($elem.peer.readonly)) { # readonly used to display not pass parms such as context tasks.
$ht[$opt.parm] = $elem.peer.text;
}
} else {
if ($this.type -ne 'script') {
$ht.remove($opt.parm);
}
}
} elseif ($opt.type -eq "combo") {
if ($elem -eq $null) {throw "elem expected for $($opt.type)"}
[string]$val = $elem.getSelectedValue();
hlog("combo select $( $val ) $( $elem.peer.SelectedIndex )");
if ($val -ne "") {
$ht[$opt.parm] = $val
} else {
$ht.remove($opt.parm);
}
} elseif ($opt.type -eq "radio") {
if ($elem -eq $null) {throw "elem expected for $($opt.type)"}
forEach ($radio in $elem.peer.Controls) {
if ($radio.checked) {
if ($radio.tag -ne $null) {
$ht[$opt.parm] = $radio.tag
} else {
$ht.remove($opt.parm);
}
}
}
} elseif ($opt.type -eq "check") {
if ($elem -eq $null) {throw "elem expected for $($opt.type)"}
if ($this.type -eq 'script') {
if ($elem.peer.checked) {
$ht[$opt.parm] = $true;
} else {
$ht[$opt.parm] = $null;
}
} else {
if ($elem.peer.checked) {
$ht[$opt.parm] = $null;
} else {
$ht.remove($opt.parm);
}
}
} elseif ($opt.type -eq "exec") {
if ($elem -ne $null) {
if ($elem.peer.checked) {
$ht[$opt.parm] = $true;
} else {
$ht[$opt.parm] = $false; #easier to remove
}
}
}
}
[void](stowConfig $this.optLocn $ht)
##$this.htOpts = $ht;
}
$htPrev = $ht;
if (exists $this.methods params) {
$ht = [hashtable]$this.custobj.params($this, $ht);
}
##if (($this.overObj -ne $null) -and (exists $this.methods ovrParams)) {
## $htParm = [hashtable]$this.overObj.ovrParams($this,$htParm);
##}
## if ($this.whenCycle -ne $null) {
## $htParm.curCycle = $this.getcurCycle();
## $htParm.curCycIX = $this.curCycIX;
## }
##if ($this.htOpts -ne $null) {
## forEach ($k in $this.htOpts.keys) {
## $htParm[$k] = $this.htOpts[$k];
## }
##}
##return $htParm;
hlogBoth("fetchTaskParams return $($ht.count) parms $($htPrev.count) opt");
return $ht;
}
[hashtable] formatJavaClassViewGrid([Flow]$flow, [Object]$ctx, [Windows.Forms.DataGridView]$dgv, [Area]$par) {
$task = $this;
hlog("formatJavaClassViewViewGrid called $task $dgv");
$dgv.ReadOnly = 'true';
#$dgv.AutoSizeColumnsMode = 'none';
$dgv.AllowUserToAddRows = $false
$dgv.RowHeadersVisible = $false;
##$ht = @{}
##$ht = $this.fetchTaskParams();
$pathStr = [string]$this.custObj.fetchJavaClassStr($this);
hlog("formatJavaClassViewViewGrid $pathStr");
$resolveStr = (& resolveClassPath $pathStr);
[Grid]::addCols($dgv, "Path Dir/350,Path Lib/350,File Date/150");
forEach ($str in ($resolveStr -split ';')) {
if ($str -ne "") {
if ($str -match '[.]((jar)|(zip))$') {
#hlogBoth("fileDate $str")
$file = (get-item -path $str);
$dateStr = get-date -date $file.LastWriteTime -format 'yyyy-MM-dd HHmmss'
#$path = $str | split-path -parent
[Grid]::addRow($dgv, @("", "$($file.name)", "$dateStr"));
} else {
[Grid]::addRow($dgv, @("$str", "", ""));
}
}
}
return @{};
}
# EC8C18 - run task Option program such as Excel.
[void]runTaskOptionProgram([string]$name) {
if (!(test-path $name)) {return};
if (exists $this.methods startApplicationProgram) {
$this.commObj = [object]($this.custobj.startApplicationProgram($this,[string]$name));
hlogBoth("Application started $name");
}
}
} ## - end of [TaskExec]
<#.md
.desc
desc tbd of the @@Task fields
.details
details tbd
#>
class ViewTaskExec : ViewTask {
ViewTaskExec([Flow]$flow,[Task]$task,[Panel]$menuPan,[Panel]$statPan,[Div]$anchors) : base($flow,$task,$menuPan,$statPan,$anchors) {}
[void] viewTaskHelp([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
[int]$txtW = $elem.form.helpW
[int]$txtH = $elem.form.helpH
[dialog]$dlg = [Dialog]::makeCommonDialog($task.menuDiv.form,$txtW,$txtH,'que',"Task Help: $($task.name)",$false)
$pan = ([Panel]::createPanel($dlg,'wrap')).setMar(0,0).setAbs(1,1);
[TextBox]$box = ([TextBox]::createTextBox($pan,"$($txtW),$($txtH)",$null,$true)).setFill();
$txthelp = $box.peer;
# Note. The RightMargin contortion was discovered thru trial and error.
# without it the lines were wrapped incorrectly (shorter).
$txtHelp.Size = "$($txtW + 20),$($txtH + 25)";
$txtHelp.RightMargin = [int]($txtW - ($txtW * 0.08))
$txtHelp.text = "help text not supplied"
$txtHelp.BackColor = rgb 240 233 241
hlogBoth("view help for $($task.name) $($task.helpLocn) helpSz=$($elem.form.helpW),$($elem.form.helpH) ");
$taskDesc = "getTaskDesc not defined";
if (exists $task.methods getTaskDesc) {
$taskDesc = "$($task.custObj.getTaskDesc($task))";
}
$textRTF = (convertAndLoadRtfFile $task.helpLocn "$($task.name)" $taskDesc);
if ($textRtf -ne $null) {
$txtHelp.RTF = $textRTF
}
$box.peer.ScrollBars = 'Vertical'
$dlg.layout();
$dlg.peer.show();
}
[void] viewRunTaskLog([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlog("viewRunTaskLog for $($task)");
$task.viewRunTaskLog();
}
[void] RunTask([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlogBoth("RunTask for $task)");
$task.runTask();
}
[void] RunJavaTask([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlogBoth("RunJavaTask for $task ctx=$ctx");
$task.runGenericTask($task.runJavaTask);
#$task.runTask();
}
[void] RunScriptTask([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlogBoth("RunScriptTask for $task ctx=$ctx");
$task.runGenericTask($task.runScriptTask);
#$task.runTask();
}
<#
[void] viewTaskParams([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlog("viewTaskParams for $($task)");
[dialog]$dlg = [Dialog]::makeCommonDialog($task.menuDiv.form,10,10,'equ',"Params View: $($task.name)",$false)
$pan = ([Panel]::createPanel($dlg,'wrap')).setMar(1,1)
[Grid]$grid = $this.formatGrid($pan,$null,$null,$task.formatParamViewGrid,$null);
if ($grid -eq $null) {return;} # formatter wants to quit
$dlg.layout();
$dlg.peer.show();
##$grid.peer.Rows[0].Cells[0].selected = $false;
}
#>
[void] viewTaskSetup([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlog("viewTaskSetup for $($task)");
[dialog]$dlg = [Dialog]::makeCommonDialog($task.menuDiv.form,10,10,'col',"Task View: $($task.name)",$false)
$pan = ([Panel]::createPanel($dlg,'wrap')).setMar(1,1)
[Grid]$grid = $this.formatGrid($pan,$null,$null,$task.formatTaskViewGrid,$null);
$dlg.layout();
#$dlg.dump("");
$dlg.peer.show();
$grid.peer.Rows[0].Cells[0].selected = $false;
}
[void] markManualTaskNotDone([Elem]$elem,[Object]$ctx) {
$task = $this.taskPtr;
hlog("markManualTaskNotDone for $($task)");
$brfHT = $task.getBriefFile();
forEach($manStep in $task.manSteps) {
$labName = "step-$($manStep.line)"
$brfHT[$labName] = $false;
$manStep.bIgnore = $true; # do not want more updates till end
$manStep.chkBox.peer.checked = $false;
$manStep.bIgnore = $false; # do not want more updates till end
}
$task.stowBriefFile($brfHT);
$task.markManualTaskStatus($true);
}
[Elem] createWflHdrLink([string]$action,[PSMethod]$meth) {
$lnk = ([Link]::createLink($this.anchors,$action)).backColor("white").setFont('hdrLink')
$lnk.tied = $this.taskPtr;
$lnk.action = $meth;
$lnk.onClick = {
param([Elem]$elem)
[Task]$task = $elem.tied
hlog("clicked $($elem.name) twin=$($elem.tied)");
$elem.action.invoke(@($elem,$elem.ctx));
}
hlog("return createWflHdrLink $lnk")
return $lnk;
}
[Elem] createWflHdrSettings([string]$action) {
$lab = [Label]::createLabel($this.anchors,"$action","40,40").setFont('taskHead')
$lab.form.toolTip.SetToolTip($lab.peer,"Right click for additional Task Functions)");
return $lab;
}
}
# Note: using a function here allows PowerShell to link at run time to this routine
# without getting into co-dependent classes
function createViewTask([Flow]$flow,[Task]$task,[Panel]$menuPan,[Panel]$statPan,[Div]$anchors) {
[ViewTaskExec]$vt = [ViewTaskExec]::new($flow,$task,$menuPan,$statPan,$anchors);
return $vt;
}
<#.md
.desc
Create menu of actions for Task
.details
#>
function createActionMenu([Flow]$flow,[Task]$task,[Label]$lab) {
$cms = New-Object System.Windows.Forms.ContextMenuStrip
[void](createActionItem $cms $flow $task "View Task Definition" $function:actionViewTaskDefn);
if ($task.type -eq [TaskType]::Java) {
[void](createActionItem $cms $flow $task "View Task Parameters" $function:actionViewTaskParms);
[void](createActionItem $cms $flow $task "View Task Class Path" $function:actionViewTaskJavaClassPath);
[void](createActionItem $cms $flow $task "Test Load Main Class" $function:testLoadMainClass);
}
if ($flow.tfs -ne $null) {
#[void](createActionItem $cms $flow $task "Edit $($flow.wflName) Workflow setup" $function:actionCfgWorkflow);
}
#[void](createActionItem $cms $flow $task "Edit $($task.name) definition" $function:actionCfgWorkflow);
$lab.peer.ContextMenuStrip = $cms
}
function createTaskDialogGrid([Flow]$flow,[Task]$task,[string]$title,[PSMethod]$formatter,[int32]$maxH) {
[dialog]$dlg = [Dialog]::makeCommonDialog($task.menuDiv.form,10,10,'col',"$title",$false)
if($maxH -ne 0) {$null = $dlg.setMaxHgt($maxH);} #according to screen height
$pan = ([Panel]::createPanel($dlg,'wrap')).setMar(1,1)
[Grid]$grid = (& formatGrid $pan $null $null $formatter $flow $null);
$dlg.layout();
$dlg.peer.show();
if ($grid.peer.Rows.count -gt 0) {
$grid.peer.Rows[0].Cells[0].selected = $false;
}
}
function createTaskDialogTextBox([Flow]$flow,[Task]$task,[string]$title,[string]$boxData,[int32]$maxH) {
[dialog]$dlg = [Dialog]::makeCommonDialog($task.form,10,10,'col',"$title",$false)
if($maxH -ne 0) {$null = $dlg.setMaxHgt($maxH);} #according to screen height
$pan = ([Panel]::createPanel($dlg,'wrap')).setMar(1,1)
$wid = $task.defLogWid;
$hgt = $task.defLogHgt;
[TextBox]$box = [TextBox]::createTextBox($pan,"$wid,$hgt",$null,$false);
$box.peer.MultiLine = $true;
$box.peer.ScrollBars = 'Vertical'
$box.peer.Font = $task.form.getFixedFont(8);
$box.peer.text = [string]::join([environment]::newline, $boxData)
$dlg.layout();
$dlg.peer.show();
$box.peer.DeselectAll();
$dlg.layout();
$dlg.peer.show();
}
<#.md
.desc
Execute Workflow configuration action
.details
#>
function actionViewTaskDefn([Flow]$flow,[Task]$task) {
hlog("actionViewTaskDefn $($flow.wflName) $task")
[void](& createTaskDialogGrid $flow $task "Task View: $($task.name)" $task.formatTaskViewGrid 0);
}
<#.md
.desc
Execute Workflow configuration action
.details
#>
function actionViewTaskParms([Flow]$flow,[Task]$task) {
hlogBoth("actionViewTaskParms $($flow.wflName) $task")
[void](& createTaskDialogGrid $flow $task "Task Params: $($task.name)" $task.formatParamViewGrid 0);
}
<#.md
.desc
Execute Workflow configuration action
.details
#>
function actionViewTaskJavaClassPath([Flow]$flow,[Task]$task) {
hlogBoth("actionViewTaskJavaClassPath $($flow.wflName) $task")
[void](& createTaskDialogGrid $flow $task "Task Java Class Path: $($task.name)" $task.formatJavaClassViewGrid -300);
}
<#.md
.desc
Execute Workflow configuration action
.details
#>
function testLoadMainClass([Flow]$flow,[Task]$task) {
$main = "org.srp.psec.TestMainLoad";
hlogBoth("testLoadMainClass $($flow.wflName) $task $main")
$testMain = [string]$task.custObj.fetchJavaMain($task,@{});
hlogBoth("======= Invoke java main=$testMain");
$pathStr = [string]$task.custObj.fetchJavaClassStr($task);
hlog("formatJavaClassViewViewGrid $pathStr");
$resolveStr = (& resolveClassPath $pathStr);
$cmdOutStr = . java -cp $resolveStr $main -main $testMain 2>&1
#hFlag("cmdOutput $($cmdOutStr.getType())");
$asStr = [string]::join("`r`n",$cmdOutStr);
[void](& createTaskDialogTextBox $flow $task "Test Java Load Main: $main" $asStr -300);
}
function formatGrid([Area]$par,[string]$size,[string]$locn,[PSMethod]$formatter,[Flow]$flow,[System.Object]$ctx) { #context object
$peer = New-Object Windows.Forms.DataGridView
if ($size -eq "") {
$peer.AutoSize = $true;
} else {
$peer.size = $size
}
if ($locn -ne "") {
$peer.Location = $locn
}
if ($formatter -ne $null) {
$ok = $formatter.invoke(@($flow,$ctx,$peer,$par));
if ($ok -eq $null) {
hlogBoth("Grid formatter failed");
return $null
}; # formatter wants to discontinue
}
$elem = [Grid]::new($peer,$par);
if ($ctx -ne $null) {
$elem.ctx = $ctx;
#if ($ctx -as [task] -ne $null) {$elem.task = $ctx;}
}
return $elem
}
<#.md
.desc
Execute Workflow configuration action
.details
#>
function actionCfgWorkflow([Flow]$flow,[Task]$task) {
hlogBoth("actionCfgWorkflow $($flow.wflName) $task")
#[Form]$form = $task.form;
#if ($form.appJob -ne $null) {
# $form.appJob.guiAppExitCmd = "xfr-config";
#}
#$form.peer.close();
}
<#.md
.desc
Create single action item for Action Menu
.details
Inserts a script block as the action item invoked when the action item is clicked.
.returns void
#>
function createActionItem([System.Windows.Forms.ContextMenuStrip]$cms,[Flow]$flow,[Task]$task,[string]$action,[ScriptBlock]$func) {
$mi = new-object System.Windows.Forms.ToolStripMenuItem::new($action);
$mi.tag = [ActionSet]::new($flow,$task,$func);
$mi.add_Click({
[ActionSet]$set = $this.tag;
hlog("action $($this.text) clicked");
& $set.func $set.flow $set.task
});
[void]$cms.Items.Add($mi);
}
<#.md
.desc
Build option line display from given option
.details
#>
function buildOptionLine([Task]$task,[Area]$div) {
$opts = $task.fetchOptions();
#if ($opts.count -gt 0) {$task.options = $opts};
$optLocn = "$($task.execLocn)/options.json.txt"
if(test-path $optLocn) {
hlog("load options $optLocn")
$ht = (loadCfgFile $optLocn)
#see $ht
} else {
$ht = @{}
}
forEach($opt in $opts) {
#hlog("buildOptionLine $($opt.keys) $task");
$optDiv = ([Div]::createDiv($div,"options")).setAbs(0,1).backColor('white').setMar(2,2).setHorz();
$optLab = ([Label]::createLabel($optDiv,$opt.label,"100,30"));
if ($opt.type -eq "input") {
$place = $null;
if (exists $opt place) {$place = $opt.place;}
$inp = ([InputBox]::createInputBox($optdiv,"300,20",$null,$place)).setName("opt-$($opt.parm)").hook($task);
if (exists $ht $opt.parm) {
$inp.peer.text = $ht[$opt.parm];
}
if (exists $opt value) {
$inp.peer.text = $opt.value;
}
if ((exists $opt readonly) -and ($opt.readonly)) {
$inp.setReadonly();
}
if (exists $opt regex) {
#hlog("Install validation $($opt.parm) $($opt.regex)")
[hashtable]$ctx = @{};
$ctx.task = $task;
$ctx.label = $optLab;
$ctx.regex = $opt.regex;
$inp.focusHandler([ElemMate]::new("focus",$function:validateOptFld,$ctx));
}
} elseif ($opt.type -eq "file") {
$place = $null;
if (exists $opt place) {$place = $opt.place;}
$inp = ([InputBox]::createInputBox($optdiv,"300,20",$null,$place)).setName("opt-$($opt.parm)").hook($task);
if (exists $ht $opt.parm) {
$inp.peer.text = $ht[$opt.parm];
}
$clickBrowse = {
param([Elem]$elem,[Object]$ctx);
hlog("clickBrowse $ctx");
#$gbl.ctx.exitStr = "cancel"; ##confirmCancel Dialog exit will confirm OK
#$elem.form.peer.close();
$dlg = New-Object System.Windows.Forms.OpenFileDialog
$dlg.FileName = $null;
if (exists $ctx.ht $ctx.opt.parm) {
$dlg.FileName = $ctx.ht[$ctx.opt.parm];
}
$dlg.Filter = 'ALL(*.*)|*.*'
if (exists $ctx.opt filter) {
$dlg.Filter = $ctx.opt.filter
}
#$dlg.title = "Select Option $($ctx.place)"
$result = $dlg.ShowDialog();
if ($result -ne "Cancel") {
hlog("result $result $($dlg.FileName)");
$elem.peer.text = $dlg.FileName;
}
#return $dlg.SelectedPath
}
$ctx = @{ht=$ht;opt=$opt;place=$place}
$inp.clickHandler([ElemMate]::new("click",$clickBrowse,$ctx));
} elseif ($opt.type -eq "dir") {
$place = $null;
if (exists $opt place) {$place = $opt.place;}
$inp = ([InputBox]::createInputBox($optdiv,"300,20",$null,$place)).setName("opt-$($opt.parm)").hook($task);
if (exists $ht $opt.parm) {
$inp.peer.text = $ht[$opt.parm];
}
$clickBrowse = {
param([Elem]$elem,[Object]$ctx);
hlog("clickBrowse $ctx");
$dlg = New-Object System.Windows.Forms.FolderBrowserDialog
$dlg.selectedPath = $null
if (exists $ctx.ht $ctx.opt.parm) {
$dlg.selectedPath = $ctx.ht[$ctx.opt.parm];
}
$dlg.ShowNewFolderButton = $true
$dlg.Description = "Folder browse for $($ctx.place)"
$result = $dlg.ShowDialog();
if ($result -ne "Cancel") {
hlog("result $result $($dlg.SelectedPath)");
$elem.peer.text = $dlg.SelectedPath;
}
}
$ctx = @{ht=$ht;opt=$opt;place=$place}
$inp.clickHandler([ElemMate]::new("click",$clickBrowse,$ctx));
} elseif ($opt.type -eq "check") {
$place = "turns on $($opt.parm) option if true";
if (exists $opt place) {$place = $opt.place;}
$inp = ([CheckBox]::createCheckBox($optdiv,"300,20",$null,$place)).setName("opt-$($opt.parm)").hook($task);
if ((exists $ht $opt.parm) -and $ht[$opt.parm]) {#existance and true implies true else false
$inp.peer.checked = $true;
}
if (exists $opt onClick) {
$inp.clickHandler([ElemMate]::new("click",$opt.onClick,$task));
}
} elseif ($opt.type -eq "radio") {
if (!(exists $opt valset)) {throw "expect valset parameter"}
$vals = parseValSet($opt.valset);
$size = "800,30"
if ((exists $opt newLine) -and ($opt.newLine)) {$size = "800,30,$($vals[1].count)"}
$inp = ([RadioBoxes]::createRadioBoxes($optdiv,$size,$null,$vals[0],$vals[1],$vals[2],$null)).setName("opt-$($opt.parm)").hook($task); #AutoSize does not work
forEach($radio in $inp.peer.Controls) {
if ((exists $ht $opt.parm) -and ($ht[$opt.parm] -eq $radio.tag)) {
$radio.checked = $true;
}
}
} elseif ($opt.type -eq "combo") {
if (!(exists $opt valset)) {throw "expect valset parameter"}
$vals = parseValSet($opt.valset);
$selected = $vals[2];
if (exists $ht $opt.parm) {
$ix = -1;
forEach($value in $vals[0]) {
$ix += 1;
if ($value -eq $ht[$opt.parm]) {
$selected = $ix;
break;
}
}
}
$inp = ([ComboBox]::createComboBox($optdiv,$null,$null,$vals[0],$vals[1],$selected)).setName("opt-$($opt.parm)").hook($task);
if (exists $opt wid) {# EC1518
$inp.peer.width = $opt.wid;
}
if (exists $ht $opt.parm) {
$ix = -1;
forEach($value in $inp.peer.tag) {
$ix += 1;
if ($value -eq $ht[$opt.parm]) {
$inp.peer.selectedIndex = $ix;
break;
}
}
}
} elseif ($opt.type -eq "exec") {
if (!(exists $opt exec)) {throw "expect exec parameter"}
if ((exists $opt auto) -and ($opt.auto)) {
$chkAuto = ([CheckBox]::createCheckBox($optdiv,"80,20",$null,"auto")).setName("opt-$($opt.parm)").hook($task)
$chkAuto.peer.checked = $false
if ((exists $ht $opt.parm) -and $ht[$opt.parm]) {#existance and true implies true else false
$chkAuto.peer.checked = $true;
}
$task.autoStartFlag = $chkAuto
$task.startAppOpts = $opt
}
$lnk = ([Link]::createLink($optdiv,"$($opt.exec)")).hook($task);
$lnk.tied = @($task,$opt.exec)
$lnk.peer.add_Click({
$elem = $this.tag;
$task = $elem.tied[0]
$exec = $elem.tied[1]
hlog("exec program $exec")
$task.runTaskOptionProgram($exec);
});
} else {
}
}
}
<#.md
.desc
Parse value set
.details
.notes
```
ValSet format:
eg. valset='--none--/*,green,red/show red,blue/set blue'
comma delimited pairs, each pair part delimited by '/'
$pair[0] - value & label if not supplied. Value of * sets value as $null and $pair[1] required to supply label.
$pair[1] - if supplied is label. *prefix removed but sets as selected value. If not supplied, value is used as label
```
#>
function parseValSet([string]$valset) {
$values = @()
$labels = @()
[int]$selected = -1
$ix = -1;
forEach($str in $valset.split(",")) {
$ix += 1
$pair = $str.split("/");
if ($pair.count -eq 1) {
$values += $pair[0];
$labels += $pair[0];
} else {
if ($pair[0] -eq "*") {
$values += $null
} else {
$values += $pair[0];
}
if ($pair[1].substring(0,1) -eq "*") {
$labels += $pair[1].substring(1);
$selected = $ix
} else {
$labels += $pair[1];
}
}
}
#hlog("valset $selected vals $($values -join ';') labels $($values -join ';')")
return @($values,$labels,$selected)
}
<#.md
.desc
Validates an option field with the regex property
.details
The hashtable contains the properties task, label and regex field.
These are used to validate the input data. If not valid the label field is marked in red
and the Run Task button disabled.
#>
function validateOptFld([Elem]$elem,[hashtable]$ctx) {
if ($elem.peer.text -match $ctx.regex) {
hlog("validateOptFld OK $($ctx.regex) $($elem.peer.text)");
if ($ctx.task.optFind("Run Task") -ne $null) {
[void]$ctx.task.find("Run Task").enableLink();
[void]$ctx.label.foreColor("black");
}
} else {
hlog("validateOptFld FAILED $($ctx.regex) $($elem.peer.text)");
if ($ctx.task.optFind("Run Task") -ne $null) {
[void]$ctx.task.find("Run Task").disableLink();
[void]$ctx.label.foreColor("red");
}
}
}