From 29a3d3e82fac89f16fd921f3eee107463fd2a71a Mon Sep 17 00:00:00 2001 From: Bounty Fix Date: Mon, 11 May 2026 11:06:12 +0200 Subject: [PATCH 1/3] fix: keep vertical scrollbar visible in data browser with wide tables Closes #2045 The vertical scrollbar was positioned at the right edge of the scrollable content area. When a table had many columns, users had to scroll all the way to the right to access the vertical scrollbar. This change separates horizontal and vertical scrolling: - .browser now only scrolls vertically (overflow-y: auto, overflow-x: hidden) - A new .browserContent wrapper handles horizontal scrolling - The sticky header and table rows scroll together horizontally - The vertical scrollbar is always visible on the viewport edge --- src/dashboard/Data/Browser/Browser.scss | 10 ++- .../Data/Browser/BrowserTable.react.js | 86 ++++++++++--------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/dashboard/Data/Browser/Browser.scss b/src/dashboard/Data/Browser/Browser.scss index fdcc8a328e..259d124f69 100644 --- a/src/dashboard/Data/Browser/Browser.scss +++ b/src/dashboard/Data/Browser/Browser.scss @@ -13,7 +13,8 @@ left: 300px; right: 0; bottom: 36px; - overflow: auto; + overflow-y: auto; + overflow-x: hidden; } body:global(.expanded) { @@ -284,3 +285,10 @@ body:global(.expanded) { .confirmConfig { padding: 10px 20px;} + +.browserContent { + position: relative; + min-height: 100%; + overflow-x: auto; + overflow-y: hidden; +} diff --git a/src/dashboard/Data/Browser/BrowserTable.react.js b/src/dashboard/Data/Browser/BrowserTable.react.js index 80ec614b7d..8afb467fcf 100644 --- a/src/dashboard/Data/Browser/BrowserTable.react.js +++ b/src/dashboard/Data/Browser/BrowserTable.react.js @@ -601,50 +601,52 @@ export default class BrowserTable extends React.Component { id="browser-table" style={{ right: rightValue, - overflowX: this.props.isResizing ? 'hidden' : 'auto', + overflowX: 'hidden', }} > - 0 && - (!!this.props.selection['*'] || - Object.values(this.props.selection).filter(checked => checked).length === - this.props.data.length) - } - indeterminate={ - !!this.props.selection && - !!this.props.data && - this.props.data.length > 0 && - !this.props.selection['*'] && - Object.values(this.props.selection).filter(checked => checked).length > 0 && - Object.values(this.props.selection).filter(checked => checked).length !== - this.props.data.length - } - selectAll={checked => - this.props.data.forEach(({ id }) => this.props.selectRow(id, checked)) - } - headers={headers} - stickyLefts={stickyLefts} - freezeIndex={this.props.freezeIndex} - freezeColumns={this.props.freezeColumns} - unfreezeColumns={this.props.unfreezeColumns} - updateOrdering={this.props.updateOrdering} - showRowNumber={this.props.showRowNumber} - setShowRowNumber={this.props.setShowRowNumber} - rowNumberWidth={rowNumberWidth} - readonly={!!this.props.relation || !!this.props.isUnique} - handleDragDrop={this.props.handleHeaderDragDrop} - onResize={this.props.handleResize} - onAddColumn={this.props.onAddColumn} - preventSchemaEdits={this.context.preventSchemaEdits} - isDataLoaded={!!this.props.data} - setSelectedObjectId={this.props.setSelectedObjectId} - setCurrent={this.props.setCurrent} - setContextMenu={this.props.setContextMenu} - /> - {table} +
+ 0 && + (!!this.props.selection['*'] || + Object.values(this.props.selection).filter(checked => checked).length === + this.props.data.length) + } + indeterminate={ + !!this.props.selection && + !!this.props.data && + this.props.data.length > 0 && + !this.props.selection['*'] && + Object.values(this.props.selection).filter(checked => checked).length > 0 && + Object.values(this.props.selection).filter(checked => checked).length !== + this.props.data.length + } + selectAll={checked => + this.props.data.forEach(({ id }) => this.props.selectRow(id, checked)) + } + headers={headers} + stickyLefts={stickyLefts} + freezeIndex={this.props.freezeIndex} + freezeColumns={this.props.freezeColumns} + unfreezeColumns={this.props.unfreezeColumns} + updateOrdering={this.props.updateOrdering} + showRowNumber={this.props.showRowNumber} + setShowRowNumber={this.props.setShowRowNumber} + rowNumberWidth={rowNumberWidth} + readonly={!!this.props.relation || !!this.props.isUnique} + handleDragDrop={this.props.handleHeaderDragDrop} + onResize={this.props.handleResize} + onAddColumn={this.props.onAddColumn} + preventSchemaEdits={this.context.preventSchemaEdits} + isDataLoaded={!!this.props.data} + setSelectedObjectId={this.props.setSelectedObjectId} + setCurrent={this.props.setCurrent} + setContextMenu={this.props.setContextMenu} + /> + {table} +
); } From 0f9c4308ce98abf0adc133c1ee81a25bb09c1f36 Mon Sep 17 00:00:00 2001 From: Deeyaan Date: Mon, 11 May 2026 13:46:59 +0200 Subject: [PATCH 2/3] fix: update scroll reset to use browser ref --- src/dashboard/Data/Browser/BrowserTable.react.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/dashboard/Data/Browser/BrowserTable.react.js b/src/dashboard/Data/Browser/BrowserTable.react.js index 8afb467fcf..528280ee7e 100644 --- a/src/dashboard/Data/Browser/BrowserTable.react.js +++ b/src/dashboard/Data/Browser/BrowserTable.react.js @@ -33,6 +33,7 @@ export default class BrowserTable extends React.Component { maxWidth: window.innerWidth - 300, }; this.tableRef = React.createRef(); + this.browserRef = React.createRef(); this.handleResize = this.handleResize.bind(this); this.updateMaxWidth = this.updateMaxWidth.bind(this); } @@ -42,16 +43,16 @@ export default class BrowserTable extends React.Component { this.setState({ offset: 0, }); - this.tableRef.current.scrollTop = 0; + this.browserRef.current.scrollTop = 0; } else if (this.props.newObject !== props.newObject) { this.setState({ offset: 0 }); - this.tableRef.current.scrollTop = 0; + this.browserRef.current.scrollTop = 0; } else if (this.props.ordering !== props.ordering) { this.setState({ offset: 0 }); - this.tableRef.current.scrollTop = 0; + this.browserRef.current.scrollTop = 0; } else if (this.props.filters.size !== props.filters.size) { this.setState({ offset: 0 }, () => { - this.tableRef.current.scrollTop = 0; + this.browserRef.current.scrollTop = 0; }); } } @@ -599,6 +600,7 @@ export default class BrowserTable extends React.Component {
Date: Mon, 11 May 2026 14:03:43 +0200 Subject: [PATCH 3/3] fix: add null guard before accessing browserRef scrollTop --- package-lock.json | 14 -------------- src/dashboard/Data/Browser/BrowserTable.react.js | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 343fee0df0..8922d7975c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16705,20 +16705,6 @@ "node": ">=18" } }, - "node_modules/filing-cabinet/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", diff --git a/src/dashboard/Data/Browser/BrowserTable.react.js b/src/dashboard/Data/Browser/BrowserTable.react.js index 528280ee7e..c333a57cdc 100644 --- a/src/dashboard/Data/Browser/BrowserTable.react.js +++ b/src/dashboard/Data/Browser/BrowserTable.react.js @@ -43,16 +43,24 @@ export default class BrowserTable extends React.Component { this.setState({ offset: 0, }); - this.browserRef.current.scrollTop = 0; + if (this.browserRef.current) { + this.browserRef.current.scrollTop = 0; + } } else if (this.props.newObject !== props.newObject) { this.setState({ offset: 0 }); - this.browserRef.current.scrollTop = 0; + if (this.browserRef.current) { + this.browserRef.current.scrollTop = 0; + } } else if (this.props.ordering !== props.ordering) { this.setState({ offset: 0 }); - this.browserRef.current.scrollTop = 0; + if (this.browserRef.current) { + this.browserRef.current.scrollTop = 0; + } } else if (this.props.filters.size !== props.filters.size) { this.setState({ offset: 0 }, () => { - this.browserRef.current.scrollTop = 0; + if (this.browserRef.current) { + this.browserRef.current.scrollTop = 0; + } }); } }