all wflows are parsed & then requested on demand
This commit is contained in:
parent
874d81b3af
commit
61d9f9f739
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
test.json
|
test.json
|
||||||
server.py
|
server.py
|
||||||
|
/workflows
|
||||||
51
app/Main.hs
51
app/Main.hs
@ -3,7 +3,8 @@ module Main where
|
|||||||
----------------Imports----------------
|
----------------Imports----------------
|
||||||
|
|
||||||
import System.Environment (getArgs)
|
import System.Environment (getArgs)
|
||||||
import Data.Yaml (ParseException, decodeEither')
|
import System.Directory
|
||||||
|
import Data.Yaml (ParseException, decodeEither', Value (String, Null))
|
||||||
import Data.Aeson (encode, encodeFile)
|
import Data.Aeson (encode, encodeFile)
|
||||||
|
|
||||||
import qualified Data.ByteString.Char8 as BS
|
import qualified Data.ByteString.Char8 as BS
|
||||||
@ -12,6 +13,7 @@ module Main where
|
|||||||
import Data.Maybe (fromJust, isNothing)
|
import Data.Maybe (fromJust, isNothing)
|
||||||
import Data.Either (isLeft, fromLeft, fromRight)
|
import Data.Either (isLeft, fromLeft, fromRight)
|
||||||
import Control.Exception (throw)
|
import Control.Exception (throw)
|
||||||
|
import Text.Regex.TDFA ((=~))
|
||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
@ -24,9 +26,9 @@ module Main where
|
|||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = getArgs >>= process >>= finish where
|
main = getArgs >>= process >>= finish where
|
||||||
process :: [String] -> IO Bool
|
process :: [String] -> IO Bool
|
||||||
process args = if length args /= 2
|
process args@[_, _] = generateJSON args >> return False
|
||||||
then print "Please provide (1) a source and (2) a target file" >> return True
|
process args@["--all", src, to] = processDirectory src to >> return False
|
||||||
else generateJSON args >> return False
|
process _ = print "Please provide (1) a source and (2) a target file or provide '--all' and (1) a source and (2) a target directory" >> return True
|
||||||
finish :: Bool -> IO ()
|
finish :: Bool -> IO ()
|
||||||
finish abort = if abort then return () else print "Done."
|
finish abort = if abort then return () else print "Done."
|
||||||
|
|
||||||
@ -36,6 +38,8 @@ module Main where
|
|||||||
-- exports the graph data to the JSON file specified in the second argument.
|
-- exports the graph data to the JSON file specified in the second argument.
|
||||||
generateJSON :: [String] -> IO ()
|
generateJSON :: [String] -> IO ()
|
||||||
generateJSON args = do
|
generateJSON args = do
|
||||||
|
print $ head args
|
||||||
|
print $ last args
|
||||||
content <- BS.readFile (head args)
|
content <- BS.readFile (head args)
|
||||||
let decoded = decodeEither' content :: Either ParseException Workflow
|
let decoded = decodeEither' content :: Either ParseException Workflow
|
||||||
if isLeft decoded then throw (fromLeft undefined decoded) else do
|
if isLeft decoded then throw (fromLeft undefined decoded) else do
|
||||||
@ -46,6 +50,45 @@ module Main where
|
|||||||
-- encodeFile (last args) $ GData (nodeData, edgeData)
|
-- encodeFile (last args) $ GData (nodeData, edgeData)
|
||||||
encodeFile (last args) $ buildData yaml
|
encodeFile (last args) $ buildData yaml
|
||||||
|
|
||||||
|
|
||||||
|
blackList = ["patch.yaml"] -- files not to parse when parsing the entire directory
|
||||||
|
|
||||||
|
|
||||||
|
-- | Processes all workflow definitions within the given directory (1) and writes the output files
|
||||||
|
-- to the other given directory (2).
|
||||||
|
processDirectory :: FilePath -> FilePath -> IO ()
|
||||||
|
processDirectory src to = listDirectory src >>= filterWorkflows >>= (\ x -> generateForAll x [] Nothing) where
|
||||||
|
filterWorkflows :: [FilePath] -> IO [FilePath]
|
||||||
|
filterWorkflows entries = return $ filter (=~ ".+\\.yaml") entries
|
||||||
|
generateForAll :: [FilePath] -> [FilePath] -> Maybe FilePath -> IO () -- sources -> targets -> _index.yaml
|
||||||
|
generateForAll [] _ Nothing = fail "_index.yaml not found"
|
||||||
|
generateForAll [] targets (Just index) = writeIndex (decodeIndex index) targets "]"
|
||||||
|
generateForAll (x:xs) targets index = let (rel, abs) = defineTarget x
|
||||||
|
(newIndex, skip) = case index of
|
||||||
|
Just _ -> (index, False)
|
||||||
|
Nothing -> if x =~ ".+index\\.yaml" then (Just x, True) else (Nothing, False)
|
||||||
|
in if skip || x `elem` blackList
|
||||||
|
then generateForAll xs targets newIndex
|
||||||
|
else generateJSON [src ++ "/" ++ x, abs] >> generateForAll xs (rel:targets) newIndex
|
||||||
|
defineTarget :: FilePath -> (FilePath, FilePath) -- (rel, abs)
|
||||||
|
defineTarget x = let (path, match, _) = x =~ "[a-zA-Z0-9+._-]+\\.yaml" :: (String, String, String)
|
||||||
|
(newFile, _, _) = match =~ "\\." :: (String, String, String)
|
||||||
|
relative = "/definitions/" ++ newFile ++ ".json"
|
||||||
|
absolute = to ++ relative
|
||||||
|
in (relative, absolute)
|
||||||
|
writeIndex :: Value -> [FilePath] -> String -> IO () -- content of _index.yaml -> targets -> content for index.json
|
||||||
|
writeIndex _ [] content = writeFile (to ++ "/index.json") ('[':content)
|
||||||
|
writeIndex index (x:xs) content = let name = x
|
||||||
|
url = x
|
||||||
|
description = ""
|
||||||
|
newContent = (if null xs then "" else ",\n") ++ "{\n\"name\": \"" ++ name
|
||||||
|
++ "\",\n\"description\": \""
|
||||||
|
++ description ++ "\",\n\"url\": \"" ++ url ++ "\"}"
|
||||||
|
in writeIndex index xs (newContent ++ content)
|
||||||
|
decodeIndex :: FilePath -> Value
|
||||||
|
decodeIndex _ = Null
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
-- https://stackoverflow.com/questions/59903779/how-to-parse-json-with-field-of-optional-and-variant-type-in-haskell
|
-- https://stackoverflow.com/questions/59903779/how-to-parse-json-with-field-of-optional-and-variant-type-in-haskell
|
||||||
|
|||||||
356
editor.js
356
editor.js
@ -64,25 +64,16 @@ function openSearchMenu(menuitem) {
|
|||||||
document.getElementById('filepanel').style.opacity = 0;
|
document.getElementById('filepanel').style.opacity = 0;
|
||||||
|
|
||||||
function openFileDisplay() {
|
function openFileDisplay() {
|
||||||
var panel = document.getElementById('filepanel');
|
deselect();
|
||||||
var heading = document.getElementById('fileheading');
|
|
||||||
var curtain = document.getElementById('curtain');
|
|
||||||
var content = document.getElementById('filecontent');
|
|
||||||
var buttons = document.getElementById('filebuttons');
|
|
||||||
function callback() {
|
function callback() {
|
||||||
heading.innerHTML = 'Open Workflow Definition';
|
fileHeading.innerHTML = 'Open Workflow Definition';
|
||||||
for (var i = 0; i < 100; i++) {
|
var pStyle = window.getComputedStyle(filePanel);
|
||||||
var item = document.createElement('div');
|
var hStyle = window.getComputedStyle(fileHeading);
|
||||||
item.innerHTML = i;
|
fileContent.style.top = fileHeading.offsetHeight + parseFloat(pStyle.paddingTop) + parseFloat(hStyle.marginTop) + parseFloat(hStyle.marginBottom);
|
||||||
content.appendChild(item);
|
var bStyle = window.getComputedStyle(fileButtons);
|
||||||
}
|
fileContent.style.bottom = fileButtons.offsetHeight + parseFloat(pStyle.paddingBottom) + parseFloat(bStyle.marginTop) + parseFloat(bStyle.marginBottom);
|
||||||
var pStyle = window.getComputedStyle(panel);
|
|
||||||
var hStyle = window.getComputedStyle(heading);
|
|
||||||
content.style.top = heading.offsetHeight + parseFloat(pStyle.paddingTop) + parseFloat(hStyle.marginTop) + parseFloat(hStyle.marginBottom);
|
|
||||||
var bStyle = window.getComputedStyle(buttons);
|
|
||||||
content.style.bottom = buttons.offsetHeight + parseFloat(pStyle.paddingBottom) + parseFloat(bStyle.marginTop) + parseFloat(bStyle.marginBottom);
|
|
||||||
}
|
}
|
||||||
fadeIn(callback, {element: panel, max: 0.95, step: 0.025}, {element: curtain, max: 0.5, step: 0.025});
|
fadeIn(callback, {element: filePanel, max: 0.95, step: 0.025}, {element: curtain, max: 0.5, step: 0.025});
|
||||||
closeMenuItem();
|
closeMenuItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +122,40 @@ function fadeOut(...items) {
|
|||||||
requestAnimationFrame(fade);
|
requestAnimationFrame(fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workflow processing
|
// Available workflow definition files
|
||||||
|
var workflowFiles = [];
|
||||||
|
// Workflow data
|
||||||
var workflow = {};
|
var workflow = {};
|
||||||
const wfGraph = ForceGraph();
|
const wfGraph = ForceGraph();
|
||||||
|
|
||||||
fetch('http://localhost:8080/test.json')
|
function defineOnClick(item, url) {
|
||||||
|
item.onclick = (_ => {
|
||||||
|
fetch(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
closeFileDisplay();
|
||||||
|
for (var key in data)
|
||||||
|
workflow[key] = data[key];
|
||||||
|
prepareWorkflow();
|
||||||
|
updateGraph();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('http://localhost:8080/index.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
workflowFiles = data;
|
||||||
|
for (var i = 0; i < workflowFiles.length; i++) {
|
||||||
|
var item = document.createElement('div');
|
||||||
|
item.innerHTML = workflowFiles[i].name;
|
||||||
|
var url = 'http://localhost:8080' + workflowFiles[i].url;
|
||||||
|
defineOnClick(item, url);
|
||||||
|
fileContent.appendChild(item);
|
||||||
|
}
|
||||||
|
var url = 'http://localhost:8080' + data[0].url;
|
||||||
|
return fetch(url);
|
||||||
|
})
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
for (var key in data)
|
for (var key in data)
|
||||||
@ -194,10 +214,17 @@ var selection = null; // The currently selected node/edge.
|
|||||||
var rightSelection = null; // The currently right clicked node/edge.
|
var rightSelection = null; // The currently right clicked node/edge.
|
||||||
var edgeTo = null; // Target of an edge to be created.
|
var edgeTo = null; // Target of an edge to be created.
|
||||||
var edgeFrom = null; // Start on an edge to be created.
|
var edgeFrom = null; // Start on an edge to be created.
|
||||||
const sidePanel = document.getElementById('sidepanel');
|
const curtain = document.getElementById('curtain');
|
||||||
|
//Side Panel
|
||||||
|
const sidePanel = document.getElementById('sidepanel');
|
||||||
const sideContent = document.getElementById('sidecontent');
|
const sideContent = document.getElementById('sidecontent');
|
||||||
const sideHeading = document.getElementById('sideheading');
|
const sideHeading = document.getElementById('sideheading');
|
||||||
const sideButtons = document.getElementById('sidebuttons');
|
const sideButtons = document.getElementById('sidebuttons');
|
||||||
|
//File panel
|
||||||
|
const filePanel = document.getElementById('filepanel');
|
||||||
|
const fileHeading = document.getElementById('fileheading');
|
||||||
|
const fileContent = document.getElementById('filecontent');
|
||||||
|
const fileButtons = document.getElementById('filebuttons');
|
||||||
//Context menus
|
//Context menus
|
||||||
const contextMenuBg = document.getElementById('ctmenubg'); //Click on background
|
const contextMenuBg = document.getElementById('ctmenubg'); //Click on background
|
||||||
const contextMenuSt = document.getElementById('ctmenust'); //Click on state
|
const contextMenuSt = document.getElementById('ctmenust'); //Click on state
|
||||||
@ -429,50 +456,131 @@ function computeCurvatures() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function prepareWorkflow() {
|
||||||
|
stateIdCounter = workflow.states ? workflow.states.length : 0;
|
||||||
|
actionIdCounter = workflow.states ? workflow.actions.length : 0;
|
||||||
|
|
||||||
|
//Parse workflow
|
||||||
|
|
||||||
function runnn() {
|
workflow.states.forEach(state => {
|
||||||
|
var messages = [];
|
||||||
|
state.stateData.messages.forEach(msg => messages.push(new Message(msg)));
|
||||||
|
state.stateData.messages = messages;
|
||||||
|
var viewers = [];
|
||||||
|
state.stateData.viewers.forEach(v => viewers.push(new Role(v)));
|
||||||
|
state.stateData.viewers = viewers;
|
||||||
|
state.stateData.payload = new Payload(state.stateData.payload);
|
||||||
|
})
|
||||||
|
|
||||||
stateIdCounter = workflow.states ? workflow.states.length : 0;
|
workflow.actions.forEach(action => {
|
||||||
actionIdCounter = workflow.states ? workflow.actions.length : 0;
|
var messages = [];
|
||||||
|
action.actionData.messages.forEach(msg => messages.push(new Message(msg)));
|
||||||
|
action.actionData.messages = messages;
|
||||||
|
var viewers = [];
|
||||||
|
action.actionData.viewers.forEach(v => viewers.push(new Role(v)));
|
||||||
|
action.actionData.viewers = viewers;
|
||||||
|
var actors = [];
|
||||||
|
action.actionData.actors.forEach(v => actors.push(new Role(v)));
|
||||||
|
action.actionData.actors = actors;
|
||||||
|
var viewActors = [];
|
||||||
|
action.actionData['actor Viewers'].forEach(v => viewActors.push(new Role(v)));
|
||||||
|
action.actionData['actor Viewers'] = viewActors;
|
||||||
|
action.actionData.form = new Payload(action.actionData.form);
|
||||||
|
})
|
||||||
|
|
||||||
//Parse workflow
|
workflow.actions.forEach(act => act.actionData.actors.forEach(a => {
|
||||||
|
var includes = false;
|
||||||
|
actors.forEach(actor => includes = includes || equalRoles(a, actor));
|
||||||
|
(!includes) && actors.push(a);
|
||||||
|
(!act.actionData.actorNames) && (act.actionData.actorNames = []);
|
||||||
|
act.actionData.actorNames.push(getRoleName(a));
|
||||||
|
}));
|
||||||
|
|
||||||
workflow.states.forEach(state => {
|
//Prepare actor highlighting
|
||||||
var messages = [];
|
var allActors = document.createElement('option');
|
||||||
state.stateData.messages.forEach(msg => messages.push(new Message(msg)));
|
allActors.text = NO_ACTOR;
|
||||||
state.stateData.messages = messages;
|
selectedActor.add(allActors);
|
||||||
var viewers = [];
|
actors.forEach(actor => {
|
||||||
state.stateData.viewers.forEach(v => viewers.push(new Role(v)));
|
var option = document.createElement('option');
|
||||||
state.stateData.viewers = viewers;
|
option.text = getRoleName(actor);
|
||||||
state.stateData.payload = new Payload(state.stateData.payload);
|
selectedActor.add(option);
|
||||||
})
|
});
|
||||||
|
|
||||||
workflow.actions.forEach(action => {
|
//Identify all viewers of every action
|
||||||
var messages = [];
|
workflow.actions.forEach(act => {
|
||||||
action.actionData.messages.forEach(msg => messages.push(new Message(msg)));
|
if (act.actionData.viewers.length === 0) {
|
||||||
action.actionData.messages = messages;
|
viewableByAll.push(act.actionData);
|
||||||
var viewers = [];
|
} else {
|
||||||
action.actionData.viewers.forEach(v => viewers.push(new Role(v)));
|
act.actionData.viewers.forEach(v => {
|
||||||
action.actionData.viewers = viewers;
|
var includes = false;
|
||||||
var actors = [];
|
viewers.forEach(viewer => includes = includes || equalRoles(v, viewer));
|
||||||
action.actionData.actors.forEach(v => actors.push(new Role(v)));
|
(!includes) && viewers.push(v);
|
||||||
action.actionData.actors = actors;
|
(!act.actionData.viewerNames) && (act.actionData.viewerNames = []);
|
||||||
var viewActors = [];
|
act.actionData.viewerNames.push(getRoleName(v));
|
||||||
action.actionData['actor Viewers'].forEach(v => viewActors.push(new Role(v)));
|
})
|
||||||
action.actionData['actor Viewers'] = viewActors;
|
}
|
||||||
action.actionData.form = new Payload(action.actionData.form);
|
if (act.actionData.mode === 'initial') {
|
||||||
})
|
act.actionData.actorNames.forEach(an => !initiators.includes(an) && initiators.push(an));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//Identify all viewers of every state
|
||||||
|
workflow.states.forEach(st => {
|
||||||
|
if (st.name === '@@INIT') {
|
||||||
|
initState = st;
|
||||||
|
} else if (st.stateData.viewers.length === 0) {
|
||||||
|
viewableByAll.push(st.stateData);
|
||||||
|
} else {
|
||||||
|
st.stateData.viewers.forEach(v => {
|
||||||
|
var includes = false;
|
||||||
|
viewers.forEach(viewer => includes = includes || equalRoles(v, viewer));
|
||||||
|
(!includes) && viewers.push(v);
|
||||||
|
(!st.stateData.viewerNames) && (st.stateData.viewerNames = []);
|
||||||
|
st.stateData.viewerNames.push(getRoleName(v));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
workflow.actions.forEach(act => act.actionData.actors.forEach(a => {
|
initState.stateData.viewerNames = initiators;
|
||||||
var includes = false;
|
|
||||||
actors.forEach(actor => includes = includes || equalRoles(a, actor));
|
const ALL_VIEW = "Not explicitly specified";
|
||||||
(!includes) && actors.push(a);
|
if (viewableByAll.length > 0) {
|
||||||
(!act.actionData.actorNames) && (act.actionData.actorNames = []);
|
viewers.push(ALL_VIEW);
|
||||||
act.actionData.actorNames.push(getRoleName(a));
|
var viewerNames = []
|
||||||
}));
|
viewers.forEach(viewer => viewerNames.push(getRoleName(viewer)));
|
||||||
// console.log(actors);
|
viewableByAll.forEach(data => {
|
||||||
// workflow.actions.forEach(a => console.log(a.actionData.actorNames));
|
data.viewerNames = viewerNames;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prepare viewer highlighting
|
||||||
|
var allViewers = document.createElement('option');
|
||||||
|
allViewers.text = NO_VIEWER;
|
||||||
|
selectedViewer.add(allViewers);
|
||||||
|
viewers.forEach(viewer => {
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.text = getRoleName(viewer);
|
||||||
|
selectedViewer.add(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Compute abbreviations of the names of all states
|
||||||
|
workflow.states.forEach(state => {
|
||||||
|
// var label = node.name.substring(0, 5);
|
||||||
|
var label = state.name.split(' '); // [node.name.substring(0, 6), node.name.substring(6, 12), node.name.substring(12, 18)];
|
||||||
|
for (var i = 0; i < label.length; i++) {
|
||||||
|
if (label[i] === '(') continue; // if the state name contains whitespace after the brace
|
||||||
|
var isBrace = label[i][0] === '(';
|
||||||
|
label[i] = label[i].substring(isBrace ? 1 : 0, isBrace ? 2 : 1);
|
||||||
|
}
|
||||||
|
labelString = label.join('').substring(0,6);
|
||||||
|
var counter = 1;
|
||||||
|
var len = labelString.length;
|
||||||
|
while (stateAbbreviations.includes(labelString)) {
|
||||||
|
labelString = labelString.substring(0,len) + "'" + counter++;
|
||||||
|
}
|
||||||
|
stateAbbreviations.push(labelString);
|
||||||
|
state.stateData.abbreviation = labelString;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getRoleName(role) {
|
function getRoleName(role) {
|
||||||
if (typeof role == 'string') {
|
if (typeof role == 'string') {
|
||||||
@ -484,80 +592,6 @@ function getRoleName(role) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Prepare actor highlighting
|
|
||||||
var allActors = document.createElement('option');
|
|
||||||
allActors.text = NO_ACTOR;
|
|
||||||
selectedActor.add(allActors);
|
|
||||||
actors.forEach(actor => {
|
|
||||||
var option = document.createElement('option');
|
|
||||||
option.text = getRoleName(actor);
|
|
||||||
selectedActor.add(option);
|
|
||||||
});
|
|
||||||
|
|
||||||
//Identify all viewers of every action
|
|
||||||
workflow.actions.forEach(act => {
|
|
||||||
if (act.actionData.viewers.length === 0) {
|
|
||||||
viewableByAll.push(act.actionData);
|
|
||||||
} else {
|
|
||||||
act.actionData.viewers.forEach(v => {
|
|
||||||
var includes = false;
|
|
||||||
viewers.forEach(viewer => includes = includes || equalRoles(v, viewer));
|
|
||||||
(!includes) && viewers.push(v);
|
|
||||||
(!act.actionData.viewerNames) && (act.actionData.viewerNames = []);
|
|
||||||
act.actionData.viewerNames.push(getRoleName(v));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (act.actionData.mode === 'initial') {
|
|
||||||
act.actionData.actorNames.forEach(an => !initiators.includes(an) && initiators.push(an));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//Identify all viewers of every state
|
|
||||||
workflow.states.forEach(st => {
|
|
||||||
if (st.name === '@@INIT') {
|
|
||||||
initState = st;
|
|
||||||
} else if (st.stateData.viewers.length === 0) {
|
|
||||||
viewableByAll.push(st.stateData);
|
|
||||||
} else {
|
|
||||||
st.stateData.viewers.forEach(v => {
|
|
||||||
var includes = false;
|
|
||||||
viewers.forEach(viewer => includes = includes || equalRoles(v, viewer));
|
|
||||||
(!includes) && viewers.push(v);
|
|
||||||
(!st.stateData.viewerNames) && (st.stateData.viewerNames = []);
|
|
||||||
st.stateData.viewerNames.push(getRoleName(v));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
initState.stateData.viewerNames = initiators;
|
|
||||||
|
|
||||||
const ALL_VIEW = "Not explicitly specified";
|
|
||||||
if (viewableByAll.length > 0) {
|
|
||||||
viewers.push(ALL_VIEW);
|
|
||||||
var viewerNames = []
|
|
||||||
viewers.forEach(viewer => viewerNames.push(getRoleName(viewer)));
|
|
||||||
viewableByAll.forEach(data => {
|
|
||||||
data.viewerNames = viewerNames;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//Prepare viewer highlighting
|
|
||||||
var allViewers = document.createElement('option');
|
|
||||||
allViewers.text = NO_VIEWER;
|
|
||||||
selectedViewer.add(allViewers);
|
|
||||||
viewers.forEach(viewer => {
|
|
||||||
var option = document.createElement('option');
|
|
||||||
option.text = getRoleName(viewer);
|
|
||||||
selectedViewer.add(option);
|
|
||||||
});
|
|
||||||
|
|
||||||
const edgeColourDefault = '#999999ff';
|
|
||||||
const edgeColourSelected = '#000000ff';
|
|
||||||
const edgeColourHighlightDefault = '#6ed4d4';
|
|
||||||
const edgeColourHighlightSelected = 'magenta';
|
|
||||||
const edgeColourSubtleDefault = '#99999955';
|
|
||||||
const edgeColourSubtleSelected = '#00000055';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if two roles are equal.
|
* Checks if two roles are equal.
|
||||||
* @param {*} role1
|
* @param {*} role1
|
||||||
@ -578,6 +612,30 @@ function equalRoles(role1, role2) {
|
|||||||
return equal;
|
return equal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
* @param {HTMLElement} menu
|
||||||
|
*/
|
||||||
|
function openContextMenu(x, y, menu) {
|
||||||
|
menu.style.top = y - 25;
|
||||||
|
menu.style.left = x + 20;
|
||||||
|
fadeIn(null, {element: menu, max: 1, step: 0.1})
|
||||||
|
// menu.style.display = 'block';
|
||||||
|
edgeFrom = edgeTo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function runnn() {
|
||||||
|
|
||||||
|
prepareWorkflow();
|
||||||
|
|
||||||
|
const edgeColourDefault = '#999999ff';
|
||||||
|
const edgeColourSelected = '#000000ff';
|
||||||
|
const edgeColourHighlightDefault = '#6ed4d4';
|
||||||
|
const edgeColourHighlightSelected = 'magenta';
|
||||||
|
const edgeColourSubtleDefault = '#99999955';
|
||||||
|
const edgeColourSubtleSelected = '#00000055';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -595,7 +653,7 @@ function getNodeColour(node) {
|
|||||||
} else if (node.stateData.final === 'not-ok') {
|
} else if (node.stateData.final === 'not-ok') {
|
||||||
return (isSelected ? '#ec4e7b' : '#e7215a') + alpha;
|
return (isSelected ? '#ec4e7b' : '#e7215a') + alpha;
|
||||||
} else {
|
} else {
|
||||||
//console.log(node.stateData.final);
|
return (isSelected ? '#ffbc15' : '#eeaa00') + alpha;
|
||||||
}
|
}
|
||||||
} else if (node.name === '@@INIT') {
|
} else if (node.name === '@@INIT') {
|
||||||
return (isSelected ? '#ffbc15' : '#eeaa00') + alpha;
|
return (isSelected ? '#ffbc15' : '#eeaa00') + alpha;
|
||||||
@ -622,40 +680,6 @@ function getEdgeColour(edge) {
|
|||||||
return isSelected ? edgeColourSelected : edgeColourDefault;
|
return isSelected ? edgeColourSelected : edgeColourDefault;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Compute abbreviations of the names of all states
|
|
||||||
workflow.states.forEach(state => {
|
|
||||||
// var label = node.name.substring(0, 5);
|
|
||||||
var label = state.name.split(' '); // [node.name.substring(0, 6), node.name.substring(6, 12), node.name.substring(12, 18)];
|
|
||||||
for (var i = 0; i < label.length; i++) {
|
|
||||||
if (label[i] === '(') continue; // if the state name contains whitespace after the brace
|
|
||||||
var isBrace = label[i][0] === '(';
|
|
||||||
label[i] = label[i].substring(isBrace ? 1 : 0, isBrace ? 2 : 1);
|
|
||||||
}
|
|
||||||
labelString = label.join('').substring(0,6);
|
|
||||||
var counter = 1;
|
|
||||||
var len = labelString.length;
|
|
||||||
while (stateAbbreviations.includes(labelString)) {
|
|
||||||
labelString = labelString.substring(0,len) + "'" + counter++;
|
|
||||||
}
|
|
||||||
stateAbbreviations.push(labelString);
|
|
||||||
state.stateData.abbreviation = labelString;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} event
|
|
||||||
* @param {HTMLElement} menu
|
|
||||||
*/
|
|
||||||
function openContextMenu(x, y, menu) {
|
|
||||||
menu.style.top = y - 25;
|
|
||||||
menu.style.left = x + 20;
|
|
||||||
fadeIn(null, {element: menu, max: 1, step: 0.1})
|
|
||||||
// menu.style.display = 'block';
|
|
||||||
edgeFrom = edgeTo = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
wfGraph
|
wfGraph
|
||||||
.linkDirectionalArrowLength(6)
|
.linkDirectionalArrowLength(6)
|
||||||
.linkDirectionalArrowRelPos(1)
|
.linkDirectionalArrowRelPos(1)
|
||||||
|
|||||||
@ -36,6 +36,8 @@ executable workflow-visualiser
|
|||||||
bytestring,
|
bytestring,
|
||||||
containers,
|
containers,
|
||||||
text,
|
text,
|
||||||
vector
|
vector,
|
||||||
|
directory,
|
||||||
|
regex-tdfa
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|||||||
@ -1,17 +1,40 @@
|
|||||||
[
|
[{
|
||||||
{
|
"name": "/definitions/theses.json",
|
||||||
"name": "Diploma",
|
"description": "",
|
||||||
"description": "",
|
"url": "/definitions/theses.json"},
|
||||||
"url": "/test.json"
|
{
|
||||||
},
|
"name": "/definitions/theses-media.json",
|
||||||
{
|
"description": "",
|
||||||
"name": "Theses",
|
"url": "/definitions/theses-media.json"},
|
||||||
"description": "",
|
{
|
||||||
"url": "/test.json"
|
"name": "/definitions/rooms-mi.json",
|
||||||
},
|
"description": "",
|
||||||
{
|
"url": "/definitions/rooms-mi.json"},
|
||||||
"name": "Recognitions",
|
{
|
||||||
"description": "",
|
"name": "/definitions/recognitions-ifi.json",
|
||||||
"url": "/test.json"
|
"description": "",
|
||||||
}
|
"url": "/definitions/recognitions-ifi.json"},
|
||||||
]
|
{
|
||||||
|
"name": "/definitions/master-practical-training.json",
|
||||||
|
"description": "",
|
||||||
|
"url": "/definitions/master-practical-training.json"},
|
||||||
|
{
|
||||||
|
"name": "/definitions/general-eo-tickets.json",
|
||||||
|
"description": "",
|
||||||
|
"url": "/definitions/general-eo-tickets.json"},
|
||||||
|
{
|
||||||
|
"name": "/definitions/diploma.json",
|
||||||
|
"description": "",
|
||||||
|
"url": "/definitions/diploma.json"},
|
||||||
|
{
|
||||||
|
"name": "/definitions/cs-minor-degrees.json",
|
||||||
|
"description": "",
|
||||||
|
"url": "/definitions/cs-minor-degrees.json"},
|
||||||
|
{
|
||||||
|
"name": "/definitions/cip-courses-mi.json",
|
||||||
|
"description": "",
|
||||||
|
"url": "/definitions/cip-courses-mi.json"},
|
||||||
|
{
|
||||||
|
"name": "/definitions/certificates.json",
|
||||||
|
"description": "",
|
||||||
|
"url": "/definitions/certificates.json"}]
|
||||||
Loading…
Reference in New Issue
Block a user