diff --git a/CHANGELOG.md b/CHANGELOG.md index e67926c57..c4918c652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Not released - Spatial Index Sources use remote widgets calculation [#898](https://github.com/CartoDB/carto-react/pull/898) +- Support for `hiddenColumnFields` parameter and `onRowClick` handler for Table Widget [#900](https://github.com/CartoDB/carto-react/pull/900) ## 3.0.0 diff --git a/DEVELOPERS.md b/DEVELOPERS.md index eb2d666bc..b7deb3756 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -31,6 +31,20 @@ Then, inside the proper template folder in carto-react-template, link packages w yarn link-carto-react ``` +## copy-packages.sh + +As an alternative to `yarn link`, `copy-packages.sh` could be used for copying the content of every package to the target directory, e.g: + +``` +./copy-packages.sh ~/workspace/repositories/cloud-native/workspace-www/node_modules/@carto +``` + +Thus, combined with the execution of `yarn build` in the root of this repository, will copy every package into the target directory: + +``` +yarn build && ./copy-packages.sh ~/workspace/repositories/cloud-native/workspace-www/node_modules/@carto +``` + ## npm release You will need npm credentials under @carto organization. diff --git a/copy-packages.sh b/copy-packages.sh new file mode 100755 index 000000000..e56e3f496 --- /dev/null +++ b/copy-packages.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "Missing target directory. Usage: $0 " + exit 1 +fi + +SOURCE_DIR="packages" +TARGET_DIR="$1" + +for dir in "$SOURCE_DIR"/*; do + if [ -d "$dir" ]; then + DIR_NAME=$(basename "$dir") + + SOURCE_PATH="$dir/dist" + TARGET_PATH="$TARGET_DIR/$DIR_NAME" + + echo "Copying $SOURCE_PATH to $TARGET_PATH" + cp -r "$SOURCE_PATH" "$TARGET_PATH" + fi +done + +echo "All directories copied successfully!" \ No newline at end of file diff --git a/packages/react-api/__tests__/api/model.test.js b/packages/react-api/__tests__/api/model.test.js index 2a8606d9a..9374ff8ff 100644 --- a/packages/react-api/__tests__/api/model.test.js +++ b/packages/react-api/__tests__/api/model.test.js @@ -123,7 +123,7 @@ describe('model', () => { expect(mockedMakeCall).toHaveBeenCalledWith({ credentials: TABLE_SOURCE.credentials, opts: { method: 'GET' }, - url: 'https://gcp-us-east1.api.carto.com/v3/sql/carto-ps-bq-developers/model/formula?type=query&client=c4react&source=SELECT+*+FROM+%60cartobq.public_account.seattle_collisions%60+WHERE+time_column+%3E+%40start+AND+time_column+%3C+%40end¶ms=%7B%22column%22%3A%22__test__%22%2C%22operation%22%3A%22avg%22%7D&queryParameters=%7B%22start%22%3A%222019-01-01%22%2C%22end%22%3A%222019-01-02%22%7D&filters=%7B%7D&filtersLogicalOperator=AND&spatialFilters=%7B%22geom%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-84.40640911186557%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C31.358634554371573%5D%5D%5D%7D%7D&spatialDataType=geo' + url: 'https://gcp-us-east1.api.carto.com/v3/sql/carto-ps-bq-developers/model/formula?type=query&client=c4react&source=SELECT+*+FROM+%60cartobq.public_account.seattle_collisions%60+WHERE+time_column+%3E+%40start+AND+time_column+%3C+%40end¶ms=%7B%22column%22%3A%22__test__%22%2C%22operation%22%3A%22avg%22%7D&queryParameters=%7B%22start%22%3A%222019-01-01%22%2C%22end%22%3A%222019-01-02%22%7D&filters=%7B%7D&filtersLogicalOperator=AND&spatialFilters=%7B%22geom%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-84.40640911186557%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C31.358634554371573%5D%5D%5D%7D%7D&spatialDataType=geo&spatialDataColumn=geom' }); }); @@ -138,7 +138,7 @@ describe('model', () => { expect(mockedMakeCall).toHaveBeenCalledWith({ credentials: TABLE_SOURCE.credentials, opts: { method: 'GET' }, - url: 'https://gcp-us-east1.api.carto.com/v3/sql/carto-ps-bq-developers/model/formula?type=query&client=c4react&source=SELECT+*+FROM+%60cartobq.public_account.seattle_collisions%60+WHERE+time_column+%3E+%40start+AND+time_column+%3C+%40end¶ms=%7B%22column%22%3A%22__test__%22%2C%22operation%22%3A%22avg%22%7D&queryParameters=%7B%22start%22%3A%222019-01-01%22%2C%22end%22%3A%222019-01-02%22%7D&filters=%7B%7D&filtersLogicalOperator=AND&spatialFilters=%7B%22abc%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-84.40640911186557%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C31.358634554371573%5D%5D%5D%7D%7D&spatialDataType=geo' + url: 'https://gcp-us-east1.api.carto.com/v3/sql/carto-ps-bq-developers/model/formula?type=query&client=c4react&source=SELECT+*+FROM+%60cartobq.public_account.seattle_collisions%60+WHERE+time_column+%3E+%40start+AND+time_column+%3C+%40end¶ms=%7B%22column%22%3A%22__test__%22%2C%22operation%22%3A%22avg%22%7D&queryParameters=%7B%22start%22%3A%222019-01-01%22%2C%22end%22%3A%222019-01-02%22%7D&filters=%7B%7D&filtersLogicalOperator=AND&spatialFilters=%7B%22abc%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-84.40640911186557%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C23.809680634191537%5D%2C%5B-78.72111096471372%2C31.358634554371573%5D%2C%5B-84.40640911186557%2C31.358634554371573%5D%5D%5D%7D%7D&spatialDataType=geo&spatialDataColumn=abc' }); }); }); diff --git a/packages/react-api/src/api/model.js b/packages/react-api/src/api/model.js index 9078e9545..cc0830144 100644 --- a/packages/react-api/src/api/model.js +++ b/packages/react-api/src/api/model.js @@ -17,6 +17,33 @@ const AVAILABLE_MODELS = [ const DEFAULT_GEO_COLUMN = 'geom'; +const extractSpatialDataFromSource = (source) => { + let spatialDataType = source.spatialDataType; + let spatialDataColumn = source.spatialDataColumn; + + if (!spatialDataType || !spatialDataColumn) { + if (source.geoColumn) { + const parsedGeoColumn = source.geoColumn.split(':'); + if (parsedGeoColumn.length === 2) { + spatialDataType = parsedGeoColumn[0]; + spatialDataColumn = parsedGeoColumn[1]; + } else if (parsedGeoColumn.length === 1) { + spatialDataColumn = parsedGeoColumn[0] || DEFAULT_GEO_COLUMN; + spatialDataType = 'geo'; + } + if (spatialDataType === 'geom') { + // fallback if for some reason someone provided old `geom:$column` + spatialDataType = 'geo'; + } + } else { + spatialDataType = 'geo'; + spatialDataColumn = DEFAULT_GEO_COLUMN; + } + } + + return { spatialDataType, spatialDataColumn }; +}; + /** * Execute a SQL model request. * @@ -56,6 +83,7 @@ export function executeModel(props) { const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) : ''; + let queryParams = { type, client: _getClient(), @@ -67,29 +95,8 @@ export function executeModel(props) { }; let spatialFilters; - if (spatialFilter) { - let spatialDataType = source.spatialDataType; - let spatialDataColumn = source.spatialDataColumn; - - if (!spatialDataType || !spatialDataColumn) { - if (source.geoColumn) { - const parsedGeoColumn = source.geoColumn.split(':'); - if (parsedGeoColumn.length === 2) { - spatialDataType = parsedGeoColumn[0]; - spatialDataColumn = parsedGeoColumn[1]; - } else if (parsedGeoColumn.length === 1) { - spatialDataColumn = parsedGeoColumn[0] || DEFAULT_GEO_COLUMN; - spatialDataType = 'geo'; - } - if (spatialDataType === 'geom') { - // fallback if for some reason someone provided old `geom:$column` - spatialDataType = 'geo'; - } - } else { - spatialDataType = 'geo'; - spatialDataColumn = DEFAULT_GEO_COLUMN; - } - } + if (spatialFilter || props.model === 'table') { + const { spatialDataType, spatialDataColumn } = extractSpatialDataFromSource(source); // API supports multiple filters, we apply it only to geometry column or spatialDataColumn spatialFilters = spatialFilter @@ -98,8 +105,10 @@ export function executeModel(props) { } : undefined; - queryParams.spatialFilters = JSON.stringify(spatialFilters); - queryParams.spatialDataType = spatialDataType; + if (spatialFilters) queryParams.spatialFilters = JSON.stringify(spatialFilters); + if (spatialDataType) queryParams.spatialDataType = spatialDataType; + if (spatialDataColumn) queryParams.spatialDataColumn = spatialDataColumn; + if (spatialDataType !== 'geo') { if (source.spatialFiltersResolution !== undefined) { queryParams.spatialFiltersResolution = source.spatialFiltersResolution; diff --git a/packages/react-widgets/src/widgets/TableWidget.js b/packages/react-widgets/src/widgets/TableWidget.js index f538d8dd7..729d1d3e1 100644 --- a/packages/react-widgets/src/widgets/TableWidget.js +++ b/packages/react-widgets/src/widgets/TableWidget.js @@ -14,6 +14,8 @@ import { _FeatureFlags, _hasFeatureFlag } from '@carto/react-core'; * @param {string} props.title - Title to show in the widget header. * @param {string} props.dataSource - ID of the data source to get the data from. * @param {Column[]} props.columns - List of data columns to display. + * @param {Column[]} props.hiddenColumnFields - List of data columns to be retrieved, but not displayed. + * @param {Function=} props.onRowClick - Function to handle on click events on rows. * @param {Function=} [props.onError] - Function to handle error messages from the widget. * @param {Function=} [props.onStateChange] - Callback to handle state updates of widgets * @param {object} [props.wrapperProps] - Extra props to pass to [WrapperWidgetUI](https://storybook-react.carto.com/?path=/docs/widgets-wrapperwidgetui--default). @@ -32,10 +34,12 @@ function TableWidget({ title, dataSource, columns, + hiddenColumnFields = [], wrapperProps, noDataAlertProps, onError, onStateChange, + onRowClick, initialPageSize = 10, onPageSizeChange, global, @@ -60,7 +64,7 @@ function TableWidget({ id, dataSource, params: { - columns: columns.map((c) => c.field), + columns: [...columns.map((c) => c.field), ...hiddenColumnFields], sortBy, sortDirection, sortByColumnType, @@ -121,6 +125,7 @@ function TableWidget({ height={height} dense={dense} isLoading={isLoading} + onRowClick={onRowClick} /> )} @@ -139,6 +144,7 @@ TableWidget.propTypes = { align: PropTypes.oneOf(['left', 'right']) }) ).isRequired, + hiddenColumnFields: PropTypes.arrayOf(PropTypes.string), onError: PropTypes.func, wrapperProps: PropTypes.object, noDataAlertProps: PropTypes.object,