Skip to content

Commit

Permalink
geosolutions-it#9553: Improving readability of long attribute values …
Browse files Browse the repository at this point in the history
…in attribute table and table widgets (geosolutions-it#9701)

* geosolutions-it#9553: handle showing tooltip on attr table cells once user hovers on cell

* geosolutions-it#9553: create a separate enhnacer for handleLongText and use it for formatter table cell

* geosolutions-it#9553: add copyright for the created handleLongTextEnhancer

* geosolutions-it#9553: handle test cases for handleLongTextEnhancer

* geosolutions-it#9553: add unit tests for handleLongTextEnhancer

* geosolutions-it#9553: fix unit test failure for featureTypeToGridColumns formatters

* geosolutions-it#9553:reset tests.webpack file

* Update web/client/components/misc/enhancers/handleLongTextEnhancer.jsx

---------

Co-authored-by: Matteo V <matteo.velludini@geosolutionsgroup.com>
  • Loading branch information
mahmoudadel54 and MV88 committed Nov 21, 2023
1 parent 6f59a61 commit b4448e3
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 2 deletions.
2 changes: 1 addition & 1 deletion web/client/components/data/featuregrid/formatters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import NumberFormat from '../../../I18N/Number';
import { dateFormats as defaultDateFormats } from "../../../../utils/FeatureGridUtils";

const BooleanFormatter = ({value} = {}) => !isNil(value) ? <span>{value.toString()}</span> : null;
const StringFormatter = ({value} = {}) => !isNil(value) ? reactStringReplace(value, /(https?:\/\/\S+)/g, (match, i) => (
export const StringFormatter = ({value} = {}) => !isNil(value) ? reactStringReplace(value, /(https?:\/\/\S+)/g, (match, i) => (
<a key={match + i} href={match} target={"_blank"}>{match}</a>
)) : null;
const NumberFormatter = ({value} = {}) => !isNil(value) ? <NumberFormat value={value} numberParams={{maximumFractionDigits: 17}}/> : null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Copyright 2023, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import expect from 'expect';

import React from 'react';
import ReactDOM from 'react-dom';
import { handleLongTextEnhancer } from '../handleLongTextEnhancer';
import { StringFormatter } from '../../../data/featuregrid/formatters';

describe("handleLongTextEnhancer enhancer", () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});

afterEach((done) => {
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
document.body.innerHTML = '';
setTimeout(done);
});

it('handleLongTextEnhancer by passing formatter as wrapper', () => {
const EnhancerWithFormatter = ()=> handleLongTextEnhancer(StringFormatter)({ value: "test12334567899999" });
ReactDOM.render(
<EnhancerWithFormatter />,
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toExist();
expect(document.getElementsByTagName('span').length).toEqual(2);
expect(document.getElementsByTagName('span')[1].innerHTML).toExist();
});

it('handleLongTextEnhancer with by passing td as wrapper', () => {
const wrapper = () => (<td>15234568965</td>);
const EnhancerWithFormatter = ()=> handleLongTextEnhancer(wrapper)({ value: "15234568965" });
ReactDOM.render(
<EnhancerWithFormatter />,
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toExist();
expect(document.getElementsByTagName('span').length).toEqual(2);
expect(document.getElementsByTagName('span')[1].innerHTML).toExist();
});


it('handleLongTextEnhancer with by passing span as wrapper', () => {
const wrapper = () => (<span>15234568965</span>);
const EnhancerWithFormatter = ()=> handleLongTextEnhancer(wrapper)({ value: "15234568965" });
ReactDOM.render(
<EnhancerWithFormatter />,
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toExist();
expect(document.getElementsByTagName('span').length).toEqual(3);
expect(document.getElementsByTagName('span')[1].innerHTML).toExist();
});


it('handleLongTextEnhancer with by passing td div wrapper', () => {
const wrapper = () => (<div>test</div>);
const EnhancerWithFormatter = ()=> handleLongTextEnhancer(wrapper)({ value: "test" });
ReactDOM.render(
<EnhancerWithFormatter />,
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toExist();
expect(document.getElementsByTagName('span').length).toEqual(2);
expect(document.getElementsByTagName('span')[1].innerHTML).toExist();
});
});
50 changes: 50 additions & 0 deletions web/client/components/misc/enhancers/handleLongTextEnhancer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2023, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from "react";
import OverlayTrigger from "../OverlayTrigger";
import { Tooltip } from "react-bootstrap";
/**
* handleLongTextEnhancer enhancer. Enhances a long text content by adding a tooltip.
* @type {function}
* @name handleLongTextEnhancer
* @memberof components.misc.enhancers
* Wraps [wrapped component with content] to add tooltip for long content if shown content less than the main content
* @param {Component} Wrapped the component wrapped with a tooltip when its content is too long
* @param {object} props the props that contains value content
* @return {Component} the rendered component that renders the content with the tooltip if the content is long or renders the content with no tooltip if not long
* @example
* const wrapper = () = > <span>testtttttttttt</span>
* const Component = ()=> handleLongTextEnhancer(wrapper)(props);
* render (){
* return <Component />
* }
*
*/
export const handleLongTextEnhancer = (Wrapped) => (props) => {
const cellRef = React.useRef(null);
const contentRef = React.useRef(null);
const [isContentOverflowing, setIsContentOverflowing] = React.useState(false);

const handleMouseEnter = () => {
const cellWidth = cellRef.current.offsetWidth;
const contentWidth = contentRef.current.offsetWidth;
setIsContentOverflowing(contentWidth > cellWidth);
};

return (<OverlayTrigger
placement="top"
overlay={isContentOverflowing ? <Tooltip id="tooltip">{<Wrapped {...props} />}</Tooltip> : <></>}
>
<div ref={cellRef} onMouseEnter={handleMouseEnter}>
<span ref={contentRef}>
<span>{<Wrapped {...props} />}</span>
</span>
</div>
</OverlayTrigger>);
};
4 changes: 3 additions & 1 deletion web/client/utils/FeatureGridUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from './ogc/WFS/base';

import { applyDefaultToLocalizedString } from '../components/I18N/LocalizedString';
import { handleLongTextEnhancer } from '../components/misc/enhancers/handleLongTextEnhancer';

const getGeometryName = (describe) => get(findGeometryProperty(describe), "name");
const getPropertyName = (name, describe) => name === "geometry" ? getGeometryName(describe) : name;
Expand Down Expand Up @@ -115,6 +116,7 @@ export const getCurrentPaginationOptions = ({ startPage, endPage }, oldPages, si
return { startIndex: nPs[0] * size, maxFeatures: needPages * size };
};


/**
* Utility function to get from a describeFeatureType response the columns to use in the react-data-grid
* @param {object} describe describeFeatureType response
Expand Down Expand Up @@ -146,7 +148,7 @@ export const featureTypeToGridColumns = (
editable,
filterable,
editor: getEditor(desc, field),
formatter: getFormatter(desc, field),
formatter: handleLongTextEnhancer(getFormatter(desc, field)),
filterRenderer: getFilterRenderer(desc, field)
};
});
Expand Down
35 changes: 35 additions & 0 deletions web/client/utils/__tests__/FeatureGridUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from "react";
import ReactDOM from "react-dom";
import expect from 'expect';

import {
updatePages,
gridUpdateToQueryUpdate,
Expand All @@ -18,6 +21,18 @@ import {


describe('FeatureGridUtils', () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});

afterEach((done) => {
ReactDOM.unmountComponentAtNode(
document.getElementById("container")
);
document.body.innerHTML = "";
setTimeout(done);
});
it('Test updatePages when needPages * size is less then features', () => {
const oldFeatures = Array(350);
const features = Array(60);
Expand Down Expand Up @@ -332,6 +347,26 @@ describe('FeatureGridUtils', () => {
// test localized alias with empty default
expect(featureTypeToGridColumns(describe, columnSettings, [{name: "Test1", alias: {"default": ""}}])[0].title.default).toEqual('Test1');

});
it('featureTypeToGridColumns formatters', () => {
const DUMMY = () => {};
const formatterWrapper = () => (<div>testtttt</div>);
const describe = {featureTypes: [{properties: [{name: 'Test1', type: "xsd:number"}, {name: 'Test2', type: "xsd:number"}]}]};
const columnSettings = {name: 'Test1', hide: false};
const options = [{name: 'Test1', title: 'Some title', description: 'Some description'}];
const featureGridColumns = featureTypeToGridColumns(describe, columnSettings, [], {options}, {getHeaderRenderer: () => DUMMY, getFilterRenderer: () => DUMMY, getFormatter: () => formatterWrapper, getEditor: () => DUMMY});
expect(featureGridColumns.length).toBe(2);
featureGridColumns.forEach((fgColumns)=>{
const Formatter = fgColumns.formatter;
ReactDOM.render(
<Formatter/>,
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toExist();
expect(document.getElementsByTagName('span').length).toEqual(2);
expect(document.getElementsByTagName('span')[1].innerHTML).toExist();
});

});
describe("supportsFeatureEditing", () => {
it('test supportsFeatureEditing with valid layer type', () => {
Expand Down

0 comments on commit b4448e3

Please sign in to comment.