Skip to content

Commit 0bdf528

Browse files
committed
Added the ability to turn on/off row expanders
1 parent 32762e7 commit 0bdf528

31 files changed

+220
-19
lines changed

docs/CONFIGURATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ lock_header_menu = False
2525
hide_header_menu = False
2626
hide_main_menu = False
2727
hide_column_menus = False
28+
hide_row_expanders = False
2829
enable_custom_filters = False
2930
enable_web_uploads = False
3031

dtale/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
HIDE_HEADER_MENU = False
2323
HIDE_MAIN_MENU = False
2424
HIDE_COLUMN_MENUS = False
25+
HIDE_ROW_EXPANDERS = False
2526
ENABLE_CUSTOM_FILTERS = False
2627
ENABLE_WEB_UPLOADS = False
2728

dtale/app.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,8 @@ def show(data=None, data_loader=None, name=None, context_vars=None, **options):
722722
:param hide_column_menus: If true, this will hide the column menus from the screen
723723
:type hide_column_menus: bool, optional
724724
:param column_edit_options: The options to allow on the front-end when editing a cell for the columns specified
725+
:param hide_row_expanders: If true, this will hide the row expanders from the screen
726+
:type hide_row_expanders: bool, optional
725727
:type column_edit_options: dict, optional
726728
:param auto_hide_empty_columns: if True, then auto-hide any columns on the front-end that are comprised entirely of
727729
NaN values
@@ -830,6 +832,7 @@ def show(data=None, data_loader=None, name=None, context_vars=None, **options):
830832
hide_header_menu=final_options.get("hide_header_menu"),
831833
hide_main_menu=final_options.get("hide_main_menu"),
832834
hide_column_menus=final_options.get("hide_column_menus"),
835+
hide_row_expanders=final_options.get("hide_row_expanders"),
833836
enable_custom_filters=final_options.get("enable_custom_filters"),
834837
enable_web_uploads=final_options.get("enable_web_uploads"),
835838
main_title=final_options.get("main_title"),

dtale/config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ def load_app_settings(config):
9696
section="app",
9797
getter="getboolean",
9898
)
99+
hide_row_expanders = get_config_val(
100+
config,
101+
curr_app_settings,
102+
"hide_row_expanders",
103+
section="app",
104+
getter="getboolean",
105+
)
99106
lock_header_menu = get_config_val(
100107
config,
101108
curr_app_settings,
@@ -155,6 +162,7 @@ def load_app_settings(config):
155162
hide_header_menu=hide_header_menu,
156163
hide_main_menu=hide_main_menu,
157164
hide_column_menus=hide_column_menus,
165+
hide_row_expanders=hide_row_expanders,
158166
enable_custom_filters=enable_custom_filters,
159167
enable_web_uploads=enable_web_uploads,
160168
)
@@ -226,6 +234,7 @@ def build_show_options(options=None):
226234
hide_header_menu=None,
227235
hide_main_menu=None,
228236
hide_column_menus=None,
237+
hide_row_expanders=None,
229238
enable_custom_filters=None,
230239
enable_web_uploads=None,
231240
main_title=None,

dtale/global_state.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"hide_column_menus": False,
3535
"enable_custom_filters": False,
3636
"enable_web_uploads": False,
37+
"hide_row_expanders": False,
3738
}
3839

