From 1bf9e599ee1033a9f7d31eee2e858ab721666571 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 10 Jun 2021 21:17:41 +0200 Subject: [PATCH] Governance: Plugins Implementation Finished --- .../Schemas/App-Schema/plugin-project.json | 30 ++++ .../UI/Function-Libraries/PluginsFunctions.js | 98 +++-------- Projects/Foundations/UI/Utilities/Plugins.js | 53 ++++++ .../Icons/Plugins/plugin-assets.png | Bin 0 -> 8942 bytes .../Icons/Plugins/plugin-features.png | Bin 0 -> 1942 bytes .../Governance/Icons/Plugins/plugin-pools.png | Bin 0 -> 8071 bytes .../Icons/Plugins/plugin-positions.png | Bin 0 -> 12363 bytes .../Icons/Plugins/plugin-user-profiles.png | Bin 0 -> 6619 bytes .../Schemas/App-Schema/plugin-assets.json | 37 ++++ .../Schemas/App-Schema/plugin-features.json | 37 ++++ .../Schemas/App-Schema/plugin-pools.json | 37 ++++ .../Schemas/App-Schema/plugin-positions.json | 37 ++++ .../App-Schema/plugin-user-profiles.json | 8 +- .../UI/Function-Libraries/ActionSwitch.js | 25 +++ .../UI/Function-Libraries/PluginsFunctions.js | 162 +++--------------- Projects/ProjectsSchema.json | 5 + 16 files changed, 317 insertions(+), 212 deletions(-) create mode 100644 Projects/Foundations/UI/Utilities/Plugins.js create mode 100644 Projects/Governance/Icons/Plugins/plugin-assets.png create mode 100644 Projects/Governance/Icons/Plugins/plugin-features.png create mode 100644 Projects/Governance/Icons/Plugins/plugin-pools.png create mode 100644 Projects/Governance/Icons/Plugins/plugin-positions.png create mode 100644 Projects/Governance/Icons/Plugins/plugin-user-profiles.png create mode 100644 Projects/Governance/Schemas/App-Schema/plugin-assets.json create mode 100644 Projects/Governance/Schemas/App-Schema/plugin-features.json create mode 100644 Projects/Governance/Schemas/App-Schema/plugin-pools.json create mode 100644 Projects/Governance/Schemas/App-Schema/plugin-positions.json diff --git a/Projects/Foundations/Schemas/App-Schema/plugin-project.json b/Projects/Foundations/Schemas/App-Schema/plugin-project.json index 1e17f8239..e4aa17c5b 100644 --- a/Projects/Foundations/Schemas/App-Schema/plugin-project.json +++ b/Projects/Foundations/Schemas/App-Schema/plugin-project.json @@ -90,6 +90,36 @@ "type": "node", "childType": "Plugin API Maps", "autoAdd": false + }, + { + "name": "pluginUserProfiles", + "type": "node", + "childType": "Plugin User Profiles", + "autoAdd": false + }, + { + "name": "pluginPools", + "type": "node", + "childType": "Plugin Pools", + "autoAdd": false + }, + { + "name": "pluginAssets", + "type": "node", + "childType": "Plugin Assets", + "autoAdd": false + }, + { + "name": "pluginFeatures", + "type": "node", + "childType": "Plugin Features", + "autoAdd": false + }, + { + "name": "pluginPositions", + "type": "node", + "childType": "Plugin Positions", + "autoAdd": false } ], "alternativeIcons": [ diff --git a/Projects/Foundations/UI/Function-Libraries/PluginsFunctions.js b/Projects/Foundations/UI/Function-Libraries/PluginsFunctions.js index dabbe14b7..f4696c081 100644 --- a/Projects/Foundations/UI/Function-Libraries/PluginsFunctions.js +++ b/Projects/Foundations/UI/Function-Libraries/PluginsFunctions.js @@ -14,31 +14,6 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } return thisObject - function getPluginFileNames(projectName, pluginType, callBack) { - httpRequest(undefined, 'PluginFileNames/' + projectName + '/' + pluginType, onResponse) - - function onResponse(err, data) { - if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { - console.log('Failed to Fetch Plugin ' + pluginType + ' from the Client') - return - } - - let pluginFileNames = JSON.parse(data) - callBack(pluginFileNames) - } - } - - function addPluginFileIfNeeded(node, fileNames) { - for (let i = 0; i < fileNames.length; i++) { - let fileName = fileNames[i] - fileName = fileName.replace('.json', '') - if (UI.projects.foundations.utilities.children.isMissingChildrenByName(node, fileName) === true) { - let child = UI.projects.foundations.functionLibraries.uiObjectsFromNodes.addUIObject(node, 'Plugin File') - child.name = fileName - } - } - } - function addMissingPluginProjects(node, rootNodes) { for (let k = 0; k < PROJECTS_SCHEMA.length; k++) { let projectDefinition = PROJECTS_SCHEMA[k] @@ -68,27 +43,8 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - function getProjectName(node) { - /* Validations to see if we can do this or not. */ - if (node.payload === undefined) { return } - if (node.payload.uiObject === undefined) { return } - - if (node.payload.parentNode === undefined) { - node.payload.uiObject.setErrorMessage('You need to have a Plugin Project node as a parent to execute this action.') - return - } - if (node.payload.parentNode.payload === undefined) { - node.payload.uiObject.setErrorMessage('You need to have a Plugin Project node as a parent to execute this action.') - return - } - let pluginProject = node.payload.parentNode - let config = JSON.parse(pluginProject.config) - - return config.codeName - } - function addMissingPluginDataMines(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -96,15 +52,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Data-Mines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Data-Mines', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginTradingMines(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -112,15 +68,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Trading-Mines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Trading-Mines', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginTradingSystems(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -128,15 +84,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Trading-Systems', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Trading-Systems', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginTradingEngines(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -144,15 +100,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Trading-Engines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Trading-Engines', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginLearningMines(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -160,15 +116,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Learning-Mines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Learning-Mines', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginLearningSystems(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -176,15 +132,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Learning-Systems', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Learning-Systems', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginLearningEngines(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -192,15 +148,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Learning-Engines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Learning-Engines', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginTutorials(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -208,15 +164,15 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Tutorials', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Tutorials', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } function addMissingPluginApiMaps(node, rootNodes) { - let projectName = getProjectName(node) + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -224,10 +180,10 @@ function newFoundationsFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'API-Maps', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'API-Maps', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } } diff --git a/Projects/Foundations/UI/Utilities/Plugins.js b/Projects/Foundations/UI/Utilities/Plugins.js new file mode 100644 index 000000000..73a096aff --- /dev/null +++ b/Projects/Foundations/UI/Utilities/Plugins.js @@ -0,0 +1,53 @@ +function newFoundationsUtilitiesPlugins() { + let thisObject = { + getPluginFileNames: getPluginFileNames, + addPluginFileIfNeeded: addPluginFileIfNeeded, + getProjectName: getProjectName + } + + return thisObject + + function getPluginFileNames(projectName, pluginType, callBack) { + httpRequest(undefined, 'PluginFileNames/' + projectName + '/' + pluginType, onResponse) + + function onResponse(err, data) { + if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { + console.log('Failed to Fetch Plugin ' + pluginType + ' from the Client') + return + } + + let pluginFileNames = JSON.parse(data) + callBack(pluginFileNames) + } + } + + function addPluginFileIfNeeded(node, fileNames) { + for (let i = 0; i < fileNames.length; i++) { + let fileName = fileNames[i] + fileName = fileName.replace('.json', '') + if (UI.projects.foundations.utilities.children.isMissingChildrenByName(node, fileName) === true) { + let child = UI.projects.foundations.functionLibraries.uiObjectsFromNodes.addUIObject(node, 'Plugin File') + child.name = fileName + } + } + } + + function getProjectName(node) { + /* Validations to see if we can do this or not. */ + if (node.payload === undefined) { return } + if (node.payload.uiObject === undefined) { return } + + if (node.payload.parentNode === undefined) { + node.payload.uiObject.setErrorMessage('You need to have a Plugin Project node as a parent to execute this action.') + return + } + if (node.payload.parentNode.payload === undefined) { + node.payload.uiObject.setErrorMessage('You need to have a Plugin Project node as a parent to execute this action.') + return + } + let pluginProject = node.payload.parentNode + let config = JSON.parse(pluginProject.config) + + return config.codeName + } +} \ No newline at end of file diff --git a/Projects/Governance/Icons/Plugins/plugin-assets.png b/Projects/Governance/Icons/Plugins/plugin-assets.png new file mode 100644 index 0000000000000000000000000000000000000000..2c3a28848f12af4967cc7ad3a093ab70a38e1579 GIT binary patch literal 8942 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 S)8qjBcl?O{;q-&&Z~Z@Jbcc-q literal 0 HcmV?d00001 diff --git a/Projects/Governance/Icons/Plugins/plugin-features.png b/Projects/Governance/Icons/Plugins/plugin-features.png new file mode 100644 index 0000000000000000000000000000000000000000..8fcb79a35fee7cae435a460897525024562be7c3 GIT binary patch literal 1942 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

Tr_!sjuHb=sh5&H zsm5%!%ZH5vfpH)Hy2%eaZU;?Hg$O>k?~mkO(vO!YL>&WsUYC0tl>2(^Y0NVORxu&D ziFsn%dtKqAlS8Q5+Z9II@o;VFm^A}`DGvAcphV@qUkULt7-x~kdy|=NeYtuC5$0sEGh)5U@1~fA4DE zEQxf%Vom^GE4@_5;9agwgd50BVs}e*y z(I}dXW-ci~x38;uUtVK_O_b|sW9}hZh6DUhC2pLgKj;o6QkyYW!RF?o51o3an1~JL z2xgK1JG`*>(50d^mrSpGVi+5}Wyi4g_lD>g^0C8Z-BZdN)EqPd$d9Dm;KcS+;S*2! zas@6Qx`Z{-9?;d^wR~|1-js0mFfwH$tnscDE6hq)c=$Fo)kGqN`&pwON_Z3BlcK@u z-yJL?`--P)t$NF=M|3?`HbB@MMK^JyRE-D>1UH<<1ee7_e;iKhCKq@4#F&5o=`DR* z@l?BrL4N#Y;d)opZYH6e7Xe;zz}E!*>3Ct`;4(S6t?H%4v89E}o}FFIY&=~R%|`wK z+Etc84IaJ3vf^pykp&0F_l((CpX$caj@Gt!1FdXqa<&b-YgI9@FmY%^jbGre0 zgPrTwHyPg5MT^hJ%@8b%rc&&2oC@Vq9u{9sbvv^5XMenp1(y0l3-4j;;r$?=KM;## za=x8hN~y%EpEbVs<_P?M4YU5m@xlL0zqG;spZUdKh8n3_!)+zS(CB^3e%)}M-Dy%< zY2xhQ)EO-`966%>oW)bmo*HqW(I9yxnSGkazf^~D(XAYs@co~iQmqQjdFgjkOo#nx zaN1#|B`v@Nu1zphtAXb2Z2};u0}jF)yNTxM%p{*3=cV%+wM?Cg;Pk@@NU~fg_4|r= z?S>hNT+psI4(y6BAwECdDd;ko7&lDO9`USKRPlugin Project->" + }, + "childrenNodesProperties": [ + { + "name": "pluginFiles", + "type": "array", + "childType": "Plugin File", + "autoAdd": false + } + ] +} \ No newline at end of file diff --git a/Projects/Governance/Schemas/App-Schema/plugin-features.json b/Projects/Governance/Schemas/App-Schema/plugin-features.json new file mode 100644 index 000000000..03d0e99bd --- /dev/null +++ b/Projects/Governance/Schemas/App-Schema/plugin-features.json @@ -0,0 +1,37 @@ +{ + "type": "Plugin Features", + "menuItems": [ + { + "action": "Add Missing Plugin Features", + "label": "Add Missing Features", + "askConfirmation": true, + "confirmationLabel": "Confirm to Proceed", + "workDoneLabel": "Done", + "relatedUiObject": "Data Mine", + "actionFunction": "payload.executeAction" + }, + { + "action": "Delete UI Object", + "askConfirmation": true, + "confirmationLabel": "Confirm to Delete", + "label": "Delete", + "iconPathOn": "delete-entity", + "iconPathOff": "delete-entity", + "actionFunction": "payload.executeAction" + } + ], + "addLeftIcons": true, + "level": 1, + "propertyNameAtParent": "pluginFeatures", + "attachingRules": { + "compatibleTypes": "->Plugin Project->" + }, + "childrenNodesProperties": [ + { + "name": "pluginFiles", + "type": "array", + "childType": "Plugin File", + "autoAdd": false + } + ] +} \ No newline at end of file diff --git a/Projects/Governance/Schemas/App-Schema/plugin-pools.json b/Projects/Governance/Schemas/App-Schema/plugin-pools.json new file mode 100644 index 000000000..cfcab0c95 --- /dev/null +++ b/Projects/Governance/Schemas/App-Schema/plugin-pools.json @@ -0,0 +1,37 @@ +{ + "type": "Plugin Pools", + "menuItems": [ + { + "action": "Add Missing Plugin Pools", + "label": "Add Missing Pools", + "askConfirmation": true, + "confirmationLabel": "Confirm to Proceed", + "workDoneLabel": "Done", + "relatedUiObject": "Data Mine", + "actionFunction": "payload.executeAction" + }, + { + "action": "Delete UI Object", + "askConfirmation": true, + "confirmationLabel": "Confirm to Delete", + "label": "Delete", + "iconPathOn": "delete-entity", + "iconPathOff": "delete-entity", + "actionFunction": "payload.executeAction" + } + ], + "addLeftIcons": true, + "level": 1, + "propertyNameAtParent": "pluginPools", + "attachingRules": { + "compatibleTypes": "->Plugin Project->" + }, + "childrenNodesProperties": [ + { + "name": "pluginFiles", + "type": "array", + "childType": "Plugin File", + "autoAdd": false + } + ] +} \ No newline at end of file diff --git a/Projects/Governance/Schemas/App-Schema/plugin-positions.json b/Projects/Governance/Schemas/App-Schema/plugin-positions.json new file mode 100644 index 000000000..bfdeffd23 --- /dev/null +++ b/Projects/Governance/Schemas/App-Schema/plugin-positions.json @@ -0,0 +1,37 @@ +{ + "type": "Plugin Positions", + "menuItems": [ + { + "action": "Add Missing Plugin Positions", + "label": "Add Missing Positions", + "askConfirmation": true, + "confirmationLabel": "Confirm to Proceed", + "workDoneLabel": "Done", + "relatedUiObject": "Data Mine", + "actionFunction": "payload.executeAction" + }, + { + "action": "Delete UI Object", + "askConfirmation": true, + "confirmationLabel": "Confirm to Delete", + "label": "Delete", + "iconPathOn": "delete-entity", + "iconPathOff": "delete-entity", + "actionFunction": "payload.executeAction" + } + ], + "addLeftIcons": true, + "level": 1, + "propertyNameAtParent": "pluginPositions", + "attachingRules": { + "compatibleTypes": "->Plugin Project->" + }, + "childrenNodesProperties": [ + { + "name": "pluginFiles", + "type": "array", + "childType": "Plugin File", + "autoAdd": false + } + ] +} \ No newline at end of file diff --git a/Projects/Governance/Schemas/App-Schema/plugin-user-profiles.json b/Projects/Governance/Schemas/App-Schema/plugin-user-profiles.json index 8599d57c8..c68c1dc16 100644 --- a/Projects/Governance/Schemas/App-Schema/plugin-user-profiles.json +++ b/Projects/Governance/Schemas/App-Schema/plugin-user-profiles.json @@ -1,9 +1,9 @@ { - "type": "Plugin Data Mines", + "type": "Plugin User Profiles", "menuItems": [ { - "action": "Add Missing Plugin Data Mines", - "label": "Add Missing Data Mines", + "action": "Add Missing Plugin User Profiles", + "label": "Add Missing User Profiles", "askConfirmation": true, "confirmationLabel": "Confirm to Proceed", "workDoneLabel": "Done", @@ -22,7 +22,7 @@ ], "addLeftIcons": true, "level": 1, - "propertyNameAtParent": "pluginDataMines", + "propertyNameAtParent": "pluginUserProfiles", "attachingRules": { "compatibleTypes": "->Plugin Project->" }, diff --git a/Projects/Governance/UI/Function-Libraries/ActionSwitch.js b/Projects/Governance/UI/Function-Libraries/ActionSwitch.js index 183067e05..01b355415 100644 --- a/Projects/Governance/UI/Function-Libraries/ActionSwitch.js +++ b/Projects/Governance/UI/Function-Libraries/ActionSwitch.js @@ -24,6 +24,31 @@ function newGovernanceActionSwitch() { break } } + case 'Add Missing Plugin User Profiles': + { + UI.projects.foundations.functionLibraries.pluginsFunctions.addMissingPluginUserProfiles(action.node, action.rootNodes) + } + break + case 'Add Missing Plugin Pools': + { + UI.projects.foundations.functionLibraries.pluginsFunctions.addMissingPluginPools(action.node, action.rootNodes) + } + break + case 'Add Missing Plugin Features': + { + UI.projects.foundations.functionLibraries.pluginsFunctions.addMissingPluginFeatures(action.node, action.rootNodes) + } + break + case 'Add Missing Plugin Assets': + { + UI.projects.foundations.functionLibraries.pluginsFunctions.addMissingPluginAssets(action.node, action.rootNodes) + } + break + case 'Add Missing Plugin Positions': + { + UI.projects.foundations.functionLibraries.pluginsFunctions.addMissingPluginPositions(action.node, action.rootNodes) + } + break } } } diff --git a/Projects/Governance/UI/Function-Libraries/PluginsFunctions.js b/Projects/Governance/UI/Function-Libraries/PluginsFunctions.js index 03112b13f..edba7d9b0 100644 --- a/Projects/Governance/UI/Function-Libraries/PluginsFunctions.js +++ b/Projects/Governance/UI/Function-Libraries/PluginsFunctions.js @@ -1,63 +1,15 @@ function newGovernanceFunctionLibraryPluginsFunctions() { let thisObject = { - addMissingPluginDataMines: addMissingPluginDataMines, - addMissingPluginTradingMines: addMissingPluginTradingMines, - addMissingPluginTradingSystems: addMissingPluginTradingSystems, - addMissingPluginTradingEngines: addMissingPluginTradingEngines, - addMissingPluginLearningMines: addMissingPluginLearningMines, - addMissingPluginLearningSystems: addMissingPluginLearningSystems, - addMissingPluginLearningEngines: addMissingPluginLearningEngines, - addMissingPluginTutorials: addMissingPluginTutorials, - addMissingPluginApiMaps: addMissingPluginApiMaps + addMissingPluginUserProfiles: addMissingPluginUserProfiles, + addMissingPluginPools: addMissingPluginPools, + addMissingPluginAssets: addMissingPluginAssets, + addMissingPluginFeatures: addMissingPluginFeatures, + addMissingPluginPositions: addMissingPluginPositionss } return thisObject - function getPluginFileNames(projectName, pluginType, callBack) { - httpRequest(undefined, 'PluginFileNames/' + projectName + '/' + pluginType, onResponse) - - function onResponse(err, data) { - if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { - console.log('Failed to Fetch Plugin ' + pluginType + ' from the Client') - return - } - - let pluginFileNames = JSON.parse(data) - callBack(pluginFileNames) - } - } - - function addPluginFileIfNeeded(node, fileNames) { - for (let i = 0; i < fileNames.length; i++) { - let fileName = fileNames[i] - fileName = fileName.replace('.json', '') - if (UI.projects.foundations.utilities.children.isMissingChildrenByName(node, fileName) === true) { - let child = UI.projects.foundations.functionLibraries.uiObjectsFromNodes.addUIObject(node, 'Plugin File') - child.name = fileName - } - } - } - - function getProjectName(node) { - /* Validations to see if we can do this or not. */ - if (node.payload === undefined) { return } - if (node.payload.uiObject === undefined) { return } - - if (node.payload.parentNode === undefined) { - node.payload.uiObject.setErrorMessage('You need to have a Plugin Project node as a parent to execute this action.') - return - } - if (node.payload.parentNode.payload === undefined) { - node.payload.uiObject.setErrorMessage('You need to have a Plugin Project node as a parent to execute this action.') - return - } - let pluginProject = node.payload.parentNode - let config = JSON.parse(pluginProject.config) - - return config.codeName - } - - function addMissingPluginDataMines(node, rootNodes) { - let projectName = getProjectName(node) + function addMissingPluginUserProfiles(node, rootNodes) { + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -65,15 +17,15 @@ function newGovernanceFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Data-Mines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'User-Profiles', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } - function addMissingPluginTradingMines(node, rootNodes) { - let projectName = getProjectName(node) + function addMissingPluginPools(node, rootNodes) { + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -81,15 +33,15 @@ function newGovernanceFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Trading-Mines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Pools', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } - function addMissingPluginTradingSystems(node, rootNodes) { - let projectName = getProjectName(node) + function addMissingPluginAssets(node, rootNodes) { + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -97,15 +49,15 @@ function newGovernanceFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Trading-Systems', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Assets', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } - function addMissingPluginTradingEngines(node, rootNodes) { - let projectName = getProjectName(node) + function addMissingPluginFeatures(node, rootNodes) { + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -113,15 +65,15 @@ function newGovernanceFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Trading-Engines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Features', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } - function addMissingPluginLearningMines(node, rootNodes) { - let projectName = getProjectName(node) + function addMissingPluginPositionss(node, rootNodes) { + let projectName = UI.projects.foundations.utilities.plugins.getProjectName(node) if (projectName === "" || projectName === undefined) { if (node.payload.parentNode !== undefined) { node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") @@ -129,74 +81,10 @@ function newGovernanceFunctionLibraryPluginsFunctions() { } } - getPluginFileNames(projectName, 'Learning-Mines', onNamesArrived) + UI.projects.foundations.utilities.plugins.getPluginFileNames(projectName, 'Positions', onNamesArrived) function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) - } - } - - function addMissingPluginLearningSystems(node, rootNodes) { - let projectName = getProjectName(node) - if (projectName === "" || projectName === undefined) { - if (node.payload.parentNode !== undefined) { - node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") - return - } - } - - getPluginFileNames(projectName, 'Learning-Systems', onNamesArrived) - - function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) - } - } - - function addMissingPluginLearningEngines(node, rootNodes) { - let projectName = getProjectName(node) - if (projectName === "" || projectName === undefined) { - if (node.payload.parentNode !== undefined) { - node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") - return - } - } - - getPluginFileNames(projectName, 'Learning-Engines', onNamesArrived) - - function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) - } - } - - function addMissingPluginTutorials(node, rootNodes) { - let projectName = getProjectName(node) - if (projectName === "" || projectName === undefined) { - if (node.payload.parentNode !== undefined) { - node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") - return - } - } - - getPluginFileNames(projectName, 'Tutorials', onNamesArrived) - - function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) - } - } - - function addMissingPluginApiMaps(node, rootNodes) { - let projectName = getProjectName(node) - if (projectName === "" || projectName === undefined) { - if (node.payload.parentNode !== undefined) { - node.payload.parentNode.payload.uiObject.setErrorMessage("Config codeName must have the name of the project.") - return - } - } - - getPluginFileNames(projectName, 'API-Maps', onNamesArrived) - - function onNamesArrived(fileNames) { - addPluginFileIfNeeded(node, fileNames) + UI.projects.foundations.utilities.plugins.addPluginFileIfNeeded(node, fileNames) } } } diff --git a/Projects/ProjectsSchema.json b/Projects/ProjectsSchema.json index 16c2073c1..3eab1e04f 100644 --- a/Projects/ProjectsSchema.json +++ b/Projects/ProjectsSchema.json @@ -212,6 +212,11 @@ "name": "Status Bar", "propertyName": "statusBar", "functionName": "newFoundationsUtilitiesStatusBar" + }, + { + "name": "Plugins", + "propertyName": "plugins", + "functionName": "newFoundationsUtilitiesPlugins" } ], "spaces": [