Skip to content

Commit

Permalink
* #155
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Schonfeld committed Apr 7, 2020
1 parent d20abc1 commit 8ca032a
Show file tree
Hide file tree
Showing 14 changed files with 183 additions and 77 deletions.
3 changes: 0 additions & 3 deletions dtale/dash_application/charts.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
valid_chart, weekday_tick_handler)
from dtale.dash_application.layout import (AGGS, ANIMATE_BY_CHARTS,
ANIMATION_CHARTS, build_error,
test_plotly_version,
update_label_for_freq)
from dtale.utils import (build_code_export, classify_type, dict_merge,
divide_chunks, export_to_csv_buffer,
Expand Down Expand Up @@ -1031,8 +1030,6 @@ def map_builder(data_id, export=False, **inputs):
code += agg_code

geo_layout = {}
if test_plotly_version('4.5.0'):
geo_layout['fitbounds'] = 'locations'
if scope is not None:
geo_layout['scope'] = scope
if proj is not None:
Expand Down
17 changes: 17 additions & 0 deletions dtale/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,23 @@ def describe(data_id, column):
return jsonify_error(e)


@dtale.route('/delete-col/<data_id>/<column>')
def delete_col(data_id, column):
try:
data = global_state.get_data(data_id)
data = data[[c for c in data.columns if c != column]]
dtypes = global_state.get_dtypes(data_id)
dtypes = [dt for dt in dtypes if dt['name'] != column]
curr_settings = global_state.get_settings(data_id)
curr_settings['locked'] = [c for c in curr_settings.get('locked', []) if c != column]
global_state.set_data(data_id, data)
global_state.set_dtypes(data_id, dtypes)
global_state.set_settings(data_id, curr_settings)
return jsonify(success=True)
except BaseException as e:
return jsonify_error(e)


@dtale.route('/column-filter-data/<data_id>/<column>')
def get_column_filter_data(data_id, column):
try:
Expand Down
28 changes: 1 addition & 27 deletions static/__tests__/dtale/DataViewer-base-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,7 @@ import { buildInnerHTML, clickMainMenuButton, withGlobalJquery } from "../test-u
const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight");
const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth");

const COL_PROPS = [
{
locked: true,
width: 70,
name: "dtale_index",
dtype: "int64",
visible: true,
},
{ locked: false, width: 20, name: "col1", dtype: "int64", visible: true },
{
locked: false,
width: 20,
name: "col2",
dtype: "float64",
visible: true,
min: 2.5,
max: 5.5,
},
{ locked: false, width: 20, name: "col3", dtype: "object", visible: true },
{
locked: false,
width: 20,
name: "col4",
dtype: "datetime64[ns]",
visible: true,
},
];
const COL_PROPS = _.map(reduxUtils.DATA.columns, (c, i) => _.assignIn({ width: i == 0 ? 70 : 20, locked: i == 0 }, c));

describe("DataViewer tests", () => {
beforeAll(() => {
Expand Down
31 changes: 26 additions & 5 deletions static/__tests__/dtale/DataViewer-heatmap-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Provider } from "react-redux";
import mockPopsicle from "../MockPopsicle";
import * as t from "../jest-assertions";
import reduxUtils from "../redux-test-utils";
import { buildInnerHTML, clickMainMenuButton, withGlobalJquery } from "../test-utils";
import { buildInnerHTML, findMainMenuButton, withGlobalJquery } from "../test-utils";

const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight");
const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth");
Expand Down Expand Up @@ -50,7 +50,11 @@ describe("DataViewer heatmap tests", () => {

setTimeout(() => {
result.update();
clickMainMenuButton(result, "Heat Map");
let heatMapBtn = findMainMenuButton(result, "By Col", "div.btn-group");
heatMapBtn
.find("button")
.first()
.simulate("click");
result.update();
let dv = result.find(ReactDataViewer).instance().state;
t.ok(
Expand All @@ -67,10 +71,27 @@ describe("DataViewer heatmap tests", () => {
.find(ReactDataViewer)
.find("div.headerCell")
.map(hc => hc.text()),
["col2"],
"should render float column headers"
["col1", "col2"],
"should render int/float column headers"
);
clickMainMenuButton(result, "Heat Map");
heatMapBtn = findMainMenuButton(result, "By Col", "div.btn-group");
heatMapBtn
.find("button")
.last()
.simulate("click");
t.deepEqual(
result
.find(ReactDataViewer)
.find("div.headerCell")
.map(hc => hc.text()),
["col1", "col2"],
"should render int/float column headers"
);
heatMapBtn = findMainMenuButton(result, "By Col", "div.btn-group");
heatMapBtn
.find("button")
.last()
.simulate("click");
dv = result.find(ReactDataViewer).instance().state;
t.ok(_.filter(dv.columns, { visible: true }).length, 5, "should turn all columns back on");
t.ok(
Expand Down
30 changes: 2 additions & 28 deletions static/__tests__/iframe/DataViewer-base-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,7 @@ import { clickColMenuButton, clickColMenuSubButton } from "./iframe-utils";
const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight");
const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth");

const COL_PROPS = [
{
locked: true,
width: 70,
name: "dtale_index",
dtype: "int64",
visible: true,
},
{ locked: false, width: 20, name: "col1", dtype: "int64", visible: true },
{
locked: false,
width: 20,
name: "col2",
dtype: "float64",
visible: true,
min: 2.5,
max: 5.5,
},
{ locked: false, width: 20, name: "col3", dtype: "object", visible: true },
{
locked: false,
width: 20,
name: "col4",
dtype: "datetime64[ns]",
visible: true,
},
];
const COL_PROPS = _.map(reduxUtils.DATA.columns, (c, i) => _.assignIn({ width: i == 0 ? 70 : 20, locked: i == 0 }, c));

class MockDateInput extends React.Component {
render() {
Expand Down Expand Up @@ -178,7 +152,7 @@ describe("DataViewer iframe tests", () => {
);
t.deepEqual(
colMenu.find("ul li span.font-weight-bold").map(s => s.text()),
["Lock", "Hide", "Describe", "Column Analysis", "Formats"],
["Lock", "Hide", "Delete", "Describe", "Column Analysis", "Formats"],
"Should render column menu options"
);
clickColMenuSubButton(result, "Asc");
Expand Down
86 changes: 86 additions & 0 deletions static/__tests__/iframe/DataViewer-delete-test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { mount } from "enzyme";
import $ from "jquery";
import React from "react";
import { Provider } from "react-redux";

import mockPopsicle from "../MockPopsicle";
import * as t from "../jest-assertions";
import reduxUtils from "../redux-test-utils";
import { buildInnerHTML, withGlobalJquery } from "../test-utils";
import { clickColMenuButton } from "./iframe-utils";

const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight");
const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth");

describe("DataViewer iframe tests", () => {
const { post } = $;

beforeAll(() => {
Object.defineProperty(HTMLElement.prototype, "offsetHeight", {
configurable: true,
value: 500,
});
Object.defineProperty(HTMLElement.prototype, "offsetWidth", {
configurable: true,
value: 500,
});

const mockBuildLibs = withGlobalJquery(() =>
mockPopsicle.mock(url => {
const { urlFetcher } = require("../redux-test-utils").default;
return urlFetcher(url);
})
);

const mockChartUtils = withGlobalJquery(() => (ctx, cfg) => {
const chartCfg = { ctx, cfg, data: cfg.data, destroyed: false };
chartCfg.destroy = () => (chartCfg.destroyed = true);
chartCfg.getElementsAtXAxis = _evt => [{ _index: 0 }];
return chartCfg;
});

jest.mock("popsicle", () => mockBuildLibs);
jest.mock("chart.js", () => mockChartUtils);
jest.mock("chartjs-plugin-zoom", () => ({}));
jest.mock("chartjs-chart-box-and-violin-plot/build/Chart.BoxPlot.js", () => ({}));
});

afterAll(() => {
Object.defineProperty(HTMLElement.prototype, "offsetHeight", originalOffsetHeight);
Object.defineProperty(HTMLElement.prototype, "offsetWidth", originalOffsetWidth);
$.post = post;
});

test("DataViewer: hiding a column", done => {
const { DataViewer } = require("../../dtale/DataViewer");

const store = reduxUtils.createDtaleStore();
buildInnerHTML({ settings: "", iframe: "True" }, store);
const result = mount(
<Provider store={store}>
<DataViewer />
</Provider>,
{
attachTo: document.getElementById("content"),
}
);

setTimeout(() => {
result.update();
result
.find(".main-grid div.headerCell div")
.last()
.simulate("click");
clickColMenuButton(result, "Delete");
setTimeout(() => {
result.update();
t.deepEqual(
result.find(".main-grid div.headerCell").map(hc => hc.text()),
["col1", "col2", "col3"],
"should render column headers"
);
done();
}, 400);
}, 600);
});
});
2 changes: 1 addition & 1 deletion static/__tests__/popups/Instances-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ describe("Instances tests", () => {
assignSpy.mockRestore();
global.window = origWindow;
result
.find(".ico-remove-circle")
.find(".ico-delete")
.first()
.simulate("click");
setTimeout(() => {
Expand Down
8 changes: 6 additions & 2 deletions static/__tests__/redux-test-utils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const DATA = {
],
columns: [
{ name: "dtale_index", dtype: "int64", visible: true },
{ name: "col1", dtype: "int64", visible: true },
{ name: "col1", dtype: "int64", min: 2, max: 5, visible: true },
{ name: "col2", dtype: "float64", min: 2.5, max: 5.5, visible: true },
{ name: "col3", dtype: "object", visible: true },
{ name: "col4", dtype: "datetime64[ns]", visible: true },
Expand Down Expand Up @@ -179,7 +179,10 @@ function urlFetcher(url) {
return chartsData;
} else if (
_.find(
["/dtale/update-visibility", "/dtale/update-settings", "/dtale/update-locked", "/dtale/update-column-position"],
_.concat(
["/dtale/update-visibility", "/dtale/update-settings", "/dtale/update-locked", "/dtale/update-column-position"],
["/dtale/delete-col"]
),
prefix => _.startsWith(url, prefix)
)
) {
Expand Down Expand Up @@ -235,4 +238,5 @@ function createDtaleStore() {
export default {
urlFetcher,
createDtaleStore,
DATA,
};
1 change: 0 additions & 1 deletion static/dtale/DataViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { Header } from "./Header";
import { MeasureText } from "./MeasureText";
import * as gu from "./gridUtils";
import { ColumnMenu } from "./iframe/ColumnMenu";
import {getActiveCols} from "./gridUtils";

require("./DataViewer.css");
const URL_PROPS = ["ids", "sortInfo"];
Expand Down
16 changes: 7 additions & 9 deletions static/dtale/DataViewerMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,14 @@ class ReactDataViewerMenu extends React.Component {
</span>
<div className="hoverable__content menu-description">{Descriptions.charts}</div>
</li>
<li className="hoverable" style={{color: "inherit"}}>
<li className="hoverable" style={{ color: "inherit" }}>
<span className="toggler-action">
<i className={`fa fa-${this.props.heatMapMode ? "fire-extinguisher" : "fire-alt"} ml-2 mr-4`} />
</span>
<span className={`font-weight-bold pl-2${!_.isNull(this.props.heatMapMode) ? " flames" : ""}`}>
<span className={`font-weight-bold pl-2${_.isNull(this.props.heatMapMode) ? "" : " flames"}`}>
{"Heat Map"}
</span>
<div className="btn-group compact ml-auto mr-3 font-weight-bold column-sorting" style={{fontSize: "75%"}}>
<div className="btn-group compact ml-auto mr-3 font-weight-bold column-sorting" style={{ fontSize: "75%" }}>
{_.map(
[
["By Col", "col"],
Expand All @@ -119,7 +119,7 @@ class ReactDataViewerMenu extends React.Component {
style={{ color: "#565b68" }}
className="btn btn-primary font-weight-bold"
onClick={toggleHeatMap(mode)}>
{mode === this.props.heatMapMode && (<span className="flames">{label}</span>)}
{mode === this.props.heatMapMode && <span className="flames">{label}</span>}
{mode !== this.props.heatMapMode && label}
</button>
)
Expand All @@ -132,17 +132,15 @@ class ReactDataViewerMenu extends React.Component {
<button className="btn btn-plain" onClick={toggleDtypeHighlighting}>
<div style={{ display: "inherit" }}>
<div className={`dtype-highlighting${this.props.dtypeHighlighting ? " spin" : ""}`} />
<span className="font-weight-bold pl-4">
Highlight Dtypes
</span>
<span className="font-weight-bold pl-4">Highlight Dtypes</span>
</div>
</button>
</span>
<div className="hoverable__content menu-description">{Descriptions.highlight_dtypes}</div>
</li>
<li className="hoverable">
<span className="toggler-action">
<button className="btn btn-plain" onClick={openPopup("instances")}>
<button className="btn btn-plain" onClick={openPopup("instances", 450, 750)}>
<i className="ico-apps" />
<span className="font-weight-bold">
{"Instances "}
Expand All @@ -163,7 +161,7 @@ class ReactDataViewerMenu extends React.Component {
</span>
<div className="hoverable__content menu-description">{Descriptions.code}</div>
</li>
<li className="hoverable" style={{color: "inherit"}}>
<li className="hoverable" style={{ color: "inherit" }}>
<span className="toggler-action">
<i className="far fa-file" />
</span>
Expand Down
13 changes: 13 additions & 0 deletions static/dtale/iframe/ColumnMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ class ReactColumnMenu extends React.Component {
};
serverState.toggleVisibility(dataId, selectedCol, hideCallback);
};
const deleteCol = () =>
this.props.propagateState(
{ columns: _.reject(this.props.columns, { name: selectedCol }) },
serverState.deleteColumn(dataId, selectedCol)
);
return (
<div
id="column-menu-div"
Expand Down Expand Up @@ -199,6 +204,14 @@ class ReactColumnMenu extends React.Component {
</button>
</span>
</li>
<li>
<span className="toggler-action">
<button className="btn btn-plain" onClick={deleteCol}>
<i className="ico-delete" />
<span className="font-weight-bold">Delete</span>
</button>
</span>
</li>
<li>
<span className="toggler-action">
<button className="btn btn-plain" onClick={openPopup("describe", 670, 1100)}>
Expand Down
1 change: 1 addition & 0 deletions static/dtale/serverStateManagement.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,5 @@ export default {
persistVisibility(dataId, { visibility: JSON.stringify(visibility) }, callback),
toggleVisibility: (dataId, toggle, callback) => persistVisibility(dataId, { toggle }, callback),
updateSettings,
deleteColumn: (dataId, col) => () => fetchJson(buildURLString(`/dtale/delete-col/${dataId}/${col}`), _.noop),
};
Loading

0 comments on commit 8ca032a

Please sign in to comment.