diff --git a/src/components/EditDefinition/LoadInDefinition.vue b/src/components/EditDefinition/LoadInDefinition.vue index 0ebc4ae..7570fe6 100644 --- a/src/components/EditDefinition/LoadInDefinition.vue +++ b/src/components/EditDefinition/LoadInDefinition.vue @@ -1,288 +1,326 @@ - - - - - + + + + + diff --git a/src/components/EditDefinition/RemoveInheritance.vue b/src/components/EditDefinition/RemoveInheritance.vue index 079686a..db0fc84 100644 --- a/src/components/EditDefinition/RemoveInheritance.vue +++ b/src/components/EditDefinition/RemoveInheritance.vue @@ -1,289 +1,290 @@ - - - - - - - + + + + + + + diff --git a/src/components/UploadOBTree.vue b/src/components/UploadOBTree.vue index 00fdcb7..eeb0070 100644 --- a/src/components/UploadOBTree.vue +++ b/src/components/UploadOBTree.vue @@ -1,759 +1,759 @@ - - - - - + + + + + diff --git a/src/components/forms/CreateDefinitionForm.vue b/src/components/forms/CreateDefinitionForm.vue index ee056ca..22fc183 100644 --- a/src/components/forms/CreateDefinitionForm.vue +++ b/src/components/forms/CreateDefinitionForm.vue @@ -1,597 +1,596 @@ - - - - - + + + + + diff --git a/src/store/index.js b/src/store/index.js index 5992c1d..7595537 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,755 +1,755 @@ -import Vue from "vue"; -import Vuex from "vuex"; -import * as JSONEditor from "../utils/JSONEditor.js"; -import * as miscUtilities from "../utils/miscUtilities"; -import FileSaver from "file-saver"; -import { version } from "../../package.json"; -Vue.use(Vuex); - -export default new Vuex.Store({ - state: { - appVersion: version || 0, - uploadedOASFileOriginal: null, - schemaFile: null, - allNodesFlat: [], - allObjNodesFlat: [], - selectorFile: null, - isSelected: null, - nodeName: null, - nodeType: null, - nodeParent: null, - nodeParentTrail: null, - nodeDescription: null, - nodeEnum: null, - nameRef: null, - listOfDefinitionElements: [], - selectDefinitionNode: false, - showCreateDefinitionForm: false, - showLoadInDefinitionForm: false, - nodeToAddToObject: "", - nodeToAddListType: "", - superClassToRemoveFromObject: "", - refreshCreateDefn: false, - isSubClassedNode: false, - - // controls if the ExportFormModal is showing or not - exportModalOpened: false, - xbrlFlat: [], - - //tracks whether you are in the OAS tab or the XBRL tab - inOASTab: true, - inXBRLTab: false, - - treeSearchTerm: "", - - //tabs update - fileTabs: [], - currentTabIndexFileEditor: null, - currentFile: null, - - //taxonomy element update - isTaxonomyElement: false, - - // get rid of master Files. just have loadedFiles, which will include master files you can't delete - - masterFiles: {}, - loadedFiles: {}, - selectedFileName: "", - selectedDefnRefFile: null, - - fileToExport: null, - fileToExportName: "", - exportModalHeader: "", - - defnIsLocal: null, - - // right pane state while in editing mode - activeEditingView: "EditDefinitionFormDisabled", - // right pane state for views - activeEditorView: null, - // view state for Item Types Editor - activeItemTypesView: null, - - // after abbrev update - - nodeOBType: "", - nodeOBUsageTips: "", - nodeOBSampleValue: {}, - - // viewer mode option, can either be 'View Mode' or 'Edit Mode' - viewerMode: 'View Mode', - viewObjs: [], - - // refresh key is needed to re-render element list when switching between edit and view modes - refreshKey: null, - - // units added to obtaxonomy update - nodeEnumsOrUnitsObj: null, - nodeOBItemTypeGroupName: null, - nodeOBItemTypeGroupObj: {} - }, - mutations: { - /* - Add sample value to object - */ - addSampleValue(state, sampleValue) { - state.nodeOBSampleValue = sampleValue - // check if it is an allOf obj or a regular obj - // should move function to JSONEditor - // should use type to check if allOf, Obj or TaxElem - if (state.currentFile.file[state.isSelected]["allOf"]) { - for (let i in state.currentFile.file[state.isSelected]["allOf"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { - state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-sample-value"] = sampleValue; - } - } - } else { - state.currentFile.file[state.isSelected]["x-ob-sample-value"] = sampleValue; - } - }, - /* - Add usage tips to object - */ - addUsageTips(state, usageTips) { - state.nodeOBUsageTips = usageTips - // check if it is an allOf obj or a regular obj - // should move function to JSONEditor - // should use type to check if allOf, Obj or TaxElem - if (state.currentFile.file[state.isSelected]["allOf"]) { - for (let i in state.currentFile.file[state.isSelected]["allOf"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { - state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-usage-tips"] = usageTips; - } - } - } else { - state.currentFile.file[state.isSelected]["x-ob-usage-tips"] = usageTips; - } - }, - - /* - Add enumeration to object - */ - addEnumToObject(state, _enum) { - JSONEditor.addEnum(state.currentFile.file, state.isSelected, _enum); - state.nodeEnum = state.currentFile.file[state.isSelected]["enum"]; - for (let i in state.currentFile.file[state.isSelected]["allOf"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["enum"]) { - state.nodeEnum = - state.currentFile.file[state.isSelected]["allOf"][i]["enum"]; - } - } - } - }, - - /* - Remove enumeration from object - */ - removeEnumFromObject(state, _enum) { - JSONEditor.removeEnum(state.currentFile.file, state.isSelected, _enum); - - //check if empty enum array to set nodeEnum to null, will not react automatically for some reason - for (let i in state.currentFile.file[state.isSelected]["allOf"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { - if (!state.currentFile.file[state.isSelected]["allOf"][i]["enum"]) { - state.nodeEnum = null; - } - } - } - }, - - /* - Add member to object - */ - addNodeToObject(state, payload) { - let parentDefnName = payload.parentName; - let childDefnName = payload.defnToAddName; - let childRefFile = state.loadedFiles[payload.referenceFileName]; - let workingFile = state.currentFile; - - JSONEditor.addChildToObject( - workingFile, - parentDefnName, - childDefnName, - childRefFile - ); - }, - - /* - Edit definition - */ - editNode(state, payload) { - JSONEditor.editNode( - state.currentFile.file, - payload.nodeName, - payload.nodeDescription - ); - state.nodeDescription = payload.nodeDescription; - }, - - /* - Add Inheritance - */ - addSuperClass(state, payload) { - let workingFile = state.currentFile.file; - let subClassName = state.isSelected; - let superClassName = payload.superClassName; - let superClassRefFileName = payload.superClassRefFileName; - - JSONEditor.addSuperClass( - workingFile, - subClassName, - superClassName, - superClassRefFileName, - state.loadedFiles - ); - }, - - /* - Remove Inheritance - */ - removeSuperClass(state, superClassName) { - JSONEditor.removeSuperClass( - state.currentFile.file, - state.isSelected, - superClassName - ); - }, - - /* - Tree view handling - */ - toggleSelectDefinitionNode(state) { - state.selectDefinitionNode = false; - }, - selectNode(state, payload) { - state.isSelected = payload.nodeName; - state.nodeName = payload.nodeName; - state.nodeParent = payload.nodeParent; - state.nodeParentTrail = payload.nodeParentTrail; - - state.nodeType = payload.nodeType; - state.nodeDescription = payload.nodeDescription; - state.nameRef = payload.nameRef; - state.isSubClassedNode = payload.isSubClassedNode; - state.isTaxonomyElement = payload.isTaxonomyElement; - state.selectedFileName = payload.selectedFileName; - state.defnIsLocal = payload.isLocal; - - state.selectedDefnRefFile = payload.referenceFile; - state.activeEditingView = "EditDefinitionFormDisabled"; - - state.nodeEnumsOrUnitsObj = null - state.nodeOBType = '' - state.nodeOBItemTypeGroupName = '' - state.nodeOBItemTypeGroupObj = {} - - if (state.selectedDefnRefFile[state.isSelected]["allOf"]) { - for (let i in state.selectedDefnRefFile[state.isSelected]["allOf"]) { - if (state.selectedDefnRefFile[state.isSelected]["allOf"][i]["type"]) { - if ( - state.selectedDefnRefFile[state.isSelected]["allOf"][i][ - "x-ob-item-type" - ] - ) { - state.nodeOBType = - state.selectedDefnRefFile[state.isSelected]["allOf"][i][ - "x-ob-item-type" - ]; - } else { - state.nodeOBType = ""; - } - - if ("x-ob-item-type-group" in state.selectedDefnRefFile[state.isSelected]["allOf"][i] - && state.selectedDefnRefFile[state.isSelected]["allOf"][i]["x-ob-item-type-group"]) { - state.nodeOBItemTypeGroupName = state.selectedDefnRefFile[state.isSelected]["allOf"][i]["x-ob-item-type-group"] - } else { - state.nodeOBItemTypeGroupName = '' - } - - if ( - state.selectedDefnRefFile[state.isSelected]["allOf"][i][ - "x-ob-usage-tips" - ] - ) { - state.nodeOBUsageTips = - state.selectedDefnRefFile[state.isSelected]["allOf"][i][ - "x-ob-usage-tips" - ]; - } else { - state.nodeOBUsageTips = ""; - } - - if ( - state.selectedDefnRefFile[state.isSelected]["allOf"][i][ - "x-ob-sample-value" - ] - ) { - state.nodeOBSampleValue = - state.selectedDefnRefFile[state.isSelected]["allOf"][i][ - "x-ob-sample-value" - ]; - } else { - state.nodeOBSampleValue = {}; - } - } - } - } else if (state.selectedDefnRefFile[state.isSelected]["type"] == "object") { - if ( - state.selectedDefnRefFile[state.isSelected][ - "x-ob-usage-tips" - ] - ) { - state.nodeOBUsageTips = - state.selectedDefnRefFile[state.isSelected][ - "x-ob-usage-tips" - ]; - } else { - state.nodeOBUsageTips = ""; - } - state.nodeOBType = ""; - } else if (state.selectedDefnRefFile[state.isSelected]["type"] == "array") { - if ( - state.selectedDefnRefFile[state.isSelected][ - "x-ob-usage-tips" - ] - ) { - state.nodeOBUsageTips = - state.selectedDefnRefFile[state.isSelected][ - "x-ob-usage-tips" - ]; - } else { - state.nodeOBUsageTips = ""; - } - state.nodeOBType = ""; - } else { - state.nodeOBType = ""; - state.nodeOBUsageTips = ""; - } - - // set nodeEnumsOrUnitsObj - if (state.nodeOBType && state.loadedFiles[state.selectedFileName]["item_types"]) { - state.nodeEnumsOrUnitsObj = state.loadedFiles[state.selectedFileName]["item_types"][state.nodeOBType] - } - - // set node item type group obj - if (state.nodeOBItemTypeGroupName && state.loadedFiles[state.selectedFileName]["item_type_groups"]) { - state.nodeOBItemTypeGroupObj = state.loadedFiles[state.selectedFileName]["item_type_groups"][state.nodeOBItemTypeGroupName] - } - }, - - /* - Editor view handling - */ - showDetailedView(state) { - state.activeEditorView = "DetailedNodeView" - }, - showEditNodeView(state) { - state.activeEditorView = "EditDefinition" - state.selectDefinitionNode = true; - }, - showCreateDefinitionForm(state) { - state.activeEditorView = "CreateDefinitionForm" - }, - showLoadInDefinitionForm(state) { - state.activeEditorView = "LoadInDefinition" - }, - showEditItemTypesMain(state) { - state.activeEditorView = "EditItemTypesMain" - }, - showNoView(state) { - state.activeEditorView = null - }, - - // show state for Item Types Editor - // todo: consolidate into one function you pass the string to - showCreateItemType(state) { - state.activeItemTypesView = "CreateItemType" - }, - showCreateItemTypeGroup(state) { - state.activeItemTypesView = "CreateItemTypeGroup" - }, - showEditItemType(state) { - state.activeItemTypesView = "EditItemType" - }, - showEditItemTypeGroup(state) { - state.activeItemTypesView = "EditItemTypeGroup" - }, - showViewAllItemTypes(state) { - state.activeItemTypesView = "ViewAllItemTypes" - }, - showViewAllItemTypeGroups(state) { - state.activeItemTypesView = "ViewAllItemTypeGroups" - }, - showNoItemTypesViews(state) { - state.activeItemTypesView = null - }, - showDeleteItemType(state) { - state.activeItemTypesView = "DeleteItemType" - }, - showDeleteItemTypeGroup(state) { - state.activeItemTypesView = "DeleteItemTypeGroup" - }, - /* - JSON file handling - */ - updateOriginalJSONFile(state, json_str) { - // uploadedOASFileOriginal is used for exporting - // schemaFile is used for referencing the schema object in uploadedOASFileOriginal - // schemaFile is used for referencing the definition object in schema in uploadedOASFileOriginal - - state.uploadedOASFileOriginal = JSON.parse(json_str); - state.schemaFile = state.uploadedOASFileOriginal.components.schemas; - - // replace all instances of schemaFile with schemaFile. schemaFile is no longer needed as we took out the definition obj. - // state.schemaFile = state.schemaFile - JSONEditor.createArrayOfAllElementDefinitions( - state.schemaFile, - state.listOfDefinitionElements - ); - }, - deleteNode(state, payload) { - if (state.nodeParent == "root") { - JSONEditor.deleteAllNodes(payload.currentFile, state.nodeName); - } else { - JSONEditor.deleteNode( - payload.currentFile, - payload.nodeName, - payload.parent - ); - } - }, - toggleSelectNode(state) { - state.isSelected = false; - }, - createNodeElement(state, payload) { - let node_attr = { - type: payload.nodeType, - description: payload.nodeElementDescription - }; - Vue.set( - state.schemaFile.definitions.properties, - payload.nodeName, - node_attr - ); - }, - exportFile(state, payload) { - let jsonFileToExport = new Blob( - [JSON.stringify(payload.file, null, 2)], - { type: "application/json" } - ); - FileSaver.saveAs(jsonFileToExport, payload.filename + ".json"); - }, - selectNone(state) { - state.isSelected = null; - state.nodeName = null; - state.nodeType = null; - state.nodeDescription = null; - state.nameRef = null; - }, - createNodeObject(state, payload) { - JSONEditor.createNodeObject( - state.schemaFile, - payload.objectName, - payload.objectDescription, - payload.elementForms - ); - }, - // todo: refactor createDefinition, remove repeated code around definition type - createDefinition(state, payload) { - let defn_attr = {}; - - if (payload.definitionType == "OB Object") { - defn_attr = { - type: "object", - description: payload.definitionDescription, - properties: {} - }; - } else if (payload.definitionType == "OB Taxonomy Element String") { - defn_attr = { - allOf: [ - { - $ref: - "Master-Solar-Taxonomy.json#/components/schemas/TaxonomyElementString" - }, - { - type: "object", - description: payload.definitionDescription, - "x-ob-item-type": payload.OBItemType, - "x-ob-item-type-group": payload.OBItemTypeGroup, - "x-ob-usage-tips": payload.OBUsageTips, - "x-ob-sample-value": payload.OBSampleValue - } - ] - }; - } else if (payload.definitionType == "OB Taxonomy Element Number") { - defn_attr = { - allOf: [ - { - $ref: - "Master-Solar-Taxonomy.json#/components/schemas/TaxonomyElementNumber" - }, - { - type: "object", - description: payload.definitionDescription, - "x-ob-item-type": payload.OBItemType, - "x-ob-item-type-group": payload.OBItemTypeGroup, - "x-ob-usage-tips": payload.OBUsageTips, - "x-ob-sample-value": payload.OBSampleValue - } - ] - }; - } else if (payload.definitionType == "OB Taxonomy Element Integer") { - defn_attr = { - allOf: [ - { - $ref: - "Master-Solar-Taxonomy.json#/components/schemas/TaxonomyElementInteger" - }, - { - type: "object", - description: payload.definitionDescription, - "x-ob-item-type": payload.OBItemType, - "x-ob-item-type-group": payload.OBItemTypeGroup, - "x-ob-usage-tips": payload.OBUsageTips, - "x-ob-sample-value": payload.OBSampleValue - } - ] - }; - } else if (payload.definitionType == "OB Taxonomy Element Boolean") { - defn_attr = { - allOf: [ - { - $ref: - "Master-Solar-Taxonomy.json#/components/schemas/TaxonomyElementBoolean" - }, - { - type: "object", - description: payload.definitionDescription, - "x-ob-item-type": payload.OBItemType, - "x-ob-item-type-group": payload.OBItemTypeGroup, - "x-ob-usage-tips": payload.OBUsageTips, - "x-ob-sample-value": payload.OBSampleValue - } - ] - }; - } else if (payload.definitionType == "OB Array") { - let ref = '' - if (state.currentFile.fileName == payload.arrayItemFileName) { - ref = "#/components/schemas/" + payload.arrayItemDefnName - } else { - ref = payload.arrayItemFileName + "#/components/schemas/" + payload.arrayItemDefnName - } - - defn_attr = { - type: "array", - items: { - $ref: ref - } - }; - } - - Vue.set(state.currentFile.file, payload.definitionName, defn_attr); - }, - createItemType(state, payload) { - let finalItemTypeObj = {} - let finalEnumsOrUnits = {} - finalItemTypeObj['description'] = payload.itemTypeDescription - - payload.itemTypeEnumsOrUnits.forEach( enumOrUnitObj => { - finalEnumsOrUnits[enumOrUnitObj['enumOrUnitID']] = { - "label": enumOrUnitObj['enumOrUnitLabel'], - "description": enumOrUnitObj['enumOrUnitDescription'] - } - }) - - if (payload.itemTypeType == 'units') { - finalItemTypeObj['units'] = finalEnumsOrUnits - } else if (payload.itemTypeType == 'enums') { - finalItemTypeObj['enums'] = finalEnumsOrUnits - } - - Vue.set(state.currentFile.item_types, payload.itemTypeName, finalItemTypeObj) - - }, - // edits the item type in the definiton file under obj 'x-ob-item-type' - editItemTypeDefn(state, payload) { - let finalEdittedItemTypeObj = {} - let finalEnumsOrUnits = {} - - finalEdittedItemTypeObj['description'] = payload.itemTypeDescription - payload.itemTypeEnumsOrUnits.forEach( enumOrUnitObj => { - finalEnumsOrUnits[enumOrUnitObj['enumOrUnitID']] = { - "label": enumOrUnitObj['enumOrUnitLabel'], - "description": enumOrUnitObj['enumOrUnitDescription'] - } - }) - - if (payload.itemTypeType == 'units') { - finalEdittedItemTypeObj['units'] = finalEnumsOrUnits - } else if (payload.itemTypeType == 'enums') { - finalEdittedItemTypeObj['enums'] = finalEnumsOrUnits - } - Vue.set(state.currentFile.item_types, payload.itemTypeName, finalEdittedItemTypeObj) - - }, - createItemTypeGroup(state, payload) { - let finalItemTypeGroupObj = {} - let finalEnumsOrUnits = [] - - if (payload.itemTypeGroupGroup.length) { - payload.itemTypeGroupGroup.forEach( enumOrUnitObj => { - finalEnumsOrUnits.push(enumOrUnitObj['enumOrUnitID']) - }) - } - - finalItemTypeGroupObj = { - "type": payload.baseItemTypeRef, - "description": payload.itemTypeGroupDescription, - "group" : finalEnumsOrUnits - } - - Vue.set(state.currentFile.item_type_groups, payload.itemTypeGroupName, finalItemTypeGroupObj) - }, - editItemTypeGroup(state, payload) { - let finalEdittedItemTypeGroupObj = {} - let finalEnumsOrUnits = [] - - if (payload.itemTypeGroupGroup.length) { - payload.itemTypeGroupGroup.forEach( enumOrUnitObj => { - finalEnumsOrUnits.push(enumOrUnitObj['enumOrUnitID']) - }) - } - - finalEdittedItemTypeGroupObj = { - "type": payload.baseItemTypeRef, - "description": payload.itemTypeGroupDescription, - "group" : finalEnumsOrUnits - } - - Vue.set(state.currentFile.item_type_groups, payload.itemTypeGroupName, finalEdittedItemTypeGroupObj) - }, - deleteItemType(state, payload) { - Vue.delete(state.currentFile.item_types, payload.itemTypeToDelete[0]["itemType"]) - - - }, - deleteItemTypeGroup(state, payload) { - Vue.delete(state.currentFile.item_type_groups, payload.itemTypeGroupToDelete[0]["itemTypeGroupName"]) - - - }, - // Refreshes form inputs when trying to hit add definition after already adding a defn - refreshCreateDefnInputs(state, refreshBool) { - state.refreshCreateDefn = refreshBool; - }, - setFileToExport(state, payload) { - state.fileToExport = payload.fileToExport; - state.fileToExportName = payload.fileToExportName; - state.exportModalHeader = payload.exportModalHeader; - }, - setShowExportModal(state, payload) { - state.exportModalOpened = payload; - }, - clearEditorView(state) { - state.activeEditorView = null - state.isSelected = null; - state.nameRef = null; - }, - - // when user loads in a file, it is put into the loadedFile object - // problem: what if someone loads in a file, references it in a new fiile, then unloads the old file. now the new file cant reference the old - loadFile(state, file) { - state.loadedFiles[file.fileName] = file; - }, - removeFile(state, fileName) { - if ( - !( - fileName == "Master-Solar-Taxonomy.json" || - fileName == "Master-OB-OpenAPI.json" - ) - ) { - delete state.loadedFiles[fileName]; - } - }, - loadInDefinition(state, payload) { - let defnName = payload.defnName; - let defnFile = payload.defnFile; - let currentFile = state.currentFile.file; - - JSONEditor.loadInDefinition(currentFile, defnName, defnFile); - }, - changeItemType(state, payload) { - - state.nodeOBType = payload.OBItemType; - - for (let i in state.currentFile.file[state.isSelected]["allOf"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { - Vue.set( - state.currentFile.file[state.isSelected]["allOf"][i], - "x-ob-item-type", - payload.OBItemType - ) - state.nodeEnumsOrUnitsObj = state.loadedFiles[state.selectedFileName]["item_types"][state.nodeOBType] - - // if item group for element does not match - if ("x-ob-item-type-group" in state.currentFile.file[state.isSelected]["allOf"][i] - && state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-item-type-group"]) { - let currentItemTypeGroup = state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-item-type-group"] - if (!state.loadedFiles[state.selectedFileName]["item_type_groups"][currentItemTypeGroup]['type'].includes(payload.OBItemType)) { - Vue.set( - state.currentFile.file[state.isSelected]["allOf"][i], - "x-ob-item-type-group", - '' - ) - state.nodeOBItemTypeGroupName = '' - state.nodeOBItemTypeGroupObj = {} - } - } - } - } - }, - changeItemTypeGroup(state, payload) { - state.nodeOBItemTypeGroupName = payload.OBItemTypeGroupName - state.nodeOBItemTypeGroupObj = {} - if (payload.OBItemTypeGroupName) { - state.nodeOBItemTypeGroupObj = state.loadedFiles[state.selectedFileName]["item_type_groups"][state.nodeOBItemTypeGroupName] - } - - for (let i in state.currentFile.file[state.isSelected]["allOf"]) { - if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { - Vue.set( - state.currentFile.file[state.isSelected]["allOf"][i], - "x-ob-item-type-group", - payload.OBItemTypeGroupName - ) - } - } - }, - changeViewerMode(state, mode) { - state.viewerMode = mode - }, - // params: - // el: name of element to add or remove - // mode: 'init' or 'create_cookie'; init is for reading cookies when the app inits - addViewObj(state, params) { - state.viewObjs.push(params['el']) - if (params['mode'] == 'create_cookie') - miscUtilities.createCookie('viewObjs', JSON.stringify(state.viewObjs), 500) - }, - removeViewObj(state, params) { - for (let i = 0; i < state.viewObjs.length; i++) { - if (params['el'] == state.viewObjs[i]) { - state.viewObjs.splice(i, 1) - break; - } - } - miscUtilities.createCookie('viewObjs', JSON.stringify(state.viewObjs), 500) - }, - - // rerenders node list - reRenderList(state) { - state.refreshKey = Math.floor((Math.random() * 100) + 1).toString() - }, - } -}); +import Vue from "vue"; +import Vuex from "vuex"; +import * as JSONEditor from "../utils/JSONEditor.js"; +import * as miscUtilities from "../utils/miscUtilities"; +import FileSaver from "file-saver"; +import { version } from "../../package.json"; +Vue.use(Vuex); + +export default new Vuex.Store({ + state: { + appVersion: version || 0, + uploadedOASFileOriginal: null, + schemaFile: null, + allNodesFlat: [], + allObjNodesFlat: [], + selectorFile: null, + isSelected: null, + nodeName: null, + nodeType: null, + nodeParent: null, + nodeParentTrail: null, + nodeDescription: null, + nodeEnum: null, + nameRef: null, + listOfDefinitionElements: [], + selectDefinitionNode: false, + showCreateDefinitionForm: false, + showLoadInDefinitionForm: false, + nodeToAddToObject: "", + nodeToAddListType: "", + superClassToRemoveFromObject: "", + refreshCreateDefn: false, + isSubClassedNode: false, + + // controls if the ExportFormModal is showing or not + exportModalOpened: false, + xbrlFlat: [], + + //tracks whether you are in the OAS tab or the XBRL tab + inOASTab: true, + inXBRLTab: false, + + treeSearchTerm: "", + + //tabs update + fileTabs: [], + currentTabIndexFileEditor: null, + currentFile: null, + + //taxonomy element update + isTaxonomyElement: false, + + // get rid of master Files. just have loadedFiles, which will include master files you can't delete + + masterFiles: {}, + loadedFiles: {}, + selectedFileName: "", + selectedDefnRefFile: null, + + fileToExport: null, + fileToExportName: "", + exportModalHeader: "", + + defnIsLocal: null, + + // right pane state while in editing mode + activeEditingView: "EditDefinitionFormDisabled", + // right pane state for views + activeEditorView: null, + // view state for Item Types Editor + activeItemTypesView: null, + + // after abbrev update + + nodeOBType: "", + nodeOBUsageTips: "", + nodeOBSampleValue: {}, + + // viewer mode option, can either be 'View Mode' or 'Edit Mode' + viewerMode: 'View Mode', + viewObjs: [], + + // refresh key is needed to re-render element list when switching between edit and view modes + refreshKey: null, + + // units added to obtaxonomy update + nodeEnumsOrUnitsObj: null, + nodeOBItemTypeGroupName: null, + nodeOBItemTypeGroupObj: {} + }, + mutations: { + /* + Add sample value to object + */ + addSampleValue(state, sampleValue) { + state.nodeOBSampleValue = sampleValue + // check if it is an allOf obj or a regular obj + // should move function to JSONEditor + // should use type to check if allOf, Obj or TaxElem + if (state.currentFile.file[state.isSelected]["allOf"]) { + for (let i in state.currentFile.file[state.isSelected]["allOf"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { + state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-sample-value"] = sampleValue; + } + } + } else { + state.currentFile.file[state.isSelected]["x-ob-sample-value"] = sampleValue; + } + }, + /* + Add usage tips to object + */ + addUsageTips(state, usageTips) { + state.nodeOBUsageTips = usageTips + // check if it is an allOf obj or a regular obj + // should move function to JSONEditor + // should use type to check if allOf, Obj or TaxElem + if (state.currentFile.file[state.isSelected]["allOf"]) { + for (let i in state.currentFile.file[state.isSelected]["allOf"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { + state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-usage-tips"] = usageTips; + } + } + } else { + state.currentFile.file[state.isSelected]["x-ob-usage-tips"] = usageTips; + } + }, + + /* + Add enumeration to object + */ + addEnumToObject(state, _enum) { + JSONEditor.addEnum(state.currentFile.file, state.isSelected, _enum); + state.nodeEnum = state.currentFile.file[state.isSelected]["enum"]; + for (let i in state.currentFile.file[state.isSelected]["allOf"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["enum"]) { + state.nodeEnum = + state.currentFile.file[state.isSelected]["allOf"][i]["enum"]; + } + } + } + }, + + /* + Remove enumeration from object + */ + removeEnumFromObject(state, _enum) { + JSONEditor.removeEnum(state.currentFile.file, state.isSelected, _enum); + + //check if empty enum array to set nodeEnum to null, will not react automatically for some reason + for (let i in state.currentFile.file[state.isSelected]["allOf"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { + if (!state.currentFile.file[state.isSelected]["allOf"][i]["enum"]) { + state.nodeEnum = null; + } + } + } + }, + + /* + Add member to object + */ + addNodeToObject(state, payload) { + let parentDefnName = payload.parentName; + let childDefnName = payload.defnToAddName; + let childRefFile = state.loadedFiles[payload.referenceFileName]; + let workingFile = state.currentFile; + + JSONEditor.addChildToObject( + workingFile, + parentDefnName, + childDefnName, + childRefFile + ); + }, + + /* + Edit definition + */ + editNode(state, payload) { + JSONEditor.editNode( + state.currentFile.file, + payload.nodeName, + payload.nodeDescription + ); + state.nodeDescription = payload.nodeDescription; + }, + + /* + Add Inheritance + */ + addSuperClass(state, payload) { + let workingFile = state.currentFile.file; + let subClassName = state.isSelected; + let superClassName = payload.superClassName; + let superClassRefFileName = payload.superClassRefFileName; + + JSONEditor.addSuperClass( + workingFile, + subClassName, + superClassName, + superClassRefFileName, + state.loadedFiles + ); + }, + + /* + Remove Inheritance + */ + removeSuperClass(state, superClassName) { + JSONEditor.removeSuperClass( + state.currentFile.file, + state.isSelected, + superClassName + ); + }, + + /* + Tree view handling + */ + toggleSelectDefinitionNode(state) { + state.selectDefinitionNode = false; + }, + selectNode(state, payload) { + state.isSelected = payload.nodeName; + state.nodeName = payload.nodeName; + state.nodeParent = payload.nodeParent; + state.nodeParentTrail = payload.nodeParentTrail; + + state.nodeType = payload.nodeType; + state.nodeDescription = payload.nodeDescription; + state.nameRef = payload.nameRef; + state.isSubClassedNode = payload.isSubClassedNode; + state.isTaxonomyElement = payload.isTaxonomyElement; + state.selectedFileName = payload.selectedFileName; + state.defnIsLocal = payload.isLocal; + + state.selectedDefnRefFile = payload.referenceFile; + state.activeEditingView = "EditDefinitionFormDisabled"; + + state.nodeEnumsOrUnitsObj = null + state.nodeOBType = '' + state.nodeOBItemTypeGroupName = '' + state.nodeOBItemTypeGroupObj = {} + + if (state.selectedDefnRefFile[state.isSelected]["allOf"]) { + for (let i in state.selectedDefnRefFile[state.isSelected]["allOf"]) { + if (state.selectedDefnRefFile[state.isSelected]["allOf"][i]["type"]) { + if ( + state.selectedDefnRefFile[state.isSelected]["allOf"][i][ + "x-ob-item-type" + ] + ) { + state.nodeOBType = + state.selectedDefnRefFile[state.isSelected]["allOf"][i][ + "x-ob-item-type" + ]; + } else { + state.nodeOBType = ""; + } + + if ("x-ob-item-type-group" in state.selectedDefnRefFile[state.isSelected]["allOf"][i] + && state.selectedDefnRefFile[state.isSelected]["allOf"][i]["x-ob-item-type-group"]) { + state.nodeOBItemTypeGroupName = state.selectedDefnRefFile[state.isSelected]["allOf"][i]["x-ob-item-type-group"] + } else { + state.nodeOBItemTypeGroupName = '' + } + + if ( + state.selectedDefnRefFile[state.isSelected]["allOf"][i][ + "x-ob-usage-tips" + ] + ) { + state.nodeOBUsageTips = + state.selectedDefnRefFile[state.isSelected]["allOf"][i][ + "x-ob-usage-tips" + ]; + } else { + state.nodeOBUsageTips = ""; + } + + if ( + state.selectedDefnRefFile[state.isSelected]["allOf"][i][ + "x-ob-sample-value" + ] + ) { + state.nodeOBSampleValue = + state.selectedDefnRefFile[state.isSelected]["allOf"][i][ + "x-ob-sample-value" + ]; + } else { + state.nodeOBSampleValue = {}; + } + } + } + } else if (state.selectedDefnRefFile[state.isSelected]["type"] == "object") { + if ( + state.selectedDefnRefFile[state.isSelected][ + "x-ob-usage-tips" + ] + ) { + state.nodeOBUsageTips = + state.selectedDefnRefFile[state.isSelected][ + "x-ob-usage-tips" + ]; + } else { + state.nodeOBUsageTips = ""; + } + state.nodeOBType = ""; + } else if (state.selectedDefnRefFile[state.isSelected]["type"] == "array") { + if ( + state.selectedDefnRefFile[state.isSelected][ + "x-ob-usage-tips" + ] + ) { + state.nodeOBUsageTips = + state.selectedDefnRefFile[state.isSelected][ + "x-ob-usage-tips" + ]; + } else { + state.nodeOBUsageTips = ""; + } + state.nodeOBType = ""; + } else { + state.nodeOBType = ""; + state.nodeOBUsageTips = ""; + } + + // set nodeEnumsOrUnitsObj + if (state.nodeOBType && state.loadedFiles[state.selectedFileName]["item_types"]) { + state.nodeEnumsOrUnitsObj = state.loadedFiles[state.selectedFileName]["item_types"][state.nodeOBType] + } + + // set node item type group obj + if (state.nodeOBItemTypeGroupName && state.loadedFiles[state.selectedFileName]["item_type_groups"]) { + state.nodeOBItemTypeGroupObj = state.loadedFiles[state.selectedFileName]["item_type_groups"][state.nodeOBItemTypeGroupName] + } + }, + + /* + Editor view handling + */ + showDetailedView(state) { + state.activeEditorView = "DetailedNodeView" + }, + showEditNodeView(state) { + state.activeEditorView = "EditDefinition" + state.selectDefinitionNode = true; + }, + showCreateDefinitionForm(state) { + state.activeEditorView = "CreateDefinitionForm" + }, + showLoadInDefinitionForm(state) { + state.activeEditorView = "LoadInDefinition" + }, + showEditItemTypesMain(state) { + state.activeEditorView = "EditItemTypesMain" + }, + showNoView(state) { + state.activeEditorView = null + }, + + // show state for Item Types Editor + // todo: consolidate into one function you pass the string to + showCreateItemType(state) { + state.activeItemTypesView = "CreateItemType" + }, + showCreateItemTypeGroup(state) { + state.activeItemTypesView = "CreateItemTypeGroup" + }, + showEditItemType(state) { + state.activeItemTypesView = "EditItemType" + }, + showEditItemTypeGroup(state) { + state.activeItemTypesView = "EditItemTypeGroup" + }, + showViewAllItemTypes(state) { + state.activeItemTypesView = "ViewAllItemTypes" + }, + showViewAllItemTypeGroups(state) { + state.activeItemTypesView = "ViewAllItemTypeGroups" + }, + showNoItemTypesViews(state) { + state.activeItemTypesView = null + }, + showDeleteItemType(state) { + state.activeItemTypesView = "DeleteItemType" + }, + showDeleteItemTypeGroup(state) { + state.activeItemTypesView = "DeleteItemTypeGroup" + }, + /* + JSON file handling + */ + updateOriginalJSONFile(state, json_str) { + // uploadedOASFileOriginal is used for exporting + // schemaFile is used for referencing the schema object in uploadedOASFileOriginal + // schemaFile is used for referencing the definition object in schema in uploadedOASFileOriginal + + state.uploadedOASFileOriginal = JSON.parse(json_str); + state.schemaFile = state.uploadedOASFileOriginal.components.schemas; + + // replace all instances of schemaFile with schemaFile. schemaFile is no longer needed as we took out the definition obj. + // state.schemaFile = state.schemaFile + JSONEditor.createArrayOfAllElementDefinitions( + state.schemaFile, + state.listOfDefinitionElements + ); + }, + deleteNode(state, payload) { + if (state.nodeParent == "root") { + JSONEditor.deleteAllNodes(payload.currentFile, state.nodeName); + } else { + JSONEditor.deleteNode( + payload.currentFile, + payload.nodeName, + payload.parent + ); + } + }, + toggleSelectNode(state) { + state.isSelected = false; + }, + createNodeElement(state, payload) { + let node_attr = { + type: payload.nodeType, + description: payload.nodeElementDescription + }; + Vue.set( + state.schemaFile.definitions.properties, + payload.nodeName, + node_attr + ); + }, + exportFile(state, payload) { + let jsonFileToExport = new Blob( + [JSON.stringify(payload.file, null, 2)], + { type: "application/json" } + ); + FileSaver.saveAs(jsonFileToExport, payload.filename + ".json"); + }, + selectNone(state) { + state.isSelected = null; + state.nodeName = null; + state.nodeType = null; + state.nodeDescription = null; + state.nameRef = null; + }, + createNodeObject(state, payload) { + JSONEditor.createNodeObject( + state.schemaFile, + payload.objectName, + payload.objectDescription, + payload.elementForms + ); + }, + // todo: refactor createDefinition, remove repeated code around definition type + createDefinition(state, payload) { + let defn_attr = {}; + + if (payload.definitionType == "OB Object") { + defn_attr = { + type: "object", + description: payload.definitionDescription, + properties: {} + }; + } else if (payload.definitionType == "OB Taxonomy Element String") { + defn_attr = { + allOf: [ + { + $ref: + "#/components/schemas/TaxonomyElementString" + }, + { + type: "object", + description: payload.definitionDescription, + "x-ob-item-type": payload.OBItemType, + "x-ob-item-type-group": payload.OBItemTypeGroup, + "x-ob-usage-tips": payload.OBUsageTips, + "x-ob-sample-value": payload.OBSampleValue + } + ] + }; + } else if (payload.definitionType == "OB Taxonomy Element Number") { + defn_attr = { + allOf: [ + { + $ref: + "#/components/schemas/TaxonomyElementNumber" + }, + { + type: "object", + description: payload.definitionDescription, + "x-ob-item-type": payload.OBItemType, + "x-ob-item-type-group": payload.OBItemTypeGroup, + "x-ob-usage-tips": payload.OBUsageTips, + "x-ob-sample-value": payload.OBSampleValue + } + ] + }; + } else if (payload.definitionType == "OB Taxonomy Element Integer") { + defn_attr = { + allOf: [ + { + $ref: + "#/components/schemas/TaxonomyElementInteger" + }, + { + type: "object", + description: payload.definitionDescription, + "x-ob-item-type": payload.OBItemType, + "x-ob-item-type-group": payload.OBItemTypeGroup, + "x-ob-usage-tips": payload.OBUsageTips, + "x-ob-sample-value": payload.OBSampleValue + } + ] + }; + } else if (payload.definitionType == "OB Taxonomy Element Boolean") { + defn_attr = { + allOf: [ + { + $ref: + "#/components/schemas/TaxonomyElementBoolean" + }, + { + type: "object", + description: payload.definitionDescription, + "x-ob-item-type": payload.OBItemType, + "x-ob-item-type-group": payload.OBItemTypeGroup, + "x-ob-usage-tips": payload.OBUsageTips, + "x-ob-sample-value": payload.OBSampleValue + } + ] + }; + } else if (payload.definitionType == "OB Array") { + let ref = '' + if (state.currentFile.fileName == payload.arrayItemFileName) { + ref = "#/components/schemas/" + payload.arrayItemDefnName + } else { + ref = payload.arrayItemFileName + "#/components/schemas/" + payload.arrayItemDefnName + } + + defn_attr = { + type: "array", + items: { + $ref: ref + } + }; + } + + Vue.set(state.currentFile.file, payload.definitionName, defn_attr); + }, + createItemType(state, payload) { + let finalItemTypeObj = {} + let finalEnumsOrUnits = {} + finalItemTypeObj['description'] = payload.itemTypeDescription + + payload.itemTypeEnumsOrUnits.forEach( enumOrUnitObj => { + finalEnumsOrUnits[enumOrUnitObj['enumOrUnitID']] = { + "label": enumOrUnitObj['enumOrUnitLabel'], + "description": enumOrUnitObj['enumOrUnitDescription'] + } + }) + + if (payload.itemTypeType == 'units') { + finalItemTypeObj['units'] = finalEnumsOrUnits + } else if (payload.itemTypeType == 'enums') { + finalItemTypeObj['enums'] = finalEnumsOrUnits + } + + Vue.set(state.currentFile.item_types, payload.itemTypeName, finalItemTypeObj) + + }, + // edits the item type in the definiton file under obj 'x-ob-item-type' + editItemTypeDefn(state, payload) { + let finalEdittedItemTypeObj = {} + let finalEnumsOrUnits = {} + + finalEdittedItemTypeObj['description'] = payload.itemTypeDescription + payload.itemTypeEnumsOrUnits.forEach( enumOrUnitObj => { + finalEnumsOrUnits[enumOrUnitObj['enumOrUnitID']] = { + "label": enumOrUnitObj['enumOrUnitLabel'], + "description": enumOrUnitObj['enumOrUnitDescription'] + } + }) + + if (payload.itemTypeType == 'units') { + finalEdittedItemTypeObj['units'] = finalEnumsOrUnits + } else if (payload.itemTypeType == 'enums') { + finalEdittedItemTypeObj['enums'] = finalEnumsOrUnits + } + Vue.set(state.currentFile.item_types, payload.itemTypeName, finalEdittedItemTypeObj) + + }, + createItemTypeGroup(state, payload) { + let finalItemTypeGroupObj = {} + let finalEnumsOrUnits = [] + + if (payload.itemTypeGroupGroup.length) { + payload.itemTypeGroupGroup.forEach( enumOrUnitObj => { + finalEnumsOrUnits.push(enumOrUnitObj['enumOrUnitID']) + }) + } + + finalItemTypeGroupObj = { + "type": payload.baseItemTypeRef, + "description": payload.itemTypeGroupDescription, + "group" : finalEnumsOrUnits + } + + Vue.set(state.currentFile.item_type_groups, payload.itemTypeGroupName, finalItemTypeGroupObj) + }, + editItemTypeGroup(state, payload) { + let finalEdittedItemTypeGroupObj = {} + let finalEnumsOrUnits = [] + + if (payload.itemTypeGroupGroup.length) { + payload.itemTypeGroupGroup.forEach( enumOrUnitObj => { + finalEnumsOrUnits.push(enumOrUnitObj['enumOrUnitID']) + }) + } + + finalEdittedItemTypeGroupObj = { + "type": payload.baseItemTypeRef, + "description": payload.itemTypeGroupDescription, + "group" : finalEnumsOrUnits + } + + Vue.set(state.currentFile.item_type_groups, payload.itemTypeGroupName, finalEdittedItemTypeGroupObj) + }, + deleteItemType(state, payload) { + Vue.delete(state.currentFile.item_types, payload.itemTypeToDelete[0]["itemType"]) + + + }, + deleteItemTypeGroup(state, payload) { + Vue.delete(state.currentFile.item_type_groups, payload.itemTypeGroupToDelete[0]["itemTypeGroupName"]) + + + }, + // Refreshes form inputs when trying to hit add definition after already adding a defn + refreshCreateDefnInputs(state, refreshBool) { + state.refreshCreateDefn = refreshBool; + }, + setFileToExport(state, payload) { + state.fileToExport = payload.fileToExport; + state.fileToExportName = payload.fileToExportName; + state.exportModalHeader = payload.exportModalHeader; + }, + setShowExportModal(state, payload) { + state.exportModalOpened = payload; + }, + clearEditorView(state) { + state.activeEditorView = null + state.isSelected = null; + state.nameRef = null; + }, + + // when user loads in a file, it is put into the loadedFile object + // problem: what if someone loads in a file, references it in a new fiile, then unloads the old file. now the new file cant reference the old + loadFile(state, file) { + state.loadedFiles[file.fileName] = file; + }, + removeFile(state, fileName) { + if ( + !( + fileName == "Master-Solar-Taxonomy.json" || + fileName == "Master-OB-OpenAPI.json" + ) + ) { + delete state.loadedFiles[fileName]; + } + }, + loadInDefinition(state, payload) { + let defnNameToLoad = payload.defnName; + let defnFileToLoadFrom = state.loadedFiles[payload.defnFile]["file"] + let currentFile = state.currentFile.file; + + JSONEditor.loadInDefinition(currentFile, defnNameToLoad, defnFileToLoadFrom); + }, + changeItemType(state, payload) { + + state.nodeOBType = payload.OBItemType; + + for (let i in state.currentFile.file[state.isSelected]["allOf"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { + Vue.set( + state.currentFile.file[state.isSelected]["allOf"][i], + "x-ob-item-type", + payload.OBItemType + ) + state.nodeEnumsOrUnitsObj = state.loadedFiles[state.selectedFileName]["item_types"][state.nodeOBType] + + // if item group for element does not match + if ("x-ob-item-type-group" in state.currentFile.file[state.isSelected]["allOf"][i] + && state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-item-type-group"]) { + let currentItemTypeGroup = state.currentFile.file[state.isSelected]["allOf"][i]["x-ob-item-type-group"] + if (!state.loadedFiles[state.selectedFileName]["item_type_groups"][currentItemTypeGroup]['type'].includes(payload.OBItemType)) { + Vue.set( + state.currentFile.file[state.isSelected]["allOf"][i], + "x-ob-item-type-group", + '' + ) + state.nodeOBItemTypeGroupName = '' + state.nodeOBItemTypeGroupObj = {} + } + } + } + } + }, + changeItemTypeGroup(state, payload) { + state.nodeOBItemTypeGroupName = payload.OBItemTypeGroupName + state.nodeOBItemTypeGroupObj = {} + if (payload.OBItemTypeGroupName) { + state.nodeOBItemTypeGroupObj = state.loadedFiles[state.selectedFileName]["item_type_groups"][state.nodeOBItemTypeGroupName] + } + + for (let i in state.currentFile.file[state.isSelected]["allOf"]) { + if (state.currentFile.file[state.isSelected]["allOf"][i]["type"]) { + Vue.set( + state.currentFile.file[state.isSelected]["allOf"][i], + "x-ob-item-type-group", + payload.OBItemTypeGroupName + ) + } + } + }, + changeViewerMode(state, mode) { + state.viewerMode = mode + }, + // params: + // el: name of element to add or remove + // mode: 'init' or 'create_cookie'; init is for reading cookies when the app inits + addViewObj(state, params) { + state.viewObjs.push(params['el']) + if (params['mode'] == 'create_cookie') + miscUtilities.createCookie('viewObjs', JSON.stringify(state.viewObjs), 500) + }, + removeViewObj(state, params) { + for (let i = 0; i < state.viewObjs.length; i++) { + if (params['el'] == state.viewObjs[i]) { + state.viewObjs.splice(i, 1) + break; + } + } + miscUtilities.createCookie('viewObjs', JSON.stringify(state.viewObjs), 500) + }, + + // rerenders node list + reRenderList(state) { + state.refreshKey = Math.floor((Math.random() * 100) + 1).toString() + }, + } +}); diff --git a/src/utils/JSONEditor.js b/src/utils/JSONEditor.js index b699713..df302d8 100644 --- a/src/utils/JSONEditor.js +++ b/src/utils/JSONEditor.js @@ -1,316 +1,411 @@ -/* - -JSONEditor.js contains functions related to manipulating OAS JSON files - -*/ - -import Vue from "vue"; -import Vuex from "vuex"; -import * as miscUtilities from "./miscUtilities.js"; -import newFileTemplate from "../assets/OB-OpenAPI-New-File-Template.json"; - -// Deletes all nodes recursively of the same node name -// used for deleting definition elements -export function deleteAllNodes(JSONFile, nodeName) { - Object.keys(JSONFile).forEach(key => { - if (key == nodeName) { - Vue.delete(JSONFile, key); - } else if (JSONFile[key].properties) { - if (JSONFile[key]["properties"][nodeName]) { - Vue.delete(JSONFile[key].properties, nodeName); - } - } else if (JSONFile[key]["allOf"]) { - for (let i in JSONFile[key]["allOf"]) { - if (JSONFile[key]["allOf"][i]["properties"]) { - if (JSONFile[key]["allOf"][i]["properties"][nodeName]) { - Vue.delete(JSONFile[key]["allOf"][i]["properties"], nodeName); - } - } - if (JSONFile[key]["allOf"][i]["$ref"]) { - let superClassName = JSONFile[key]["allOf"][i]["$ref"].slice( - JSONFile[key]["allOf"][i]["$ref"].lastIndexOf("/") + 1, - JSONFile[key]["allOf"][i]["$ref"].length - ); - if (superClassName == nodeName) { - Vue.delete(JSONFile[key]["allOf"], i); - } - } - } - } - }); -} - -//Remove single node from object. Removes every instance of the node which is in the object -export function deleteNode(JSONFile, nodeName, parentName) { - if (parentName == "root") { - Vue.delete(JSONFile, nodeName); - for (let i in JSONFile) { - if (JSONFile[i]["properties"]) { - if (JSONFile[i]["properties"][nodeName]) { - Vue.delete(JSONFile[i]["properties"], nodeName); - } - } else if (JSONFile[i]["allOf"]) { - for (let j in JSONFile[i]["allOf"]) { - if (JSONFile[i]["allOf"][j]["$ref"]) { - for (let k in JSONFile[i]["allOf"][j]["$ref"]) { - let superClassSubStringIndex = - JSONFile[i]["allOf"][j]["$ref"][k].lastIndexOf("/") + 1; - let superClassSubString = JSONFile[i]["allOf"][j]["$ref"][ - k - ].slice(superClassSubStringIndex); - if (superClassSubString == nodeName) { - Vue.delete(JSONFile[i]["allOf"][j]["$ref"], k); - } - } - } else if (JSONFile[i]["allOf"][j]["properties"]) { - if (JSONFile[i]["allOf"][j]["properties"][nodeName]) { - Vue.delete(JSONFile[i]["allOf"][j]["properties"], nodeName); - } - } - } - } - } - } else { - if (JSONFile[parentName]["properties"]) { - Vue.delete(JSONFile[parentName]["properties"], nodeName); - } else { - for (let i in JSONFile[parentName]["allOf"]) { - if (JSONFile[parentName]["allOf"][i]["properties"]) { - Vue.delete(JSONFile[parentName]["allOf"][i]["properties"], nodeName); - } - } - } - } -} - -//Edit node -export function editNode(JSONFile, nodeName, newDescription) { - let nodeEdit = { - description: newDescription - }; - if (miscUtilities.hasInheritance(JSONFile[nodeName])) { - for (let i in JSONFile[nodeName]["allOf"]) { - if (JSONFile[nodeName]["allOf"][i]["type"]) { - JSONFile[nodeName]["allOf"][i]["description"] = newDescription; - } - } - } else if (JSONFile[nodeName]["type"] == "object") { - nodeEdit.properties = JSONFile[nodeName]["properties"]; - nodeEdit.type = "object"; - Vue.set(JSONFile, nodeName, nodeEdit); - } else { - Vue.set(JSONFile, nodeName, nodeEdit); - } -} - -//Create node -export function createNodeElement( - JSONFile, - nodeName, - nodeType, - nodeDescription -) { - let node_attr = { - type: nodeType, - description: nodeDescription - }; - Vue.set(JSONFile, nodeName, node_attr); -} - -//Create object -export function createNodeObject( - JSONFile, - objectName, - objectDescription, - elementForms -) { - let properties = {}; - for (let i in elementForms) { - properties[elementForms[i].nodeName] = { - type: elementForms[i].nodeType, - description: elementForms[i].nodeDescription - }; - } - let obj_attr = { - type: "object", - description: objectDescription, - properties: properties - }; - Vue.set(JSONFile, objectName, obj_attr); -} - -//create list of all element definitions into array for use in selecting elements in object creation. -export function createArrayOfAllElementDefinitions(JSONFile, array) { - Object.keys(JSONFile).forEach(key => { - if (!JSONFile[key].properties) { - array.push(key); - } - }); -} - -//add child to object whether element or object -//adding children to the top level object does not propagate throughout the reference objects -// if all non-top level elements/objects are references, do we need to add the child to anything other than the top level defn? probably not -export function addChildToObject( - JSONFile, - parentName, - childName, - childRefFile -) { - let childObj = null; - let parentFile = JSONFile.file; - let parentFileName = JSONFile.fileName; - - let childFile = childRefFile.file; - let childFileName = childRefFile.fileName; - - if (JSONFile.fileName == childFileName) { - childObj = { - $ref: "#/components/schemas/" + childName - }; - - if (JSONFile["file"][parentName]["allOf"]) { - for (let i in JSONFile["file"][parentName]["allOf"]) { - if (JSONFile["file"][parentName]["allOf"][i]["properties"]) { - Vue.set( - JSONFile["file"][parentName]["allOf"][i]["properties"], - childName, - childObj - ); - } - } - } else { - Vue.set(JSONFile["file"][parentName].properties, childName, childObj); - } - } else { - childObj = { - $ref: childFileName + "#/components/schemas/" + childName - }; - - if (JSONFile["file"][parentName]["allOf"]) { - for (let i in JSONFile["file"][parentName]["allOf"]) { - if (JSONFile["file"][parentName]["allOf"][i]["properties"]) { - Vue.set( - JSONFile["file"][parentName]["allOf"][i]["properties"], - childName, - childObj - ); - } - } - } else { - Vue.set(JSONFile["file"][parentName].properties, childName, childObj); - } - } -} - -// add superClass to object, making that object a subclass -export function addSuperClass( - workingFile, - subClassName, - superClassName, - superClassRefFileName, - loadedFiles -) { - let refExists = false; - let allOfArr = []; - let allOfObj = {}; - - if (workingFile[subClassName]["allOf"] !== undefined) { - for (let i of JSONFile[workingFile].allOf) { - if ( - i["ref"] == - superClassRefFileName + "#/components/schemas/" + superClassName - ) { - refExists = true; - } - } - if (!refExists) { - JSONFile[subClassName].allOf.push({ - $ref: superClassRefFileName + "#/components/schemas/" + superClassName - }); - } - } else { - allOfArr.push({ - $ref: superClassRefFileName + "#/components/schemas/" + superClassName - }); - allOfArr.push(JSON.parse(JSON.stringify(workingFile[subClassName]))); - allOfObj = { - allOf: allOfArr - }; - Vue.delete(workingFile, subClassName); - Vue.set(workingFile, subClassName, allOfObj); - } -} - -export function removeSuperClass(JSONFile, subClassName, superClassName) { - if (JSONFile[subClassName]["allOf"].length > 2) { - for (let i in JSONFile[subClassName]["allOf"]) { - if (JSONFile[subClassName]["allOf"][i]["$ref"]) { - if ( - JSONFile[subClassName]["allOf"][i]["$ref"].includes(superClassName) - ) { - Vue.delete(JSONFile[subClassName]["allOf"], i); - } - } - } - } else { - let temp_subClass_obj = {}; - for (let i in JSONFile[subClassName]["allOf"]) { - if (JSONFile[subClassName]["allOf"][i]["type"]) { - temp_subClass_obj = JSONFile[subClassName]["allOf"][i]; - } - } - Vue.set(JSONFile, subClassName, temp_subClass_obj); - } -} - -// add enumeration to definition element -export function addEnum(JSONFile, defnName, enumName) { - let temp_enum = {}; - - for (let i in JSONFile[defnName]["allOf"]) { - if (JSONFile[defnName]["allOf"][i]["type"]) { - if (JSONFile[defnName]["allOf"][i]["enum"]) { - JSONFile[defnName]["allOf"][i]["enum"].push(enumName); - } else { - temp_enum = [enumName]; - Vue.set(JSONFile[defnName]["allOf"][i], "enum", temp_enum); - } - } - } -} - -// remove enumeration from definition element -export function removeEnum(JSONFile, defnName, enumName) { - for (let i in JSONFile[defnName]["allOf"]) { - if (JSONFile[defnName]["allOf"][i]["enum"]) { - let enum_index = JSONFile[defnName]["allOf"][i]["enum"].indexOf(enumName); - if (JSONFile[defnName]["allOf"][i]["enum"].length == 1) { - Vue.delete(JSONFile[defnName]["allOf"][i], "enum"); - } else { - Vue.delete(JSONFile[defnName]["allOf"][i]["enum"], enum_index); - } - } - } -} - -export function createNewDefnFile(title, description, fileName) { - let returnNewFileObj = {}; - returnNewFileObj["fullFileForExport"] = newFileTemplate; - returnNewFileObj["file"] = - returnNewFileObj["fullFileForExport"].components.schemas; - returnNewFileObj["fileName"] = fileName; - - returnNewFileObj["fullFileForExport"]["info"]["title"] = title; - returnNewFileObj["fullFileForExport"]["info"]["description"] = description; - - return returnNewFileObj; -} - -export function loadInDefinition(workingFile, defnName, refFile) { - let defnObj = { - $ref: refFile + "#/components/schemas/" + defnName - }; - - Vue.set(workingFile, defnName, defnObj); -} +/* + +JSONEditor.js contains functions related to manipulating OAS JSON files + +*/ + +import Vue from "vue"; +import Vuex from "vuex"; +import * as miscUtilities from "./miscUtilities.js"; +import newFileTemplate from "../assets/OB-OpenAPI-New-File-Template.json"; + +// Deletes all nodes recursively of the same node name +// used for deleting definition elements +export function deleteAllNodes(JSONFile, nodeName) { + Object.keys(JSONFile).forEach(key => { + if (key == nodeName) { + Vue.delete(JSONFile, key); + } else if (JSONFile[key].properties) { + if (JSONFile[key]["properties"][nodeName]) { + Vue.delete(JSONFile[key].properties, nodeName); + } + } else if (JSONFile[key]["allOf"]) { + for (let i in JSONFile[key]["allOf"]) { + if (JSONFile[key]["allOf"][i]["properties"]) { + if (JSONFile[key]["allOf"][i]["properties"][nodeName]) { + Vue.delete(JSONFile[key]["allOf"][i]["properties"], nodeName); + } + } + if (JSONFile[key]["allOf"][i]["$ref"]) { + let superClassName = JSONFile[key]["allOf"][i]["$ref"].slice( + JSONFile[key]["allOf"][i]["$ref"].lastIndexOf("/") + 1, + JSONFile[key]["allOf"][i]["$ref"].length + ); + if (superClassName == nodeName) { + Vue.delete(JSONFile[key]["allOf"], i); + } + } + } + } + }); +} + +//Remove single node from object. Removes every instance of the node which is in the object +export function deleteNode(JSONFile, nodeName, parentName) { + if (parentName == "root") { + Vue.delete(JSONFile, nodeName); + for (let i in JSONFile) { + if (JSONFile[i]["properties"]) { + if (JSONFile[i]["properties"][nodeName]) { + Vue.delete(JSONFile[i]["properties"], nodeName); + } + } else if (JSONFile[i]["allOf"]) { + for (let j in JSONFile[i]["allOf"]) { + if (JSONFile[i]["allOf"][j]["$ref"]) { + for (let k in JSONFile[i]["allOf"][j]["$ref"]) { + let superClassSubStringIndex = + JSONFile[i]["allOf"][j]["$ref"][k].lastIndexOf("/") + 1; + let superClassSubString = JSONFile[i]["allOf"][j]["$ref"][ + k + ].slice(superClassSubStringIndex); + if (superClassSubString == nodeName) { + Vue.delete(JSONFile[i]["allOf"][j]["$ref"], k); + } + } + } else if (JSONFile[i]["allOf"][j]["properties"]) { + if (JSONFile[i]["allOf"][j]["properties"][nodeName]) { + Vue.delete(JSONFile[i]["allOf"][j]["properties"], nodeName); + } + } + } + } + } + } else { + if (JSONFile[parentName]["properties"]) { + Vue.delete(JSONFile[parentName]["properties"], nodeName); + } else { + for (let i in JSONFile[parentName]["allOf"]) { + if (JSONFile[parentName]["allOf"][i]["properties"]) { + Vue.delete(JSONFile[parentName]["allOf"][i]["properties"], nodeName); + } + } + } + } +} + +//Edit node +export function editNode(JSONFile, nodeName, newDescription) { + let nodeEdit = { + description: newDescription + }; + if (miscUtilities.hasInheritance(JSONFile[nodeName])) { + for (let i in JSONFile[nodeName]["allOf"]) { + if (JSONFile[nodeName]["allOf"][i]["type"]) { + JSONFile[nodeName]["allOf"][i]["description"] = newDescription; + } + } + } else if (JSONFile[nodeName]["type"] == "object") { + nodeEdit.properties = JSONFile[nodeName]["properties"]; + nodeEdit.type = "object"; + Vue.set(JSONFile, nodeName, nodeEdit); + } else { + Vue.set(JSONFile, nodeName, nodeEdit); + } +} + +//Create node +export function createNodeElement( + JSONFile, + nodeName, + nodeType, + nodeDescription +) { + let node_attr = { + type: nodeType, + description: nodeDescription + }; + Vue.set(JSONFile, nodeName, node_attr); +} + +//Create object +export function createNodeObject( + JSONFile, + objectName, + objectDescription, + elementForms +) { + let properties = {}; + for (let i in elementForms) { + properties[elementForms[i].nodeName] = { + type: elementForms[i].nodeType, + description: elementForms[i].nodeDescription + }; + } + let obj_attr = { + type: "object", + description: objectDescription, + properties: properties + }; + Vue.set(JSONFile, objectName, obj_attr); +} + +//create list of all element definitions into array for use in selecting elements in object creation. +export function createArrayOfAllElementDefinitions(JSONFile, array) { + Object.keys(JSONFile).forEach(key => { + if (!JSONFile[key].properties) { + array.push(key); + } + }); +} + +//add child to object whether element or object +//adding children to the top level object does not propagate throughout the reference objects +// if all non-top level elements/objects are references, do we need to add the child to anything other than the top level defn? probably not +export function addChildToObject( + JSONFile, + parentName, + childName, + childRefFile +) { + let childObj = null; + let parentFile = JSONFile.file; + let parentFileName = JSONFile.fileName; + + let childFile = childRefFile.file; + let childFileName = childRefFile.fileName; + + if (JSONFile.fileName == childFileName) { + childObj = { + $ref: "#/components/schemas/" + childName + }; + + if (JSONFile["file"][parentName]["allOf"]) { + for (let i in JSONFile["file"][parentName]["allOf"]) { + if (JSONFile["file"][parentName]["allOf"][i]["properties"]) { + Vue.set( + JSONFile["file"][parentName]["allOf"][i]["properties"], + childName, + childObj + ); + } + } + } else { + Vue.set(JSONFile["file"][parentName].properties, childName, childObj); + } + } else { + childObj = { + $ref: childFileName + "#/components/schemas/" + childName + }; + + if (JSONFile["file"][parentName]["allOf"]) { + for (let i in JSONFile["file"][parentName]["allOf"]) { + if (JSONFile["file"][parentName]["allOf"][i]["properties"]) { + Vue.set( + JSONFile["file"][parentName]["allOf"][i]["properties"], + childName, + childObj + ); + } + } + } else { + Vue.set(JSONFile["file"][parentName].properties, childName, childObj); + } + } +} + +// add superClass to object, making that object a subclass +export function addSuperClass( + workingFile, + subClassName, + superClassName, + superClassRefFileName, + loadedFiles +) { + let refExists = false; + let allOfArr = []; + let allOfObj = {}; + + if (workingFile[subClassName]["allOf"] !== undefined) { + for (let i of JSONFile[workingFile].allOf) { + if ( + i["ref"] == + "#/components/schemas/" + superClassName + ) { + refExists = true; + } + } + if (!refExists) { + JSONFile[subClassName].allOf.push({ + $ref: "#/components/schemas/" + superClassName + }); + } + } else { + allOfArr.push({ + $ref: "#/components/schemas/" + superClassName + }); + allOfArr.push(JSON.parse(JSON.stringify(workingFile[subClassName]))); + allOfObj = { + allOf: allOfArr + }; + Vue.delete(workingFile, subClassName); + Vue.set(workingFile, subClassName, allOfObj); + } +} + +export function removeSuperClass(JSONFile, subClassName, superClassName) { + if (JSONFile[subClassName]["allOf"].length > 2) { + for (let i in JSONFile[subClassName]["allOf"]) { + if (JSONFile[subClassName]["allOf"][i]["$ref"]) { + if ( + JSONFile[subClassName]["allOf"][i]["$ref"].includes(superClassName) + ) { + Vue.delete(JSONFile[subClassName]["allOf"], i); + } + } + } + } else { + let temp_subClass_obj = {}; + for (let i in JSONFile[subClassName]["allOf"]) { + if (JSONFile[subClassName]["allOf"][i]["type"]) { + temp_subClass_obj = JSONFile[subClassName]["allOf"][i]; + } + } + Vue.set(JSONFile, subClassName, temp_subClass_obj); + } +} + +// add enumeration to definition element +export function addEnum(JSONFile, defnName, enumName) { + let temp_enum = {}; + + for (let i in JSONFile[defnName]["allOf"]) { + if (JSONFile[defnName]["allOf"][i]["type"]) { + if (JSONFile[defnName]["allOf"][i]["enum"]) { + JSONFile[defnName]["allOf"][i]["enum"].push(enumName); + } else { + temp_enum = [enumName]; + Vue.set(JSONFile[defnName]["allOf"][i], "enum", temp_enum); + } + } + } +} + +// remove enumeration from definition element +export function removeEnum(JSONFile, defnName, enumName) { + for (let i in JSONFile[defnName]["allOf"]) { + if (JSONFile[defnName]["allOf"][i]["enum"]) { + let enum_index = JSONFile[defnName]["allOf"][i]["enum"].indexOf(enumName); + if (JSONFile[defnName]["allOf"][i]["enum"].length == 1) { + Vue.delete(JSONFile[defnName]["allOf"][i], "enum"); + } else { + Vue.delete(JSONFile[defnName]["allOf"][i]["enum"], enum_index); + } + } + } +} + +export function createNewDefnFile(title, description, fileName) { + let returnNewFileObj = {}; + returnNewFileObj["fullFileForExport"] = newFileTemplate; + returnNewFileObj["file"] = + returnNewFileObj["fullFileForExport"].components.schemas; + returnNewFileObj["fileName"] = fileName; + + returnNewFileObj["fullFileForExport"]["info"]["title"] = title; + returnNewFileObj["fullFileForExport"]["info"]["description"] = description; + + return returnNewFileObj; +} + +// todo: handle loading in inheritance +export function loadInDefinition(workingFile, defnName, refFile) { + let dependenciesToAdd = getObjChildren(refFile, defnName) + let elToAdd = [] + let objToAdd = [] + let alreadyAdded = [] + + for (let i = 0; i < dependenciesToAdd.length; i++) { + if (dependenciesToAdd[i]["type"] == "object" || dependenciesToAdd[i]["type"] == "array") { + objToAdd.push(dependenciesToAdd[i]["defnName"]) + } else { + elToAdd.push(dependenciesToAdd[i]["defnName"]) + } + } + + for (let i = 0; i < elToAdd.length; i++) { + if (!alreadyAdded.includes(elToAdd[i])) { + alreadyAdded.push(elToAdd[i]) + Vue.set(workingFile, elToAdd[i], refFile[elToAdd[i]]); + } + } + + for (let i = 0; i < objToAdd.length; i++) { + if (!alreadyAdded.includes(objToAdd[i])) { + alreadyAdded.push(objToAdd[i]) + + Vue.set(workingFile, objToAdd[i], refFile[objToAdd[i]]); + } + } + + // todo: needs error handling and error reporting +} + +export function getDefnNameFromRef(ref) { + return ref.slice(ref.lastIndexOf("/") + 1) +} + +// returns a list of dependencies of an obj +export function getObjChildren(refFile, defnName) { + // don't need to pull in these objects if they are referenced as superclass + var superClassWhiteList = ["TaxonomyElementString", "TaxonomyElementNumber", + "TaxonomyElementInteger", "TaxonomyElementBoolean"] + // don't re-add primitives + var primitiveWhiteList = ["Value", "Unit", "Decimals", "Precision", "StartTime", "EndTime"] + let dependencies = [] + + let defnObj = refFile[defnName] + + if (defnObj["type"] == "object") { + dependencies.push( + { + "type": "object", + "defnName": defnName + } + ) + for (let i in defnObj["properties"]) { + dependencies = dependencies.concat(getObjChildren(refFile, i)) + } + } else if (defnObj["type"] == "array") { + dependencies.push( + { + "type": "array", + "defnName": defnName + } + ) + let item = getDefnNameFromRef(defnObj["items"]["$ref"]) + + dependencies = dependencies.concat(getObjChildren(refFile, item)) + + } else { + if (!primitiveWhiteList.includes(defnName)) { + for (let i in defnObj["allOf"]) { + if ("$ref" in defnObj["allOf"][i]) { + if (superClassWhiteList.includes(getDefnNameFromRef(defnObj["allOf"][i]["$ref"]))) { + dependencies.push( + { + "type": "element", + "defnName": defnName + } + ) + } else { + dependencies.push( + { + "type": "object", + "defnName": defnName + } + ) + + dependencies = dependencies.concat(getObjChildren(refFile, getDefnNameFromRef(defnObj["allOf"][i]["$ref"]))) + } + } else if ("properties" in defnObj["allOf"][i]) { + for (let j in defnObj["allOf"][i]["properties"]) { + + dependencies = dependencies.concat(getObjChildren(refFile, j)) + } + } + } + } + } + + return dependencies +} diff --git a/src/views/OBEditor.vue b/src/views/OBEditor.vue index ceec2fb..8c790cd 100644 --- a/src/views/OBEditor.vue +++ b/src/views/OBEditor.vue @@ -1,1366 +1,1367 @@ - - - - - + + + + +