Skip to content

Commit

Permalink
Added TSV as an export option (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
piter75 authored Mar 5, 2018
1 parent 9eaf795 commit cd8d269
Showing 5 changed files with 58 additions and 33 deletions.
20 changes: 11 additions & 9 deletions src/client/components/hiluk-menu/hiluk-menu.tsx
Original file line number Diff line number Diff line change
@@ -20,8 +20,8 @@ import * as React from 'react';
import { Dataset } from 'plywood';
import { Fn } from '../../../common/utils/general/general';
import { Stage, Essence, Timekeeper, ExternalView } from '../../../common/models/index';
import { STRINGS } from '../../config/constants';
import { download, makeFileName } from '../../utils/download/download';
import { exportOptions , STRINGS } from '../../config/constants';
import { download, FileFormat, makeFileName } from '../../utils/download/download';
import { BubbleMenu } from '../bubble-menu/bubble-menu';


@@ -71,7 +71,7 @@ export class HilukMenu extends React.Component<HilukMenuProps, HilukMenuState> {
onClose();
}

onExport() {
onExport(fileFormat: FileFormat) {
const { onClose, getDownloadableDataset, essence, timekeeper } = this.props;
const { dataCube, splits } = essence;
if (!getDownloadableDataset) return;
@@ -83,7 +83,7 @@ export class HilukMenu extends React.Component<HilukMenuProps, HilukMenuState> {
return `${STRINGS.splitDelimiter}_${dimension.name}`;
}).join("_");

download(getDownloadableDataset(), makeFileName(dataCube.name, filters, splitsString), 'csv');
download(getDownloadableDataset(), makeFileName(dataCube.name, filters, splitsString), fileFormat);
onClose();
}

@@ -118,11 +118,13 @@ export class HilukMenu extends React.Component<HilukMenuProps, HilukMenuState> {
}

if (getDownloadableDataset()) {
shareOptions.push(<li
className="export"
key="export"
onClick={this.onExport.bind(this)}
>{STRINGS.exportToCSV}</li>);
exportOptions.forEach(({ label, fileFormat }) => {
shareOptions.push(<li
className="export"
key="export"
onClick={this.onExport.bind(this, fileFormat)}
>{label}</li>);
});
}

shareOptions.push(<li
7 changes: 6 additions & 1 deletion src/client/config/constants.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,6 @@
* limitations under the License.
*/

import { $, SortExpression } from 'plywood';
import { Locale } from '../../common/utils/time/time';

export const TITLE_HEIGHT = 36;
@@ -86,6 +85,7 @@ export const STRINGS: any = {
exclude: 'Exclude',
explore: 'Explore',
exportToCSV: 'Export to CSV',
exportToTSV: 'Export to TSV',
filter: 'Filter',
generalSettings: 'General settings',
goToUrl: 'Go to URL',
@@ -158,3 +158,8 @@ const EN_US: Locale = {
export function getLocale(): Locale {
return EN_US;
}

export const exportOptions = [
{ label: STRINGS.exportToCSV, fileFormat: 'csv' },
{ label: STRINGS.exportToTSV, fileFormat: 'tsv' }
];
45 changes: 31 additions & 14 deletions src/client/modals/raw-data-modal/raw-data-modal.tsx
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ import { arraySum, Fn, formatFilterClause, makeTitle } from '../../../common/uti
import { download, makeFileName } from '../../utils/download/download';
import { classNames } from '../../utils/dom/dom';
import { getVisibleSegments } from '../../utils/sizing/sizing';
import { STRINGS } from '../../config/constants';
import { exportOptions, STRINGS } from '../../config/constants';

import { Button, Loader, Modal, QueryError, Scroller, ScrollerLayout } from '../../components';

@@ -256,15 +256,41 @@ export class RawDataModal extends React.Component<RawDataModalProps, RawDataModa
});
}

renderButtons(): JSX.Element {
const { essence, onClose, timekeeper } = this.props;
const { dataset, loading, error } = this.state;
const { dataCube } = essence;

const filtersString = essence.getEffectiveFilter(timekeeper).getFileString(dataCube.timeAttribute);

const buttons: JSX.Element[] = [];

buttons.push(<Button type="primary" className="close" onClick={onClose} title={STRINGS.close} />);

exportOptions.forEach(({ label, fileFormat }) => {
buttons.push(
<Button
type="secondary"
className="download"
onClick={download.bind(this, dataset, makeFileName(dataCube.name, filtersString, 'raw'), fileFormat)}
title={label}
disabled={Boolean(loading || error)}
/>
);
});

return <div className="button-bar">
{buttons}
</div>
}

render() {
const { essence, timekeeper, onClose } = this.props;
const { essence, onClose } = this.props;
const { dataset, loading, error, stage } = this.state;
const { dataCube } = essence;

const title = `${makeTitle(STRINGS.rawData)}`;

const filtersString = essence.getEffectiveFilter(timekeeper).getFileString(dataCube.timeAttribute);

const scrollerLayout: ScrollerLayout = {
// Inner dimensions
bodyWidth: arraySum(dataCube.attributes.map(getColumnWidth)),
@@ -294,16 +320,7 @@ export class RawDataModal extends React.Component<RawDataModalProps, RawDataModa
/>
{error ? <QueryError error={error} /> : null}
{loading ? <Loader /> : null}
<div className="button-bar">
<Button type="primary" className="close" onClick={onClose} title={STRINGS.close} />
<Button
type="secondary"
className="download"
onClick={download.bind(this, dataset, makeFileName(dataCube.name, filtersString, 'raw'), 'csv')}
title={STRINGS.download}
disabled={Boolean(loading || error)}
/>
</div>
{this.renderButtons()}
</div>
</Modal>;
}
12 changes: 6 additions & 6 deletions src/client/utils/download/download.mocha.ts
Original file line number Diff line number Diff line change
@@ -19,26 +19,26 @@ import '../../utils/test-utils/index';
import { Dataset } from 'plywood';
import { datasetToFileString, getMIMEType } from './download';

describe.skip('Download', () => {
describe('Download', () => {
describe('datasetToFileString', () => {

it('defaults to JSON if no type specified', () => {
var dsJS = [
const dsJS = [
{ x: 1, y: "hello", z: 2 },
{ x: 2, y: "world", z: 3 }
];
var ds = Dataset.fromJS(dsJS);
const ds = Dataset.fromJS(dsJS);
expect(() => { JSON.parse(datasetToFileString(ds)); }).to.not.throw();
expect(JSON.parse(datasetToFileString(ds))).to.deep.equal(dsJS);
});

it('encloses set/string in brackets appropriately', () => {
var ds = Dataset.fromJS([
const ds = Dataset.fromJS([
{ y: ["dear", "john"] },
{ y: ["from", "peter"] }
]);
expect(datasetToFileString(ds, 'csv').indexOf("\"[dear,john\"]"), 'csv').to.not.equal(-1);
expect(datasetToFileString(ds, 'tsv').indexOf("[dear,john]"), 'tsv').to.not.equal(-1);
expect(datasetToFileString(ds, 'csv').indexOf("\"dear, john\""), 'csv').to.not.equal(-1);
expect(datasetToFileString(ds, 'tsv').indexOf("dear, john"), 'tsv').to.not.equal(-1);
});
});

7 changes: 4 additions & 3 deletions src/client/utils/download/download.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
*/

import * as filesaver from 'browser-filesaver';
import { Dataset } from 'plywood';
import { Dataset, DatasetJSFull } from 'plywood';

export type FileFormat = "csv" | "tsv" | "json" | "txt";

@@ -32,7 +32,7 @@ export function getMIMEType(fileType: string) {

export function download(dataset: Dataset, fileName?: string, fileFormat?: FileFormat): void {
const type = `${getMIMEType(fileFormat)};charset=utf-8`;
const blob = new Blob([datasetToFileString(dataset, fileFormat)], {type});
const blob = new Blob([datasetToFileString(dataset, fileFormat)], { type });
if (!fileName) fileName = `${new Date()}-data`;
fileName += `.${fileFormat}`;
filesaver.saveAs(blob, fileName, true); // true == disable auto BOM
@@ -44,7 +44,8 @@ export function datasetToFileString(dataset: Dataset, fileFormat?: FileFormat):
} else if (fileFormat === 'tsv') {
return dataset.toTSV();
} else {
return JSON.stringify(dataset.toJS(), null, 2);
const datasetJS = dataset.toJS() as DatasetJSFull;
return JSON.stringify(datasetJS.data, null, 2);
}
}

0 comments on commit cd8d269

Please sign in to comment.