Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add layerOrder in LegendWidget #433

Merged
merged 23 commits into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
83739a9
feat(widgets): :sparkles: add sortArrayByPropValues utils
flipasg Jun 16, 2022
1b5380e
feat(test): :white_check_mark: add sortArrayByPropValues test
flipasg Jun 16, 2022
53bbde8
feat(LegendWidget): :sparkles: sort layers by identifier array
flipasg Jun 16, 2022
10d8068
chore(gitignore): add vscode folder to gitignore
flipasg Jun 16, 2022
a07f539
feat(doc): :memo: add comment with the method signature
flipasg Jun 16, 2022
ed34f1d
feat(core): :truck: move assert from api to core package
flipasg Jun 17, 2022
917d287
feat(sortLayersById): :sparkles: add sortLayersById
flipasg Jun 17, 2022
a5270fa
test(sortLayersById): :speech_balloon: modifying test descriptions
flipasg Jun 17, 2022
aef5d6e
Update packages/react-widgets/src/widgets/utils/sortLayersById.js
flipasg Jun 17, 2022
282f0ac
Update packages/react-widgets/src/widgets/utils/sortLayersById.js
flipasg Jun 17, 2022
505838e
feat(sortLayers): :sparkles: final changes
flipasg Jun 17, 2022
709e537
fix(test): :bug: fix expected error message
flipasg Jun 17, 2022
fe10765
Merge branch 'master' into feature/ch222396/add-layerorder-legendwidget
Jun 17, 2022
1054495
feat(api): unify import & export individually
flipasg Jun 17, 2022
8b62dbd
chore(CHANGELOG): :bookmark: add not released change to the changelog
flipasg Jun 17, 2022
1f7db5d
test(sortlayers): :white_check_mark: remove berofeAll setup
flipasg Jun 17, 2022
4a685a0
chore(CHANGELOG): :bookmark: update changelog
flipasg Jun 17, 2022
f8550e0
feat(types): :label: add layerOrder to LegendWidget type
flipasg Jun 17, 2022
576db3a
feat(api): use assert from core package directly
flipasg Jun 17, 2022
1871a7c
Update CHANGELOG.md
Jun 17, 2022
3c2dc8d
refactor(api): :ok_hand: export assert as private function
flipasg Jun 17, 2022
af3f218
Merge branch 'feature/ch222396/add-layerorder-legendwidget' of https:…
flipasg Jun 17, 2022
6648248
fix(sortlayer): :bug: fix assert import
flipasg Jun 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/coverage
/reports
/.nyc_output
/.vscode

/packages/*/node_modules
/packages/*/coverage
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Not released

- Add layerOrder in LegendWidget [#433](https://github.com/CartoDB/carto-react/pull/433)
- Allow FormulaWidget column to be undefined when using COUNT [#434](https://github.com/CartoDB/carto-react/pull/434)

## 1.3
Expand Down
6 changes: 0 additions & 6 deletions packages/react-api/src/api/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ export function dealWithApiError({ response, data }) {
}
}

export function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}

export function checkCredentials(credentials) {
if (!credentials || !credentials.apiBaseUrl || !credentials.accessToken) {
throw new Error('Missing or bad credentials provided');
Expand Down
3 changes: 2 additions & 1 deletion packages/react-api/src/api/model.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assert, checkCredentials, makeCall } from './common';
import { checkCredentials, makeCall } from './common';
import { MAP_TYPES, API_VERSIONS } from '@deck.gl/carto';
import { _assert as assert } from '@carto/react-core/';

const URL_LENGTH = 2048;

Expand Down
4 changes: 2 additions & 2 deletions packages/react-api/src/api/stats.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assert, checkCredentials, makeCall } from './common';
import { checkCredentials, makeCall } from './common';
import { MAP_TYPES, API_VERSIONS } from '@deck.gl/carto';
import { getTileJson } from './tilejson';
import { InvalidColumnError } from '@carto/react-core/';
import { InvalidColumnError, _assert as assert } from '@carto/react-core/';

