diff --git a/FloatingSpace/CircularMenu.js b/FloatingSpace/CircularMenu.js index 33fed0473..0eeba34f7 100644 --- a/FloatingSpace/CircularMenu.js +++ b/FloatingSpace/CircularMenu.js @@ -67,6 +67,7 @@ function newCircularMenu () { menuItem.currentStatus = menuItemInitialValue.currentStatus menuItem.relatedStrategyPart = menuItemInitialValue.relatedStrategyPart menuItem.dontShowAtFullscreen = menuItemInitialValue.dontShowAtFullscreen + menuItem.askConfirmation = menuItemInitialValue.askConfirmation if (menuItem.label === undefined) { menuItem.type = 'Icon Only' diff --git a/FloatingSpace/CircularMenuItem.js b/FloatingSpace/CircularMenuItem.js index ee77de716..1ed429791 100644 --- a/FloatingSpace/CircularMenuItem.js +++ b/FloatingSpace/CircularMenuItem.js @@ -5,6 +5,7 @@ function newCircularMenuItem () { let thisObject = { type: undefined, isDeployed: undefined, + askConfirmation: undefined, iconOn: undefined, iconOff: undefined, currentIcon: undefined, @@ -170,7 +171,7 @@ function newCircularMenuItem () { } async function onMouseClick (event) { - if (temporaryStatus === 0) { + if (temporaryStatus === 0 && thisObject.askConfirmation !== true) { if (thisObject.workingLabel !== undefined) { setTemporaryStatus(thisObject.workingLabel, UI_COLOR.GREY, 500) } @@ -187,6 +188,14 @@ function newCircularMenuItem () { } } } + + if (temporaryStatus > 0 && thisObject.askConfirmation === true) { + thisObject.currentStatus = await thisObject.actionFunction(thisObject.payload, thisObject.action) + } + + if (temporaryStatus === 0 && thisObject.askConfirmation === true) { + setTemporaryStatus('Confirm to Delete', UI_COLOR.GREY, 50) + } } function setTemporaryStatus (text, backgroundColor, waitingCycles) { diff --git a/FloatingSpace/FloatingObject.js b/FloatingSpace/FloatingObject.js index 10164b2ab..bc9462f71 100644 --- a/FloatingSpace/FloatingObject.js +++ b/FloatingSpace/FloatingObject.js @@ -34,7 +34,7 @@ function newFloatingObject () { initializeRadius: initializeRadius, initializeImageSize: initializeImageSize, initializeFontSize: initializeFontSize, - radomizeCurrentPosition: radomizeCurrentPosition, + initializeCurrentPosition: initializeCurrentPosition, radomizeCurrentSpeed: radomizeCurrentSpeed, drawBackground: drawBackground, drawMiddleground: drawMiddleground, @@ -89,7 +89,7 @@ function newFloatingObject () { /* Assign a position and speed */ - thisObject.radomizeCurrentPosition(thisObject.payload.targetPosition) + thisObject.initializeCurrentPosition(thisObject.payload.targetPosition) thisObject.radomizeCurrentSpeed() } @@ -297,10 +297,19 @@ function newFloatingObject () { thisObject.currentFontSize = size / 3 } - function radomizeCurrentPosition (arroundPoint) { - let position = { - x: Math.floor((Math.random() * (200) - 100)) + arroundPoint.x, - y: Math.floor((Math.random() * (200) - 100)) + arroundPoint.y + function initializeCurrentPosition (arroundPoint) { + let position + + if (thisObject.payload.position === undefined) { + position = { + x: Math.floor((Math.random() * (200) - 100)) + arroundPoint.x, + y: Math.floor((Math.random() * (200) - 100)) + arroundPoint.y + } + } else { + position = { + x: thisObject.payload.position.x, + y: thisObject.payload.position.y + } } setPosition(position) diff --git a/FloatingSpace/StrategyPart.js b/FloatingSpace/StrategyPart.js index 6da021f37..f05522867 100644 --- a/FloatingSpace/StrategyPart.js +++ b/FloatingSpace/StrategyPart.js @@ -849,7 +849,7 @@ function newStrategyPart () { browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS, 0, Math.PI * 2, true) browserCanvasContext.closePath() - browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TURQUOISE + ', ' + OPACITY + ')' + browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.LIGHT_GREY + ', ' + OPACITY + ')' browserCanvasContext.lineWidth = 10 browserCanvasContext.setLineDash([4, 20]) diff --git a/FloatingSpace/StrategyPartConstructor.js b/FloatingSpace/StrategyPartConstructor.js index 91f43dc5a..94d0b458f 100644 --- a/FloatingSpace/StrategyPartConstructor.js +++ b/FloatingSpace/StrategyPartConstructor.js @@ -79,6 +79,52 @@ function newStrategyPartConstructor () { function getMenuItemsInitialValues (strategyPart, floatingObject, payload) { let menuItemsInitialValues = [] switch (payload.node.type) { + case 'Workspace': { + floatingObject.isPinned = true + floatingObject.positionLocked = true + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + actionStatus: floatingObject.getPinStatus, + currentStatus: true, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Freeze / Unfreeze', + actionFunction: floatingObject.freezeToggle, + actionStatus: floatingObject.getFreezeStatus, + currentStatus: true, + label: undefined, + visible: false, + iconPathOn: 'broken-link', + iconPathOff: 'targeting', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 135 + }, + { + action: 'Download Workspace', + actionFunction: payload.onMenuItemClick, + label: 'Download', + visible: false, + iconPathOn: 'upload', + iconPathOff: 'upload', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }] + break + } case 'Trading System': { floatingObject.isPinned = true floatingObject.positionLocked = true @@ -140,6 +186,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Trading System', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete Trading System', visible: false, @@ -222,6 +269,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Parameters', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete Parameters', visible: false, @@ -290,6 +338,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Base Asset', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete Base Asset', visible: false, @@ -371,6 +420,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Strategy', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Strategy', visible: false, @@ -452,6 +502,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Trigger Stage', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Stage', visible: false, @@ -520,6 +571,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Open Stage', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Stage', visible: false, @@ -588,6 +640,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Manage Stage', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Stage', visible: false, @@ -644,6 +697,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Close Stage', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Stage', visible: false, @@ -700,6 +754,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Position Size', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete Trading System', visible: false, @@ -782,6 +837,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Event', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Event', visible: false, @@ -851,6 +907,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Event', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Event', visible: false, @@ -920,6 +977,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Event', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Event', visible: false, @@ -988,6 +1046,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Initial Definition', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Definition', visible: false, @@ -1057,6 +1116,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Managed Item', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Item', visible: false, @@ -1126,6 +1186,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Managed Item', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Item', visible: false, @@ -1208,6 +1269,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Phase', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Phase', visible: false, @@ -1282,6 +1344,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Formula', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Formula', visible: false, @@ -1351,6 +1414,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Event', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Event', visible: false, @@ -1420,6 +1484,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Situation', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Situation', visible: false, @@ -1489,6 +1554,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Condition', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Condition', visible: false, @@ -1563,6 +1629,7 @@ function newStrategyPartConstructor () { }, { action: 'Delete Code', + askConfirmation: true, actionFunction: payload.onMenuItemClick, label: 'Delete This Code', visible: false, @@ -1600,6 +1667,10 @@ function newStrategyPartConstructor () { const INITIAL_FRICTION = 0.99 switch (payload.node.type) { + case 'Workspace': { + level_0() + break + } case 'Trading System': { level_0() break diff --git a/FloatingSpace/StrategyPartTitle.js b/FloatingSpace/StrategyPartTitle.js index d00a9eccd..aa239fa0c 100644 --- a/FloatingSpace/StrategyPartTitle.js +++ b/FloatingSpace/StrategyPartTitle.js @@ -48,6 +48,10 @@ function newStrategyPartTitle () { thisObject.payload = payload switch (payload.node.type) { + case 'Workspace': { + thisObject.allwaysVisible = true + break + } case 'Trading System': { thisObject.allwaysVisible = true break diff --git a/Spaces/StrategySpace.js b/Spaces/StrategySpace.js index 01e7bc5df..10b73a164 100644 --- a/Spaces/StrategySpace.js +++ b/Spaces/StrategySpace.js @@ -40,6 +40,7 @@ function newStrategySpace () { function buildIconByPartTypeMap () { const relationshipArray = [ + ['Workspace', 'design-tool'], ['Trading System', 'analysis'], ['Parameters', 'settings'], ['Base Asset', 'sitemap'], diff --git a/StrategySpace/StrategizerGateway.js b/StrategySpace/StrategizerGateway.js index 1743521cc..e8ce8ce3d 100644 --- a/StrategySpace/StrategizerGateway.js +++ b/StrategySpace/StrategizerGateway.js @@ -47,12 +47,12 @@ function newStrategizerGateway () { } user = JSON.parse(user) - let fbSlug = 'simulator' + '-' + 'bot' + '-' + user.alias.replace('.','') + let fbSlug = 'simulator' + '-' + 'bot' + '-' + user.alias.replace('.', '') /* See if we need to update or create a new record at the strategizer */ let tradingSystem = canvas.strategySpace.workspace.getProtocolTradingSystem() - let idAtStrategizer = canvas.strategySpace.workspace.idAtStrategizer + let idAtStrategizer = window.localStorage.getItem(MODULE_NAME) if (idAtStrategizer === undefined) { let response = await axios({ @@ -85,7 +85,7 @@ function newStrategizerGateway () { console.log('Error getting events: ' + JSON.stringify(response.data.errors)) throw 'Error getting events: ' + JSON.stringify(response.data.errors) } else { - canvas.strategySpace.workspace.idAtStrategizer = response.data.data.strategizer_CreateTradingSystem.id + window.localStorage.setItem(MODULE_NAME, response.data.data.strategizer_CreateTradingSystem.id) } } else { const graphQLServer = await axios({ @@ -132,7 +132,7 @@ function newStrategizerGateway () { } user = JSON.parse(user) - let fbSlug = 'simulator' + '-' + 'bot' + '-' + user.alias.replace('.','') + let fbSlug = 'simulator' + '-' + 'bot' + '-' + user.alias.replace('.', '') let response = await axios({ url: window.canvasApp.graphQL.masterAppApiUrl, @@ -166,9 +166,8 @@ function newStrategizerGateway () { return false } } else { - window.localStorage.setItem('userStrategies', JSON.stringify(response.data.data.strategizer_TradingSystemByFb.data)) thisObject.strategizerData = JSON.parse(JSON.stringify(response.data.data.strategizer_TradingSystemByFb.data)) - canvas.strategySpace.workspace.idAtStrategizer = response.data.data.strategizer_TradingSystemByFb.id + window.localStorage.setItem(MODULE_NAME, response.data.data.strategizer_TradingSystemByFb.id) return true } } catch (err) { diff --git a/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js b/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js index c5a69fece..4b1d23c86 100644 --- a/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js +++ b/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js @@ -1,5 +1,6 @@ function newNodeDeleter () { thisObject = { + deleteWorkspace: deleteWorkspace, deleteTradingSystem: deleteTradingSystem, deleteParameters: deleteParameters, deleteBaseAsset: deleteBaseAsset, @@ -25,19 +26,104 @@ function newNodeDeleter () { canvas.floatingSpace.strategyPartConstructor.destroyStrategyPart(node.payload) } - function deleteTradingSystem (node, rootNodes) { -/* Can not delete if it is the last one */ - let counter = 0 - for (let i = 0; i < rootNodes.length; i++) { - let rootNode = rootNodes[i] - if (rootNode.type === node.type) { - counter++ + function deleteWorkspace (node, rootNodes) { + while (node.rootNodes.length > 0) { + let rootNode = node.rootNodes[0] + switch (rootNode.type) { + + case 'Trading System': { + deleteTradingSystem(rootNode, rootNodes, true) + break + } + case 'Parameters': { + deleteParameters(rootNode, rootNodes) + break + } + case 'Base Asset': { + deleteBaseAsset(rootNode, rootNodes) + break + } + case 'Strategy': { + deleteStrategy(rootNode, rootNodes) + break + } + case 'Trigger Stage': { + deleteTriggerStage(rootNode, rootNodes) + break + } + case 'Open Stage': { + deleteOpenStage(rootNode, rootNodes) + break + } + case 'Manage Stage': { + deleteManageStage(rootNode, rootNodes) + break + } + case 'Close Stage': { + deleteCloseStage(rootNode, rootNodes) + break + } + case 'Position Size': { + deletePositionSize(rootNode, rootNodes) + break + } + case 'Initial Definition': { + deleteInitialDefinition(rootNode, rootNodes) + break + } + case 'Event': { + deleteEvent(rootNode, rootNodes) + break + } + case 'Managed Item': { + deleteManagedItem(rootNode, rootNodes) + break + } + case 'Phase': { + deletePhase(rootNode, rootNodes) + break + } + case 'Formula': { + deleteFormula(rootNode, rootNodes) + break + } + case 'Situation': { + deleteSituation(rootNode, rootNodes) + break + } + case 'Condition': { + deleteCondition(rootNode, rootNodes) + break + } + case 'Code': { + deleteCode(rootNode, rootNodes) + break + } + default: + } } - if (counter <= 1) { return } + + completeDeletion(node, rootNodes) + destroyPart(node) + cleanNode(node) + } + + function deleteTradingSystem (node, rootNodes, forced) { + if (forced !== true) { + /* Can not delete if it is the last one */ + let counter = 0 + for (let i = 0; i < rootNodes.length; i++) { + let rootNode = rootNodes[i] + if (rootNode.type === node.type) { + counter++ + } + } + if (counter <= 1) { return } + } if (node.payload.uiObject.isRunning === true) { - strategyPart.setNotRunningStatus() + node.payload.uiObject.setNotRunningStatus() } while (node.strategies.length > 0) { diff --git a/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js b/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js index 480f0ece0..326121ce3 100644 --- a/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js +++ b/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js @@ -235,6 +235,11 @@ function newPartsFromNodes () { } return } + case 'Workspace': { + let workspace = node + createPart('Workspace', workspace.name, workspace, parentNode, chainParent, 'Workspace') + return + } } } @@ -573,6 +578,12 @@ function newPartsFromNodes () { x: spawnPosition.x, y: spawnPosition.y } + if (partType === 'Workspace' || partType === 'Trading System') { + payload.position = { + x: spawnPosition.x, + y: spawnPosition.y + } + } } else { payload.targetPosition = { x: chainParent.payload.position.x, diff --git a/StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js b/StrategySpace/Workspace/FunctionLibraries/StringifyNode.js similarity index 80% rename from StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js rename to StrategySpace/Workspace/FunctionLibraries/StringifyNode.js index 04e69a3fd..c7691e2bb 100644 --- a/StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js +++ b/StrategySpace/Workspace/FunctionLibraries/StringifyNode.js @@ -1,10 +1,10 @@ -function newWorkspaceNode () { +function newStringifyNode () { thisObject = { - getWorkspaceNode: getWorkspaceNode + prepareForStringify: prepareForStringify } return thisObject - function getWorkspaceNode (node) { + function prepareForStringify (node) { if (node === undefined) { return } switch (node.type) { case 'Code': @@ -26,7 +26,7 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - code: getWorkspaceNode(node.code), + code: prepareForStringify(node.code), savedPayload: getSavedPayload(node) } return condition @@ -42,7 +42,7 @@ function newWorkspaceNode () { } for (let m = 0; m < node.conditions.length; m++) { - let condition = getWorkspaceNode(node.conditions[m]) + let condition = prepareForStringify(node.conditions[m]) situation.conditions.push(condition) } return situation @@ -70,7 +70,7 @@ function newWorkspaceNode () { savedPayload: getSavedPayload(node) } for (let m = 0; m < node.situations.length; m++) { - let situation = getWorkspaceNode(node.situations[m]) + let situation = prepareForStringify(node.situations[m]) event.situations.push(situation) } return event @@ -81,8 +81,8 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - formula: getWorkspaceNode(node.formula), - nextPhaseEvent: getWorkspaceNode(node.nextPhaseEvent), + formula: prepareForStringify(node.formula), + nextPhaseEvent: prepareForStringify(node.nextPhaseEvent), savedPayload: getSavedPayload(node) } return phase @@ -99,7 +99,7 @@ function newWorkspaceNode () { } for (let m = 0; m < node.phases.length; m++) { - let phase = getWorkspaceNode(node.phases[m]) + let phase = prepareForStringify(node.phases[m]) stop.phases.push(phase) } return stop @@ -116,7 +116,7 @@ function newWorkspaceNode () { } for (let m = 0; m < node.phases.length; m++) { - let phase = getWorkspaceNode(node.phases[m]) + let phase = prepareForStringify(node.phases[m]) takeProfit.phases.push(phase) } return takeProfit @@ -132,7 +132,7 @@ function newWorkspaceNode () { } for (let m = 0; m < node.situations.length; m++) { - let situation = getWorkspaceNode(node.situations[m]) + let situation = prepareForStringify(node.situations[m]) event.situations.push(situation) } return event @@ -148,7 +148,7 @@ function newWorkspaceNode () { } for (let m = 0; m < node.situations.length; m++) { - let situation = getWorkspaceNode(node.situations[m]) + let situation = prepareForStringify(node.situations[m]) event.situations.push(situation) } return event @@ -164,7 +164,7 @@ function newWorkspaceNode () { } for (let m = 0; m < node.situations.length; m++) { - let situation = getWorkspaceNode(node.situations[m]) + let situation = prepareForStringify(node.situations[m]) event.situations.push(situation) } return event @@ -175,8 +175,8 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - stopLoss: getWorkspaceNode(node.stopLoss), - takeProfit: getWorkspaceNode(node.takeProfit), + stopLoss: prepareForStringify(node.stopLoss), + takeProfit: prepareForStringify(node.takeProfit), savedPayload: getSavedPayload(node) } return object @@ -187,7 +187,7 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - formula: getWorkspaceNode(node.formula), + formula: prepareForStringify(node.formula), savedPayload: getSavedPayload(node) } return object @@ -198,10 +198,10 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - triggerOn: getWorkspaceNode(node.triggerOn), - triggerOff: getWorkspaceNode(node.triggerOff), - takePosition: getWorkspaceNode(node.takePosition), - positionSize: getWorkspaceNode(node.positionSize), + triggerOn: prepareForStringify(node.triggerOn), + triggerOff: prepareForStringify(node.triggerOff), + takePosition: prepareForStringify(node.takePosition), + positionSize: prepareForStringify(node.positionSize), savedPayload: getSavedPayload(node) } return stage @@ -212,7 +212,7 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - initialDefinition: getWorkspaceNode(node.initialDefinition), + initialDefinition: prepareForStringify(node.initialDefinition), savedPayload: getSavedPayload(node) } return stage @@ -223,8 +223,8 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - stopLoss: getWorkspaceNode(node.stopLoss), - takeProfit: getWorkspaceNode(node.takeProfit), + stopLoss: prepareForStringify(node.stopLoss), + takeProfit: prepareForStringify(node.takeProfit), savedPayload: getSavedPayload(node) } return stage @@ -245,10 +245,10 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - triggerStage: getWorkspaceNode(node.triggerStage), - openStage: getWorkspaceNode(node.openStage), - manageStage: getWorkspaceNode(node.manageStage), - closeStage: getWorkspaceNode(node.closeStage), + triggerStage: prepareForStringify(node.triggerStage), + openStage: prepareForStringify(node.openStage), + manageStage: prepareForStringify(node.manageStage), + closeStage: prepareForStringify(node.closeStage), savedPayload: getSavedPayload(node) } return strategy @@ -259,7 +259,7 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - formula: getWorkspaceNode(node.formula), + formula: prepareForStringify(node.formula), savedPayload: getSavedPayload(node) } return object @@ -270,7 +270,7 @@ function newWorkspaceNode () { type: node.type, subType: node.subType, name: node.name, - baseAsset: getWorkspaceNode(node.baseAsset), + baseAsset: prepareForStringify(node.baseAsset), savedPayload: getSavedPayload(node) } return object @@ -282,12 +282,12 @@ function newWorkspaceNode () { subType: node.subType, name: node.name, strategies: [], - parameters: getWorkspaceNode(node.parameters), + parameters: prepareForStringify(node.parameters), savedPayload: getSavedPayload(node) } for (let m = 0; m < node.strategies.length; m++) { - let strategy = getWorkspaceNode(node.strategies[m]) + let strategy = prepareForStringify(node.strategies[m]) tradingSystem.strategies.push(strategy) } return tradingSystem diff --git a/StrategySpace/Workspace/Workspace.js b/StrategySpace/Workspace/Workspace.js index 3107151f9..e0c81f559 100644 --- a/StrategySpace/Workspace/Workspace.js +++ b/StrategySpace/Workspace/Workspace.js @@ -5,7 +5,6 @@ function newWorkspace () { let thisObject = { tradingSystem: undefined, container: undefined, - idAtStrategizer: undefined, onMenuItemClick: onMenuItemClick, getProtocolTradingSystem: getProtocolTradingSystem, physics: physics, @@ -34,13 +33,14 @@ function newWorkspace () { y: canvas.floatingSpace.container.frame.height / 2 } - let rootNodes = [] + let workspaceNode = {} + workspaceNode.rootNodes = [] functionLibraryAttachDetach = newAttachDetach() functionLibraryNodeDeleter = newNodeDeleter() functionLibraryPartsFromNodes = newPartsFromNodes() functionLibraryProtocolNode = newProtocolNode() - functionLibraryWorkspaceNodes = newWorkspaceNode() + functionLibraryWorkspaceNodes = newStringifyNode() let isInitialized = false return thisObject @@ -52,22 +52,24 @@ function newWorkspace () { } async function initialize () { - functionLibraryAttachDetach = newAttachDetach() - functionLibraryNodeDeleter = newNodeDeleter() - functionLibraryPartsFromNodes = newPartsFromNodes() - functionLibraryProtocolNode = newProtocolNode() - functionLibraryWorkspaceNodes = newWorkspaceNode() + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE_KEY) + if (user === null) { + return + } + user = JSON.parse(user) - let savedWorkspace = window.localStorage.getItem('workspace') + let savedWorkspace = window.localStorage.getItem(user.alias + '.' + 'workspace') if (savedWorkspace === null) { + workspaceNode.type = 'Workspace' + workspaceNode.name = 'My Workspace' + functionLibraryPartsFromNodes.createPartFromNode(workspaceNode, undefined, undefined) + spawnPosition.y = spawnPosition.y + 250 initializeLoadingFromStrategizer() } else { - workspace = JSON.parse(savedWorkspace) - rootNodes = workspace.rootNodes - thisObject.idAtStrategizer = workspace.idAtStrategizer - - for (let i = 0; i < rootNodes.length; i++) { - let rootNode = rootNodes[i] + workspaceNode = JSON.parse(savedWorkspace) + functionLibraryPartsFromNodes.createPartFromNode(workspaceNode, undefined, undefined) + for (let i = 0; i < workspaceNode.rootNodes.length; i++) { + let rootNode = workspaceNode.rootNodes[i] functionLibraryPartsFromNodes.createPartFromNode(rootNode, undefined, undefined) } isInitialized = true @@ -78,7 +80,7 @@ function newWorkspace () { let result = await canvas.strategySpace.strategizerGateway.loadFromStrategyzer() if (result === true) { thisObject.tradingSystem = canvas.strategySpace.strategizerGateway.strategizerData - rootNodes.push(thisObject.tradingSystem) + workspaceNode.rootNodes.push(thisObject.tradingSystem) functionLibraryPartsFromNodes.createPartFromNode(thisObject.tradingSystem, undefined, undefined) thisObject.tradingSystem.payload.uiObject.setRunningStatus() } else { @@ -87,7 +89,7 @@ function newWorkspace () { type: 'Trading System', strategies: [] } - rootNodes.push(thisObject.tradingSystem) + workspaceNode.rootNodes.push(thisObject.tradingSystem) functionLibraryPartsFromNodes.createPartFromNode(thisObject.tradingSystem, undefined, undefined) thisObject.tradingSystem.payload.uiObject.setRunningStatus() } @@ -103,28 +105,39 @@ function newWorkspace () { } function detachNode (node) { - functionLibraryAttachDetach.detachNode(node, rootNodes) + functionLibraryAttachDetach.detachNode(node, workspaceNode.rootNodes) } function attachNode (node, attachToNode) { - functionLibraryAttachDetach.attachNode(node, attachToNode, rootNodes) + functionLibraryAttachDetach.attachNode(node, attachToNode, workspaceNode.rootNodes) } function physics () { if (isInitialized !== true) { return } /* Here we will save all the workspace related objects into the local storage */ + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE_KEY) + if (user === null) { + return + } + user = JSON.parse(user) + + let textToSave = stringifyWorkspace() + window.localStorage.setItem(user.alias + '.' + 'workspace', textToSave) + } + + function stringifyWorkspace () { let stringifyReadyNodes = [] - for (let i = 0; i < rootNodes.length; i++) { - let rootNode = rootNodes[i] - let workspaceNode = functionLibraryWorkspaceNodes.getWorkspaceNode(rootNode) - stringifyReadyNodes.push(workspaceNode) + for (let i = 0; i < workspaceNode.rootNodes.length; i++) { + let rootNode = workspaceNode.rootNodes[i] + let workspace = functionLibraryWorkspaceNodes.prepareForStringify(rootNode) + stringifyReadyNodes.push(workspace) } let workspace = { - idAtStrategizer: thisObject.idAtStrategizer, + type: 'Workspace', + name: workspaceNode.name, rootNodes: stringifyReadyNodes } - let textToSave = JSON.stringify(workspace) - window.localStorage.setItem('workspace', textToSave) + return JSON.stringify(workspace) } function spawn (nodeText, point) { @@ -132,14 +145,33 @@ function newWorkspace () { spawnPosition.x = point.x spawnPosition.y = point.y - let dirtyNode = JSON.parse(nodeText) - let rootNode = functionLibraryProtocolNode.getProtocolNode(dirtyNode) - rootNodes.push(rootNode) - functionLibraryPartsFromNodes.createPartFromNode(rootNode, undefined, undefined) + let droppedNode = JSON.parse(nodeText) + + if (droppedNode.type === 'Workspace') { + functionLibraryNodeDeleter.deleteWorkspace(workspaceNode, workspaceNode.rootNodes) + workspaceNode = droppedNode + functionLibraryPartsFromNodes.createPartFromNode(workspaceNode, undefined, undefined) + for (let i = 0; i < workspaceNode.rootNodes.length; i++) { + let rootNode = workspaceNode.rootNodes[i] + functionLibraryPartsFromNodes.createPartFromNode(rootNode, undefined, undefined) + } + } else { + let rootNode = functionLibraryProtocolNode.getProtocolNode(droppedNode) + workspaceNode.rootNodes.push(rootNode) + functionLibraryPartsFromNodes.createPartFromNode(rootNode, undefined, undefined) + } } async function onMenuItemClick (payload, action) { switch (action) { + case 'Download Workspace': + { + let text = stringifyWorkspace() + let fileName = payload.node.type + ' - ' + payload.node.name + '.json' + download(fileName, text) + } + + break case 'Save Trading System': { let result = await canvas.strategySpace.strategizerGateway.saveToStrategyzer() @@ -151,16 +183,17 @@ function newWorkspace () { break case 'Download': - - let text = JSON.stringify(functionLibraryProtocolNode.getProtocolNode(payload.node)) - let nodeName = payload.node.name - if (nodeName === undefined) { - nodeName = '' - } else { - nodeName = '.' + nodeName + { + let text = JSON.stringify(functionLibraryProtocolNode.getProtocolNode(payload.node)) + let nodeName = payload.node.name + if (nodeName === undefined) { + nodeName = '' + } else { + nodeName = '.' + nodeName + } + let fileName = payload.node.type + ' - ' + nodeName + '.json' + download(fileName, text) } - let fileName = payload.node.type + nodeName + '.json' - download(fileName, text) break @@ -235,71 +268,71 @@ function newWorkspace () { } break case 'Delete Trading System': { - functionLibraryNodeDeleter.deleteTradingSystem(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteTradingSystem(payload.node, workspaceNode.rootNodes) break } case 'Delete Parameters': { - functionLibraryNodeDeleter.deleteParameters(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteParameters(payload.node, workspaceNode.rootNodes) break } case 'Delete Base Asset': { - functionLibraryNodeDeleter.deleteBaseAsset(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteBaseAsset(payload.node, workspaceNode.rootNodes) break } case 'Delete Strategy': { - functionLibraryNodeDeleter.deleteStrategy(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteStrategy(payload.node, workspaceNode.rootNodes) break } case 'Delete Trigger Stage': { - functionLibraryNodeDeleter.deleteTriggerStage(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteTriggerStage(payload.node, workspaceNode.rootNodes) break } case 'Delete Open Stage': { - functionLibraryNodeDeleter.deleteOpenStage(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteOpenStage(payload.node, workspaceNode.rootNodes) break } case 'Delete Manage Stage': { - functionLibraryNodeDeleter.deleteManageStage(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteManageStage(payload.node, workspaceNode.rootNodes) break } case 'Delete Close Stage': { - functionLibraryNodeDeleter.deleteCloseStage(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteCloseStage(payload.node, workspaceNode.rootNodes) break } case 'Delete Position Size': { - functionLibraryNodeDeleter.deletePositionSize(payload.node, rootNodes) + functionLibraryNodeDeleter.deletePositionSize(payload.node, workspaceNode.rootNodes) break } case 'Delete Initial Definition': { - functionLibraryNodeDeleter.deleteInitialDefinition(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteInitialDefinition(payload.node, workspaceNode.rootNodes) break } case 'Delete Event': { - functionLibraryNodeDeleter.deleteEvent(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteEvent(payload.node, workspaceNode.rootNodes) break } case 'Delete Managed Item': { - functionLibraryNodeDeleter.deleteManagedItem(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteManagedItem(payload.node, workspaceNode.rootNodes) break } case 'Delete Phase': { - functionLibraryNodeDeleter.deletePhase(payload.node, rootNodes) + functionLibraryNodeDeleter.deletePhase(payload.node, workspaceNode.rootNodes) break } case 'Delete Formula': { - functionLibraryNodeDeleter.deleteFormula(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteFormula(payload.node, workspaceNode.rootNodes) break } case 'Delete Situation': { - functionLibraryNodeDeleter.deleteSituation(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteSituation(payload.node, workspaceNode.rootNodes) break } case 'Delete Condition': { - functionLibraryNodeDeleter.deleteCondition(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteCondition(payload.node, workspaceNode.rootNodes) break } case 'Delete Code': { - functionLibraryNodeDeleter.deleteCode(payload.node, rootNodes) + functionLibraryNodeDeleter.deleteCode(payload.node, workspaceNode.rootNodes) break } default: