Note: The following instructions assume that the user's preferred process views are set to “Valid Version”. Furthermore, it is assumed that email notifications are enabled in PkitConfig.xml and Stages knows about the user's email address. Finally, the user needs process application permissions.
Usually a process is not a standalone entity, but is integrated into a system of dependent processes. E.g. there might be a system level process for 'System A' with dependent processes for each subsystem like 'Mechanics', 'Hardware' and 'Software'. The phases of the subsystems probably correlate in some way with the phases on system level and it might be desirable to keep track of the freeze subsystem phases on system level. This can be accomplished as shown in the following example by additional modeling and programming of a custom process start page.
<processtype ident="..."> [...] <element ident="phase" subtypes="phase milestone" freezableSubtypes="phase" freezeScript="local/freeze/moduleSpec.js"> <model> <associations> <association target="phase"> <association-type ident="correlate" sourceRole="system" targetRole="subsystem"/> </association> [...] </associations> [...] </model> <view> [...] <!--Extend the view to be able to model the correlate association--> </view> </element> [...] </processtype>
An additional association is needed to define the correlation of the system phase to the subsystem phase. Please note that the association ident can be defined freely as it is only used in the custom process start page as shown below.
Provide a custom start page at [installDir]/tomcat/webapps/pkit/local/process/pkit/[metamodelIdent]/view/screen/PkitProcess.ftl
<#ftl strip_whitespace=true> <#import "../../../view/common/object/object.ftl" as object/> <#import "../../../view/common/core/page/page.ftl" as page/> <@page.page> <@page.mainHeading> <@page.mainHeadingName> ${self.getText("process.main.title")} <@object.writeProtection /> </@page.mainHeadingName> <@page.mainHeadingInfo> ${self.processType}, ${self.getText("process.process.version", [self.version!""])} </@page.mainHeadingInfo> </@page.mainHeading> <#macro renderPhaseOverview> <#local script> function PhaseAdapter(phase) { this.phase = phase; this.dependentPhases = new Packages.org.eclipse.emf.common.util.BasicEList(); this.duration = 1; } function SubsystemAdapter(subsystem) { this.subsystem = subsystem; this.phases = new Array(); this.duration = 0; this.addPhase = function(phase, i) { this.phases.push(phase); if (this.duration <i + 1) { phase.duration = i + 1 - this.duration; } this.duration = i + 1; } } function PhaseMatrix(process) { this.system = new SubsystemAdapter(process.subsystem); this.subsystems = new Packages.java.util.LinkedHashMap(); this.init = function () { var phases = this.filter(process.phaseIndex_.list); for (var i = 0; i <phases.size(); i++) { var phase = phases.get(i); var phaseAdapter = new PhaseAdapter(phase); this.add(phaseAdapter, i); var associations = phase.getModelAssociation("correlate", "Phase", "system", null).references; for (var iterator = associations.iterator(); iterator.hasNext();) { var dependentPhase = iterator.next().target; this.add(new PhaseAdapter(dependentPhase), i); phaseAdapter.dependentPhases.add(dependentPhase); } } } this.add = function(phaseAdapter, i) { var subsystem = phaseAdapter.phase.process.subsystem; if (this.system.subsystem.equals(subsystem)) { this.system.addPhase(phaseAdapter, i); } else { var subsystemAdapter = this.subsystems.get(subsystem.id); if (subsystemAdapter == null) { subsystemAdapter = new SubsystemAdapter(subsystem); this.subsystems.put(subsystem.id, subsystemAdapter); } subsystemAdapter.addPhase(phaseAdapter, i); } } this.filter = function (phases) { var filteredPhases = new Packages.java.util.ArrayList(); for (var i = 0; i <phases.size(); i++) { var phase = phases.get(i); if (phase.findSubtype() == "phase") { filteredPhases.add(phase); } } return filteredPhases; } this.init(); } new PhaseMatrix(self); </#local> <#local phaseOverview = javascript(self, script) /> <table class="phaseOverview"> <tr> <td></td> <#local nmbrOfSubsystems=phaseOverview.subsystems?size/> <#local hasDependentPhases=nmbrOfSubsystems> 0> <@renderPhases phases = phaseOverview.system.phases hasDependents = hasDependentPhases/> </tr> <#list phaseOverview.subsystems?values as subsystem> <tr> <td>${subsystem.subsystem.name}</td> <@renderPhases phases = subsystem.phases hasDependents = false/> <#if phaseOverview.system.phases?size> subsystem.duration> <#list 0..phaseOverview.system.phases?size - 1 - subsystem.duration as i> <td></td> </#list> </#if> </tr> </#list> </table> </#macro> <#macro renderPhases phases hasDependents> <#if phases?size != 0> <#local phaseNr = -1 /> <#list 0..phases?size-1 as i> <#local phase = phases[i] /> <#local phaseNr = phaseNr + phase.duration /> <#local frozen><#if phase.phase.isFrozen()>frozen</#if></#local> <#local freezeLinkName><#if hasDependents>[Freeze all]<#else>[Freeze]</#if></#local> <@renderPhase phase=phase class="phase phase${phaseNr} ${frozen}" linkName=freezeLinkName/> </#list> </#if> </#macro> <#macro renderPhase phase linkName class="phase"> <#assign freezeLink = phase.phase.getFreezeLink(phase.dependentPhases)/> <td colspan="${phase.duration}"> <div class="wrapper"> <div class="${class}"><div class="name"> ${phase.phase.getViewLink().getHtml(phase.phase.name)}</div><div class="freezeLink">${freezeLink.getHtml(linkName)}</div></div> </div> </td> </#macro> <@renderPhaseOverview /> ${self.description!""} </@page.page>
Provide css styling for the custom start page at [installDir]/tomcat/webapps/pkit/local/process/pkit/[metamodelIdent]/view/screen/style.css.
.phaseOverview + .stages_description { margin-top: 3em; } .phaseOverview { border-spacing: 0; border-collapse: collapse; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .phaseOverview tr:nth-child(2n) { background-color: #f9f9f9; border-top: 1px solid #ebebed; border-bottom: 1px solid #ebebed; } .phaseOverview td { text-align: left; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; vertical-align: middle; } .phaseOverview td:first-child { text-align: right; min-width: 120px; } .phaseOverview .wrapper { display: table; width: 100%; min-width: 120px; } .phaseOverview .phase { vertical-align: middle; height: 32px; display: table-cell; padding-left: 5px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px; } .phaseOverview .phase .name { white-space: nowrap; } .phaseOverview .phase .freezeLink { white-space: nowrap; text-align: right; } .phaseOverview .phase.frozen { background-image: url(../../../../../img/frozen.png); background-repeat: no-repeat; background-position: right; padding-right: 40px; } .phaseOverview .phase *, .phaseOverview .phase a:link, .phaseOverview .phase a:visited { color: #ffffff; } .phaseOverview .phase a:focus, .phaseOverview .phase a:hover { color: #000000; text-decoration: none; } .phaseOverview .phase a:active { color: #ffffff; } .phaseOverview .phase { transition: all 0.2s; -webkit-transition: all 0.2s; -moz-transition: all 0.2s; -o-transition: all 0.2s; } .phaseOverview .phase0 { background-color: #3366cc;} .phaseOverview .phase0:hover { background-color: #7094db; } .phaseOverview .phase1 { background-color: #ff9900; } .phaseOverview .phase1:hover { background-color: #ffb84d; } .phaseOverview .phase2 { background-color: #990099; } .phaseOverview .phase2:hover { background-color: #b84db8; } .phaseOverview .phase3 { background-color: #dc3912; } .phaseOverview .phase3:hover { background-color: #e77459; } .phaseOverview .phase4 { background-color: #66aa00; } .phaseOverview .phase4:hover { background-color: #94c44d; } .phaseOverview .phase5 { background-color: #316395; } .phaseOverview .phase5:hover { background-color: #6f92b5; } .phaseOverview .phase6 { background-color: #b82e2e; } .phaseOverview .phase6:hover { background-color: #cb6b6b; } .phaseOverview .phase7 { background-color: #6633cc; } .phaseOverview .phase7:hover { background-color: #9470db; } .phaseOverview .phase8 { background-color: #aaaa11; } .phaseOverview .phase8:hover { background-color: #c4c458; }