Skip to content

Commit aca99fa

Browse files
committed
feat(data-catalog): support drag to resize tree
1 parent 27c59b7 commit aca99fa

2 files changed

Lines changed: 53 additions & 4 deletions

File tree

testgen/ui/components/frontend/js/components/tree.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
* @property {number?} level
1111
* @property {boolean?} expanded
1212
* @property {boolean?} hidden
13-
*
13+
*
1414
* @typedef Properties
1515
* @type {object}
16+
* @property {string} id
1617
* @property {TreeNode[]} nodes
1718
* @property {string} selected
1819
* @property {string} classes
@@ -42,7 +43,10 @@ const Tree = (/** @type Properties */ props) => {
4243
});
4344

4445
return div(
45-
{ class: () => `flex-column ${getValue(props.classes)}` },
46+
{
47+
id: props.id,
48+
class: () => `flex-column ${getValue(props.classes)}`,
49+
},
4650
div(
4751
{ class: 'flex-row fx-gap-1 tg-tree--actions' },
4852
Input({
@@ -176,6 +180,10 @@ stylesheet.replace(`
176180
margin: 4px;
177181
}
178182
183+
.tg-tree--actions > label {
184+
flex: auto;
185+
}
186+
179187
.tg-tree--nodes {
180188
width: fit-content;
181189
min-width: 100%;

testgen/ui/components/frontend/js/pages/data_catalog.js

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ import { RadioGroup } from '../components/radio_group.js';
3434

3535
const { div, h2, span, i } = van.tags;
3636

37+
// https://www.sam.today/blog/html5-dnd-globe-icon
38+
const EMPTY_IMAGE = new Image(1, 1);
39+
EMPTY_IMAGE.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
40+
3741
const DataCatalog = (/** @type Properties */ props) => {
3842
loadStylesheet('data-catalog', stylesheet);
3943
Streamlit.setFrameHeight(1); // Non-zero value is needed to render
@@ -77,14 +81,46 @@ const DataCatalog = (/** @type Properties */ props) => {
7781
}
7882
});
7983

84+
const treeDomId = 'data-catalog-tree';
85+
const dragState = van.state(null);
86+
const dragConstraints = { min: 250, max: 600 };
87+
const dragResize = (event) => {
88+
// https://stackoverflow.com/questions/36308460/why-is-clientx-reset-to-0-on-last-drag-event-and-how-to-solve-it
89+
if (event.screenX && dragState.val) {
90+
const dragWidth = dragState.val.startWidth + event.screenX - dragState.val.startX;
91+
const constrainedWidth = Math.min(dragConstraints.max, Math.max(dragWidth, dragConstraints.min));
92+
document.getElementById(treeDomId).style.minWidth = `${constrainedWidth}px`;
93+
}
94+
};
95+
8096
return div(
81-
{ class: 'flex-row tg-dh' },
97+
{
98+
class: 'flex-row tg-dh',
99+
ondragover: (event) => event.preventDefault(),
100+
},
82101
Tree({
102+
id: treeDomId,
83103
nodes: treeNodes,
84104
// Use .rawVal, so only initial value from query params is passed to tree
85105
selected: selectedItem.rawVal ? `${selectedItem.rawVal.type}_${selectedItem.rawVal.id}` : null,
86106
classes: 'tg-dh--tree',
87107
}),
108+
div(
109+
{
110+
class: 'tg-dh--dragger',
111+
draggable: true,
112+
ondragstart: (event) => {
113+
event.dataTransfer.effectAllowed = 'move';
114+
event.dataTransfer.setDragImage(EMPTY_IMAGE, 0, 0);
115+
dragState.val = { startX: event.screenX, startWidth: document.getElementById(treeDomId).offsetWidth };
116+
},
117+
ondragend: (event) => {
118+
dragResize(event);
119+
dragState.val = null;
120+
},
121+
ondrag: van.derive(() => dragState.val ? dragResize : null),
122+
},
123+
),
88124
() => {
89125
const item = selectedItem.val;
90126
if (item) {
@@ -239,6 +275,11 @@ stylesheet.replace(`
239275
align-items: stretch;
240276
}
241277
278+
.tg-dh--dragger {
279+
min-width: 16px;
280+
cursor: col-resize;
281+
}
282+
242283
.tg-dh--tree {
243284
min-width: 250px;
244285
border-radius: 8px;
@@ -247,7 +288,7 @@ stylesheet.replace(`
247288
}
248289
249290
.tg-dh--details {
250-
padding: 8px 0 0 20px;
291+
padding-top: 8px;
251292
overflow: auto;
252293
flex-grow: 1;
253294
}

0 commit comments

Comments
 (0)