/**
* Execute a stats service request.
Expand Down
3 changes: 2 additions & 1 deletion packages/react-api/src/api/tilejson.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assert, checkCredentials } from './common';
import { checkCredentials } from './common';
import { MAP_TYPES, API_VERSIONS, fetchLayerData, FORMATS } from '@deck.gl/carto';
import { _assert as assert } from '@carto/react-core/';

/**
* Get the TileJson for static tilesets
Expand Down
1 change: 1 addition & 0 deletions packages/react-core/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { InvalidColumnError } from './utils/InvalidColumnError';
export { debounce } from './utils/debounce';
export { throttle } from './utils/throttle';
export { randomString } from './utils/randomString';
export { assert as _assert } from './utils/assert';

export { makeIntervalComplete } from './utils/makeIntervalComplete';

Expand Down
1 change: 1 addition & 0 deletions packages/react-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { InvalidColumnError } from './utils/InvalidColumnError';
export { debounce } from './utils/debounce';
export { throttle } from './utils/throttle';
export { randomString } from './utils/randomString';
export { assert as _assert } from './utils/assert';

export { makeIntervalComplete } from './utils/makeIntervalComplete';

Expand Down
5 changes: 5 additions & 0 deletions packages/react-core/src/utils/assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
70 changes: 70 additions & 0 deletions packages/react-widgets/__tests__/widgets/utils/sortLayers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import sortLayers from '../../../src/widgets/utils/sortLayers';

describe('sortLayersById', () => {
const ELEMENTS = [
{
id: 'storesLayer0',
source: 'storesSource',
title: 'Store types 0'
},
{
id: 'storesLayer1',
source: 'storesSource',
title: 'Store types 1'
},
{
id: 'storesLayer2',
source: 'storesSource',
title: 'Store types 2'
},
{
id: 'storesLayer3',
source: 'storesSource',
title: 'Store types 3'
}
];

test('should ignore not existing ids', () => {
const ORDER = [
'not_existing_value',
'storesLayer3',
'storesLayer1',
'storesLayer2',
'storesLayer0'
];
expect(ORDER.slice(1)).toStrictEqual(
sortLayers(ELEMENTS, ORDER)
.map(({ id }) => id)
.reverse()
);
});

test('should add missing ids at end', () => {
const ORDER = ['storesLayer1', 'storesLayer2', 'storesLayer0'];
const orderedElements = sortLayers(ELEMENTS, ORDER)
.map(({ id }) => id)
.slice(ORDER.length);
expect(orderedElements.every((id) => ORDER.indexOf(id) === -1)).toBeTruthy();
expect(orderedElements.length).toBe(1);
});
test('should throw an error when elements have no id property', () => {
const ELEMENT_WITH_NO_PROP = [
...ELEMENTS,
{
source: 'storesSource',
title: 'Store types 4'
}
];
const ORDER = ['storesLayer1', 'storesLayer2', 'storesLayer0'];
expect(() => sortLayers(ELEMENT_WITH_NO_PROP, ORDER)).toThrowError(
'Layer must have an id'
);
});

test('should sort in reverse order', () => {
const ORDER = ['storesLayer1', 'storesLayer2', 'storesLayer0', 'storesLayer3'];

const orderedElements = sortLayers(ELEMENTS, ORDER).map(({ id }) => id);
expect(ORDER).toStrictEqual(orderedElements.reverse());
});
});
3 changes: 2 additions & 1 deletion packages/react-widgets/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export type LegendWidget = {
className?: string;
initialCollapsed?: boolean;
customLegendTypes?: Record<string, Function>;
layerOrder?: string[];
}

export type WidgetWithAlert = {
Expand All @@ -106,4 +107,4 @@ export type WidgetWithAlert = {
noDataAlertProps?: object;
droppingFeaturesAlertProps?: object;
children?: React.ReactNode;
}
}
16 changes: 12 additions & 4 deletions packages/react-widgets/src/widgets/LegendWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { updateLayer } from '@carto/react-redux/';
import { LegendWidgetUI } from '@carto/react-ui';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import sortLayers from './utils/sortLayers';

/**
* Renders a <LegendWidget /> component
Expand All @@ -11,16 +12,21 @@ import PropTypes from 'prop-types';
* @param {Object.<string, function>} [props.customLayerOptions] - Allow to add custom controls to a legend item to tweak the associated layer
* @param {Object.<string, function>} [props.customLegendTypes] - Allow to customise by default legend types that can be rendered
* @param {boolean} [props.initialCollapsed] - Define initial collapsed value. false by default.
* @param {string[]} [props.layerOrder] - Array of layer identifiers. Defines the order of layer legends. [] by default.
*/
function LegendWidget({
className,
customLayerOptions,
customLegendTypes,
initialCollapsed
initialCollapsed,
layerOrder = []
flipasg marked this conversation as resolved.
Show resolved Hide resolved
}) {
const dispatch = useDispatch();
const layers = useSelector((state) =>
Object.values(state.carto.layers).filter((layer) => !!layer.legend)
sortLayers(
Object.values(state.carto.layers).filter((layer) => !!layer.legend),
layerOrder
)
);
const [collapsed, setCollapsed] = useState(initialCollapsed);

Expand Down Expand Up @@ -73,11 +79,13 @@ function LegendWidget({
LegendWidget.propTypes = {
className: PropTypes.string,
customLegendTypes: PropTypes.objectOf(PropTypes.func),
initialCollapsed: PropTypes.bool
initialCollapsed: PropTypes.bool,
layerOrder: PropTypes.arrayOf(PropTypes.string)
};

LegendWidget.defaultProps = {
initialCollapsed: false
initialCollapsed: false,
layerOrder: []
};

export default LegendWidget;
17 changes: 17 additions & 0 deletions packages/react-widgets/src/widgets/utils/sortLayers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { assert } from '@carto/react-core';

/**
* Sorts a list of layers based on a list of id property values
* @param {{ id: string }[]} layers - Array of layers to sort
* @param {string[]} layerOrder - Array of ids to sort by
* @returns sorted array
*/
export default function sortLayers(layers = [], layerOrder = []) {
if (!layerOrder.length) {
return layers;
}
return [...layers].sort((layerA, layerB) => {
assert(layerA.id && layerB.id, 'Layer must have an id');
return layerOrder.indexOf(layerB.id) - layerOrder.indexOf(layerA.id);
});
}