diff --git a/superset-frontend/cccs-viz/README.md b/superset-frontend/cccs-viz/README.md index 7cdb0dbf52b3b..1287ea012f7cf 100644 --- a/superset-frontend/cccs-viz/README.md +++ b/superset-frontend/cccs-viz/README.md @@ -113,7 +113,8 @@ Make sure to point package install dir ``` -You can test that the cccs-viz plugins will build in docker. +It's important to know that the docker-compose uses the files of the host system so you absolutely need to build your cccs-viz inside your git clone. + This will create the esm and lib files. ```bash @@ -123,7 +124,7 @@ npm install yarn build ``` -Build the frontend +The same goes for the frontend it will use those files so you need to build the frontend ``` cd superset/superset-frontend diff --git a/superset-frontend/cccs-viz/plugins/plugin-chart-hello-world/src/plugin/controlPanel.ts b/superset-frontend/cccs-viz/plugins/plugin-chart-hello-world/src/plugin/controlPanel.ts index 7c06e8853c900..91c34de50d6c6 100644 --- a/superset-frontend/cccs-viz/plugins/plugin-chart-hello-world/src/plugin/controlPanel.ts +++ b/superset-frontend/cccs-viz/plugins/plugin-chart-hello-world/src/plugin/controlPanel.ts @@ -28,10 +28,11 @@ import { ControlPanelConfig, ControlPanelsContainerProps, sections, + ControlState, } from '@superset-ui/chart-controls'; -import cidrRegex from 'cidr-regex'; +import cidrRegex from 'cidr-regex'; @@ -61,15 +62,6 @@ function isQueryMode(mode: QueryMode) { const isAggMode = isQueryMode(QueryMode.aggregate); const isRawMode = isQueryMode(QueryMode.raw); -function getDataSourceSql(controls: ControlStateMapping): QueryMode { - return controls?.datasource?.datasource?.sql; -} - -function datasourceAcceptsParam(paramType: string) { - return ({ controls }: ControlPanelsContainerProps) => getDataSourceSql(controls)?.includes(paramType); -} - -const datasourceAcceptsIpParam = datasourceAcceptsParam('_ipv4_parameter_'); const queryMode: ControlConfig<'RadioButtonControl'> = { @@ -94,7 +86,6 @@ const queryMode: ControlConfig<'RadioButtonControl'> = { - function isIP(v: unknown) { if (typeof v === 'string' && v.trim().length > 0) { //console.log(v.trim()); @@ -122,10 +113,55 @@ function validateIP(v: unknown) { } } - return ('is expected to be an ip address or cidr'); + return (' is expected to be an IP address in dotted decimal or CIDR notation'); } - +/** + * Validates the adhoc filter control. Each filter has a subject (the column name for example SRC_PORT) and a comparator (the value being tested), + * it can be a single value for operators like !=, >, <= etc + * or it can be an array of values for example when the IN or NOT IN operator is used. + * + * @param filters an array of adhoc filter with the following attributes + * @param state the current state of the adhoc filter control it includes a copy of the columns as defined in the dataset model + * @returns a string explaining the reason why the control is in an invalid state or false if there is no errors + */ +function adhocFilterValidator(filters: unknown, state: ControlState) { + if (Array.isArray(filters)) { + for (let i = 0; i < filters.length; i++) { + const filter = filters[i]; + // Find the corresponding column in the model + const column = state.columns.find((c: any) => c.column_name == filter.subject); + if (typeof column !== 'undefined' && typeof column.type !== 'undefined') { + // Currently supporting 2 types of columns + // IPV4 + // IPV4 FILTER + if (column.type.includes('IPV4')) { + const v = filter.comparator; + // check single value + if (typeof v === 'string' && v.trim().length > 0) { + const error = validateIP(v.trim()); + if (error) { + return filter.subject + error; + } + } + // check array of values + else if (Array.isArray(v)) { + for (let index = 0; index < v.length; index++) { + const element = v[index]; + const error = validateIP(element.trim()); + if (error) { + return filter.subject + error; + } + } + } + } + // else we assume the value is okay + // more type validators can be added here + } + } + } + return false; +} const config: ControlPanelConfig = { @@ -137,28 +173,6 @@ const config: ControlPanelConfig = { label: t('Query'), expanded: true, controlSetRows: [ - [ - { - name: '_ipv4_parameter_', - config: { - type: 'SelectControl', - label: t('IP Params'), - default: [], - multi: true, - allowClear: true, - freeForm: true, - allowAll: true, - tokenSeparators: [' ', ',', '\n', '\t', ';'], - validators: [validateIP], - renderTrigger: false, - description: t('The IPs or CIDRs to filter'), - visibility: datasourceAcceptsIpParam, - } - - }, - - ], - [ { name: 'query_mode', @@ -211,7 +225,14 @@ const config: ControlPanelConfig = { }, ], - ['adhoc_filters'], + [ + { + name: 'adhoc_filters', + override: { + validators: [adhocFilterValidator], + } + } + ], [ { name: 'row_limit', @@ -279,13 +300,17 @@ const config: ControlPanelConfig = { }, ], + // override controls that are inherited by the default configuration controlOverrides: { series: { validators: [validateNonEmpty], clearable: false, }, - row_limit: { - default: 100, + viz_type: { + default: 'hello_world' + }, + time_range: { + default: t('Last day'), }, }, }; diff --git a/superset-frontend/src/explore/store.js b/superset-frontend/src/explore/store.js index 9b33aaa49f6a9..9f12dc172b409 100644 --- a/superset-frontend/src/explore/store.js +++ b/superset-frontend/src/explore/store.js @@ -41,7 +41,7 @@ export function getControlsState(state, inputFormData) { * */ // Getting a list of active control names for the current viz const formData = { ...inputFormData }; - const vizType = formData.viz_type || 'table'; + const vizType = formData.viz_type || state.common.conf.DEFAULT_EXPLORER_VIZ || 'table'; handleDeprecatedControls(formData); diff --git a/superset/views/base.py b/superset/views/base.py index 69c9383ffccc1..173751b0a6439 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -74,6 +74,7 @@ "DISABLE_DATASET_SOURCE_EDIT", "ENABLE_JAVASCRIPT_CONTROLS", "DEFAULT_SQLLAB_LIMIT", + "DEFAULT_EXPLORER_VIZ", "SQL_MAX_ROW", "SUPERSET_WEBSERVER_DOMAINS", "SQLLAB_SAVE_WARNING_MESSAGE",