-
Notifications
You must be signed in to change notification settings - Fork 445
Description
Description
This task aims to refactor the dependencies system to:
- clarify and generalize available interactions
- review the dependencies logic
- allow introduction of new widgets in the connections system, in particular the dynamic filter widget
Current state of the implementation
The connections system was introduced in #2783 as support for the map bounding box filter and over time we included additional type of interactions.
Summary of available connection interactions:
- Map widget can:
- filter by extent other widget
- pass layers/groups information to other widgets (legend)
- Table widget can:
- apply filter on columns to other widget (quickFilters)
- zoom to extent using filter on columns bounds in map widget (quickFilters)
- zoom to a single feature in map widget
- Legend widget can:
- update visibility, expanded and opacity properties of layers in map widget
- apply interactive legend filter when available
Looking to the list above we can divide connections in following types:
- filter action
- map events action (specific implementation: from table to map)
- properties update action (specific implementation: from legend to map)
At the current state some connections are available only when the source layer name match with the target layer name or (in case of map) one of the available layers with the same name. We should review how connection can be provided based in some cases we want to connections between different data sources but with similar attributes.
The current system uses a property inside the widget that describe the mapping of properties of another widget, e.g:
{
id: 'w-map-01',
widgetType: 'map',
selectedMapId: 'm-01',
maps: [
{ mapId: 'm-01' }
],
dependenciesMap: {
"filter": "widgets[w-table-01].filter",
"quickFilters": "widgets[w-table-01].quickFilters",
"layer": "widgets[w-table-01].layer",
"options": "widgets[w-table-01].options",
"dependenciesMap": "widgets[w-table-01].dependenciesMap",
"mapSync": "widgets[w-table-01].mapSync"
}
},
{
id: 'w-table-01',
widgetType: 'table'
}The sample above is a map connected to a table and the dependenciesMap is an object where for each property we have a map to other widgets, in this case we can say a table because the id in the path is using w-table-01. With this approach a dependenciesMap could get properties from different widget without declaring a hierarchical structure. The widget components (enhandedWidgets) are then implemented with a set of HOC where each of them will prepare props combining them with the one coming from the dependencies:
export const MapWidget = compose(
dependenciesToWidget,
dependenciesToLayers,
dependenciesToMapProp('center'),
dependenciesToMapProp('zoom'),
dependenciesToExtent,
mapWidget
)(BaseMapWidget);Note: dependenciesToWidget performs the transformation from the path to the actual value
Dependencies supported at the moment:
filterfilter applied in the builder available for chart, table and counterquickFiltersadditional filter used by the tablelayercould contain filter objectoptionsintroduced to maintain viewparams from a layer of the parent connection Fix #3088 viewparams support for widgets #3094. It seems also to used for other parameters inside the table widget, let's check other cases.mapSyncused to apply viewport filter from a mapviewportrelated to mapSynczoomrelated to mapSynccenterrelated to mapSynclayersused by the legend to display list of layersdependenciesMapnested dependencies e.g. used in map with parent tablezoomLoaderused to manage zoom to in the table widget #9567: handle functionality of zoom to record in table widgets #9608extentObjused to manage zoom to in the table widget #9567: handle functionality of zoom to record in table widgets #9608
Refactor proposal
We could approach with a graph declaration structure:
"widgets": [
{
"id": "w-map-01",
"widgetType": "map",
"selectedMapId": "m-01",
"maps": [ { "id": "m-01" } ]
},
{
"id": "w-table-01",
"widgetType": "table",
"filter": {}
},
],
"interactions": [
{
"id": "interaction-01"
"trigger": {
"eventType": "CHANGE",
"source": "widgets["w-map-01"].maps["w-map-01"].extent"
},
"transformers": [{type: "delay", 500}, {
"type": "extentToFilter"
}],
"effect": {
"target": "widgets["w-table-01"].filter",
"type": "UPSERT",
"filterId": "interaction-01"
}
}
]In this example of the interactions, when the extent of the map changes.
All the connected widgets as object with following properties:
In term of connection interactions we could have:
- direct connection:
- side effect connection, e.g. a widget update a map view that update the filter viewport and has effect on children
Each widget should define the connection interface that will be used to represent in UI possible connections:
- MapWidget
interface: {
"sendProps": ["BBOX", "FILTER"],
"receiveProps": ["BBOX", "FILTER"]
},
- TableWidget
interface: {
"receiveProps": ["FILTER"],
"sendProps": ["BBOX", "FILTER"]
},
- ChartWidget
We could define following interface type based on the current support:
- FILTER -> we should uniform all type of filter in a single object instead to have different naming
- BBOX -> trigger zoom to extent
- ZOOM -> trigger zoom (not sure it's current supported)
- LAYERS -> used by legend to list the layers
- GROUPS -> used by legend to list the groups
Refactor requirements
- Review current dependencies system configuration
- Implement method to convert current configuration with the improved one
- Refactor how widget component reconstruct their relation to other widgets (current
dependenciesTo...HOC) - Generalize usage of the current available interaction actions, avoiding specific implementation to a widget type
- Implementation should take into account dashboard and widgets on a map. (While refactoring we should think to map with widgets as a dashboard with a single map)
What kind of improvement you want to add? (check one with "x", remove the others)
- Refactoring (no functional changes, no api changes)