Skip to content

Commit

Permalink
feat(compass-crud): allows nested elements to also expand in steps (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
himanshusinghs authored Jul 23, 2024
1 parent de2ae28 commit ed3980d
Show file tree
Hide file tree
Showing 13 changed files with 768 additions and 135 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React, { useState } from 'react';
import { expect } from 'chai';
import { render, cleanup, screen, within } from '@testing-library/react';
import {
render,
cleanup,
screen,
within,
waitFor,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import HadronDocument from 'hadron-document';
import Document from './document';
Expand Down Expand Up @@ -244,4 +250,52 @@ describe('Document', function () {
expect(() => screen.getByText('firstName')).to.throw;
expect(() => screen.getByText('lastName')).to.throw;
});

it('should render "Show more" toggle when number of fields are more than allowed visible fields', async function () {
const hadronDoc = new HadronDocument({
prop1: 'prop1',
prop2: 'prop2',
prop3: 'prop3',
prop4: 'prop4',
});
hadronDoc.setMaxVisibleElementsCount(2);
render(<Document value={hadronDoc}></Document>);
expect(screen.getByText('prop1')).to.exist;
expect(screen.getByText('prop2')).to.exist;
expect(() => screen.getByText('prop3')).to.throw;
expect(() => screen.getByText('prop4')).to.throw;
expect(screen.getByText('Show 2 more fields')).to.exist;

hadronDoc.setMaxVisibleElementsCount(25);
await waitFor(() => {
expect(screen.getByText('prop3')).to.exist;
expect(screen.getByText('prop4')).to.exist;
});
});

it('should render "Show more" toggle on element when its nested fields are more than allowed visible fields', async function () {
const hadronDoc = new HadronDocument({
nested: {
prop1: 'prop1',
prop2: 'prop2',
prop3: 'prop3',
prop4: 'prop4',
},
});
const [nestedElement] = [...hadronDoc.elements];
hadronDoc.expand();
render(<Document value={hadronDoc}></Document>);
expect(screen.getByText('nested')).to.exist;
expect(screen.getByText('prop1')).to.exist;
expect(screen.getByText('prop2')).to.exist;
expect(screen.getByText('prop3')).to.exist;
expect(screen.getByText('prop4')).to.exist;

nestedElement.setMaxVisibleElementsCount(2);
await waitFor(() => {
expect(() => screen.getByText('prop3')).to.throw;
expect(() => screen.getByText('prop4')).to.throw;
});
expect(screen.getByText('Show 2 more fields in nested')).to.exist;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,31 @@ import type {
default as HadronDocumentType,
Element as HadronElementType,
} from 'hadron-document';
import { ElementEvents } from 'hadron-document';
import {
DEFAULT_VISIBLE_DOCUMENT_ELEMENTS,
DocumentEvents,
ElementEvents,
} from 'hadron-document';
import { AutoFocusContext } from './auto-focus-context';
import { useForceUpdate } from './use-force-update';
import { HadronElement } from './element';
import { calculateShowMoreToggleOffset, HadronElement } from './element';
import { usePrevious } from './use-previous';
import DocumentFieldsToggleGroup from './document-fields-toggle-group';
import VisibleFieldsToggle from './visible-field-toggle';
import { documentTypography } from './typography';

function useHadronDocument(doc: HadronDocumentType) {
const prevDoc = usePrevious(doc);
const forceUpdate = useForceUpdate();

const onVisibleElementsChanged = useCallback(
(document: HadronDocumentType) => {
if (document === doc) {
forceUpdate();
}
},
[doc, forceUpdate]
);

const onDocumentFieldsAddedOrRemoved = useCallback(
(
_el: HadronElementType,
Expand All @@ -39,17 +52,20 @@ function useHadronDocument(doc: HadronDocumentType) {
}, [prevDoc, doc, forceUpdate]);

useEffect(() => {
doc.on(DocumentEvents.VisibleElementsChanged, onVisibleElementsChanged);
doc.on(ElementEvents.Added, onDocumentFieldsAddedOrRemoved);
doc.on(ElementEvents.Removed, onDocumentFieldsAddedOrRemoved);

return () => {
doc.off(DocumentEvents.VisibleElementsChanged, onVisibleElementsChanged);
doc.off(ElementEvents.Added, onDocumentFieldsAddedOrRemoved);
doc.off(ElementEvents.Removed, onDocumentFieldsAddedOrRemoved);
};
}, [doc, onDocumentFieldsAddedOrRemoved]);
}, [doc, onDocumentFieldsAddedOrRemoved, onVisibleElementsChanged]);

return {
elements: [...doc.elements],
visibleElements: doc.getVisibleElements(),
};
}

Expand All @@ -61,8 +77,6 @@ const hadronDocument = css({
counterReset: 'line-number',
});

const INITIAL_FIELD_LIMIT = 25;

// TODO: This element should implement treegrid aria role to be accessible
// https://www.w3.org/TR/wai-aria-practices/examples/treegrid/treegrid-1.html
// https://jira.mongodb.org/browse/COMPASS-5614
Expand All @@ -72,12 +86,7 @@ const HadronDocument: React.FunctionComponent<{
editing?: boolean;
onEditStart?: () => void;
}> = ({ value: document, editable = false, editing = false, onEditStart }) => {
const { elements } = useHadronDocument(document);
const [visibleFieldsCount, setVisibleFieldsCount] =
useState(INITIAL_FIELD_LIMIT);
const visibleElements = useMemo(() => {
return elements.filter(Boolean).slice(0, visibleFieldsCount);
}, [elements, visibleFieldsCount]);
const { elements, visibleElements } = useHadronDocument(document);
const [autoFocus, setAutoFocus] = useState<{
id: string;
type: 'key' | 'value' | 'type';
Expand All @@ -89,6 +98,25 @@ const HadronDocument: React.FunctionComponent<{
}
}, [editing]);

const handleVisibleFieldsChanged = useCallback(
(totalVisibleFields: number) => {
document.setMaxVisibleElementsCount(totalVisibleFields);
},
[document]
);

// To render the "Show more" toggle for the document we need to calculate a
// proper offset so that it aligns with the expand icon of top level fields
const showMoreToggleOffset = useMemo(
() =>
calculateShowMoreToggleOffset({
editable,
level: 0,
alignWithNestedExpandIcon: false,
}),
[editable]
);

return (
<div>
<div
Expand Down Expand Up @@ -124,20 +152,23 @@ const HadronDocument: React.FunctionComponent<{
})}
</AutoFocusContext.Provider>
</div>
<DocumentFieldsToggleGroup
<VisibleFieldsToggle
// TODO: "Hide items" button will only be shown when document is not
// edited because it's not decided how to handle changes to the fields
// that are changed but then hidden
// https://jira.mongodb.org/browse/COMPASS-5587
showHideButton={!editing}
currentSize={visibleFieldsCount}
currentSize={document.maxVisibleElementsCount}
totalSize={elements.length}
minSize={INITIAL_FIELD_LIMIT}
minSize={DEFAULT_VISIBLE_DOCUMENT_ELEMENTS}
// In the editing mode we allow to show / hide less fields because
// historically Compass was doing this for "performance" reasons
step={editing ? 100 : 1000}
onSizeChange={setVisibleFieldsCount}
></DocumentFieldsToggleGroup>
onSizeChange={handleVisibleFieldsChanged}
style={{
paddingLeft: showMoreToggleOffset,
}}
></VisibleFieldsToggle>
</div>
);
};
Expand Down
Loading

0 comments on commit ed3980d

Please sign in to comment.