From 79b3fa779ded177a09cb0570b0242ff57dcf5578 Mon Sep 17 00:00:00 2001 From: Oskar Hane Date: Wed, 13 Nov 2019 10:43:32 +0100 Subject: [PATCH] Bring back JSON data export --- src/browser/modules/Frame/FrameTitlebar.jsx | 35 ++- src/browser/modules/Stream/FrameTitlebar.jsx | 315 ------------------- 2 files changed, 32 insertions(+), 318 deletions(-) delete mode 100644 src/browser/modules/Stream/FrameTitlebar.jsx diff --git a/src/browser/modules/Frame/FrameTitlebar.jsx b/src/browser/modules/Frame/FrameTitlebar.jsx index 6e5adadc230..3c5ca389cd3 100644 --- a/src/browser/modules/Frame/FrameTitlebar.jsx +++ b/src/browser/modules/Frame/FrameTitlebar.jsx @@ -22,6 +22,8 @@ import { connect } from 'react-redux' import React, { Component } from 'react' import { withBus } from 'react-suber' import { saveAs } from 'file-saver' +import { map } from 'lodash-es' + import * as editor from 'shared/modules/editor/editorDuck' import * as commands from 'shared/modules/commands/commandsDuck' import { @@ -55,22 +57,26 @@ import { StyledFrameTitleBar, StyledFrameTitlebarButtonSection, StyledFrameCommand -} from 'browser/modules/Frame/styled' +} from './styled' import { downloadPNGFromSVG, downloadSVG } from 'shared/services/exporting/imageUtils' import { stringifyResultArray, - transformResultRecordsToResultArray + transformResultRecordsToResultArray, + recordToJSONMapper } from 'browser/modules/Stream/CypherFrame/helpers' import { csvFormat } from 'services/bolt/cypherTypesFormatting' import arrayHasItems from 'shared/utils/array-has-items' +const JSON_EXPORT_INDENT = 2 + class FrameTitlebar extends Component { hasData () { return this.props.numRecords > 0 } + exportCSV (records) { const exportData = stringifyResultArray( csvFormat, @@ -108,25 +114,43 @@ class FrameTitlebar extends Component { } } + exportJSON (records) { + const data = JSON.stringify( + map(records, recordToJSONMapper), + null, + JSON_EXPORT_INDENT + ) + const blob = new Blob([data], { + type: 'text/plain;charset=utf-8' + }) + + saveAs(blob, 'records.json') + } + exportPNG () { const { svgElement, graphElement, type } = this.props.visElement downloadPNGFromSVG(svgElement, graphElement, type) } + exportSVG () { const { svgElement, graphElement, type } = this.props.visElement downloadSVG(svgElement, graphElement, type) } + exportGrass (data) { var blob = new Blob([data], { type: 'text/plain;charset=utf-8' }) saveAs(blob, 'style.grass') } + canExport = () => { let props = this.props const { frame = {} } = props + return ( - (frame.type === 'cypher' && (this.hasData() || props.visElement)) || + this.canExportTXT() || + (frame.type === 'cypher' && (this.hasData() || this.props.visElement)) || (frame.type === 'style' && this.hasData()) ) } @@ -175,6 +199,11 @@ class FrameTitlebar extends Component { > Export CSV + this.exportJSON(props.getRecords())} + > + Export JSON + diff --git a/src/browser/modules/Stream/FrameTitlebar.jsx b/src/browser/modules/Stream/FrameTitlebar.jsx deleted file mode 100644 index 52f96b4121e..00000000000 --- a/src/browser/modules/Stream/FrameTitlebar.jsx +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2002-2019 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import { connect } from 'react-redux' -import React, { Component } from 'react' -import { withBus } from 'react-suber' -import { saveAs } from 'file-saver' -import { map } from 'lodash-es' - -import * as editor from 'shared/modules/editor/editorDuck' -import * as commands from 'shared/modules/commands/commandsDuck' -import { - cancel as cancelRequest, - getRequest, - REQUEST_STATUS_PENDING -} from 'shared/modules/requests/requestsDuck' -import { remove, pin, unpin } from 'shared/modules/stream/streamDuck' -import { removeComments, sleep } from 'shared/services/utils' -import { FrameButton } from 'browser-components/buttons' -import Render from 'browser-components/Render' -import { CSVSerializer } from 'services/serializer' -import { - ExpandIcon, - ContractIcon, - RefreshIcon, - CloseIcon, - UpIcon, - DownIcon, - PinIcon, - DownloadIcon -} from 'browser-components/icons/Icons' -import { - StyledFrameTitleBar, - StyledFrameCommand, - DottedLineHover, - FrameTitlebarButtonSection, - DropdownList, - DropdownContent, - DropdownButton, - DropdownItem -} from './styled' -import { - downloadPNGFromSVG, - downloadSVG -} from 'shared/services/exporting/imageUtils' -import { - stringifyResultArray, - transformResultRecordsToResultArray, - recordToJSONMapper -} from 'browser/modules/Stream/CypherFrame/helpers' -import { csvFormat } from 'services/bolt/cypherTypesFormatting' -import arrayHasItems from 'shared/utils/array-has-items' - -const JSON_EXPORT_INDENT = 2 - -class FrameTitlebar extends Component { - hasData () { - return this.props.numRecords > 0 - } - - exportCSV (records) { - const exportData = stringifyResultArray( - csvFormat, - transformResultRecordsToResultArray(records) - ) - let data = exportData.slice() - const csv = CSVSerializer(data.shift()) - csv.appendRows(data) - var blob = new Blob([csv.output()], { - type: 'text/plain;charset=utf-8' - }) - saveAs(blob, 'export.csv') - } - - exportTXT = () => { - const { frame } = this.props - - if (frame.type === 'history') { - const asTxt = frame.result - .map(result => { - const safe = `${result}`.trim() - - if (safe.startsWith(':')) { - return safe - } - - return safe.endsWith(';') ? safe : `${safe};` - }) - .join('\n\n') - const blob = new Blob([asTxt], { - type: 'text/plain;charset=utf-8' - }) - - saveAs(blob, 'history.txt') - } - } - - exportJSON (records) { - const data = JSON.stringify( - map(records, recordToJSONMapper), - null, - JSON_EXPORT_INDENT - ) - const blob = new Blob([data], { - type: 'text/plain;charset=utf-8' - }) - - saveAs(blob, 'records.json') - } - - exportPNG () { - const { svgElement, graphElement, type } = this.props.visElement - downloadPNGFromSVG(svgElement, graphElement, type) - } - - exportSVG () { - const { svgElement, graphElement, type } = this.props.visElement - downloadSVG(svgElement, graphElement, type) - } - - exportGrass (data) { - var blob = new Blob([data], { - type: 'text/plain;charset=utf-8' - }) - saveAs(blob, 'style.grass') - } - - canExport = () => { - let props = this.props - const { frame = {} } = props - - return ( - this.canExportTXT() || - (frame.type === 'cypher' && (this.hasData() || this.props.visElement)) || - (frame.type === 'style' && this.hasData()) - ) - } - - canExportTXT () { - const { frame = {} } = this.props - - return frame.type === 'history' && arrayHasItems(frame.result) - } - - render () { - let props = this.props - const { frame = {} } = props - const fullscreenIcon = props.fullscreen ? : - const expandCollapseIcon = props.collapse ? : - const cmd = removeComments(frame.cmd) - return ( - - - props.onTitlebarClick(frame.cmd)} - > - {cmd} - - - - - - - - - - - this.exportPNG()}> - Export PNG - - this.exportSVG()}> - Export SVG - - - - - this.exportCSV(props.getRecords())} - > - Export CSV - - this.exportJSON(props.getRecords())} - > - Export JSON - - - - - Export TXT - - - - this.exportGrass(props.getRecords())} - > - Export GraSS - - - - - - - { - props.togglePin() - props.togglePinning(frame.id, frame.isPinned) - }} - pressed={props.pinned} - > - - - - props.fullscreenToggle()} - > - {fullscreenIcon} - - - props.collapseToggle()} - > - {expandCollapseIcon} - - - - props.onReRunClick(frame.cmd, frame.id, frame.requestId) - } - > - - - - - props.onCloseClick(frame.id, frame.requestId, props.request) - } - > - - - - - ) - } -} - -const mapStateToProps = (state, ownProps) => { - const request = ownProps.frame.requestId - ? getRequest(state, ownProps.frame.requestId) - : null - - return { - request - } -} - -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onTitlebarClick: cmd => { - ownProps.bus.send(editor.SET_CONTENT, editor.setContent(cmd)) - }, - onCloseClick: async (id, requestId, request) => { - if (request && request.status === REQUEST_STATUS_PENDING) { - dispatch(cancelRequest(requestId)) - await sleep(3000) // sleep for 3000 ms to let user read the cancel info - } - dispatch(remove(id)) - }, - onReRunClick: (cmd, id, requestId) => { - if (requestId) { - dispatch(cancelRequest(requestId)) - } - dispatch(commands.executeCommand(cmd, id)) - }, - togglePinning: (id, isPinned) => { - isPinned ? dispatch(unpin(id)) : dispatch(pin(id)) - } - } -} - -export default withBus( - connect( - mapStateToProps, - mapDispatchToProps - )(FrameTitlebar) -)