diff --git a/packages/compass-crud/src/components/document-list.tsx b/packages/compass-crud/src/components/document-list.tsx index 26e4851009e..6d847994e64 100644 --- a/packages/compass-crud/src/components/document-list.tsx +++ b/packages/compass-crud/src/components/document-list.tsx @@ -145,11 +145,15 @@ const DocumentViewComponent: React.FunctionComponent< initialScrollTop?: number; scrollTriggerRef?: React.Ref; scrollableContainerRef?: React.Ref; + columnWidths: Record; + onColumnWidthChange: (newColumnWidths: Record) => void; } > = ({ initialScrollTop, scrollTriggerRef, scrollableContainerRef, + columnWidths, + onColumnWidthChange, ...props }) => { if (props.docs?.length === 0) { @@ -180,6 +184,8 @@ const DocumentViewComponent: React.FunctionComponent< key={props.darkMode ? 'dark' : 'light'} {...props} className={tableStyles} + columnWidths={columnWidths} + onColumnWidthChange={onColumnWidthChange} /> ); @@ -420,6 +426,18 @@ const DocumentList: React.FunctionComponent = (props) => { ] ); + const [columnWidths, setColumnWidths] = useTabState>( + 'columnWidths', + {} + ); + + const onColumnWidthChange = useCallback((newColumnWidths) => { + setColumnWidths({ + ...columnWidths, + ...newColumnWidths, + }); + }, []); + const renderContent = useCallback( (scrollTriggerRef: React.Ref) => { let content = null; @@ -482,6 +500,8 @@ const DocumentList: React.FunctionComponent = (props) => { initialScrollTop={currentViewInitialScrollTop} scrollableContainerRef={scrollRef} scrollTriggerRef={scrollTriggerRef} + columnWidths={columnWidths} + onColumnWidthChange={onColumnWidthChange} /> ); } diff --git a/packages/compass-crud/src/components/table-view/document-table-view.spec.tsx b/packages/compass-crud/src/components/table-view/document-table-view.spec.tsx new file mode 100644 index 00000000000..3682ad1805b --- /dev/null +++ b/packages/compass-crud/src/components/table-view/document-table-view.spec.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import type { ReactWrapper } from 'enzyme'; +import HadronDocument from 'hadron-document'; +import { expect } from 'chai'; +import sinon from 'sinon'; + +import DocumentTableView, { + DocumentTableView as RawDocumentTableView, +} from './document-table-view'; + +describe('', function () { + describe('#render', function () { + context('when the documents have objects for ids', function () { + const docs = [{ _id: '6909a21e9e548506e786c1e5', name: 'test-1' }]; + const hadronDocs = docs.map((doc) => new HadronDocument(doc)); + + let component: ReactWrapper; + beforeEach(function () { + component = mount( + + ); + }); + + afterEach(function () { + component?.unmount(); + }); + + it('columnWidths data is applied to the relevant grid column', async function () { + // Ensure we wait for GridReadyEvent so columnApi is set + await new Promise(setImmediate); + + const instance = component.find(RawDocumentTableView).instance(); + expect(instance).to.not.be.undefined; + + const columnState = instance.columnApi.getColumnState(); + const nameCol = columnState.find((column) => column.colId === 'name'); + const idCol = columnState.find((column) => column.colId === '_id'); + + expect(nameCol.width).to.equal(1337); + expect(idCol.width).to.equal(200); // Default width is 200 + }); + }); + }); +}); diff --git a/packages/compass-crud/src/components/table-view/document-table-view.tsx b/packages/compass-crud/src/components/table-view/document-table-view.tsx index 4f957b248f3..798bfdd5ce3 100644 --- a/packages/compass-crud/src/components/table-view/document-table-view.tsx +++ b/packages/compass-crud/src/components/table-view/document-table-view.tsx @@ -37,6 +37,7 @@ import type { GridReadyEvent, RowNode, ValueGetterParams, + ColumnResizedEvent, } from 'ag-grid-community'; const MIXED = 'Mixed' as const; @@ -70,6 +71,8 @@ export type DocumentTableViewProps = { tz: string; className?: string; darkMode?: boolean; + columnWidths: Record; + onColumnWidthChange: (newColumnWidths: Record) => void; }; export type GridContext = { @@ -88,7 +91,7 @@ export type GridContext = { /** * Represents the table view of the documents tab. */ -class DocumentTableView extends React.Component { +export class DocumentTableView extends React.Component { AGGrid: React.ReactElement; collection: string; topLevel: boolean; @@ -148,6 +151,7 @@ class DocumentTableView extends React.Component { const fid = data.isFooter ? '1' : '0'; return String(data.hadronDocument.getStringId()) + fid; }, + onColumnResized: this.onColumnResized.bind(this), }; this.collection = mongodbns(props.ns).collection; @@ -211,6 +215,23 @@ class DocumentTableView extends React.Component { this.addFooter(event.node, event.data, 'editing'); } + /** + * Callback for when a column's width is changed + * + * @param {Object} event + * finished {Boolean} - indicates the end of a stream of column resize events + */ + onColumnResized(event: ColumnResizedEvent) { + if (event.finished) { + const columnState = this.columnApi?.getColumnState() || []; + const currentColumnWidths: Record = {}; + for (const column of columnState) { + if (column.width) currentColumnWidths[column.colId] = column.width; + } + this.props.onColumnWidthChange(currentColumnWidths); + } + } + /** * Add a row to the table that represents the update/cancel footer for the * row directly above. The row will be a full-width row that has the same @@ -845,6 +866,8 @@ class DocumentTableView extends React.Component { tz: this.props.tz, darkMode: this.props.darkMode, }, + resizable: true, + width: this.props.columnWidths[String(path[path.length - 1])], }; };