3940
AUTH_SETTINGS = {"active": False, "username": None, "password": None}
@@ -612,6 +613,8 @@ def set_app_settings(settings):
612613
instance_updates["hide_main_menu"] = settings.get("hide_main_menu")
613614
if settings.get("hide_column_menus") is not None:
614615
instance_updates["hide_column_menus"] = settings.get("hide_column_menus")
616+
if settings.get("hide_row_expanders") is not None:
617+
instance_updates["hide_row_expanders"] = settings.get("hide_row_expanders")
615618
if settings.get("enable_custom_filters") is not None:
616619
instance_updates["enable_custom_filters"] = settings.get(
617620
"enable_custom_filters"

dtale/templates/dtale/base.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<input type="hidden" id="hide_header_menu" value="{{hide_header_menu}}" />
4545
<input type="hidden" id="hide_main_menu" value="{{hide_main_menu}}" />
4646
<input type="hidden" id="hide_column_menus" value="{{hide_column_menus}}" />
47+
<input type="hidden" id="hide_row_expanders" value="{{hide_row_expanders}}" />
4748
<input type="hidden" id="enable_custom_filters" value="{{enable_custom_filters}}" />
4849
<input type="hidden" id="enable_web_uploads" value="{{enable_web_uploads}}" />
4950
<input type="hidden" id="allow_cell_edits" value="{{allow_cell_edits}}" />

dtale/views.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ def update_settings(self, **updates):
366366
* hide_header_menu - if true, this will hide the header menu from the screen
367367
* hide_main_menu - if true, this will hide the main menu from the screen
368368
* hide_column_menus - if true, this will hide the column menus from the screen
369+
* hide_row_expanders - if true, this will hide row expanders from the screen
369370
* enable_custom_filters - if True, allow users to specify custom filters from the UI using pandas.query strings
370371
* enable_web_uploads - if True, allow users to upload files using URLs from the UI
371372
@@ -938,6 +939,7 @@ def startup(
938939
hide_header_menu=None,
939940
hide_main_menu=None,
940941
hide_column_menus=None,
942+
hide_row_expanders=None,
941943
enable_custom_filters=None,
942944
enable_web_uploads=None,
943945
force_save=True,
@@ -1069,6 +1071,7 @@ def startup(
10691071
hide_header_menu=hide_header_menu,
10701072
hide_main_menu=hide_main_menu,
10711073
hide_column_menus=hide_column_menus,
1074+
hide_row_expanders=hide_row_expanders,
10721075
enable_custom_filters=enable_custom_filters,
10731076
enable_web_uploads=enable_web_uploads,
10741077
main_title=main_title,
@@ -1144,6 +1147,7 @@ def startup(
11441147
hide_header_menu=hide_header_menu,
11451148
hide_main_menu=hide_main_menu,
11461149
hide_column_menus=hide_column_menus,
1150+
hide_row_expanders=hide_row_expanders,
11471151
enable_custom_filters=enable_custom_filters,
11481152
enable_web_uploads=enable_web_uploads,
11491153
main_title=main_title,
@@ -1215,6 +1219,8 @@ def startup(
12151219
base_settings["hide_main_menu"] = hide_main_menu
12161220
if hide_column_menus is not None:
12171221
base_settings["hide_column_menus"] = hide_column_menus
1222+
if hide_row_expanders is not None:
1223+
base_settings["hide_row_expanders"] = hide_row_expanders
12181224
if enable_custom_filters is not None:
12191225
base_settings["enable_custom_filters"] = enable_custom_filters
12201226
if enable_web_uploads is not None:
@@ -1317,6 +1323,7 @@ def base_render_template(template, data_id, **kwargs):
13171323
hide_header_menu = global_state.load_flag(data_id, "hide_header_menu", False)
13181324
hide_main_menu = global_state.load_flag(data_id, "hide_main_menu", False)
13191325
hide_column_menus = global_state.load_flag(data_id, "hide_column_menus", False)
1326+
hide_row_expanders = global_state.load_flag(data_id, "hide_row_expanders", False)
13201327
main_title = global_state.load_flag(data_id, "main_title", None)
13211328
main_title_font = global_state.load_flag(data_id, "main_title_font", None)
13221329
enable_custom_filters = global_state.load_flag(
@@ -1331,6 +1338,7 @@ def base_render_template(template, data_id, **kwargs):
13311338
hide_header_menu=hide_header_menu,
13321339
hide_main_menu=hide_main_menu,
13331340
hide_column_menus=hide_column_menus,
1341+
hide_row_expanders=hide_row_expanders,
13341342
enable_custom_filters=enable_custom_filters,
13351343
enable_web_uploads=enable_web_uploads,
13361344
github_fork=github_fork,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { act, fireEvent, render } from '@testing-library/react';
2+
import * as React from 'react';
3+
import { Provider } from 'react-redux';
4+
import { Store } from 'redux';
5+
6+
import HideRowExpanders from '../../../dtale/menu/HideRowExpanders';
7+
import * as serverState from '../../../dtale/serverStateManagement';
8+
import reduxUtils from '../../redux-test-utils';
9+
import { buildInnerHTML } from '../../test-utils';
10+
11+
describe('HideRowExpanders tests', () => {
12+
let result: Element;
13+
let store: Store;
14+
let updateSettingsSpy: jest.SpyInstance;
15+
16+
const setupOption = async (settings = ''): Promise<void> => {
17+
store = reduxUtils.createDtaleStore();
18+
buildInnerHTML({ settings }, store);
19+
result = await act(() => {
20+
return render(
21+
<Provider store={store}>
22+
<HideRowExpanders />,
23+
</Provider>,
24+
{
25+
container: document.getElementById('content') ?? undefined,
26+
},
27+
).container;
28+
});
29+
};
30+
31+
beforeEach(() => {
32+
updateSettingsSpy = jest.spyOn(serverState, 'updateSettings');
33+
updateSettingsSpy.mockImplementation(() => undefined);
34+
});
35+
36+
afterEach(jest.resetAllMocks);
37+
38+
afterAll(jest.restoreAllMocks);
39+
40+
it('renders successfully with defaults', async () => {
41+
await setupOption();
42+
expect(result.getElementsByClassName('ico-check-box-outline-blank')).toHaveLength(1);
43+
});
44+
45+
it('renders successfully with specified value', async () => {
46+
await setupOption('{&quot;hide_row_expanders&quot;:&quot;True&quot;}');
47+
expect(result.getElementsByClassName('ico-check-box')).toHaveLength(1);
48+
});
49+
50+
it('handles changes to checkbox', async () => {
51+
await setupOption();
52+
await act(async () => {
53+
await fireEvent.click(result.getElementsByClassName('ico-check-box-outline-blank')[0]);
54+
});
55+
expect(updateSettingsSpy).toBeCalledTimes(1);
56+
expect(store.getState().settings).toEqual(expect.objectContaining({ hide_row_expanders: true }));
57+
await act(async () => {
58+
await fireEvent.click(result.getElementsByClassName('ico-check-box')[0]);
59+
});
60+
expect(updateSettingsSpy).toBeCalledTimes(2);
61+
expect(updateSettingsSpy.mock.calls[1][0]).toEqual({
62+
hide_row_expanders: false,
63+
});
64+
expect(store.getState().settings).toEqual(expect.objectContaining({ hide_row_expanders: false }));
65+
});
66+
});

frontend/static/__tests__/dtale/reduxGridUtils-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ describe('reduxGridUtils', () => {
2323
hide_header_menu: false,
2424
hide_main_menu: false,
2525
hide_column_menus: false,
26+
hide_row_expanders: false,
2627
enable_custom_filters: false,
2728
};
2829
reduxUtils.handleReduxState(

frontend/static/__tests__/reducers/dtale-test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ describe('reducer tests', () => {
2828
hideHeaderMenu: false,
2929
hideMainMenu: false,
3030
hideColumnMenus: false,
31+
hideRowExpanders: false,
3132
enableCustomFilters: false,
3233
enableWebUploads: false,
3334
hideDropRows: false,
@@ -54,6 +55,7 @@ describe('reducer tests', () => {
5455
hide_header_menu: false,
5556
hide_main_menu: false,
5657
hide_column_menus: false,
58+
hide_row_expanders: false,
5759
enable_custom_filters: false,
5860
},
5961
pythonVersion: null,

0 commit comments

Comments
 (0)