diff --git a/CHANGELOG.md b/CHANGELOG.md index eb0ee185..db96452d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [1.19.0] - 2024-09-17 + +### Added +- Support loading of fonts from Fusion +- Support dashboard rendering of text widgets and chart plugins + +### Changed +- Fix missing spaces in headings for `MemberFilterTile`, `Table`, and `PivotTable` +- Extend `DataPoint` types with metadata +- Fix rendering of charts without values to match Fusion +- Fix pivot table error due to invalid datetime formatting +- Improve type guards for narrowing filter types + ## [1.18.1] - 2024-09-04 ### Added @@ -11,7 +24,6 @@ ### Added - Add auto zoom feature to `DashboardWidget` -- Support forecast and trend in Fusion widgets ### Changed diff --git a/docs-md/sdk/CHANGELOG.md b/docs-md/sdk/CHANGELOG.md index eb0ee185..db96452d 100644 --- a/docs-md/sdk/CHANGELOG.md +++ b/docs-md/sdk/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [1.19.0] - 2024-09-17 + +### Added +- Support loading of fonts from Fusion +- Support dashboard rendering of text widgets and chart plugins + +### Changed +- Fix missing spaces in headings for `MemberFilterTile`, `Table`, and `PivotTable` +- Extend `DataPoint` types with metadata +- Fix rendering of charts without values to match Fusion +- Fix pivot table error due to invalid datetime formatting +- Improve type guards for narrowing filter types + ## [1.18.1] - 2024-09-04 ### Added @@ -11,7 +24,6 @@ ### Added - Add auto zoom feature to `DashboardWidget` -- Support forecast and trend in Fusion widgets ### Changed diff --git a/docs-md/sdk/guides/charts/guide-external-charts.md b/docs-md/sdk/guides/charts/guide-external-charts.md index 6c60e11e..a52b5b97 100644 --- a/docs-md/sdk/guides/charts/guide-external-charts.md +++ b/docs-md/sdk/guides/charts/guide-external-charts.md @@ -44,7 +44,7 @@ In this snippet, we’re querying the Sample ECommerce model to get total cost a ```ts import * as DM from '../../sample-ecommerce'; -import { measures } from '@sisense/sdk-data'; +import { measureFactory } from '@sisense/sdk-data'; import { QueryService } from '@sisense/sdk-ui-angular'; //... @@ -56,8 +56,8 @@ async ngOnInit(): Promise { dataSource: DM.DataSource, dimensions: [DM.Commerce.AgeRange], measures: [ - measures.sum(DM.Commerce.Cost, 'Total Cost'), - measures.sum(DM.Commerce.Revenue, 'Total Revenue'), + measureFactory.sum(DM.Commerce.Cost, 'Total Cost'), + measureFactory.sum(DM.Commerce.Revenue, 'Total Revenue'), ], }); //.. @@ -206,7 +206,7 @@ When we put the steps together, the code for populating our 3rd party chart with ```ts import { useExecuteQuery } from '@sisense/sdk-ui'; import * as DM from '../sample-ecommerce'; -import { measures } from '@sisense/sdk-data'; +import { measureFactory } from '@sisense/sdk-data'; import Plot from 'react-plotly.js'; @@ -215,7 +215,7 @@ function MyPlotlyChart() { const { data, isLoading, isError } = useExecuteQuery({ dataSource: DM.DataSource, dimensions: [DM.Commerce.AgeRange], - measures: [measures.sum(DM.Commerce.Cost, 'Total Cost'), measures.sum(DM.Commerce.Revenue, 'Total Revenue')], + measures: [measureFactory.sum(DM.Commerce.Cost, 'Total Cost'), measureFactory.sum(DM.Commerce.Revenue, 'Total Revenue')], }); if (isLoading) { @@ -273,7 +273,7 @@ export default MyPlotlyChart; ```ts import { Component } from '@angular/core'; import * as DM from '../../sample-ecommerce'; -import { measures } from '@sisense/sdk-data'; +import { measureFactory } from '@sisense/sdk-data'; import { QueryService } from '@sisense/sdk-ui-angular'; import { PlotData } from 'plotly.js-dist-min'; @@ -293,8 +293,8 @@ export class AnalyticsComponent { dataSource: DM.DataSource, dimensions: [DM.Commerce.AgeRange], measures: [ - measures.sum(DM.Commerce.Cost, 'Total Cost'), - measures.sum(DM.Commerce.Revenue, 'Total Revenue'), + measureFactory.sum(DM.Commerce.Cost, 'Total Cost'), + measureFactory.sum(DM.Commerce.Revenue, 'Total Revenue'), ], }); diff --git a/docs-md/sdk/guides/migration-guide-1.0.0.md b/docs-md/sdk/guides/migration-guide-1.0.0.md index 8e023fef..b393c407 100644 --- a/docs-md/sdk/guides/migration-guide-1.0.0.md +++ b/docs-md/sdk/guides/migration-guide-1.0.0.md @@ -207,8 +207,8 @@ AFTER { ( { data, isLoading, isError } ) => { diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.bottomRanking.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.bottomRanking.md index 48caac15..c53c7f0d 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.bottomRanking.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.bottomRanking.md @@ -31,7 +31,7 @@ Filter for age ranges with the bottom 3 lowest total revenue in the Sample EComm ```ts filterFactory.bottomRanking( DM.Commerce.AgeRange, - measures.sum(DM.Commerce.Revenue), + measureFactory.sum(DM.Commerce.Revenue), 3 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetween.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetween.md index 83d329e8..376707c4 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetween.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetween.md @@ -31,7 +31,7 @@ Filter for categories that have an average revenue greater than or equal to 50 a or equal to 100 in the Sample ECommerce data model. ```ts filterFactory.measureBetween( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 50, 100 ) diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetweenNotEqual.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetweenNotEqual.md index eca33368..2d227c98 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetweenNotEqual.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureBetweenNotEqual.md @@ -31,7 +31,7 @@ Filter for categories that have an average revenue greater than 50 and less than 100 in the Sample ECommerce data model. ```ts filterFactory.measureBetweenNotEqual( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 50, 100 ) diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureEquals.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureEquals.md index 78f342ab..e3945dfa 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureEquals.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureEquals.md @@ -26,7 +26,7 @@ A filter instance Filter for categories that have an average revenue equal 50 in the Sample ECommerce data model. ```ts filterFactory.measureEquals( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 50 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThan.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThan.md index 3e147168..74d13212 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThan.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThan.md @@ -27,7 +27,7 @@ Filter for categories that have an average revenue greater than to 50 in the Sample ECommerce data model. ```ts filterFactory.measureGreaterThan( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 50 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThanOrEqual.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThanOrEqual.md index bad38e1c..57d55915 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThanOrEqual.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureGreaterThanOrEqual.md @@ -27,7 +27,7 @@ Filter for categories that have an average revenue greater than or equal to 50 in the Sample ECommerce data model. ```ts filterFactory.measureGreaterThanOrEqual( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 50 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThan.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThan.md index a63d3db7..1b89d3a5 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThan.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThan.md @@ -26,7 +26,7 @@ A filter instance Filter for categories that have an average revenue less than 100 in the Sample ECommerce data model. ```ts filterFactory.measureLessThan( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 100 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThanOrEqual.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThanOrEqual.md index 0b3eccc9..19c47d0a 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThanOrEqual.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.measureLessThanOrEqual.md @@ -27,7 +27,7 @@ Filter for categories that have an average revenue less than or equal to 100 in the Sample ECommerce data model. ```ts filterFactory.measureLessThanOrEqual( - measures.average(DM.Commerce.Revenue), + measureFactory.average(DM.Commerce.Revenue), 100 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.topRanking.md b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.topRanking.md index 0238a2ba..0c7d2617 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.topRanking.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.filterFactory/functions/function.topRanking.md @@ -31,7 +31,7 @@ Filter for age ranges with the top 3 highest total revenue in the Sample ECommer ```ts filterFactory.topRanking( DM.Commerce.AgeRange, - measures.sum(DM.Commerce.Revenue), + measureFactory.sum(DM.Commerce.Revenue), 3 ) ``` diff --git a/docs-md/sdk/modules/sdk-data/factories/namespace.measureFactory/functions/function.measuredValue.md b/docs-md/sdk/modules/sdk-data/factories/namespace.measureFactory/functions/function.measuredValue.md index 3c3acc35..9af2b39b 100644 --- a/docs-md/sdk/modules/sdk-data/factories/namespace.measureFactory/functions/function.measuredValue.md +++ b/docs-md/sdk/modules/sdk-data/factories/namespace.measureFactory/functions/function.measuredValue.md @@ -41,7 +41,7 @@ where the cost is greater than 100. Additional filtering on the cost will not af ```ts measureFactory.measuredValue( measureFactory.sum(DM.Commerce.Cost), - [filters.greaterThan(DM.Commerce.Cost, 100)], + [filterFactory.greaterThan(DM.Commerce.Cost, 100)], 'Cost Greater Than 100' ), ``` diff --git a/docs-md/sdk/modules/sdk-data/interfaces/interface.Filter.md b/docs-md/sdk/modules/sdk-data/interfaces/interface.Filter.md index 3ca0d1af..b78cafc3 100644 --- a/docs-md/sdk/modules/sdk-data/interfaces/interface.Filter.md +++ b/docs-md/sdk/modules/sdk-data/interfaces/interface.Filter.md @@ -16,6 +16,14 @@ Attribute this filter instance is filtering *** +### filterType + +> **`readonly`** **filterType**: `string` + +Filter type + +*** + ### guid > **`readonly`** **guid**: `string` diff --git a/docs-md/sdk/modules/sdk-data/type-aliases/index.md b/docs-md/sdk/modules/sdk-data/type-aliases/index.md index aa128850..17289ca8 100644 --- a/docs-md/sdk/modules/sdk-data/type-aliases/index.md +++ b/docs-md/sdk/modules/sdk-data/type-aliases/index.md @@ -4,6 +4,7 @@ title: Type Aliases # Type Aliases +- [AnyObject](type-alias.AnyObject.md) - [DataSource](type-alias.DataSource.md) - [DataSourceInfo](type-alias.DataSourceInfo.md) - [FilterRelationsJaqlIdNode](type-alias.FilterRelationsJaqlIdNode.md) diff --git a/docs-md/sdk/modules/sdk-data/type-aliases/type-alias.AnyObject.md b/docs-md/sdk/modules/sdk-data/type-aliases/type-alias.AnyObject.md new file mode 100644 index 00000000..9e9ca0e3 --- /dev/null +++ b/docs-md/sdk/modules/sdk-data/type-aliases/type-alias.AnyObject.md @@ -0,0 +1,9 @@ +--- +title: AnyObject +--- + +# Type alias AnyObject + +> **AnyObject**: `Record`\< `string`, `any` \> + +Abstract object with any unknown values diff --git a/docs-md/sdk/modules/sdk-ui-angular/fusion-embed/class.WidgetModel.md b/docs-md/sdk/modules/sdk-ui-angular/fusion-embed/class.WidgetModel.md index e453ab2b..d055350e 100644 --- a/docs-md/sdk/modules/sdk-ui-angular/fusion-embed/class.WidgetModel.md +++ b/docs-md/sdk/modules/sdk-ui-angular/fusion-embed/class.WidgetModel.md @@ -134,6 +134,29 @@ Note: this method is not supported for chart and pivot widgets. Use [getChartProps](class.WidgetModel.md#getchartprops) instead for getting props for the `` component. Use [getPivotTableProps](class.WidgetModel.md#getpivottableprops) instead for getting props for the `` component. +*** + +### getTextWidgetProps + +> **getTextWidgetProps**(): [`TextWidgetProps`](../../sdk-ui/type-aliases/type-alias.TextWidgetProps.md) + +Returns the props to be used for rendering a text widget. + +#### Returns + +[`TextWidgetProps`](../../sdk-ui/type-aliases/type-alias.TextWidgetProps.md) + +#### Example + +```ts + +``` + +Note: this method is not supported for chart, table, or pivot widgets. +Use [getChartWidgetProps](class.WidgetModel.md#getchartwidgetprops) instead for getting props for the `` component. +Use getTableWidgetProps instead for getting props for the `` component. +Use getPivotTableWidgetProps instead for getting props for the `` component. + ## Properties ### chartType diff --git a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.BoxplotDataPoint.md b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.BoxplotDataPoint.md index 6ab67a84..63e506cc 100644 --- a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.BoxplotDataPoint.md +++ b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.BoxplotDataPoint.md @@ -12,7 +12,7 @@ Data point in a Boxplot chart. ### `boxMax` -**boxMax**: `number` +**boxMax**?: `number` Value of the box maximum @@ -20,7 +20,7 @@ Value of the box maximum ### `boxMedian` -**boxMedian**: `number` +**boxMedian**?: `number` Value of the box median @@ -28,7 +28,7 @@ Value of the box median ### `boxMin` -**boxMin**: `number` +**boxMin**?: `number` Value of the box minimum @@ -50,9 +50,17 @@ Value of the category for the data point *** +### `outlier` + +**outlier**?: `number` + +Value of the outlier + +*** + ### `whiskerMax` -**whiskerMax**: `number` +**whiskerMax**?: `number` Value of the box maximal whisker @@ -60,6 +68,6 @@ Value of the box maximal whisker ### `whiskerMin` -**whiskerMin**: `number` +**whiskerMin**?: `number` Value of the box minimal whisker diff --git a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.Navigator.md b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.Navigator.md index 5429fb69..d1d462b8 100644 --- a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.Navigator.md +++ b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.Navigator.md @@ -20,4 +20,16 @@ Boolean flag that defines if navigator should be shown on the chart ### `scrollerLocation` -**scrollerLocation**?: [`AutoZoomNavigatorScrollerLocation`](../../sdk-ui/type-aliases/type-alias.AutoZoomNavigatorScrollerLocation.md) +**scrollerLocation**?: `object` + +The scroll location of the navigator scroller / auto zoom feature + +> #### `scrollerLocation.max` +> +> **max**: `number` +> +> #### `scrollerLocation.min` +> +> **min**: `number` +> +> diff --git a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetDataOptions.md b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetDataOptions.md index c0842259..bb1c9dfd 100644 --- a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetDataOptions.md +++ b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetDataOptions.md @@ -4,6 +4,6 @@ title: WidgetDataOptions # Type alias WidgetDataOptions -> **WidgetDataOptions**: [`ChartDataOptions`](type-alias.ChartDataOptions.md) \| [`PivotTableDataOptions`](../interfaces/interface.PivotTableDataOptions.md) +> **WidgetDataOptions**: [`ChartDataOptions`](type-alias.ChartDataOptions.md) \| [`PivotTableDataOptions`](../interfaces/interface.PivotTableDataOptions.md) \| [`EmptyObject`](../../sdk-ui/type-aliases/type-alias.EmptyObject.md) Widget data options. diff --git a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetStyleOptions.md b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetStyleOptions.md index 84dbc0f6..5a73639a 100644 --- a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetStyleOptions.md @@ -4,6 +4,6 @@ title: WidgetStyleOptions # Type alias WidgetStyleOptions -> **WidgetStyleOptions**: [`ChartStyleOptions`](type-alias.ChartStyleOptions.md) \| [`TableStyleOptions`](../interfaces/interface.TableStyleOptions.md) & [`WidgetContainerStyleOptions`](../../sdk-ui/interfaces/interface.WidgetContainerStyleOptions.md) +> **WidgetStyleOptions**: [`ChartStyleOptions`](type-alias.ChartStyleOptions.md) \| [`TableStyleOptions`](../interfaces/interface.TableStyleOptions.md) \| [`TextWidgetStyleOptions`](../../sdk-ui/type-aliases/type-alias.TextWidgetStyleOptions.md) & [`WidgetContainerStyleOptions`](../../sdk-ui/interfaces/interface.WidgetContainerStyleOptions.md) Complete set of configuration options that define functional style of the various elements of the charts as well as the look and feel of widget itself and widget header. diff --git a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetType.md b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetType.md index 851a2e87..0d9f3c10 100644 --- a/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetType.md +++ b/docs-md/sdk/modules/sdk-ui-angular/type-aliases/type-alias.WidgetType.md @@ -4,6 +4,6 @@ title: WidgetType # Type alias WidgetType -> **WidgetType**: [`CartesianWidgetType`](type-alias.CartesianWidgetType.md) \| [`CategoricalWidgetType`](type-alias.CategoricalWidgetType.md) \| `"chart/scatter"` \| `"indicator"` \| [`TabularWidgetType`](type-alias.TabularWidgetType.md) \| `"chart/boxplot"` \| `"map/scatter"` \| `"map/area"` \| `"plugin"` +> **WidgetType**: [`CartesianWidgetType`](type-alias.CartesianWidgetType.md) \| [`CategoricalWidgetType`](type-alias.CategoricalWidgetType.md) \| `"chart/scatter"` \| `"indicator"` \| [`TabularWidgetType`](type-alias.TabularWidgetType.md) \| `"chart/boxplot"` \| `"map/scatter"` \| `"map/area"` \| [`TextWidgetType`](../../sdk-ui/type-aliases/type-alias.TextWidgetType.md) \| `"plugin"` The type of a widget on a dashboard. diff --git a/docs-md/sdk/modules/sdk-ui-vue/fusion-embed/class.WidgetModel.md b/docs-md/sdk/modules/sdk-ui-vue/fusion-embed/class.WidgetModel.md index e2133701..b267ea31 100644 --- a/docs-md/sdk/modules/sdk-ui-vue/fusion-embed/class.WidgetModel.md +++ b/docs-md/sdk/modules/sdk-ui-vue/fusion-embed/class.WidgetModel.md @@ -134,6 +134,29 @@ Note: this method is not supported for chart and pivot widgets. Use [getChartProps](class.WidgetModel.md#getchartprops) instead for getting props for the `` component. Use [getPivotTableProps](class.WidgetModel.md#getpivottableprops) instead for getting props for the `` component. +*** + +### getTextWidgetProps + +> **getTextWidgetProps**(): [`TextWidgetProps`](../../sdk-ui/type-aliases/type-alias.TextWidgetProps.md) + +Returns the props to be used for rendering a text widget. + +#### Returns + +[`TextWidgetProps`](../../sdk-ui/type-aliases/type-alias.TextWidgetProps.md) + +#### Example + +```ts + +``` + +Note: this method is not supported for chart, table, or pivot widgets. +Use [getChartWidgetProps](class.WidgetModel.md#getchartwidgetprops) instead for getting props for the `` component. +Use getTableWidgetProps instead for getting props for the `` component. +Use getPivotTableWidgetProps instead for getting props for the `` component. + ## Properties ### chartType diff --git a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.BoxplotDataPoint.md b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.BoxplotDataPoint.md index 6ab67a84..63e506cc 100644 --- a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.BoxplotDataPoint.md +++ b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.BoxplotDataPoint.md @@ -12,7 +12,7 @@ Data point in a Boxplot chart. ### `boxMax` -**boxMax**: `number` +**boxMax**?: `number` Value of the box maximum @@ -20,7 +20,7 @@ Value of the box maximum ### `boxMedian` -**boxMedian**: `number` +**boxMedian**?: `number` Value of the box median @@ -28,7 +28,7 @@ Value of the box median ### `boxMin` -**boxMin**: `number` +**boxMin**?: `number` Value of the box minimum @@ -50,9 +50,17 @@ Value of the category for the data point *** +### `outlier` + +**outlier**?: `number` + +Value of the outlier + +*** + ### `whiskerMax` -**whiskerMax**: `number` +**whiskerMax**?: `number` Value of the box maximal whisker @@ -60,6 +68,6 @@ Value of the box maximal whisker ### `whiskerMin` -**whiskerMin**: `number` +**whiskerMin**?: `number` Value of the box minimal whisker diff --git a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.Navigator.md b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.Navigator.md index 5429fb69..d1d462b8 100644 --- a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.Navigator.md +++ b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.Navigator.md @@ -20,4 +20,16 @@ Boolean flag that defines if navigator should be shown on the chart ### `scrollerLocation` -**scrollerLocation**?: [`AutoZoomNavigatorScrollerLocation`](../../sdk-ui/type-aliases/type-alias.AutoZoomNavigatorScrollerLocation.md) +**scrollerLocation**?: `object` + +The scroll location of the navigator scroller / auto zoom feature + +> #### `scrollerLocation.max` +> +> **max**: `number` +> +> #### `scrollerLocation.min` +> +> **min**: `number` +> +> diff --git a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetDataOptions.md b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetDataOptions.md index c0842259..bb1c9dfd 100644 --- a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetDataOptions.md +++ b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetDataOptions.md @@ -4,6 +4,6 @@ title: WidgetDataOptions # Type alias WidgetDataOptions -> **WidgetDataOptions**: [`ChartDataOptions`](type-alias.ChartDataOptions.md) \| [`PivotTableDataOptions`](../interfaces/interface.PivotTableDataOptions.md) +> **WidgetDataOptions**: [`ChartDataOptions`](type-alias.ChartDataOptions.md) \| [`PivotTableDataOptions`](../interfaces/interface.PivotTableDataOptions.md) \| [`EmptyObject`](../../sdk-ui/type-aliases/type-alias.EmptyObject.md) Widget data options. diff --git a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetStyleOptions.md b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetStyleOptions.md index 84dbc0f6..5a73639a 100644 --- a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetStyleOptions.md @@ -4,6 +4,6 @@ title: WidgetStyleOptions # Type alias WidgetStyleOptions -> **WidgetStyleOptions**: [`ChartStyleOptions`](type-alias.ChartStyleOptions.md) \| [`TableStyleOptions`](../interfaces/interface.TableStyleOptions.md) & [`WidgetContainerStyleOptions`](../../sdk-ui/interfaces/interface.WidgetContainerStyleOptions.md) +> **WidgetStyleOptions**: [`ChartStyleOptions`](type-alias.ChartStyleOptions.md) \| [`TableStyleOptions`](../interfaces/interface.TableStyleOptions.md) \| [`TextWidgetStyleOptions`](../../sdk-ui/type-aliases/type-alias.TextWidgetStyleOptions.md) & [`WidgetContainerStyleOptions`](../../sdk-ui/interfaces/interface.WidgetContainerStyleOptions.md) Complete set of configuration options that define functional style of the various elements of the charts as well as the look and feel of widget itself and widget header. diff --git a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetType.md b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetType.md index 851a2e87..0d9f3c10 100644 --- a/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetType.md +++ b/docs-md/sdk/modules/sdk-ui-vue/type-aliases/type-alias.WidgetType.md @@ -4,6 +4,6 @@ title: WidgetType # Type alias WidgetType -> **WidgetType**: [`CartesianWidgetType`](type-alias.CartesianWidgetType.md) \| [`CategoricalWidgetType`](type-alias.CategoricalWidgetType.md) \| `"chart/scatter"` \| `"indicator"` \| [`TabularWidgetType`](type-alias.TabularWidgetType.md) \| `"chart/boxplot"` \| `"map/scatter"` \| `"map/area"` \| `"plugin"` +> **WidgetType**: [`CartesianWidgetType`](type-alias.CartesianWidgetType.md) \| [`CategoricalWidgetType`](type-alias.CategoricalWidgetType.md) \| `"chart/scatter"` \| `"indicator"` \| [`TabularWidgetType`](type-alias.TabularWidgetType.md) \| `"chart/boxplot"` \| `"map/scatter"` \| `"map/area"` \| [`TextWidgetType`](../../sdk-ui/type-aliases/type-alias.TextWidgetType.md) \| `"plugin"` The type of a widget on a dashboard. diff --git a/docs-md/sdk/modules/sdk-ui/fusion-embed/class.WidgetModel.md b/docs-md/sdk/modules/sdk-ui/fusion-embed/class.WidgetModel.md index a6577903..7ea1641e 100644 --- a/docs-md/sdk/modules/sdk-ui/fusion-embed/class.WidgetModel.md +++ b/docs-md/sdk/modules/sdk-ui/fusion-embed/class.WidgetModel.md @@ -134,6 +134,29 @@ Note: this method is not supported for chart and pivot widgets. Use [getChartProps](class.WidgetModel.md#getchartprops) instead for getting props for the `` component. Use [getPivotTableProps](class.WidgetModel.md#getpivottableprops) instead for getting props for the `` component. +*** + +### getTextWidgetProps + +> **getTextWidgetProps**(): [`TextWidgetProps`](../type-aliases/type-alias.TextWidgetProps.md) + +Returns the props to be used for rendering a text widget. + +#### Returns + +[`TextWidgetProps`](../type-aliases/type-alias.TextWidgetProps.md) + +#### Example + +```ts + +``` + +Note: this method is not supported for chart, table, or pivot widgets. +Use [getChartWidgetProps](class.WidgetModel.md#getchartwidgetprops) instead for getting props for the `` component. +Use getTableWidgetProps instead for getting props for the `` component. +Use getPivotTableWidgetProps instead for getting props for the `` component. + ## Properties ### chartType @@ -202,7 +225,7 @@ Unique identifier of the widget. ### styleOptions -> **styleOptions**: [`WidgetStyleOptions`](../type-aliases/type-alias.WidgetStyleOptions.md) +> **styleOptions**: `ChartStyleOptions | TextWidgetStyleOptions` & [`WidgetContainerStyleOptions`](../interfaces/interface.WidgetContainerStyleOptions.md) Widget style options. diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/index.md b/docs-md/sdk/modules/sdk-ui/interfaces/index.md index 64dd13ce..0bc04885 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/index.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/index.md @@ -42,6 +42,7 @@ TypeScript interfaces for components and hooks listed above - [ExecuteQueryByWidgetIdProps](interface.ExecuteQueryByWidgetIdProps.md) - [ExecuteQueryParams](interface.ExecuteQueryParams.md) - [ExecuteQueryProps](interface.ExecuteQueryProps.md) +- [FontsLoaderSettings](interface.FontsLoaderSettings.md) - [FunnelChartProps](interface.FunnelChartProps.md) - [FunnelStyleOptions](interface.FunnelStyleOptions.md) - [GaugeIndicatorStyleOptions](interface.GaugeIndicatorStyleOptions.md) @@ -89,6 +90,7 @@ TypeScript interfaces for components and hooks listed above - [TableProps](interface.TableProps.md) - [TableStyleOptions](interface.TableStyleOptions.md) - [ThemeSettings](interface.ThemeSettings.md) +- [ThemeSettingsFont](interface.ThemeSettingsFont.md) - [TreemapChartProps](interface.TreemapChartProps.md) - [TreemapStyleOptions](interface.TreemapStyleOptions.md) - [TypographyThemeSettings](interface.TypographyThemeSettings.md) diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.FontsLoaderSettings.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.FontsLoaderSettings.md new file mode 100644 index 00000000..c4944ed9 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.FontsLoaderSettings.md @@ -0,0 +1,15 @@ +--- +title: FontsLoaderSettings +--- + +# Interface FontsLoaderSettings + +Settings for fonts loading + +## Properties + +### fonts + +> **fonts**: [`ThemeSettingsFont`](interface.ThemeSettingsFont.md)[] + +List of fonts diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.NumericSimpleIndicatorStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.NumericSimpleIndicatorStyleOptions.md index 3d8b6a96..eb2f8ad1 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.NumericSimpleIndicatorStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.NumericSimpleIndicatorStyleOptions.md @@ -30,7 +30,7 @@ Boolean flag to force render indicator in ticker mode regardless of display size ### skin -> **skin**: `"vertical"` \| `"horizontal"` +> **skin**: `"horizontal"` \| `"vertical"` *** diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettingsFont.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettingsFont.md new file mode 100644 index 00000000..f7c377a5 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettingsFont.md @@ -0,0 +1,31 @@ +--- +title: ThemeSettingsFont +--- + +# Interface ThemeSettingsFont + +Loading font details + +## Properties + +### fontFamily + +> **fontFamily**: `string` + +*** + +### fontStyle + +> **fontStyle**: `string` + +*** + +### fontWeight + +> **fontWeight**: `string` \| `number` + +*** + +### src + +> **src**: [`ThemeSettingsFontSource`](../type-aliases/type-alias.ThemeSettingsFontSource.md)[] diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.TypographyThemeSettings.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.TypographyThemeSettings.md index aeedbdd8..daabd0b6 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.TypographyThemeSettings.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.TypographyThemeSettings.md @@ -16,6 +16,14 @@ Font family name to style component text *** +### fontsLoader + +> **fontsLoader**?: [`FontsLoaderSettings`](interface.FontsLoaderSettings.md) + +Settings for font loading + +*** + ### primaryTextColor > **primaryTextColor**?: `string` diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/index.md b/docs-md/sdk/modules/sdk-ui/type-aliases/index.md index d3b050ca..4fb2e4da 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/index.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/index.md @@ -73,6 +73,7 @@ TypeScript type aliases for components and hooks listed above - [DrilldownOptions](type-alias.DrilldownOptions.md) - [DrilldownSelection](type-alias.DrilldownSelection.md) - [DrilldownWidgetConfig](type-alias.DrilldownWidgetConfig.md) +- [EmptyObject](type-alias.EmptyObject.md) - [ExecuteCSVQueryConfig](type-alias.ExecuteCSVQueryConfig.md) - [ExecuteQueryResult](type-alias.ExecuteQueryResult.md) - [FilterThemeSettings](type-alias.FilterThemeSettings.md) @@ -146,8 +147,12 @@ TypeScript type aliases for components and hooks listed above - [TabularChartDataOptions](type-alias.TabularChartDataOptions.md) - [TabularChartStyleOptions](type-alias.TabularChartStyleOptions.md) - [TabularWidgetType](type-alias.TabularWidgetType.md) +- [TextWidgetProps](type-alias.TextWidgetProps.md) +- [TextWidgetStyleOptions](type-alias.TextWidgetStyleOptions.md) +- [TextWidgetType](type-alias.TextWidgetType.md) - [ThemeOid](type-alias.ThemeOid.md) - [ThemeProviderProps](type-alias.ThemeProviderProps.md) +- [ThemeSettingsFontSource](type-alias.ThemeSettingsFontSource.md) - [UniformDataColorOptions](type-alias.UniformDataColorOptions.md) - [UseQueryResult](type-alias.UseQueryResult.md) - [ValueToColorMap](type-alias.ValueToColorMap.md) diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.AreamapDataPoint.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.AreamapDataPoint.md index 2357704c..c26636fb 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.AreamapDataPoint.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.AreamapDataPoint.md @@ -4,6 +4,6 @@ title: AreamapDataPoint # Type alias AreamapDataPoint -> **AreamapDataPoint**: [`GeoDataElement`](type-alias.GeoDataElement.md) +> **AreamapDataPoint**: [`GeoDataElement`](type-alias.GeoDataElement.md) & \{} Data point in an Areamap chart. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.BoxplotDataPoint.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.BoxplotDataPoint.md index 6ab67a84..63e506cc 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.BoxplotDataPoint.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.BoxplotDataPoint.md @@ -12,7 +12,7 @@ Data point in a Boxplot chart. ### `boxMax` -**boxMax**: `number` +**boxMax**?: `number` Value of the box maximum @@ -20,7 +20,7 @@ Value of the box maximum ### `boxMedian` -**boxMedian**: `number` +**boxMedian**?: `number` Value of the box median @@ -28,7 +28,7 @@ Value of the box median ### `boxMin` -**boxMin**: `number` +**boxMin**?: `number` Value of the box minimum @@ -50,9 +50,17 @@ Value of the category for the data point *** +### `outlier` + +**outlier**?: `number` + +Value of the outlier + +*** + ### `whiskerMax` -**whiskerMax**: `number` +**whiskerMax**?: `number` Value of the box maximal whisker @@ -60,6 +68,6 @@ Value of the box maximal whisker ### `whiskerMin` -**whiskerMin**: `number` +**whiskerMin**?: `number` Value of the box minimal whisker diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CartesianChartType.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CartesianChartType.md index 94624eb6..1225596e 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CartesianChartType.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CartesianChartType.md @@ -4,6 +4,6 @@ title: CartesianChartType # Type alias CartesianChartType -> **CartesianChartType**: `"line" | "bar" | "area" | "column" | "polar"` +> **CartesianChartType**: `"line" | "area" | "bar" | "column" | "polar"` Cartesian family of chart types diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CategoricalChartType.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CategoricalChartType.md index e6514e36..ffef3c3c 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CategoricalChartType.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CategoricalChartType.md @@ -4,6 +4,6 @@ title: CategoricalChartType # Type alias CategoricalChartType -> **CategoricalChartType**: `"treemap" | "sunburst" | "pie" | "funnel"` +> **CategoricalChartType**: `"pie" | "funnel" | "treemap" | "sunburst"` Categorical family of chart types diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoint.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoint.md index db0de498..e47b2adf 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoint.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoint.md @@ -4,6 +4,6 @@ title: ChartDataPoint # Type alias ChartDataPoint -> **ChartDataPoint**: [`DataPoint`](type-alias.DataPoint.md) \| [`ScatterDataPoint`](type-alias.ScatterDataPoint.md) \| [`BoxplotDataPoint`](type-alias.BoxplotDataPoint.md) \| [`AreamapDataPoint`](type-alias.AreamapDataPoint.md) +> **ChartDataPoint**: [`DataPoint`](type-alias.DataPoint.md) \| [`ScatterDataPoint`](type-alias.ScatterDataPoint.md) \| [`BoxplotDataPoint`](type-alias.BoxplotDataPoint.md) \| [`AreamapDataPoint`](type-alias.AreamapDataPoint.md) \| [`ScattermapDataPoint`](type-alias.ScattermapDataPoint.md) Abstract data point in a chart - union of all types of data points. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoints.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoints.md index 7db1e94e..b702323a 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoints.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ChartDataPoints.md @@ -4,6 +4,6 @@ title: ChartDataPoints # Type alias ChartDataPoints -> **ChartDataPoints**: [`DataPoint`](type-alias.DataPoint.md)[] \| [`ScatterDataPoint`](type-alias.ScatterDataPoint.md)[] \| [`BoxplotDataPoint`](type-alias.BoxplotDataPoint.md)[] \| [`AreamapDataPoint`](type-alias.AreamapDataPoint.md)[] +> **ChartDataPoints**: [`DataPoint`](type-alias.DataPoint.md)[] \| [`ScatterDataPoint`](type-alias.ScatterDataPoint.md)[] \| [`BoxplotDataPoint`](type-alias.BoxplotDataPoint.md)[] \| [`AreamapDataPoint`](type-alias.AreamapDataPoint.md)[] \| [`ScattermapDataPoint`](type-alias.ScattermapDataPoint.md)[] Data points in a chart. Array of data points of the same data point type. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.EmptyObject.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.EmptyObject.md new file mode 100644 index 00000000..94f70a9b --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.EmptyObject.md @@ -0,0 +1,9 @@ +--- +title: EmptyObject +--- + +# Type alias EmptyObject + +> **EmptyObject**: `Record`\< `string`, `never` \> + +Empty object with no properties diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.Navigator.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.Navigator.md index ec7637a2..d1d462b8 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.Navigator.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.Navigator.md @@ -20,4 +20,16 @@ Boolean flag that defines if navigator should be shown on the chart ### `scrollerLocation` -**scrollerLocation**?: [`AutoZoomNavigatorScrollerLocation`](type-alias.AutoZoomNavigatorScrollerLocation.md) +**scrollerLocation**?: `object` + +The scroll location of the navigator scroller / auto zoom feature + +> #### `scrollerLocation.max` +> +> **max**: `number` +> +> #### `scrollerLocation.min` +> +> **min**: `number` +> +> diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetProps.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetProps.md new file mode 100644 index 00000000..1ac66334 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetProps.md @@ -0,0 +1,17 @@ +--- +title: TextWidgetProps +--- + +# Type alias TextWidgetProps + +> **TextWidgetProps**: `object` + +Props for the TextWidget component. + +## Type declaration + +### `styleOptions` + +**styleOptions**: [`TextWidgetStyleOptions`](type-alias.TextWidgetStyleOptions.md) + +Style options for the text widget. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetStyleOptions.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetStyleOptions.md new file mode 100644 index 00000000..c799a7ed --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetStyleOptions.md @@ -0,0 +1,27 @@ +--- +title: TextWidgetStyleOptions +--- + +# Type alias TextWidgetStyleOptions + +> **TextWidgetStyleOptions**: `object` + +Style settings defining the look and feel of TextWidget + +## Type declaration + +### `bgColor` + +**bgColor**: `string` + +*** + +### `html` + +**html**: `string` + +*** + +### `vAlign` + +**vAlign**: \`valign-$\{"middle" \| "top" \| "bottom"}\` diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetType.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetType.md new file mode 100644 index 00000000..96770043 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.TextWidgetType.md @@ -0,0 +1,9 @@ +--- +title: TextWidgetType +--- + +# Type alias TextWidgetType + +> **TextWidgetType**: `"richtexteditor"` + +The type of a widget on a dashboard that is a variant of text widget. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ThemeSettingsFontSource.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ThemeSettingsFontSource.md new file mode 100644 index 00000000..aa830161 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ThemeSettingsFontSource.md @@ -0,0 +1,14 @@ +--- +title: ThemeSettingsFontSource +--- + +# Type alias ThemeSettingsFontSource + +> **ThemeSettingsFontSource**: \{ + `local`: `string`; + } \| \{ + `url`: `string`; + } \| \{ + `format`: `string`; + `url`: `string`; + } diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetDataOptions.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetDataOptions.md index c0842259..84f15140 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetDataOptions.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetDataOptions.md @@ -4,6 +4,6 @@ title: WidgetDataOptions # Type alias WidgetDataOptions -> **WidgetDataOptions**: [`ChartDataOptions`](type-alias.ChartDataOptions.md) \| [`PivotTableDataOptions`](../interfaces/interface.PivotTableDataOptions.md) +> **WidgetDataOptions**: [`ChartDataOptions`](type-alias.ChartDataOptions.md) \| [`PivotTableDataOptions`](../interfaces/interface.PivotTableDataOptions.md) \| [`EmptyObject`](type-alias.EmptyObject.md) Widget data options. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetStyleOptions.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetStyleOptions.md index 5e01faea..f47ff94f 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetStyleOptions.md @@ -4,6 +4,6 @@ title: WidgetStyleOptions # Type alias WidgetStyleOptions -> **WidgetStyleOptions**: [`ChartStyleOptions`](type-alias.ChartStyleOptions.md) \| [`TableStyleOptions`](../interfaces/interface.TableStyleOptions.md) & [`WidgetContainerStyleOptions`](../interfaces/interface.WidgetContainerStyleOptions.md) +> **WidgetStyleOptions**: [`ChartStyleOptions`](type-alias.ChartStyleOptions.md) \| [`TableStyleOptions`](../interfaces/interface.TableStyleOptions.md) \| [`TextWidgetStyleOptions`](type-alias.TextWidgetStyleOptions.md) & [`WidgetContainerStyleOptions`](../interfaces/interface.WidgetContainerStyleOptions.md) Complete set of configuration options that define functional style of the various elements of the charts as well as the look and feel of widget itself and widget header. diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetType.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetType.md index 851a2e87..0e33db40 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetType.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.WidgetType.md @@ -4,6 +4,6 @@ title: WidgetType # Type alias WidgetType -> **WidgetType**: [`CartesianWidgetType`](type-alias.CartesianWidgetType.md) \| [`CategoricalWidgetType`](type-alias.CategoricalWidgetType.md) \| `"chart/scatter"` \| `"indicator"` \| [`TabularWidgetType`](type-alias.TabularWidgetType.md) \| `"chart/boxplot"` \| `"map/scatter"` \| `"map/area"` \| `"plugin"` +> **WidgetType**: [`CartesianWidgetType`](type-alias.CartesianWidgetType.md) \| [`CategoricalWidgetType`](type-alias.CategoricalWidgetType.md) \| `"chart/scatter"` \| `"indicator"` \| [`TabularWidgetType`](type-alias.TabularWidgetType.md) \| `"chart/boxplot"` \| `"map/scatter"` \| `"map/area"` \| [`TextWidgetType`](type-alias.TextWidgetType.md) \| `"plugin"` The type of a widget on a dashboard. diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_area-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_area-chart.png index ce2680a2..f39ba458 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_area-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_area-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_bar-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_bar-chart.png index 34218604..2666a05a 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_bar-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_bar-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_boxplot-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_boxplot-chart.png index 5bd68b2a..98d4be3f 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_boxplot-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_boxplot-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_column-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_column-chart.png index 18f6a155..a24dc05a 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_column-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_column-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_line-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_line-chart.png index 71129690..a9a6fe0e 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_line-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_line-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_pie-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_pie-chart.png index 096439cf..1876db91 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_pie-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_pie-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_polar-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_polar-chart.png index d889ee37..2829870a 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_polar-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_polar-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_scatter-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_scatter-chart.png index 44d0d244..747c834d 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_scatter-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_scatter-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_sunburst-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_sunburst-chart.png index a625c831..44995dea 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_sunburst-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_sunburst-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_treemap-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_treemap-chart.png index 8d21acf5..c5a80a38 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_treemap-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-dark-mode_treemap-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_area-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_area-chart.png index 8a3697e7..2c641401 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_area-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_area-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_bar-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_bar-chart.png index f22e848d..9b0cd265 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_bar-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_bar-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_boxplot-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_boxplot-chart.png index c1985e2b..02b44f11 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_boxplot-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_boxplot-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_column-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_column-chart.png index 4d21bf48..45ae9ac5 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_column-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_column-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_line-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_line-chart.png index 033890a9..3338ba47 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_line-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_line-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_pie-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_pie-chart.png index 93f722a1..081b9525 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_pie-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_pie-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_polar-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_polar-chart.png index cb86d6e1..bf962686 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_polar-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_polar-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scatter-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scatter-chart.png index 94b72942..eced3a1e 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scatter-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scatter-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scattermap.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scattermap.png index e0b9cda4..f936311b 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scattermap.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_scattermap.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_sunburst-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_sunburst-chart.png index 95d85872..7392cd6d 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_sunburst-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_sunburst-chart.png differ diff --git a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_treemap-chart.png b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_treemap-chart.png index 629a14c3..f8f85ede 100644 Binary files a/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_treemap-chart.png and b/e2e/visual-tests/react-local-demo/__screenshots__/test-suites.spec.ts/verify-test-suites-in-light-mode_treemap-chart.png differ diff --git a/package.json b/package.json index 594234b5..108b7405 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "1.18.1", + "version": "1.19.0", "type": "module", "license": "SEE LICENSE IN LICENSE.md", "private": true, diff --git a/packages/sdk-cli/package.json b/packages/sdk-cli/package.json index c25d3e96..cf0f44ef 100644 --- a/packages/sdk-cli/package.json +++ b/packages/sdk-cli/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -20,12 +20,12 @@ "license": "SEE LICENSE IN LICENSE.md", "bin": "./dist/index.js", "dependencies": { - "@sisense/sdk-common": "^1.18.1", - "@sisense/sdk-data": "^1.18.1", - "@sisense/sdk-modeling": "^1.18.1", - "@sisense/sdk-query-client": "^1.18.1", - "@sisense/sdk-rest-client": "^1.18.1", - "@sisense/sdk-tracking": "^1.18.1", + "@sisense/sdk-common": "^1.19.0", + "@sisense/sdk-data": "^1.19.0", + "@sisense/sdk-modeling": "^1.19.0", + "@sisense/sdk-query-client": "^1.19.0", + "@sisense/sdk-rest-client": "^1.19.0", + "@sisense/sdk-tracking": "^1.19.0", "cross-fetch": "^4.0.0", "inquirer": "^8.1.2", "js-levenshtein": "^1.1.6", diff --git a/packages/sdk-common/package.json b/packages/sdk-common/package.json index 081062d9..30543c96 100644 --- a/packages/sdk-common/package.json +++ b/packages/sdk-common/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": "./dist/index.js" diff --git a/packages/sdk-data/package.json b/packages/sdk-data/package.json index 26e1c594..9e83f17f 100644 --- a/packages/sdk-data/package.json +++ b/packages/sdk-data/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "main": "./dist/cjs/index.js", "module": "./dist/index.js", @@ -27,8 +27,8 @@ "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-common": "^1.18.1", - "@sisense/sdk-rest-client": "^1.18.1", + "@sisense/sdk-common": "^1.19.0", + "@sisense/sdk-rest-client": "^1.19.0", "guid-typescript": "^1.0.9", "hash-it": "^6.0.0", "lodash-es": "^4.17.21", diff --git a/packages/sdk-data/src/dimensional-model/attributes.ts b/packages/sdk-data/src/dimensional-model/attributes.ts index b74a4703..ab8332fe 100644 --- a/packages/sdk-data/src/dimensional-model/attributes.ts +++ b/packages/sdk-data/src/dimensional-model/attributes.ts @@ -26,7 +26,7 @@ export class DimensionalAttribute extends DimensionalElement implements Attribut protected _sort: Sort = Sort.None; constructor(name: string, expression: string, type?: string, desc?: string, sort?: Sort) { - super(normalizeName(name), type || MetadataTypes.Attribute, desc); + super(name, type || MetadataTypes.Attribute, desc); this.expression = expression; this._sort = sort || Sort.None; diff --git a/packages/sdk-data/src/dimensional-model/dimensions.ts b/packages/sdk-data/src/dimensional-model/dimensions.ts index 496cc714..734fce65 100644 --- a/packages/sdk-data/src/dimensional-model/dimensions.ts +++ b/packages/sdk-data/src/dimensional-model/dimensions.ts @@ -72,16 +72,17 @@ export class DimensionalDimension extends DimensionalElement implements Dimensio } private getAttachedName(name: string, expression: string): string { - let result = normalizeName(name); + let result = name; // if exists fallback to expression + const normalizedName = normalizeName(name); if ( - result === 'id' || - result === 'name' || - Object.getOwnPropertyDescriptor(this, result) !== undefined || - this[result] !== undefined + normalizedName === 'id' || + normalizedName === 'name' || + Object.getOwnPropertyDescriptor(this, normalizedName) !== undefined || + this[normalizedName] !== undefined ) { - result = normalizeName(expression.replace('.', '_').replace('[', '').replace(']', '')); + result = expression; } return result; @@ -93,7 +94,7 @@ export class DimensionalDimension extends DimensionalElement implements Dimensio for (let i = 0; i < dimensions.length; i++) { const n = this.getAttachedName(dimensions[i].name, dimensions[i].attributes[0].expression); - this[n] = dimensions[i]; + this[normalizeName(n)] = dimensions[i]; if (n != dimensions[i].name) { dimensions[i].name = n; @@ -107,7 +108,7 @@ export class DimensionalDimension extends DimensionalElement implements Dimensio for (let i = 0; i < attributes.length; i++) { const n = this.getAttachedName(attributes[i].name, attributes[i].expression); - this[n] = attributes[i]; + this[normalizeName(n)] = attributes[i]; if (attributes[i].name != n) { attributes[i].name = n; diff --git a/packages/sdk-data/src/dimensional-model/filters/factory.ts b/packages/sdk-data/src/dimensional-model/filters/factory.ts index 459d83ee..438b5dbb 100644 --- a/packages/sdk-data/src/dimensional-model/filters/factory.ts +++ b/packages/sdk-data/src/dimensional-model/filters/factory.ts @@ -771,7 +771,7 @@ export function measureBase( * Filter for categories that have an average revenue equal 50 in the Sample ECommerce data model. * ```ts * filterFactory.measureEquals( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 50 * ) * ``` @@ -800,7 +800,7 @@ export function measureEquals(measure: BaseMeasure, value: number, guid?: string * to 50 in the Sample ECommerce data model. * ```ts * filterFactory.measureGreaterThan( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 50 * ) * ``` @@ -829,7 +829,7 @@ export function measureGreaterThan(measure: BaseMeasure, value: number, guid?: s * or equal to 50 in the Sample ECommerce data model. * ```ts * filterFactory.measureGreaterThanOrEqual( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 50 * ) * ``` @@ -862,7 +862,7 @@ export function measureGreaterThanOrEqual( * or equal to 100 in the Sample ECommerce data model. * ```ts * filterFactory.measureLessThanOrEqual( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 100 * ) * ``` @@ -890,7 +890,7 @@ export function measureLessThanOrEqual(measure: BaseMeasure, value: number, guid * Filter for categories that have an average revenue less than 100 in the Sample ECommerce data model. * ```ts * filterFactory.measureLessThan( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 100 * ) * ``` @@ -919,7 +919,7 @@ export function measureLessThan(measure: BaseMeasure, value: number, guid?: stri * or equal to 100 in the Sample ECommerce data model. * ```ts * filterFactory.measureBetween( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 50, * 100 * ) @@ -955,7 +955,7 @@ export function measureBetween( * 100 in the Sample ECommerce data model. * ```ts * filterFactory.measureBetweenNotEqual( - * measures.average(DM.Commerce.Revenue), + * measureFactory.average(DM.Commerce.Revenue), * 50, * 100 * ) @@ -993,7 +993,7 @@ export function measureBetweenNotEqual( * ```ts * filterFactory.topRanking( * DM.Commerce.AgeRange, - * measures.sum(DM.Commerce.Revenue), + * measureFactory.sum(DM.Commerce.Revenue), * 3 * ) * ``` @@ -1020,7 +1020,7 @@ export function topRanking( * ```ts * filterFactory.bottomRanking( * DM.Commerce.AgeRange, - * measures.sum(DM.Commerce.Revenue), + * measureFactory.sum(DM.Commerce.Revenue), * 3 * ) * ``` diff --git a/packages/sdk-data/src/dimensional-model/filters/filters.test.ts b/packages/sdk-data/src/dimensional-model/filters/filters.test.ts index fd962d54..bd30265f 100644 --- a/packages/sdk-data/src/dimensional-model/filters/filters.test.ts +++ b/packages/sdk-data/src/dimensional-model/filters/filters.test.ts @@ -26,16 +26,15 @@ describe('Filters jaql preparations', () => { it('must prepare members filter jaql', () => { const result = { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { members: ['Female'] }, }, }; - const filter = new MembersFilter( - new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), - ['Female'], - ); + const filter = new MembersFilter(new DimensionalAttribute('Gender', '[Commerce.Gender]'), [ + 'Female', + ]); const jaql = filter.jaql(); @@ -45,16 +44,14 @@ describe('Filters jaql preparations', () => { it('must prepare exclude filter jaql', () => { const result = { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { exclude: { members: ['Female'] } }, }, }; const filter = new ExcludeFilter( - new MembersFilter(new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), [ - 'Female', - ]), + new MembersFilter(new DimensionalAttribute('Gender', '[Commerce.Gender]'), ['Female']), ); const jaql = filter.jaql(); @@ -110,7 +107,7 @@ describe('Filters jaql preparations', () => { it('must prepare logical attribute filter jaql', () => { const result = { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { @@ -120,13 +117,9 @@ describe('Filters jaql preparations', () => { }; const filter = new LogicalAttributeFilter( [ - new MembersFilter(new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), [ - 'Female', - ]), + new MembersFilter(new DimensionalAttribute('Gender', '[Commerce.Gender]'), ['Female']), new ExcludeFilter( - new MembersFilter(new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), [ - 'Male', - ]), + new MembersFilter(new DimensionalAttribute('Gender', '[Commerce.Gender]'), ['Male']), ), ], 'or', @@ -148,10 +141,10 @@ describe('Filters jaql preparations', () => { }, }; const filter = new MeasureFilter( - new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), + new DimensionalAttribute('Gender', '[Commerce.Gender]'), new DimensionalBaseMeasure( 'Cost', - new DimensionalAttribute('[Commerce.Cost]', '[Commerce.Cost]', 'numeric-attribute'), + new DimensionalAttribute('Cost', '[Commerce.Cost]', 'numeric-attribute'), 'sum', ), ); @@ -219,14 +212,14 @@ describe('Filters jaql preparations', () => { it('must prepare text filter jaql', () => { const result = { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { contains: 'Male' }, }, }; const filter = new TextFilter( - new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), + new DimensionalAttribute('Gender', '[Commerce.Gender]'), TextOperators.Contains, 'Male', ); @@ -239,14 +232,14 @@ describe('Filters jaql preparations', () => { it('must prepare numeric filter jaql', () => { const result = { jaql: { - title: 'CommerceCost', + title: 'Cost', dim: '[Commerce.Cost]', datatype: 'numeric', filter: { from: 1, to: 3 }, }, }; const filter = new NumericFilter( - new DimensionalAttribute('[Commerce.Cost]', '[Commerce.Cost]', 'numeric-attribute'), + new DimensionalAttribute('Cost', '[Commerce.Cost]', 'numeric-attribute'), NumericOperators.From, 1, NumericOperators.To, @@ -261,7 +254,7 @@ describe('Filters jaql preparations', () => { it('must prepare ranking filter jaql', () => { const result = { jaql: { - title: 'CommerceCost', + title: 'Cost', dim: '[Commerce.Cost]', datatype: 'numeric', filter: { @@ -271,10 +264,10 @@ describe('Filters jaql preparations', () => { }, }; const filter = new RankingFilter( - new DimensionalAttribute('[Commerce.Cost]', '[Commerce.Cost]', 'numeric-attribute'), + new DimensionalAttribute('Cost', '[Commerce.Cost]', 'numeric-attribute'), new DimensionalBaseMeasure( 'Cost', - new DimensionalAttribute('[Commerce.Cost]', '[Commerce.Cost]', 'numeric-attribute'), + new DimensionalAttribute('Cost', '[Commerce.Cost]', 'numeric-attribute'), 'sum', ), RankingOperators.Top, @@ -290,7 +283,7 @@ describe('Filters jaql preparations', () => { const result = [ { jaql: { - title: 'CategoryCategory', + title: 'Category', dim: '[Category.Category]', datatype: 'text', filter: { @@ -301,7 +294,7 @@ describe('Filters jaql preparations', () => { }, { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { @@ -313,12 +306,12 @@ describe('Filters jaql preparations', () => { ]; const levelFilter1: Filter = new MembersFilter( - new DimensionalAttribute('[Category.Category]', '[Category.Category]'), + new DimensionalAttribute('Category', '[Category.Category]'), ['Apple Mac Desktops', 'Apple Mac Laptops', 'Calculators'], ); const levelFilter2: Filter = new MembersFilter( - new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), + new DimensionalAttribute('Gender', '[Commerce.Gender]'), ['Female'], ); @@ -331,13 +324,13 @@ describe('Filters jaql preparations', () => { it('must prepare members filter jaql with inner background filter', () => { const result = { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { and: [{ members: ['Female'] }, { members: ['Female', 'Male'] }] }, }, }; - const attribute = new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'); + const attribute = new DimensionalAttribute('Gender', '[Commerce.Gender]'); const backgroundFilter = new MembersFilter(attribute, ['Female', 'Male']); const filter = new MembersFilter( attribute, diff --git a/packages/sdk-data/src/dimensional-model/filters/filters.ts b/packages/sdk-data/src/dimensional-model/filters/filters.ts index bcc01f40..7ac32771 100644 --- a/packages/sdk-data/src/dimensional-model/filters/filters.ts +++ b/packages/sdk-data/src/dimensional-model/filters/filters.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-return */ @@ -10,7 +11,7 @@ import { LevelAttribute, Attribute, Measure, Filter } from '../interfaces.js'; import { DimensionalElement } from '../base.js'; -import { DateLevels, MetadataTypes } from '../types.js'; +import { AnyObject, DateLevels, MetadataTypes } from '../types.js'; import { create } from '../factory.js'; import { DimensionalBaseMeasure } from '../measures/measures.js'; @@ -93,7 +94,7 @@ export const FilterTypes = { ranking: 'ranking', text: 'text', numeric: 'numeric', - date: 'date', + dateRange: 'dateRange', relativeDate: 'relativeDate', cascading: 'cascading', advanced: 'advanced', @@ -754,7 +755,7 @@ export class DateRangeFilter extends DoubleOperatorFilter { valueTo?: Date | string, guid?: string, ) { - super(l, FilterTypes.date, DateOperators.From, valueFrom, DateOperators.To, valueTo, guid); + super(l, FilterTypes.dateRange, DateOperators.From, valueFrom, DateOperators.To, valueTo, guid); if (typeof valueFrom === 'object') { this.valueA = valueFrom.toISOString(); @@ -908,6 +909,123 @@ export class CustomFilter extends AbstractFilter { } } +/** + * Checks if a filter is a CustomFilter. + * + * @param filter - The filter to check. + * @internal + */ +export function isCustomFilter(filter: Filter & AnyObject): filter is CustomFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.advanced; +} + +/** + * Checks if a filter is a MembersFilter. + * + * @param filter - The filter to check. + * @internal + */ +export function isMembersFilter(filter: Filter & AnyObject): filter is MembersFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.members; +} + +/** + * Checks if a filter is a NumericFilter. + * + * @param filter - The filter to check. + * @internal + */ +export function isNumericFilter(filter: Filter & AnyObject): filter is NumericFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.numeric; +} + +/** + * Checks if a filter is a TextFilter. + * + * @param filter - The filter to check. + * @internal + */ +export function isRankingFilter(filter: Filter & AnyObject): filter is RankingFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.ranking; +} + +/** + * Checks if a filter is a MeasureFilter. + * + * @param filter - The filter to check. + * @internal + */ +export function isMeasureFilter(filter: Filter & AnyObject): filter is MeasureFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.measure; +} + +/** + * Checks if a filter is a ExcludeFilter. + * + * @param filter - The filter to check. + * @internal + */ + +export function isExcludeFilter(filter: Filter & AnyObject): filter is ExcludeFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.exclude; +} + +/** + * Checks if a filter is a LogicalAttributeFilter. + * + * @param filter - The filter to check. + * @internal + */ + +export function isLogicalAttributeFilter( + filter: Filter & AnyObject, +): filter is LogicalAttributeFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.logicalAttribute; +} + +/** + * Checks if a filter is a CascadingFilter. + * + * @param filter - The filter to check. + * @internal + */ + +export function isCascadingFilter(filter: Filter & AnyObject): filter is CascadingFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.cascading; +} + +/** + * Checks if a filter is a RelativeDateFilter. + * + * @param filter - The filter to check. + * @internal + */ + +export function isRelativeDateFilter(filter: Filter & AnyObject): filter is RelativeDateFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.relativeDate; +} + +/** + * Checks if a filter is a TextFilter. + * + * @param filter - The filter to check. + * @internal + */ + +export function isTextFilter(filter: Filter & AnyObject): filter is TextFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.text; +} + +/** + * Checks if a filter is a DateRangeFilter. + * + * @param filter - The filter to check. + * @internal + */ +export function isDateRangeFilter(filter: Filter & AnyObject): filter is DateRangeFilter { + return 'filterType' in filter && filter.filterType === FilterTypes.dateRange; +} + /** * @param json - Filter JSON representation * @internal @@ -973,7 +1091,7 @@ export function createFilter(json: any): Filter { ); break; - case FilterTypes.date: + case FilterTypes.dateRange: return new DateRangeFilter( create(json.attribute) as LevelAttribute, json.valueA, diff --git a/packages/sdk-data/src/dimensional-model/filters/utils/attribute-measure-util.ts b/packages/sdk-data/src/dimensional-model/filters/utils/attribute-measure-util.ts index 2ac0fd77..99141a08 100644 --- a/packages/sdk-data/src/dimensional-model/filters/utils/attribute-measure-util.ts +++ b/packages/sdk-data/src/dimensional-model/filters/utils/attribute-measure-util.ts @@ -19,6 +19,7 @@ const DATA_MODEL_MODULE_NAME = 'DM'; * @param column - Column name * @param level - Date level * @param dataType - Data type + * @param title - Attribute title * @returns attribute or level attribute */ export const createAttributeHelper = ( @@ -27,6 +28,7 @@ export const createAttributeHelper = ( column: string, level: string | undefined, dataType: string, + title?: string, ): Attribute | LevelAttribute => { // if table is undefined, extract it from dim const dimTable = table ?? dim.slice(1, -1).split('.')[0]; @@ -35,7 +37,7 @@ export const createAttributeHelper = ( const dateLevel = DimensionalLevelAttribute.translateJaqlToGranularity({ level }); const format = DimensionalLevelAttribute.getDefaultFormatForGranularity(dateLevel); const levelAttribute: LevelAttribute = new DimensionalLevelAttribute( - column, + title ?? column, dim, dateLevel, format, @@ -51,7 +53,7 @@ export const createAttributeHelper = ( const attributeType = isNumber(dataType) ? MetadataTypes.NumericAttribute : MetadataTypes.TextAttribute; - const attribute: Attribute = new DimensionalAttribute(column, dim, attributeType); + const attribute: Attribute = new DimensionalAttribute(title ?? column, dim, attributeType); attribute.composeCode = normalizeAttributeName( dimTable, column, @@ -71,7 +73,14 @@ export const createAttributeHelper = ( export const createAttributeFromFilterJaql = ( jaql: FilterJaql | FilterJaqlInternal, ): Attribute | LevelAttribute => { - return createAttributeHelper(jaql.dim, jaql.table, jaql.column, jaql.level, jaql.datatype); + return createAttributeHelper( + jaql.dim, + jaql.table, + jaql.column, + jaql.level, + jaql.datatype, + jaql.title, + ); }; /** @@ -92,8 +101,9 @@ export const createMeasureHelper = ( level: string | undefined, dataType: string, agg: string, + title?: string, ): BaseMeasure => { - const attribute = createAttributeHelper(dim, table, column, level, dataType); + const attribute = createAttributeHelper(dim, table, column, level, dataType, title); const measure = measureFactory.aggregate(attribute, agg); measure.composeCode = `measureFactory.${agg}(${attribute.composeCode})`; return measure; @@ -106,9 +116,9 @@ export const createMeasureHelper = ( * @returns Measure */ export const createMeasureFromFilterJaql = (jaql: FilterJaqlInternal): BaseMeasure | undefined => { - const { dim, table, column, level, datatype: dataType, agg } = jaql; + const { dim, table, column, title, level, datatype: dataType, agg } = jaql; if (!agg) return undefined; - return createMeasureHelper(dim, table, column, level, dataType, agg); + return createMeasureHelper(dim, table, column, level, dataType, agg, title); }; /** diff --git a/packages/sdk-data/src/dimensional-model/interfaces.ts b/packages/sdk-data/src/dimensional-model/interfaces.ts index bc83a4f6..c6450821 100644 --- a/packages/sdk-data/src/dimensional-model/interfaces.ts +++ b/packages/sdk-data/src/dimensional-model/interfaces.ts @@ -402,6 +402,11 @@ export interface Filter extends Element { */ readonly attribute: Attribute; + /** + * Filter type + */ + readonly filterType: string; + /** * Boolean flag whether the filter is a scope filter */ diff --git a/packages/sdk-data/src/dimensional-model/measures/factory.ts b/packages/sdk-data/src/dimensional-model/measures/factory.ts index a5447528..1bb2e6eb 100644 --- a/packages/sdk-data/src/dimensional-model/measures/factory.ts +++ b/packages/sdk-data/src/dimensional-model/measures/factory.ts @@ -482,7 +482,7 @@ export function countDistinct(attribute: Attribute, name?: string, format?: stri * ```ts * measureFactory.measuredValue( * measureFactory.sum(DM.Commerce.Cost), - * [filters.greaterThan(DM.Commerce.Cost, 100)], + * [filterFactory.greaterThan(DM.Commerce.Cost, 100)], * 'Cost Greater Than 100' * ), * ``` diff --git a/packages/sdk-data/src/dimensional-model/measures/measures.test.ts b/packages/sdk-data/src/dimensional-model/measures/measures.test.ts index 4dc27a73..ea660eb0 100644 --- a/packages/sdk-data/src/dimensional-model/measures/measures.test.ts +++ b/packages/sdk-data/src/dimensional-model/measures/measures.test.ts @@ -75,11 +75,11 @@ describe('Measures jaql preparations', () => { it('must prepare template measure jaql', () => { const result = { - jaql: { title: 'sum CommerceCost', agg: 'sum', dim: '[Commerce.Cost]', datatype: 'numeric' }, + jaql: { title: 'sum Cost', agg: 'sum', dim: '[Commerce.Cost]', datatype: 'numeric' }, }; const measure = new DimensionalMeasureTemplate( 'Count', - new DimensionalAttribute('[Commerce.Cost]', '[Commerce.Cost]', 'numeric-attribute'), + new DimensionalAttribute('Cost', '[Commerce.Cost]', 'numeric-attribute'), ); const jaql = measure.jaql(); diff --git a/packages/sdk-data/src/dimensional-model/types.ts b/packages/sdk-data/src/dimensional-model/types.ts index c33c3bc5..7864aaaf 100644 --- a/packages/sdk-data/src/dimensional-model/types.ts +++ b/packages/sdk-data/src/dimensional-model/types.ts @@ -387,6 +387,7 @@ export type BaseJaql = { jaql: FilterJaql; }; }; + merged?: boolean; }; /** @internal */ @@ -473,3 +474,8 @@ type AndFilter = { export type OrFilter = { or: FilterItem[]; }; + +/** + * Abstract object with any unknown values + */ +export type AnyObject = Record; diff --git a/packages/sdk-modeling/package.json b/packages/sdk-modeling/package.json index a2140b51..865e34c9 100644 --- a/packages/sdk-modeling/package.json +++ b/packages/sdk-modeling/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "type": "module", @@ -20,7 +20,7 @@ "module": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "@sisense/sdk-data": "^1.18.1", + "@sisense/sdk-data": "^1.19.0", "prettier": "^3.2.5", "typescript": "4.8.4" }, diff --git a/packages/sdk-modeling/src/typescript/__snapshots__/writer.test.ts.snap b/packages/sdk-modeling/src/typescript/__snapshots__/writer.test.ts.snap index 22d36606..e9b64d6a 100644 --- a/packages/sdk-modeling/src/typescript/__snapshots__/writer.test.ts.snap +++ b/packages/sdk-modeling/src/typescript/__snapshots__/writer.test.ts.snap @@ -12,7 +12,7 @@ export var Brand = createDimension({ description: 'Brand name', }), BrandID: createAttribute({ - name: 'BrandID', + name: 'Brand ID', type: 'numeric-attribute', expression: '[Brand.Brand ID]', description: 'Brand ID', @@ -26,7 +26,7 @@ export var Category = createDimension({ expression: '[Category.Category]', }), CategoryID: createAttribute({ - name: 'CategoryID', + name: 'Category ID', type: 'numeric-attribute', expression: "[Category.'Category ID']", }), @@ -34,17 +34,17 @@ export var Category = createDimension({ export var Commerce = createDimension({ name: 'Commerce', AgeRange: createAttribute({ - name: 'AgeRange', + name: 'Age Range', type: 'text-attribute', expression: '[Commerce.Age Range]', }), BrandID: createAttribute({ - name: 'BrandID', + name: 'Brand ID', type: 'numeric-attribute', expression: '[Commerce.Brand ID]', }), CategoryID: createAttribute({ - name: 'CategoryID', + name: 'Category ID', type: 'numeric-attribute', expression: "[Commerce.'Category ID']", }), @@ -59,12 +59,12 @@ export var Commerce = createDimension({ expression: '[Commerce.Cost]', }), CountryID: createAttribute({ - name: 'CountryID', + name: 'Country ID', type: 'numeric-attribute', expression: '[Commerce.Country ID]', }), DateMonth: createAttribute({ - name: 'DateMonth', + name: 'Date (Month)', type: 'numeric-attribute', expression: '[Commerce.Date (Month)]', }), @@ -84,7 +84,7 @@ export var Commerce = createDimension({ expression: '[Commerce.Revenue]', }), VisitID: createAttribute({ - name: 'VisitID', + name: 'Visit ID', type: 'numeric-attribute', expression: '[Commerce.Visit ID]', }), @@ -101,7 +101,7 @@ export var Country = createDimension({ expression: '[Country.Country]', }), CountryID: createAttribute({ - name: 'CountryID', + name: 'Country ID', type: 'numeric-attribute', expression: '[Country.Country ID]', }), @@ -162,7 +162,7 @@ export const Brand = createDimension({ description: \`Brand name\`, }), BrandID: createAttribute({ - name: 'BrandID', + name: 'Brand ID', type: 'numeric-attribute', expression: '[Brand.Brand ID]', description: \`Brand ID\`, @@ -181,7 +181,7 @@ export const Category = createDimension({ expression: '[Category.Category]', }), CategoryID: createAttribute({ - name: 'CategoryID', + name: 'Category ID', type: 'numeric-attribute', expression: "[Category.'Category ID']", }), @@ -204,17 +204,17 @@ interface CommerceDimension extends Dimension { export const Commerce = createDimension({ name: 'Commerce', AgeRange: createAttribute({ - name: 'AgeRange', + name: 'Age Range', type: 'text-attribute', expression: '[Commerce.Age Range]', }), BrandID: createAttribute({ - name: 'BrandID', + name: 'Brand ID', type: 'numeric-attribute', expression: '[Commerce.Brand ID]', }), CategoryID: createAttribute({ - name: 'CategoryID', + name: 'Category ID', type: 'numeric-attribute', expression: "[Commerce.'Category ID']", }), @@ -229,12 +229,12 @@ export const Commerce = createDimension({ expression: '[Commerce.Cost]', }), CountryID: createAttribute({ - name: 'CountryID', + name: 'Country ID', type: 'numeric-attribute', expression: '[Commerce.Country ID]', }), DateMonth: createAttribute({ - name: 'DateMonth', + name: 'Date (Month)', type: 'numeric-attribute', expression: '[Commerce.Date (Month)]', }), @@ -254,7 +254,7 @@ export const Commerce = createDimension({ expression: '[Commerce.Revenue]', }), VisitID: createAttribute({ - name: 'VisitID', + name: 'Visit ID', type: 'numeric-attribute', expression: '[Commerce.Visit ID]', }), @@ -276,7 +276,7 @@ export const Country = createDimension({ expression: '[Country.Country]', }), CountryID: createAttribute({ - name: 'CountryID', + name: 'Country ID', type: 'numeric-attribute', expression: '[Country.Country ID]', }), @@ -304,7 +304,7 @@ export const Brand = createDimension({ description: \`Brand name\`, }), BrandID: createAttribute({ - name: 'BrandID', + name: 'Brand ID', type: 'numeric-attribute', expression: '[Brand.Brand ID]', description: \`Brand ID\`, @@ -323,7 +323,7 @@ export const Category = createDimension({ expression: '[Category.Category]', }), CategoryID: createAttribute({ - name: 'CategoryID', + name: 'Category ID', type: 'numeric-attribute', expression: "[Category.'Category ID']", }), @@ -346,17 +346,17 @@ interface CommerceDimension extends Dimension { export const Commerce = createDimension({ name: 'Commerce', AgeRange: createAttribute({ - name: 'AgeRange', + name: 'Age Range', type: 'text-attribute', expression: '[Commerce.Age Range]', }), BrandID: createAttribute({ - name: 'BrandID', + name: 'Brand ID', type: 'numeric-attribute', expression: '[Commerce.Brand ID]', }), CategoryID: createAttribute({ - name: 'CategoryID', + name: 'Category ID', type: 'numeric-attribute', expression: "[Commerce.'Category ID']", }), @@ -371,12 +371,12 @@ export const Commerce = createDimension({ expression: '[Commerce.Cost]', }), CountryID: createAttribute({ - name: 'CountryID', + name: 'Country ID', type: 'numeric-attribute', expression: '[Commerce.Country ID]', }), DateMonth: createAttribute({ - name: 'DateMonth', + name: 'Date (Month)', type: 'numeric-attribute', expression: '[Commerce.Date (Month)]', }), @@ -396,7 +396,7 @@ export const Commerce = createDimension({ expression: '[Commerce.Revenue]', }), VisitID: createAttribute({ - name: 'VisitID', + name: 'Visit ID', type: 'numeric-attribute', expression: '[Commerce.Visit ID]', }), @@ -418,7 +418,7 @@ export const Country = createDimension({ expression: '[Country.Country]', }), CountryID: createAttribute({ - name: 'CountryID', + name: 'Country ID', type: 'numeric-attribute', expression: '[Country.Country ID]', }), diff --git a/packages/sdk-pivot-client/package.json b/packages/sdk-pivot-client/package.json index 50c0106d..8828c5d8 100644 --- a/packages/sdk-pivot-client/package.json +++ b/packages/sdk-pivot-client/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -39,8 +39,8 @@ ], "dependencies": { "@mui/material": "^5.11.0", - "@sisense/sdk-data": "^1.18.1", - "@sisense/sdk-rest-client": "^1.18.1", + "@sisense/sdk-data": "^1.19.0", + "@sisense/sdk-rest-client": "^1.19.0", "classnames": "2.3.2", "dom-css": "2.1.0", "immer": "^10.0.2", diff --git a/packages/sdk-query-client/package.json b/packages/sdk-query-client/package.json index bf8745a5..5a476166 100644 --- a/packages/sdk-query-client/package.json +++ b/packages/sdk-query-client/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -20,10 +20,10 @@ "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-common": "^1.18.1", - "@sisense/sdk-data": "^1.18.1", - "@sisense/sdk-pivot-client": "^1.18.1", - "@sisense/sdk-rest-client": "^1.18.1", + "@sisense/sdk-common": "^1.19.0", + "@sisense/sdk-data": "^1.19.0", + "@sisense/sdk-pivot-client": "^1.19.0", + "@sisense/sdk-rest-client": "^1.19.0", "@sisense/task-manager": "^0.1.0", "numeral": "^2.0.6", "ts-deepmerge": "6.0.2", diff --git a/packages/sdk-query-client/src/jaql/metadata/highlights.test.ts b/packages/sdk-query-client/src/jaql/metadata/highlights.test.ts index 651be15c..61b3f4d3 100644 --- a/packages/sdk-query-client/src/jaql/metadata/highlights.test.ts +++ b/packages/sdk-query-client/src/jaql/metadata/highlights.test.ts @@ -22,7 +22,7 @@ describe('Highlight filters applying', () => { in: { selected: { jaql: { - title: 'CommerceGender', + title: 'Gender', dim: '[Commerce.Gender]', datatype: 'text', filter: { members: ['Female'] }, @@ -32,10 +32,9 @@ describe('Highlight filters applying', () => { }, }; const attribute = new DimensionalAttribute('Gender', '[Commerce.Gender]', 'text-attribute'); - const filter = new MembersFilter( - new DimensionalAttribute('[Commerce.Gender]', '[Commerce.Gender]'), - ['Female'], - ); + const filter = new MembersFilter(new DimensionalAttribute('Gender', '[Commerce.Gender]'), [ + 'Female', + ]); const metadata = applyHighlightFilters(attribute.jaql(), [filter]); diff --git a/packages/sdk-rest-client/package.json b/packages/sdk-rest-client/package.json index 7767a8cb..6f4400ee 100644 --- a/packages/sdk-rest-client/package.json +++ b/packages/sdk-rest-client/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -20,7 +20,7 @@ "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-common": "^1.18.1", + "@sisense/sdk-common": "^1.19.0", "fetch-intercept": "^2.4.0" }, "scripts": { diff --git a/packages/sdk-tracking/package.json b/packages/sdk-tracking/package.json index a3e4975b..ed14abad 100644 --- a/packages/sdk-tracking/package.json +++ b/packages/sdk-tracking/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": "./dist/index.js" diff --git a/packages/sdk-ui-angular/package.json b/packages/sdk-ui-angular/package.json index bab088c2..7dbd9821 100644 --- a/packages/sdk-ui-angular/package.json +++ b/packages/sdk-ui-angular/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "main": "dist", diff --git a/packages/sdk-ui-angular/src/lib/component-wrapper-helpers/context-connectors.ts b/packages/sdk-ui-angular/src/lib/component-wrapper-helpers/context-connectors.ts index 793625be..990f959e 100644 --- a/packages/sdk-ui-angular/src/lib/component-wrapper-helpers/context-connectors.ts +++ b/packages/sdk-ui-angular/src/lib/component-wrapper-helpers/context-connectors.ts @@ -5,10 +5,13 @@ import { CustomSisenseContextProvider, CustomThemeProvider, CustomThemeProviderProps, + CustomPluginsProvider, + CustomPluginsProviderProps, } from '@sisense/sdk-ui-preact'; import { map } from 'rxjs'; import { SisenseContextService } from '../services/sisense-context.service'; import { ThemeService } from '../services/theme.service'; +import { PluginsService } from '../services/plugins.service'; /** * Creates theme context connector @@ -63,3 +66,24 @@ export const createSisenseContextConnector = ( renderContextProvider: createContextProviderRenderer(CustomSisenseContextProvider), }; }; + +/** + * Creates plugins context connector + * + * @param pluginsService - The plugin service + * @internal + */ +export const createPluginsContextConnector = ( + pluginsService: PluginsService, +): ContextConnector => { + return { + prepareContext() { + return { + pluginMap: pluginsService.getPlugins().value, + registerPlugin: pluginsService.registerPlugin.bind(pluginsService), + getPlugin: pluginsService.getPlugin.bind(pluginsService), + }; + }, + renderContextProvider: createContextProviderRenderer(CustomPluginsProvider), + }; +}; diff --git a/packages/sdk-ui-angular/src/lib/components/dashboard/dashboard-by-id.component.ts b/packages/sdk-ui-angular/src/lib/components/dashboard/dashboard-by-id.component.ts index 75f131e3..957b6e9d 100644 --- a/packages/sdk-ui-angular/src/lib/components/dashboard/dashboard-by-id.component.ts +++ b/packages/sdk-ui-angular/src/lib/components/dashboard/dashboard-by-id.component.ts @@ -16,10 +16,12 @@ import { import { SisenseContextService } from '../../services/sisense-context.service'; import { ThemeService } from '../../services/theme.service'; import { + createPluginsContextConnector, createSisenseContextConnector, createThemeContextConnector, } from '../../component-wrapper-helpers'; import { template, rootId } from '../../component-wrapper-helpers/template'; +import { PluginsService } from '../../services/plugins.service'; /** * An Angular component used for easily rendering a dashboard by its ID created in a Sisense Fusion instance. @@ -86,12 +88,20 @@ export class DashboardByIdComponent implements AfterViewInit, OnChanges, OnDestr * @category Constructor */ public themeService: ThemeService, + /** + * Plugin service + * + * @internal + * @category Constructor + */ + public pluginService: PluginsService, ) { this.componentAdapter = new ComponentAdapter( () => this.createPreactComponent(), [ createSisenseContextConnector(this.sisenseContextService), createThemeContextConnector(this.themeService), + createPluginsContextConnector(this.pluginService), ], ); } diff --git a/packages/sdk-ui-angular/src/lib/services/index.ts b/packages/sdk-ui-angular/src/lib/services/index.ts index 9d6dd2f1..04503e06 100644 --- a/packages/sdk-ui-angular/src/lib/services/index.ts +++ b/packages/sdk-ui-angular/src/lib/services/index.ts @@ -1,5 +1,6 @@ export * from './query.service'; export * from './sisense-context.service'; export * from './theme.service'; +export * from './plugins.service'; export * from './dashboard.service'; export * from './widget.service'; diff --git a/packages/sdk-ui-angular/src/lib/services/plugins.service.ts b/packages/sdk-ui-angular/src/lib/services/plugins.service.ts new file mode 100644 index 00000000..c15479c8 --- /dev/null +++ b/packages/sdk-ui-angular/src/lib/services/plugins.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; +import { WidgetPlugin } from '@sisense/sdk-ui-preact'; + +/** + * Service for working with plugins fetched from an external environment. + * + * Provides methods for registering, retrieving, and interacting with plugins. + * + * @internal + * @group Contexts + */ +@Injectable({ + providedIn: 'root', +}) +export class PluginsService { + private pluginMap$: BehaviorSubject>; + + constructor() { + this.pluginMap$ = new BehaviorSubject(new Map()); + } + + /** + * Registers a new plugin into the plugin map. + * + * @param pluginType - The unique identifier for the plugin type. + * @param plugin - The plugin instance to register. + */ + registerPlugin(pluginType: string, plugin: WidgetPlugin): void { + const pluginMap = this.pluginMap$.value; + if (!pluginMap.has(pluginType)) { + pluginMap.set(pluginType, plugin); + this.pluginMap$.next(pluginMap); + } + } + + /** + * Retrieves a plugin by its type. + * + * @param pluginType - The unique identifier for the plugin type. + * @returns The plugin instance if found, otherwise undefined. + */ + getPlugin(pluginType: string): WidgetPlugin | undefined { + return this.pluginMap$.value.get(pluginType); + } + + /** + * Retrieves a complete plugin map. + * + * @returns A plugin map. + */ + getPlugins() { + return this.pluginMap$; + } +} diff --git a/packages/sdk-ui-preact/package.json b/packages/sdk-ui-preact/package.json index afa230b9..2b6e07bd 100644 --- a/packages/sdk-ui-preact/package.json +++ b/packages/sdk-ui-preact/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -25,7 +25,7 @@ "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-ui": "^1.18.1", + "@sisense/sdk-ui": "^1.19.0", "preact": "^10.13.2" }, "scripts": { diff --git a/packages/sdk-ui-vue/package.json b/packages/sdk-ui-vue/package.json index cc601866..8fb67f0d 100644 --- a/packages/sdk-ui-vue/package.json +++ b/packages/sdk-ui-vue/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", diff --git a/packages/sdk-ui-vue/src/composables/index.ts b/packages/sdk-ui-vue/src/composables/index.ts index aed3f963..cd7c8542 100644 --- a/packages/sdk-ui-vue/src/composables/index.ts +++ b/packages/sdk-ui-vue/src/composables/index.ts @@ -5,4 +5,5 @@ export { useGetDashboardModels } from './use-get-dashboard-models.js'; export { useGetSharedFormula } from './use-get-shared-formula.js'; export { useGetWidgetModel } from './use-get-widget-model.js'; export { useFetch } from './use-fetch.js'; +export { usePlugins } from './use-plugins.js'; export type { UseFetchOptions } from './use-fetch.js'; diff --git a/packages/sdk-ui-vue/src/composables/use-plugins.ts b/packages/sdk-ui-vue/src/composables/use-plugins.ts new file mode 100644 index 00000000..e88151b2 --- /dev/null +++ b/packages/sdk-ui-vue/src/composables/use-plugins.ts @@ -0,0 +1,9 @@ +import { getPluginsContext } from '../providers/plugins-provider.js'; + +/** + * @internal + */ +export const usePlugins = () => { + const context = getPluginsContext(); + return context.value; +}; diff --git a/packages/sdk-ui-vue/src/providers/index.ts b/packages/sdk-ui-vue/src/providers/index.ts index 27196145..f1b11135 100644 --- a/packages/sdk-ui-vue/src/providers/index.ts +++ b/packages/sdk-ui-vue/src/providers/index.ts @@ -4,3 +4,4 @@ export { getSisenseContext, } from './sisense-context-provider'; export { ThemeProvider, createThemeContextConnector } from './theme-provider'; +export { PluginsProvider, createPluginsContextConnector } from './plugins-provider'; diff --git a/packages/sdk-ui-vue/src/providers/plugins-provider.ts b/packages/sdk-ui-vue/src/providers/plugins-provider.ts new file mode 100644 index 00000000..cd09d475 --- /dev/null +++ b/packages/sdk-ui-vue/src/providers/plugins-provider.ts @@ -0,0 +1,58 @@ +import { defineComponent, inject, provide, ref, watchEffect } from 'vue'; +import type { InjectionKey, Ref } from 'vue'; +import type { CustomPluginsContext } from '@sisense/sdk-ui-preact'; +import { createContextProviderRenderer, CustomPluginsProvider } from '@sisense/sdk-ui-preact'; + +const pluginsContextKey = Symbol('pluginsContextKey') as InjectionKey>; + +const defaultPluginsContext: CustomPluginsContext = { + pluginMap: new Map(), + registerPlugin: (pluginType: string, plugin: any) => { + if (!defaultPluginsContext.pluginMap.has(pluginType)) { + defaultPluginsContext.pluginMap.set(pluginType, plugin); + } + }, + getPlugin: (pluginType: string) => defaultPluginsContext.pluginMap.get(pluginType), +}; + +/** + * Gets Plugins context + * + * @group Contexts + */ +export const getPluginsContext = () => { + return inject(pluginsContextKey, ref(defaultPluginsContext)); +}; + +/** + * Creates plugins context connector + * + * @group Contexts + * @internal + */ +export const createPluginsContextConnector = (context: CustomPluginsContext) => { + return { + async prepareContext() { + return context; + }, + renderContextProvider: createContextProviderRenderer(CustomPluginsProvider), + }; +}; + +/** + * Provider for working with plugins fetched from an external environment. + * + * Provides methods for registering, retrieving, and interacting with plugins. + * + * @internal + * @group Contexts + */ +export const PluginsProvider = defineComponent({ + setup(props, { slots }) { + provide(pluginsContextKey, ref(defaultPluginsContext)); + + return () => { + return slots.default?.(); + }; + }, +}); diff --git a/packages/sdk-ui-vue/src/setup-helper.ts b/packages/sdk-ui-vue/src/setup-helper.ts index 79352022..e6508cd0 100644 --- a/packages/sdk-ui-vue/src/setup-helper.ts +++ b/packages/sdk-ui-vue/src/setup-helper.ts @@ -1,9 +1,14 @@ import { h, ref, toRaw, type FunctionalComponent, isReactive, type Slots } from 'vue'; -import { createSisenseContextConnector, createThemeContextConnector } from './providers'; +import { + createPluginsContextConnector, + createSisenseContextConnector, + createThemeContextConnector, +} from './providers'; import { ComponentAdapter, createElement, createWrapperElement } from '@sisense/sdk-ui-preact'; import { getSisenseContext } from './providers/sisense-context-provider'; import { getThemeContext } from './providers/theme-provider'; import { isObject } from './utils'; +import { getPluginsContext } from './providers/plugins-provider'; export function getRawData(data: T): T { return isReactive(data) ? toRaw(data) : data; @@ -35,6 +40,7 @@ export const setupHelper = (component: C, props: P) => { const refElement = ref(null); const context = getSisenseContext(); const themeSettings = getThemeContext(); + const pluginsContext = getPluginsContext(); return () => { if (refElement.value) { @@ -44,6 +50,7 @@ export const setupHelper = (component: C, props: P) => { const componentAdapter = new ComponentAdapter(createPreactComponent, [ createSisenseContextConnector(context.value), createThemeContextConnector(themeSettings ? themeSettings.value : undefined), + createPluginsContextConnector(pluginsContext.value), ]); componentAdapter.render(refElement.value); @@ -68,6 +75,7 @@ export const setupHelperWithChildren = ( const contextMenuChildrenRef = ref(); const context = getSisenseContext(); const themeSettings = getThemeContext(); + const pluginsContext = getPluginsContext(); return () => { if (contextMenuRef.value && contextMenuChildrenRef.value) { @@ -81,6 +89,7 @@ export const setupHelperWithChildren = ( : [ createSisenseContextConnector(context.value), createThemeContextConnector(themeSettings ? themeSettings.value : undefined), + createPluginsContextConnector(pluginsContext.value), ], ); diff --git a/packages/sdk-ui/package.json b/packages/sdk-ui/package.json index e9acf585..2b8baff7 100644 --- a/packages/sdk-ui/package.json +++ b/packages/sdk-ui/package.json @@ -11,7 +11,7 @@ "Sisense", "Compose SDK" ], - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -53,12 +53,12 @@ "@emotion/styled": "^11.10.5", "@mui/material": "^5.15.16", "@mui/system": "^5.15.15", - "@sisense/sdk-common": "^1.18.1", - "@sisense/sdk-data": "^1.18.1", - "@sisense/sdk-pivot-client": "^1.18.1", - "@sisense/sdk-query-client": "^1.18.1", - "@sisense/sdk-rest-client": "^1.18.1", - "@sisense/sdk-tracking": "^1.18.1", + "@sisense/sdk-common": "^1.19.0", + "@sisense/sdk-data": "^1.19.0", + "@sisense/sdk-pivot-client": "^1.19.0", + "@sisense/sdk-query-client": "^1.19.0", + "@sisense/sdk-rest-client": "^1.19.0", + "@sisense/sdk-tracking": "^1.19.0", "@sisense/sisense-charts": "5.1.1", "@tanstack/react-query": "4.36.1", "classnames": "^2.3.2", @@ -66,6 +66,7 @@ "date-fns": "^2.29.3", "date-fns-tz": "^2.0.0", "dayjs": "^1.11.7", + "dompurify": "^3.1.6", "fixed-data-table-2": "^1.2.18", "geojson": "^0.5.0", "guid-typescript": "^1.0.9", @@ -121,6 +122,7 @@ "@swc-node/register": "^1.6.5", "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^14.0.0", + "@types/dompurify": "^3.0.5", "@types/fixed-data-table-2": "^1.0.0", "@types/leaflet": "^1.9.8", "@types/lodash": "^4.14.194", diff --git a/packages/sdk-ui/src/__snapshots__/boxplot-chart.test.tsx.snap b/packages/sdk-ui/src/__snapshots__/boxplot-chart.test.tsx.snap index 7f317448..a3c82308 100644 --- a/packages/sdk-ui/src/__snapshots__/boxplot-chart.test.tsx.snap +++ b/packages/sdk-ui/src/__snapshots__/boxplot-chart.test.tsx.snap @@ -124,6 +124,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p { "blur": false, "color": "#0090a1", + "custom": { + "xValue": [ + "Apple Mac Desktops", + ], + }, "fillColor": "#00cee6", "high": 1192.295066833496, "innerBoxColor": "#00afc4", @@ -136,6 +141,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p { "blur": false, "color": "#0090a1", + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "fillColor": "#00cee6", "high": 1167.9941291809082, "innerBoxColor": "#00afc4", @@ -164,6 +174,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p "data": [ { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Desktops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -172,6 +187,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Desktops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -180,6 +200,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -188,6 +213,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -196,6 +226,11 @@ exports[`Boxplot Chart > render boxplot with custom data options that allow to p }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -468,6 +503,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = { "blur": false, "color": "#0090a1", + "custom": { + "xValue": [ + "Apple Mac Desktops", + ], + }, "fillColor": "#00cee6", "high": 1192.295066833496, "innerBoxColor": "#00afc4", @@ -480,6 +520,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = { "blur": false, "color": "#0090a1", + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "fillColor": "#00cee6", "high": 1167.9941291809082, "innerBoxColor": "#00afc4", @@ -508,6 +553,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = "data": [ { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Desktops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -516,6 +566,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Desktops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -524,6 +579,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -532,6 +592,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "marker": { "lineColor": "#0090a1", }, @@ -540,6 +605,11 @@ exports[`Boxplot Chart > render boxplot with single value in data options 1`] = }, { "blur": false, + "custom": { + "xValue": [ + "Apple Mac Laptops", + ], + }, "marker": { "lineColor": "#0090a1", }, diff --git a/packages/sdk-ui/src/__snapshots__/sunburst-chart.test.tsx.snap b/packages/sdk-ui/src/__snapshots__/sunburst-chart.test.tsx.snap index 6d416a92..40e52dbf 100644 --- a/packages/sdk-ui/src/__snapshots__/sunburst-chart.test.tsx.snap +++ b/packages/sdk-ui/src/__snapshots__/sunburst-chart.test.tsx.snap @@ -468,7 +468,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + ], "subtotalValue": 936, + "xValues": [ + "2018", + ], }, "id": "2018-01-01T00:00:00.000Z", "name": "2018", @@ -479,7 +485,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + ], "subtotalValue": 2045, + "xValues": [ + "2013", + ], }, "id": "2013-01-01T00:00:00.000Z", "name": "2013", @@ -490,7 +502,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + ], "subtotalValue": 3010, + "xValues": [ + "2014", + ], }, "id": "2014-01-01T00:00:00.000Z", "name": "2014", @@ -501,7 +519,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + ], "subtotalValue": 3056, + "xValues": [ + "2011", + ], }, "id": "2011-01-01T00:00:00.000Z", "name": "2011", @@ -512,7 +536,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + ], "subtotalValue": 4242, + "xValues": [ + "2016", + ], }, "id": "2016-01-01T00:00:00.000Z", "name": "2016", @@ -523,7 +553,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + ], "subtotalValue": 5447, + "xValues": [ + "2015", + ], }, "id": "2015-01-01T00:00:00.000Z", "name": "2015", @@ -534,7 +570,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + ], "subtotalValue": 6814, + "xValues": [ + "2010", + ], }, "id": "2010-01-01T00:00:00.000Z", "name": "2010", @@ -545,7 +587,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + ], "subtotalValue": 8103, + "xValues": [ + "2009", + ], }, "id": "2009-01-01T00:00:00.000Z", "name": "2009", @@ -556,7 +604,13 @@ exports[`Sunburst Chart > render a sunburst with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + ], "subtotalValue": 8423, + "xValues": [ + "2012", + ], }, "id": "2012-01-01T00:00:00.000Z", "name": "2012", @@ -976,7 +1030,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + ], "subtotalValue": 936, + "xValues": [ + "2018", + ], }, "id": "2018-01-01T00:00:00.000Z", "name": "2018", @@ -987,7 +1047,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + ], "subtotalValue": 2045, + "xValues": [ + "2013", + ], }, "id": "2013-01-01T00:00:00.000Z", "name": "2013", @@ -998,7 +1064,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + ], "subtotalValue": 3010, + "xValues": [ + "2014", + ], }, "id": "2014-01-01T00:00:00.000Z", "name": "2014", @@ -1009,7 +1081,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + ], "subtotalValue": 3056, + "xValues": [ + "2011", + ], }, "id": "2011-01-01T00:00:00.000Z", "name": "2011", @@ -1020,7 +1098,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + ], "subtotalValue": 4242, + "xValues": [ + "2016", + ], }, "id": "2016-01-01T00:00:00.000Z", "name": "2016", @@ -1031,7 +1115,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + ], "subtotalValue": 5447, + "xValues": [ + "2015", + ], }, "id": "2015-01-01T00:00:00.000Z", "name": "2015", @@ -1042,7 +1132,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + ], "subtotalValue": 6814, + "xValues": [ + "2010", + ], }, "id": "2010-01-01T00:00:00.000Z", "name": "2010", @@ -1053,7 +1149,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + ], "subtotalValue": 8103, + "xValues": [ + "2009", + ], }, "id": "2009-01-01T00:00:00.000Z", "name": "2009", @@ -1064,7 +1166,13 @@ exports[`Sunburst Chart > render a sunburst with two categories and legend 1`] = "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + ], "subtotalValue": 8423, + "xValues": [ + "2012", + ], }, "id": "2012-01-01T00:00:00.000Z", "name": "2012", diff --git a/packages/sdk-ui/src/__snapshots__/treemap-chart.test.tsx.snap b/packages/sdk-ui/src/__snapshots__/treemap-chart.test.tsx.snap index 7929e0c1..67252104 100644 --- a/packages/sdk-ui/src/__snapshots__/treemap-chart.test.tsx.snap +++ b/packages/sdk-ui/src/__snapshots__/treemap-chart.test.tsx.snap @@ -78,6 +78,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + ], + "xValues": [ + "2009", + ], }, "id": "2009-01-01T00:00:00.000Z", "name": "2009", @@ -88,6 +94,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2009", + "A", + ], }, "id": "2009-01-01T00:00:00.000Z_A", "name": "A", @@ -97,6 +111,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + ], + "xValues": [ + "2010", + ], }, "id": "2010-01-01T00:00:00.000Z", "name": "2010", @@ -107,6 +127,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2010", + "A", + ], }, "id": "2010-01-01T00:00:00.000Z_A", "name": "A", @@ -116,6 +144,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + ], + "xValues": [ + "2011", + ], }, "id": "2011-01-01T00:00:00.000Z", "name": "2011", @@ -126,6 +160,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2011", + "B", + ], }, "id": "2011-01-01T00:00:00.000Z_B", "name": "B", @@ -135,6 +177,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + ], + "xValues": [ + "2012", + ], }, "id": "2012-01-01T00:00:00.000Z", "name": "2012", @@ -145,6 +193,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2012", + "B", + ], }, "id": "2012-01-01T00:00:00.000Z_B", "name": "B", @@ -154,6 +210,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + ], + "xValues": [ + "2013", + ], }, "id": "2013-01-01T00:00:00.000Z", "name": "2013", @@ -164,6 +226,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2013", + "A", + ], }, "id": "2013-01-01T00:00:00.000Z_A", "name": "A", @@ -173,6 +243,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + ], + "xValues": [ + "2014", + ], }, "id": "2014-01-01T00:00:00.000Z", "name": "2014", @@ -183,6 +259,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2014", + "B", + ], }, "id": "2014-01-01T00:00:00.000Z_B", "name": "B", @@ -192,6 +276,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + ], + "xValues": [ + "2015", + ], }, "id": "2015-01-01T00:00:00.000Z", "name": "2015", @@ -202,6 +292,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2015", + "A", + ], }, "id": "2015-01-01T00:00:00.000Z_A", "name": "A", @@ -211,6 +309,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + ], + "xValues": [ + "2016", + ], }, "id": "2016-01-01T00:00:00.000Z", "name": "2016", @@ -221,6 +325,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2016", + "B", + ], }, "id": "2016-01-01T00:00:00.000Z_B", "name": "B", @@ -230,6 +342,12 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + ], + "xValues": [ + "2018", + ], }, "id": "2018-01-01T00:00:00.000Z", "name": "2018", @@ -240,6 +358,14 @@ exports[`Treemap Chart > render a treemap with coloring 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2018", + "B", + ], }, "id": "2018-01-01T00:00:00.000Z_B", "name": "B", @@ -766,6 +892,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2009", + ], + "xValues": [ + "2009", + ], }, "id": "2009", "name": "2009", @@ -775,6 +907,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2010", + ], + "xValues": [ + "2010", + ], }, "id": "2010", "name": "2010", @@ -784,6 +922,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2011", + ], + "xValues": [ + "2011", + ], }, "id": "2011", "name": "2011", @@ -793,6 +937,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2012", + ], + "xValues": [ + "2012", + ], }, "id": "2012", "name": "2012", @@ -802,6 +952,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2009", + "A", + ], + "xValues": [ + "2009", + "A", + ], }, "id": "2009_A", "name": "A", @@ -811,6 +969,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + ], + "xValues": [ + "2010", + ], }, "id": "2010-01-01T00:00:00.000Z", "name": "2010", @@ -820,6 +984,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2010", + "A", + ], }, "id": "2010-01-01T00:00:00.000Z_A", "name": "A", @@ -829,6 +1001,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2010", + "A", + ], + "xValues": [ + "2010", + "A", + ], }, "id": "2010_A", "name": "A", @@ -838,6 +1018,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + ], + "xValues": [ + "2011", + ], }, "id": "2011-01-01T00:00:00.000Z", "name": "2011", @@ -847,6 +1033,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2011", + "B", + ], }, "id": "2011-01-01T00:00:00.000Z_B", "name": "B", @@ -856,6 +1050,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2011", + "B", + ], + "xValues": [ + "2011", + "B", + ], }, "id": "2011_B", "name": "B", @@ -865,6 +1067,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + ], + "xValues": [ + "2012", + ], }, "id": "2012-01-01T00:00:00.000Z", "name": "2012", @@ -874,6 +1082,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2012", + "B", + ], }, "id": "2012-01-01T00:00:00.000Z_B", "name": "B", @@ -883,6 +1099,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2012", + "B", + ], + "xValues": [ + "2012", + "B", + ], }, "id": "2012_B", "name": "B", @@ -892,6 +1116,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + ], + "xValues": [ + "2013", + ], }, "id": "2013-01-01T00:00:00.000Z", "name": "2013", @@ -901,6 +1131,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2013", + "A", + ], }, "id": "2013-01-01T00:00:00.000Z_A", "name": "A", @@ -910,6 +1148,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + ], + "xValues": [ + "2014", + ], }, "id": "2014-01-01T00:00:00.000Z", "name": "2014", @@ -919,6 +1163,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2014", + "B", + ], }, "id": "2014-01-01T00:00:00.000Z_B", "name": "B", @@ -928,6 +1180,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + ], + "xValues": [ + "2015", + ], }, "id": "2015-01-01T00:00:00.000Z", "name": "2015", @@ -937,6 +1195,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2015", + "A", + ], }, "id": "2015-01-01T00:00:00.000Z_A", "name": "A", @@ -946,6 +1212,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + ], + "xValues": [ + "2016", + ], }, "id": "2016-01-01T00:00:00.000Z", "name": "2016", @@ -955,6 +1227,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2016", + "B", + ], }, "id": "2016-01-01T00:00:00.000Z_B", "name": "B", @@ -964,6 +1244,12 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + ], + "xValues": [ + "2018", + ], }, "id": "2018-01-01T00:00:00.000Z", "name": "2018", @@ -973,6 +1259,14 @@ exports[`Treemap Chart > render a treemap with highlights 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2018", + "B", + ], }, "id": "2018-01-01T00:00:00.000Z_B", "name": "B", @@ -1835,6 +2129,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + ], + "xValues": [ + "2009", + ], }, "id": "2009-01-01T00:00:00.000Z", "name": "2009", @@ -1844,6 +2144,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2009", + "A", + ], }, "id": "2009-01-01T00:00:00.000Z_A", "name": "A", @@ -1853,6 +2161,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + ], + "xValues": [ + "2010", + ], }, "id": "2010-01-01T00:00:00.000Z", "name": "2010", @@ -1862,6 +2176,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2010", + "A", + ], }, "id": "2010-01-01T00:00:00.000Z_A", "name": "A", @@ -1871,6 +2193,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + ], + "xValues": [ + "2011", + ], }, "id": "2011-01-01T00:00:00.000Z", "name": "2011", @@ -1880,6 +2208,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2011", + "B", + ], }, "id": "2011-01-01T00:00:00.000Z_B", "name": "B", @@ -1889,6 +2225,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + ], + "xValues": [ + "2012", + ], }, "id": "2012-01-01T00:00:00.000Z", "name": "2012", @@ -1898,6 +2240,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2012", + "B", + ], }, "id": "2012-01-01T00:00:00.000Z_B", "name": "B", @@ -1907,6 +2257,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + ], + "xValues": [ + "2013", + ], }, "id": "2013-01-01T00:00:00.000Z", "name": "2013", @@ -1916,6 +2272,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2013", + "A", + ], }, "id": "2013-01-01T00:00:00.000Z_A", "name": "A", @@ -1925,6 +2289,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + ], + "xValues": [ + "2014", + ], }, "id": "2014-01-01T00:00:00.000Z", "name": "2014", @@ -1934,6 +2304,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2014", + "B", + ], }, "id": "2014-01-01T00:00:00.000Z_B", "name": "B", @@ -1943,6 +2321,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + ], + "xValues": [ + "2015", + ], }, "id": "2015-01-01T00:00:00.000Z", "name": "2015", @@ -1952,6 +2336,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + "A", + ], + "xValues": [ + "2015", + "A", + ], }, "id": "2015-01-01T00:00:00.000Z_A", "name": "A", @@ -1961,6 +2353,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + ], + "xValues": [ + "2016", + ], }, "id": "2016-01-01T00:00:00.000Z", "name": "2016", @@ -1970,6 +2368,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2016", + "B", + ], }, "id": "2016-01-01T00:00:00.000Z_B", "name": "B", @@ -1979,6 +2385,12 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + ], + "xValues": [ + "2018", + ], }, "id": "2018-01-01T00:00:00.000Z", "name": "2018", @@ -1988,6 +2400,14 @@ exports[`Treemap Chart > render a treemap with three categories 1`] = ` "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + "B", + ], + "xValues": [ + "2018", + "B", + ], }, "id": "2018-01-01T00:00:00.000Z_B", "name": "B", @@ -2506,6 +2926,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2009-01-01T00:00:00.000Z", + ], + "xValues": [ + "2009", + ], }, "id": "2009-01-01T00:00:00.000Z", "name": "2009", @@ -2515,6 +2941,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2010-01-01T00:00:00.000Z", + ], + "xValues": [ + "2010", + ], }, "id": "2010-01-01T00:00:00.000Z", "name": "2010", @@ -2524,6 +2956,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2011-01-01T00:00:00.000Z", + ], + "xValues": [ + "2011", + ], }, "id": "2011-01-01T00:00:00.000Z", "name": "2011", @@ -2533,6 +2971,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2012-01-01T00:00:00.000Z", + ], + "xValues": [ + "2012", + ], }, "id": "2012-01-01T00:00:00.000Z", "name": "2012", @@ -2542,6 +2986,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2013-01-01T00:00:00.000Z", + ], + "xValues": [ + "2013", + ], }, "id": "2013-01-01T00:00:00.000Z", "name": "2013", @@ -2551,6 +3001,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2014-01-01T00:00:00.000Z", + ], + "xValues": [ + "2014", + ], }, "id": "2014-01-01T00:00:00.000Z", "name": "2014", @@ -2560,6 +3016,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2015-01-01T00:00:00.000Z", + ], + "xValues": [ + "2015", + ], }, "id": "2015-01-01T00:00:00.000Z", "name": "2015", @@ -2569,6 +3031,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2016-01-01T00:00:00.000Z", + ], + "xValues": [ + "2016", + ], }, "id": "2016-01-01T00:00:00.000Z", "name": "2016", @@ -2578,6 +3046,12 @@ exports[`Treemap Chart > render a treemap with two categories 1`] = ` "custom": { "level": 1, "levelsCount": 2, + "rawValues": [ + "2018-01-01T00:00:00.000Z", + ], + "xValues": [ + "2018", + ], }, "id": "2018-01-01T00:00:00.000Z", "name": "2018", diff --git a/packages/sdk-ui/src/__stories__/relative-date-filter-tile.stories.tsx b/packages/sdk-ui/src/__stories__/relative-date-filter-tile.stories.tsx index 25b16da0..6dc63947 100644 --- a/packages/sdk-ui/src/__stories__/relative-date-filter-tile.stories.tsx +++ b/packages/sdk-ui/src/__stories__/relative-date-filter-tile.stories.tsx @@ -6,7 +6,7 @@ import { DimensionalLevelAttribute, Filter, RelativeDateFilter, - filterFactory as filters, + filterFactory, } from '@sisense/sdk-data'; const template = templateForComponent(RelativeDateFilterTile); @@ -33,7 +33,9 @@ const onUpdate = (filter: Filter | null) => { export const Vertical = template({ title: 'Relative Date: Vertical', - filter: (filters.dateRelativeTo(mockAttributeDays, 0, 2) as RelativeDateFilter).serializable(), + filter: ( + filterFactory.dateRelativeTo(mockAttributeDays, 0, 2) as RelativeDateFilter + ).serializable(), arrangement: 'vertical', onUpdate, limit: { @@ -44,7 +46,9 @@ export const Vertical = template({ export const Horizontal = template({ title: 'Relative Date: Horizontal', - filter: (filters.dateRelativeFrom(mockAttributeYears, 0, 1) as RelativeDateFilter).serializable(), + filter: ( + filterFactory.dateRelativeFrom(mockAttributeYears, 0, 1) as RelativeDateFilter + ).serializable(), arrangement: 'horizontal', onUpdate, }); diff --git a/packages/sdk-ui/src/app/settings/settings.test.ts b/packages/sdk-ui/src/app/settings/settings.test.ts index 3e360586..01265ef3 100644 --- a/packages/sdk-ui/src/app/settings/settings.test.ts +++ b/packages/sdk-ui/src/app/settings/settings.test.ts @@ -15,8 +15,9 @@ const mockGet = vi.fn().mockImplementation((url) => { } }); -const mockHttpClient: Pick = { +const mockHttpClient: Pick = { get: mockGet, + url: 'http://test.com/', }; describe('getSettings function', () => { diff --git a/packages/sdk-ui/src/app/settings/settings.ts b/packages/sdk-ui/src/app/settings/settings.ts index 723917eb..efd2f15a 100644 --- a/packages/sdk-ui/src/app/settings/settings.ts +++ b/packages/sdk-ui/src/app/settings/settings.ts @@ -67,7 +67,7 @@ const defaultAppConfig: Required = { */ export async function getSettings( customConfig: ConfigurableAppSettings, - httpClient: Pick, + httpClient: Pick, useDefaultPalette?: boolean, ): Promise { const serverSettings = await loadServerSettings(httpClient, useDefaultPalette); @@ -102,7 +102,10 @@ function mapFeatures(features: Features): FeatureMap { * @param isWat - Whether the application is running with WAT authentication * @returns - Server settings */ -async function loadServerSettings(httpClient: Pick, useDefaultPalette = false) { +async function loadServerSettings( + httpClient: Pick, + useDefaultPalette = false, +) { const globals = await httpClient.get('api/globals'); if (!globals) { throw new Error('Failed to load server settings'); @@ -111,7 +114,7 @@ async function loadServerSettings(httpClient: Pick, useDefaul ? ({ colors: getDefaultThemeSettings().palette.variantColors } as LegacyPalette) : await getLegacyPalette(getPaletteName(globals.designSettings), httpClient); const serverSettings: ServerSettings = { - serverThemeSettings: convertToThemeSettings(globals.designSettings, palette), + serverThemeSettings: convertToThemeSettings(globals.designSettings, palette, httpClient.url), serverLanguage: globals.language, serverVersion: globals.version, serverFeatures: mapFeatures(globals.features), diff --git a/packages/sdk-ui/src/chart-data-options/utils.ts b/packages/sdk-ui/src/chart-data-options/utils.ts index 3e2a5ac3..53fa679d 100644 --- a/packages/sdk-ui/src/chart-data-options/utils.ts +++ b/packages/sdk-ui/src/chart-data-options/utils.ts @@ -34,6 +34,13 @@ const safeMerge = (sourceToInherit: AnyObject, sourceToAbsorb: AnyObject): AnyOb return Object.assign(Object.create(sourceToInherit), sourceToAbsorb) as AnyObject; }; +const safeUnmerge = (sourceWithInheritance: AnyObject) => { + return { + child: { ...sourceWithInheritance }, + parent: Object.getPrototypeOf(sourceWithInheritance), + }; +}; + /** * Combines two objects into a single one with saving prototype inheritance of "sourceWithInheritance" argument * @@ -122,3 +129,32 @@ export const translateColumnToMeasure = ( ) => { return translateValueToMeasure(translateColumnToValue(c)); }; + +export const translateCategoryOrValueToColumn = < + Source extends Category | Value, + Target extends AnyColumn, +>( + option: Source, +) => { + const { child: style, parent: column } = safeUnmerge(option); + + if (isEmpty(style)) { + return column as Target; + } + + return { + ...style, + column, + } as Target; +}; + +export const translateCategoryToColumn = (option: Category) => { + return translateCategoryOrValueToColumn(option); +}; + +export const translateValueToColumn = (option: Value) => { + return translateCategoryOrValueToColumn< + Value, + MeasureColumn | CalculatedMeasureColumn | StyledMeasureColumn + >(option); +}; diff --git a/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.test.ts b/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.test.ts index bca67ef2..9da77658 100644 --- a/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.test.ts +++ b/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.test.ts @@ -11,14 +11,14 @@ describe('validateCategoricalChartDataOptions', () => { const VALUE_2 = measureFactory.sum(DM.Commerce.Cost); const VALUE_3 = measureFactory.sum(DM.Commerce.Quantity); - it('should throw an error when dataOptions.value is empty', () => { + it('should not throw an error when dataOptions.value is empty', () => { const chartType = 'pie'; const dataOptions = { category: [CATEGORY_1], value: [], }; - expect(() => validateCategoricalChartDataOptions(chartType, dataOptions)).toThrow(); + expect(() => validateCategoricalChartDataOptions(chartType, dataOptions)).not.toThrow(); }); it('should not throw an error when dataOptions.value is not empty', () => { diff --git a/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.ts b/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.ts index 84383f49..34e85911 100644 --- a/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.ts +++ b/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-categorical-data-options.ts @@ -1,4 +1,3 @@ -import { TranslatableError } from '../../translation/translatable-error'; import { CategoricalChartType } from '../../types'; import { CategoricalChartDataOptions } from '../types'; @@ -6,9 +5,6 @@ export function validateCategoricalChartDataOptions( chartType: CategoricalChartType, dataOptions: CategoricalChartDataOptions, ): CategoricalChartDataOptions { - if (!dataOptions.value || dataOptions.value.length === 0) { - throw new TranslatableError('errors.dataOptions.emptyValueArray'); - } return filterCategoricalDataOptionsByAllowedLength(chartType, dataOptions); } diff --git a/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-data-options.test.ts b/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-data-options.test.ts index 2ed3e87c..b351be6d 100644 --- a/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-data-options.test.ts +++ b/packages/sdk-ui/src/chart-data-options/validate-data-options/validate-data-options.test.ts @@ -203,30 +203,30 @@ describe('isDataOptionsValid', () => { }); }); - describe('should falsy validate incorrect categorical chart dataOptions', () => { - const invalidDataOptions = { + describe('should truly validate empty categorical chart dataOptions', () => { + const emptyDataOptions = { category: [], value: [], } as ChartDataOptions; - it('should falsy validate incorrect pie chart dataOptions', () => { + it('should truly validate empty pie chart dataOptions', () => { let errorThrownForPie = false; try { - validateDataOptions('pie', invalidDataOptions); + validateDataOptions('pie', emptyDataOptions); } catch (e) { errorThrownForPie = true; } - expect(errorThrownForPie).toBeTruthy(); + expect(errorThrownForPie).toBeFalsy(); }); - it('should falsy validate incorrect funnel chart dataOptions', () => { + it('should truly validate empty funnel chart dataOptions', () => { let errorThrownForPie = false; try { - validateDataOptions('funnel', invalidDataOptions); + validateDataOptions('funnel', emptyDataOptions); } catch (e) { errorThrownForPie = true; } - expect(errorThrownForPie).toBeTruthy(); + expect(errorThrownForPie).toBeFalsy(); }); }); }); diff --git a/packages/sdk-ui/src/chart-data/cartesian-data.ts b/packages/sdk-ui/src/chart-data/cartesian-data.ts index 8f7fcc94..6c0cd97c 100644 --- a/packages/sdk-ui/src/chart-data/cartesian-data.ts +++ b/packages/sdk-ui/src/chart-data/cartesian-data.ts @@ -48,8 +48,12 @@ export const validateCartesianChartDataOptions = ( }; }; -// Given table of data and options, create cartesian data for -// chart like line/area/bar and others +/** + * Creates cartesian data for chart like line/area/bar and others given table of data and options + * @param chartDataOptions - Internal cartesian chart data options + * @param dataTable - Data table + * @returns Cartesian chart data + */ export const cartesianData = ( chartDataOptions: CartesianChartDataOptionsInternal, dataTable: DataTable, @@ -211,6 +215,40 @@ export const getOrderedXValues = ( }); }; +/** + * Get single series value for a row + * taking into account whether the y-axis column is specified + */ +const getSingleSeriesValue = ( + row: Row, + xValue: CategoricalXValues, + yAggColumn: Column | undefined, +) => { + // use a small value instead of 0 so pie chart can render + const value = yAggColumn ? (getValue(row, yAggColumn) as number) : 0.00001; + const { color, rawValue } = row[yAggColumn?.index ?? 0] ?? {}; + + return { + rawValue, + xValue: xValue.rawValues, + xDisplayValue: xValue.xValues, + xCompareValue: xValue.compareValues, + value: value === undefined ? NaN : value, + blur: yAggColumn ? isBlurred(row, yAggColumn) : undefined, + ...(color && { color }), + }; +}; + +/** + * Builds series data for multiple measures without break by. + * If there is no measure specified, returns series of 0 values. + * + * @param dataTable - Data table + * @param xValuesOrdered - Ordered x-axis values + * @param xColumns - x-axis columns + * @param yColumnNames - y-axis column names + * @returns series data + */ const withMultipleValues = ( dataTable: DataTable, xValuesOrdered: CategoricalXValues[], @@ -218,17 +256,13 @@ const withMultipleValues = ( yColumnNames: string[], yDataOptions: Value[], ) => { - const yAggColumns = getColumnsByName(dataTable, yColumnNames); + const yAggColumns = + yColumnNames.length > 0 ? getColumnsByName(dataTable, yColumnNames) : [undefined]; const optionsByColumn = yDataOptions.reduce>((acc, opts) => { acc[opts.name] = opts; return acc; }, {}); - // require at least one measure - if (yAggColumns.length === 0) { - return { type: 'cartesian', series: [], xValues: [] }; - } - // separate rows by series const rowsByXColumns = getIndexedRows(dataTable.rows, xColumns); @@ -239,27 +273,20 @@ const withMultipleValues = ( // since we aggregated we know it is single number // expect one row or none const row = rows ? rows[0] : []; - const value = getValue(row, yAggColumn) as number; - const { color, rawValue } = row[yAggColumn.index] ?? {}; - return { - rawValue, - xValue: xValue.rawValues, - xDisplayValue: xValue.xValues, - xCompareValue: xValue.compareValues, - value: value === undefined ? NaN : value, - blur: isBlurred(row, yAggColumn), - ...(color && { color }), - }; + return getSingleSeriesValue(row, xValue, yAggColumn); }); - const colorOpts = optionsByColumn[yAggColumn.name].color; + const yAggColumnName = yAggColumn?.name ?? ''; + const seriesTitle = yAggColumnName ? getDataOptionTitle(optionsByColumn[yAggColumnName]) : ''; + + const colorOpts = optionsByColumn[yAggColumnName]?.color; if (colorOpts) { seriesYValues = seriesDataColoringFunction(seriesYValues, colorOpts); } return { - name: yAggColumn.name, - title: getDataOptionTitle(optionsByColumn[yAggColumn.name]), + name: yAggColumnName, + title: seriesTitle, data: seriesYValues, }; }); @@ -283,6 +310,18 @@ const getSeriesValues = (row: Row, columns: readonly Column[]) => { return getValues(row, columns).map(({ rawValue }) => rawValue); }; +/** + * Builds series data for a single measure taking into break by. + * If there is no measure specified, returns series of 0 values. + * + * @param dataTable - Data table + * @param xValuesOrdered - Ordered x-axis values + * @param xColumns - x-axis columns + * @param yColumnName - y-axis column name + * @param seriesColumns - series columns + * @param breakBy - break by category + * @returns series data + */ const withBreakBy = ( dataTable: DataTable, xValuesOrdered: CategoricalXValues[], @@ -293,11 +332,6 @@ const withBreakBy = ( ) => { const yAggColumn = getColumnByName(dataTable, yColumnName); - // require a measure - if (!yAggColumn) { - return { type: 'cartesian', series: [], xValues: [] }; - } - // separate rows by series const rowsBySeries = separateBy(dataTable.rows, seriesColumns); @@ -320,19 +354,10 @@ const withBreakBy = ( const seriesValues = seriesRowsIndexByXValues.map((seriesRowsIndexed) => { const seriesYValues = xValuesOrdered.map((xValue): SeriesValueData => { const rows = seriesRowsIndexed.rowsByXColumns[xValue.key]; + // since we aggregated we know it is single number + // expect one row or none const row = rows ? rows[0] : []; - // since we aggregated, expect one row or none - const value = getValue(row, yAggColumn) as number; - const { color, rawValue } = row[yAggColumn.index] ?? {}; - return { - rawValue, - value: value === undefined ? NaN : value, - xValue: xValue.rawValues, - xDisplayValue: xValue.xValues, - xCompareValue: xValue.compareValues, - blur: isBlurred(row, yAggColumn), - ...(color && { color }), - }; + return getSingleSeriesValue(row, xValue, yAggColumn); }); return { name: seriesRowsIndexed.seriesName, diff --git a/packages/sdk-ui/src/chart-options-processor/apply-event-handlers.ts b/packages/sdk-ui/src/chart-options-processor/apply-event-handlers.ts index 9065414e..2984eb3d 100644 --- a/packages/sdk-ui/src/chart-options-processor/apply-event-handlers.ts +++ b/packages/sdk-ui/src/chart-options-processor/apply-event-handlers.ts @@ -2,22 +2,18 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ import merge from 'deepmerge'; import { - DataPoint, HighchartsPointerEvent, HighchartsSelectEvent, HighchartsPoint, HighchartsSelectEventAxis, - ScatterDataPoint, - ChartDataPoints, - BoxplotDataPoint, } from '../types'; -import { DataPointsEventHandler, ScatterDataPointsEventHandler } from '../props'; import { HighchartsOptionsInternal } from '../chart-options-processor/chart-options-service'; import { - SisenseChartDataPoint, SisenseChartDataPointEventHandler, SisenseChartDataPointsEventHandler, } from '../sisense-chart/types'; +import { ChartDataOptionsInternal } from '..'; +import { getDataPoint } from './data-points'; export type HighchartsEventOptions = { chart: { zoomType?: string; events: { selection?: (ev: HighchartsSelectEvent) => void } }; @@ -35,6 +31,7 @@ export type HighchartsEventOptions = { export const applyEventHandlersToChart = ( chartOptions: HighchartsOptionsInternal, + dataOptions: ChartDataOptionsInternal, { onDataPointClick, onDataPointContextMenu, @@ -61,11 +58,9 @@ export const applyEventHandlersToChart = ( if (onDataPointsSelected) { eventOptions.chart.zoomType = 'x'; - onDataPointsSelected = onDataPointsSelected as DataPointsEventHandler; // make selection two dimensional for scatter charts if (['scatter', 'bubble'].includes(chartOptions.chart?.type)) { eventOptions.chart.zoomType = 'xy'; - onDataPointsSelected = onDataPointsSelected as ScatterDataPointsEventHandler; } eventOptions.chart.events.selection = (nativeEvent: HighchartsSelectEvent) => { nativeEvent.preventDefault(); @@ -74,8 +69,8 @@ export const applyEventHandlersToChart = ( selectedPoints.forEach((point) => { point.state = ''; }); - (onDataPointsSelected as DataPointsEventHandler | ScatterDataPointsEventHandler)( - selectedPoints.map(getDataPoint) as ChartDataPoints, + onDataPointsSelected( + selectedPoints.map((p) => getDataPoint(p, dataOptions)), originalEvent, ); }; @@ -84,7 +79,7 @@ export const applyEventHandlersToChart = ( if (onDataPointClick) { eventOptions.plotOptions.series.point.events.click = (nativeEvent: HighchartsPointerEvent) => { nativeEvent.point.state = 'hover'; - onDataPointClick(getDataPoint(nativeEvent.point), nativeEvent); + onDataPointClick(getDataPoint(nativeEvent.point, dataOptions), nativeEvent); }; } @@ -93,27 +88,13 @@ export const applyEventHandlersToChart = ( nativeEvent: HighchartsPointerEvent, ) => { nativeEvent.preventDefault(); - onDataPointContextMenu(getDataPoint(nativeEvent.point), nativeEvent); + onDataPointContextMenu(getDataPoint(nativeEvent.point, dataOptions), nativeEvent); }; } return merge(chartOptions, eventOptions); }; -const getDataPoint = (point: HighchartsPoint): SisenseChartDataPoint => { - switch (point.series?.initialType || point.series?.type) { - case 'bubble': - case 'scatter': - return getScatterDataPoint(point); - case 'funnel': - return getFunnelDataPoint(point); - case 'boxplot': - return getBoxplotDataPoint(point); - default: - return getCartesianDataPoint(point); - } -}; - const getSelectedPoints = ( xAxis: HighchartsSelectEventAxis, yAxis?: HighchartsSelectEventAxis, @@ -130,36 +111,3 @@ const getSelectedPoints = ( return xPoints.filter((point) => yPoints.includes(point)); }; - -const getCartesianDataPoint = (point: HighchartsPoint): DataPoint => ({ - value: point.custom?.rawValue, - categoryValue: point.custom?.xValue?.[0], - seriesValue: point.series?.options?.custom?.rawValue?.[0], - categoryDisplayValue: point.name ?? point.category, -}); - -const getScatterDataPoint = (point: HighchartsPoint): ScatterDataPoint => ({ - x: point.x, - y: point.y, - size: point.z, - breakByPoint: point.custom?.maskedBreakByPoint, - breakByColor: point.custom?.maskedBreakByColor, -}); - -const getFunnelDataPoint = (point: HighchartsPoint): DataPoint => ({ - value: point.options.custom.number1, - categoryValue: point.options.name, - categoryDisplayValue: point.name, -}); - -const getBoxplotDataPoint = (point: HighchartsPoint): BoxplotDataPoint => { - return { - boxMin: point.options.q1!, - boxMedian: point.options.median!, - boxMax: point.options.q3!, - whiskerMin: point.options.low!, - whiskerMax: point.options.high!, - categoryValue: point.category, - categoryDisplayValue: point.category, - }; -}; diff --git a/packages/sdk-ui/src/chart-options-processor/chart-options-service.test.ts b/packages/sdk-ui/src/chart-options-processor/chart-options-service.test.ts index 854a7801..8308bb52 100644 --- a/packages/sdk-ui/src/chart-options-processor/chart-options-service.test.ts +++ b/packages/sdk-ui/src/chart-options-processor/chart-options-service.test.ts @@ -1551,31 +1551,31 @@ describe('funnelChart', () => { name: 'Website visits', y: 15654, color: '#00cee6', - custom: { number1: 100 }, + custom: { number1: 100, rawValue: 15654, xValue: ['Website visits'] }, }, { name: 'Downloads', y: 4064, color: '#9b9bd7', - custom: { number1: 25.96141561262297 }, + custom: { number1: 25.96141561262297, rawValue: 4064, xValue: ['Downloads'] }, }, { name: 'Requested price list', y: 1987, color: '#6eda55', - custom: { number1: 12.693241344065415 }, + custom: { number1: 12.693241344065415, rawValue: 1987, xValue: ['Requested price list'] }, }, { name: 'Invoice sent', y: 976, color: '#fc7570', - custom: { number1: 6.234828158937013 }, + custom: { number1: 6.234828158937013, rawValue: 976, xValue: ['Invoice sent'] }, }, { name: 'Finalized', y: 846, color: '#fbb755', - custom: { number1: 5.40436949022614 }, + custom: { number1: 5.40436949022614, rawValue: 846, xValue: ['Finalized'] }, }, ]); }); diff --git a/packages/sdk-ui/src/chart-options-processor/data-points.test.ts b/packages/sdk-ui/src/chart-options-processor/data-points.test.ts new file mode 100644 index 00000000..277e8424 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/data-points.test.ts @@ -0,0 +1,366 @@ +import uniqueId from 'lodash-es/uniqueId'; +import merge from 'ts-deepmerge'; +import { + BoxplotChartDataOptionsInternal, + CartesianChartDataOptionsInternal, + CategoricalChartDataOptionsInternal, + Category, + HighchartsPoint, + RangeChartDataOptionsInternal, + ScatterChartDataOptionsInternal, + Value, +} from '..'; +import { getDataPoint } from './data-points'; + +const createPointMock = (chartType: string, point: Partial) => { + return merge( + { + series: { + chart: { + options: { + chart: { + type: chartType, + }, + }, + }, + }, + options: { + custom: {}, + }, + }, + point, + ) as HighchartsPoint; +}; + +const createDataOptionMock = (isMeasure?: boolean): Category | Value => { + const base = { testId: uniqueId() }; + + if (isMeasure) { + return { + ...base, + aggregation: 'sum', + } as unknown as Value; + } + return { + ...base, + type: 'attribute', + } as unknown as Category; +}; + +describe('getDataPoint', () => { + it('should prepare scatter data point with valid entries', () => { + const rawPoint = createPointMock('scatter', { + custom: { + maskedX: '1', + maskedY: '2', + maskedBreakByPoint: '3', + maskedBreakByColor: '4', + maskedSize: '5', + }, + }); + const dataOptions = { + x: createDataOptionMock(), + y: createDataOptionMock(), + breakByPoint: createDataOptionMock(), + breakByColor: createDataOptionMock(), + size: createDataOptionMock(true), + } as ScatterChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + x: { + id: 'x', + value: '1', + dataOption: dataOptions.x, + }, + y: { + id: 'y', + value: '2', + dataOption: dataOptions.y, + }, + breakByPoint: { + id: 'breakByPoint', + value: '3', + dataOption: dataOptions.breakByPoint, + }, + breakByColor: { + id: 'breakByColor', + value: '4', + dataOption: dataOptions.breakByColor, + }, + size: { + id: 'size', + value: '5', + dataOption: dataOptions.size, + }, + }); + }); + + it('should prepare funnel data point with valid entries', () => { + const rawPoint = createPointMock('funnel', { + custom: { + xValue: [1], + rawValue: 2, + }, + }); + const dataOptions = { + breakBy: [createDataOptionMock()], + y: [createDataOptionMock(true)], + } as unknown as CategoricalChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + category: [ + { + id: 'category.0', + value: 1, + dataOption: dataOptions.breakBy[0], + }, + ], + value: [ + { + id: 'value.0', + value: 2, + dataOption: dataOptions.y[0], + }, + ], + }); + }); + + it('should prepare pie data point with valid entries', () => { + const rawPoint = createPointMock('pie', { + custom: { + xValue: [1], + rawValue: 2, + }, + }); + const dataOptions = { + breakBy: [createDataOptionMock()], + y: [createDataOptionMock(true)], + } as unknown as CategoricalChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + category: [ + { + id: 'category.0', + value: 1, + dataOption: dataOptions.breakBy[0], + }, + ], + value: [ + { + id: 'value.0', + value: 2, + dataOption: dataOptions.y[0], + }, + ], + }); + }); + + it('should prepare treemap/sunburst data point with valid entries', () => { + const rawPoint = createPointMock('treemap', { + custom: { + rawValues: [1], + }, + value: 2, + options: { + custom: { + level: 1, + }, + }, + } as unknown as HighchartsPoint); + const dataOptions = { + breakBy: [createDataOptionMock()], + y: [createDataOptionMock(true)], + } as unknown as CategoricalChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + category: [ + { + id: 'category.0', + value: 1, + dataOption: dataOptions.breakBy[0], + }, + ], + value: [ + { + id: 'value.0', + value: 2, + dataOption: dataOptions.y[0], + }, + ], + }); + }); + + it('should prepare boxplot data point with valid entries', () => { + const rawPoint = createPointMock('boxplot', { + options: { + q1: 1, + median: 2, + q3: 3, + low: 4, + high: 5, + }, + custom: { + xValue: [6], + }, + } as HighchartsPoint); + const dataOptions = { + category: createDataOptionMock(), + boxMin: createDataOptionMock(true), + boxMedian: createDataOptionMock(true), + boxMax: createDataOptionMock(true), + whiskerMin: createDataOptionMock(true), + whiskerMax: createDataOptionMock(true), + } as BoxplotChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + category: [ + { + id: 'category.0', + value: 6, + dataOption: dataOptions.category, + }, + ], + value: [ + { + id: 'value.0.boxMin', + value: 1, + dataOption: dataOptions.boxMin, + }, + { + id: 'value.0.boxMedian', + value: 2, + dataOption: dataOptions.boxMedian, + }, + { + id: 'value.0.boxMax', + value: 3, + dataOption: dataOptions.boxMax, + }, + { + id: 'value.0.whiskerMin', + value: 4, + dataOption: dataOptions.whiskerMin, + }, + { + id: 'value.0.whiskerMax', + value: 5, + dataOption: dataOptions.whiskerMax, + }, + ], + }); + }); + + it('should prepare arearange data point with valid entries', () => { + const rawPoint = createPointMock('arearange', { + custom: { + xValue: [1], + }, + options: { + low: 2, + high: 3, + }, + series: { + index: 0, + options: { + custom: { + rawValue: [4], + }, + }, + }, + } as HighchartsPoint); + const dataOptions = { + x: [createDataOptionMock()], + rangeValues: [[createDataOptionMock(true), createDataOptionMock(true)]], + breakBy: [createDataOptionMock()], + } as unknown as RangeChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + category: [ + { + id: 'category.0', + value: 1, + dataOption: dataOptions.x[0], + }, + ], + value: [ + { + id: 'value.0.lowerBound', + value: 2, + dataOption: dataOptions.rangeValues[0][0], + }, + { + id: 'value.0.upperBound', + value: 3, + dataOption: dataOptions.rangeValues[0][1], + }, + ], + breakBy: [ + { + id: 'breakBy.0', + value: 4, + dataOption: dataOptions.breakBy[0], + }, + ], + }); + }); + + it('should prepare cartesian data point with valid entries', () => { + const rawPoint = createPointMock('column', { + custom: { + rawValue: 2, + xValue: [1], + }, + series: { + index: 0, + options: { + custom: { + rawValue: [3], + }, + }, + }, + } as HighchartsPoint); + const dataOptions = { + x: [createDataOptionMock()], + y: [createDataOptionMock(true)], + breakBy: [createDataOptionMock()], + } as unknown as CartesianChartDataOptionsInternal; + + const { entries } = getDataPoint(rawPoint, dataOptions); + + expect(entries).toMatchObject({ + category: [ + { + id: 'category.0', + value: 1, + dataOption: dataOptions.x[0], + }, + ], + value: [ + { + id: 'value.0', + value: 2, + dataOption: dataOptions.y[0], + }, + ], + breakBy: [ + { + id: 'breakBy.0', + value: 3, + dataOption: dataOptions.breakBy[0], + }, + ], + }); + }); +}); diff --git a/packages/sdk-ui/src/chart-options-processor/data-points.ts b/packages/sdk-ui/src/chart-options-processor/data-points.ts new file mode 100644 index 00000000..3c040431 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/data-points.ts @@ -0,0 +1,363 @@ +import { MetadataTypes } from '@sisense/sdk-data'; +import { DataPoint, HighchartsPoint, ScatterDataPoint, BoxplotDataPoint } from '../types'; +import { SisenseChartDataPoint } from '../sisense-chart/types'; +import { + BoxplotChartDataOptionsInternal, + CartesianChartDataOptionsInternal, + CategoricalChartDataOptionsInternal, + Category, + ChartDataOptionsInternal, + DataPointEntry, + RangeChartDataOptionsInternal, + ScatterChartDataOptionsInternal, + Value, +} from '..'; +import { + translateCategoryOrValueToColumn, + translateCategoryToAttribute, + translateValueToMeasure, +} from '@/chart-data-options/utils'; + +export function getDataPointMetadata(dataOptionPath: string, dataOption: Category | Value) { + return { + id: dataOptionPath, + dataOption: translateCategoryOrValueToColumn(dataOption), + ...(MetadataTypes.isAttribute(dataOption) && { + attribute: translateCategoryToAttribute(dataOption as Category), + }), + ...(MetadataTypes.isMeasure(dataOption) && { + measure: translateValueToMeasure(dataOption as Value), + }), + }; +} + +const getBaseCartesianDataPoint = (point: HighchartsPoint): DataPoint => ({ + value: point.custom?.rawValue, + categoryValue: point.custom?.xValue?.[0], + seriesValue: point.series?.options?.custom?.rawValue?.[0], + categoryDisplayValue: point.name ?? point.category, +}); + +const getCartesianDataPoint = ( + point: HighchartsPoint, + dataOptions: CartesianChartDataOptionsInternal, +): DataPoint => { + const categoryEntries: DataPointEntry[] = dataOptions.x.map((item, index) => { + return { + ...getDataPointMetadata(`category.${index}`, item), + value: point.custom?.xValue?.[index], + } as DataPointEntry; + }); + + const hasMultipleValues = dataOptions.y.length >= 2; + const valueEntries: DataPointEntry[] = dataOptions.y + .filter((item, index) => !hasMultipleValues || point.series.index === index) + .flatMap((item) => { + return { + ...getDataPointMetadata(`value.${point.series.index}`, item), + value: point.custom?.rawValue, + } as DataPointEntry; + }); + + const breakByEntries: DataPointEntry[] = dataOptions.breakBy.map((item, index) => { + return { + ...getDataPointMetadata(`breakBy.${index}`, item), + value: point.series?.options.custom?.rawValue?.[0], + } as DataPointEntry; + }); + + const entries = { + category: categoryEntries, + value: valueEntries, + breakBy: breakByEntries, + }; + + return { + ...getBaseCartesianDataPoint(point), + entries, + }; +}; + +const getRangeDataPoint = ( + point: HighchartsPoint, + dataOptions: RangeChartDataOptionsInternal, +): DataPoint => { + const categoryEntries: DataPointEntry[] = dataOptions.x.map((item, index) => { + return { + ...getDataPointMetadata(`category.${index}`, item), + value: point.custom?.xValue?.[index], + } as DataPointEntry; + }); + + const hasMultipleValues = dataOptions.rangeValues.length >= 2; + const valueEntries: DataPointEntry[] = dataOptions.rangeValues + .filter((item, index) => !hasMultipleValues || point.series.index === index) + .flatMap((item) => { + return item.map((boundItem, boundIndex) => { + const isLowerBound = boundIndex === 0; + const dataOptionPath = `value.${point.series.index}.${ + isLowerBound ? 'lowerBound' : 'upperBound' + }`; + const value = isLowerBound ? point.options?.low : point.options?.high; + return { + ...getDataPointMetadata(dataOptionPath, boundItem), + value, + } as DataPointEntry; + }); + }); + + const breakByEntries: DataPointEntry[] = dataOptions.breakBy.map((item, index) => { + return { + ...getDataPointMetadata(`breakBy.${index}`, item), + value: point.series?.options.custom?.rawValue?.[0], + } as DataPointEntry; + }); + + const entries = { + category: categoryEntries, + value: valueEntries, + breakBy: breakByEntries, + }; + + return { + ...getBaseCartesianDataPoint(point), + entries, + }; +}; + +const getScatterDataPoint = ( + point: HighchartsPoint, + dataOptions: ScatterChartDataOptionsInternal, +): ScatterDataPoint => { + const entries: NonNullable = {}; + + if (dataOptions.x) { + entries.x = { + ...getDataPointMetadata(`x`, dataOptions.x), + value: point.custom.maskedX, + } as DataPointEntry; + } + + if (dataOptions.y) { + entries.y = { + ...getDataPointMetadata(`y`, dataOptions.y), + value: point.custom.maskedY, + } as DataPointEntry; + } + + if (dataOptions.breakByPoint) { + entries.breakByPoint = { + ...getDataPointMetadata(`breakByPoint`, dataOptions.breakByPoint), + value: point.custom?.maskedBreakByPoint, + } as DataPointEntry; + } + + if (dataOptions.breakByColor) { + entries.breakByColor = { + ...getDataPointMetadata(`breakByColor`, dataOptions.breakByColor), + value: point.custom?.maskedBreakByColor, + } as DataPointEntry; + } + + if (dataOptions.size) { + entries.size = { + ...getDataPointMetadata(`size`, dataOptions.size), + value: point.custom.maskedSize, + } as DataPointEntry; + } + + return { + x: point.x, + y: point.y, + size: point.z, + breakByPoint: point.custom?.maskedBreakByPoint, + breakByColor: point.custom?.maskedBreakByColor, + entries, + }; +}; + +const getFunnelDataPoint = ( + point: HighchartsPoint, + dataOptions: CategoricalChartDataOptionsInternal, +): DataPoint => { + const categoryEntries: DataPointEntry[] = dataOptions.breakBy.map((item, index) => { + return { + ...getDataPointMetadata(`category.${index}`, item), + value: point.custom?.xValue?.[index], + } as DataPointEntry; + }); + + const valueEntries: DataPointEntry[] = dataOptions.y.map((item, index) => { + return { + ...getDataPointMetadata(`value.${index}`, item), + value: point.custom?.rawValue, + } as DataPointEntry; + }); + + const entries = { + category: categoryEntries, + value: valueEntries, + }; + + return { + value: point.options.custom.number1, + categoryValue: point.options.name, + categoryDisplayValue: point.name, + entries, + }; +}; + +const getPieDataPoint = ( + point: HighchartsPoint, + dataOptions: CategoricalChartDataOptionsInternal, +): DataPoint => { + const categoryEntries: DataPointEntry[] = dataOptions.breakBy.map((item, index) => { + return { + ...getDataPointMetadata(`category.${index}`, item), + value: point.custom?.xValue?.[index], + } as DataPointEntry; + }); + + const hasMultipleValues = dataOptions.y.length >= 2; + const valueEntries: DataPointEntry[] = dataOptions.y + .filter((item, index) => !hasMultipleValues || point.series.index === index) + .map((item, index) => { + return { + ...getDataPointMetadata(`value.${index}`, item), + value: point.custom?.rawValue, + } as DataPointEntry; + }); + + const entries = { + category: categoryEntries, + value: valueEntries, + }; + + return { + ...getBaseCartesianDataPoint(point), + entries, + }; +}; + +const getTreemapDataPoint = ( + point: HighchartsPoint, + dataOptions: CategoricalChartDataOptionsInternal, +): DataPoint => { + const pointLevel = point.options.custom.level!; + const isParent = pointLevel !== point.options.custom.levelsCount; + + const categoryEntries: DataPointEntry[] = dataOptions.breakBy + .slice(0, pointLevel) + .map((item, index) => { + return { + ...getDataPointMetadata(`category.${index}`, item), + value: isParent ? point.custom?.rawValues?.[index] : point.custom?.xValue?.[index], + } as DataPointEntry; + }); + + const hasMultipleValues = dataOptions.y.length >= 2; + const valueEntries: DataPointEntry[] = dataOptions.y + .filter((item, index) => !hasMultipleValues || point.series.index === index) + .map((item, index) => { + const value = isParent ? point.value : point.custom?.rawValue; + return { + ...getDataPointMetadata(`value.${index}`, item), + value, + } as DataPointEntry; + }); + + const entries = { + category: categoryEntries, + value: valueEntries, + }; + + return { + ...getBaseCartesianDataPoint(point), + entries, + }; +}; + +const getBoxplotDataPoint = ( + point: HighchartsPoint, + dataOptions: BoxplotChartDataOptionsInternal, +): BoxplotDataPoint => { + const isOutlierPoint = point.series.type === 'scatter'; + const entries = {} as NonNullable; + + if (isOutlierPoint) { + entries.value = [ + { + ...getDataPointMetadata(`value.0.outlier`, dataOptions.outliers!), + value: point.options.y, + } as DataPointEntry, + ]; + } else { + entries.value = [ + { + ...getDataPointMetadata(`value.0.boxMin`, dataOptions.boxMin), + value: point.options.q1!, + }, + { + ...getDataPointMetadata(`value.0.boxMedian`, dataOptions.boxMedian), + value: point.options.median!, + }, + { + ...getDataPointMetadata(`value.0.boxMax`, dataOptions.boxMax), + value: point.options.q3!, + }, + { + ...getDataPointMetadata(`value.0.whiskerMin`, dataOptions.whiskerMin), + value: point.options.low!, + }, + { + ...getDataPointMetadata(`value.0.whiskerMax`, dataOptions.whiskerMax), + value: point.options.high!, + }, + ]; + } + + if (dataOptions.category) { + entries.category = [ + { + ...getDataPointMetadata(`category.0`, dataOptions.category), + value: point.custom.xValue?.[0], + } as DataPointEntry, + ]; + } + + return { + boxMin: point.options.q1, + boxMedian: point.options.median, + boxMax: point.options.q3, + whiskerMin: point.options.low, + whiskerMax: point.options.high, + outlier: point.options.y, + categoryValue: point.category, + categoryDisplayValue: point.category, + entries, + }; +}; + +export function getDataPoint( + point: HighchartsPoint, + dataOptions: ChartDataOptionsInternal, +): SisenseChartDataPoint { + switch (point.series.chart.options.chart.type) { + case 'bubble': + case 'scatter': + return getScatterDataPoint(point, dataOptions as ScatterChartDataOptionsInternal); + case 'funnel': + return getFunnelDataPoint(point, dataOptions as CategoricalChartDataOptionsInternal); + case 'pie': + return getPieDataPoint(point, dataOptions as CategoricalChartDataOptionsInternal); + case 'treemap': + case 'sunburst': + return getTreemapDataPoint(point, dataOptions as CategoricalChartDataOptionsInternal); + case 'boxplot': + return getBoxplotDataPoint(point, dataOptions as BoxplotChartDataOptionsInternal); + case 'arearange': + return getRangeDataPoint(point, dataOptions as RangeChartDataOptionsInternal); + default: + return getCartesianDataPoint(point, dataOptions as CartesianChartDataOptionsInternal); + } +} diff --git a/packages/sdk-ui/src/chart-options-processor/translations/boxplot/boxplot-series.ts b/packages/sdk-ui/src/chart-options-processor/translations/boxplot/boxplot-series.ts index 80e94f36..6d46f732 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/boxplot/boxplot-series.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/boxplot/boxplot-series.ts @@ -28,12 +28,15 @@ export const buildBoxplotSeries = ( const series: SeriesType[] = [ { ...boxSerie, - data: boxSerie.data.map((item) => ({ + data: boxSerie.data.map((item, index) => ({ ...item, color: lineColor, fillColor: boxplotType === 'hollow' ? 'transparent' : upperQuartileColor, innerBoxColor: boxplotType === 'hollow' ? 'transparent' : lowerQuartileColor, selected: item.blur ?? false, + custom: { + xValue: data.xValues[index].rawValues, + }, })), medianWidth: 1, maxPointWidth: 42, @@ -57,6 +60,9 @@ export const buildBoxplotSeries = ( marker: { lineColor: item.blur ? blurredLineColor : lineColor, }, + custom: { + xValue: data.xValues[item.x].rawValues, + }, })), type: 'scatter', legendIndex: 1, diff --git a/packages/sdk-ui/src/chart-options-processor/translations/funnel-series.ts b/packages/sdk-ui/src/chart-options-processor/translations/funnel-series.ts index b708d970..f6c05a9b 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/funnel-series.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/funnel-series.ts @@ -96,7 +96,7 @@ const computeFunnelPercents = (seriesValues: HighchartsSeriesValues): Highcharts const data = seriesValues.data.map((value: SeriesPointStructure, index: number) => { const y = value.y as number; if (index === 0) baseY = y; - value.custom = { number1: fromFraction(baseY, y) }; + value.custom = { ...value.custom, number1: fromFraction(baseY, y) }; return value; }); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/sunburst/__snapshots__/sunburst-series.test.ts.snap b/packages/sdk-ui/src/chart-options-processor/translations/sunburst/__snapshots__/sunburst-series.test.ts.snap index 5b3a6d1c..70fa21e8 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/sunburst/__snapshots__/sunburst-series.test.ts.snap +++ b/packages/sdk-ui/src/chart-options-processor/translations/sunburst/__snapshots__/sunburst-series.test.ts.snap @@ -15,7 +15,13 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "Refurbished", + ], "subtotalValue": 1765420.5938019156, + "xValues": [ + "Refurbished", + ], }, "id": "Refurbished", "name": "Refurbished", @@ -26,7 +32,13 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "Unspecified", + ], "subtotalValue": 2706285.6384671647, + "xValues": [ + "Unspecified", + ], }, "id": "Unspecified", "name": "Unspecified", @@ -37,7 +49,13 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "New", + ], "subtotalValue": 11850787.423742265, + "xValues": [ + "New", + ], }, "id": "New", "name": "New", @@ -48,7 +66,13 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 1, "levelsCount": 3, + "rawValues": [ + "Used", + ], "subtotalValue": 23437131.859015867, + "xValues": [ + "Used", + ], }, "id": "Used", "name": "Used", @@ -59,7 +83,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "New", + "Female", + ], "subtotalValue": 419689.739569366, + "xValues": [ + "New", + "Female", + ], }, "id": "New_Female", "name": "Female", @@ -70,7 +102,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "New", + "Male", + ], "subtotalValue": 3145290.8236471266, + "xValues": [ + "New", + "Male", + ], }, "id": "New_Male", "name": "Male", @@ -81,7 +121,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "New", + "Unspecified", + ], "subtotalValue": 8285806.860525772, + "xValues": [ + "New", + "Unspecified", + ], }, "id": "New_Unspecified", "name": "Unspecified", @@ -92,7 +140,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Refurbished", + "Female", + ], "subtotalValue": 43991.970816612244, + "xValues": [ + "Refurbished", + "Female", + ], }, "id": "Refurbished_Female", "name": "Female", @@ -103,7 +159,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Refurbished", + "Male", + ], "subtotalValue": 750247.1492648125, + "xValues": [ + "Refurbished", + "Male", + ], }, "id": "Refurbished_Male", "name": "Male", @@ -114,7 +178,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Refurbished", + "Unspecified", + ], "subtotalValue": 971181.4737204909, + "xValues": [ + "Refurbished", + "Unspecified", + ], }, "id": "Refurbished_Unspecified", "name": "Unspecified", @@ -125,7 +197,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Unspecified", + "Female", + ], "subtotalValue": 107972.20067983866, + "xValues": [ + "Unspecified", + "Female", + ], }, "id": "Unspecified_Female", "name": "Female", @@ -136,7 +216,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Unspecified", + "Male", + ], "subtotalValue": 521698.6592757795, + "xValues": [ + "Unspecified", + "Male", + ], }, "id": "Unspecified_Male", "name": "Male", @@ -147,7 +235,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Unspecified", + "Unspecified", + ], "subtotalValue": 2076614.7785115466, + "xValues": [ + "Unspecified", + "Unspecified", + ], }, "id": "Unspecified_Unspecified", "name": "Unspecified", @@ -158,7 +254,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Used", + "Female", + ], "subtotalValue": 358606.70924161375, + "xValues": [ + "Used", + "Female", + ], }, "id": "Used_Female", "name": "Female", @@ -169,7 +273,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Used", + "Male", + ], "subtotalValue": 1741417.177718103, + "xValues": [ + "Used", + "Male", + ], }, "id": "Used_Male", "name": "Male", @@ -180,7 +292,15 @@ exports[`prepareSunburstDataItems > should prepare data items with sorting and c "custom": { "level": 2, "levelsCount": 3, + "rawValues": [ + "Used", + "Unspecified", + ], "subtotalValue": 21337107.97205615, + "xValues": [ + "Used", + "Unspecified", + ], }, "id": "Used_Unspecified", "name": "Unspecified", diff --git a/packages/sdk-ui/src/chart-options-processor/translations/sunburst/sunburst-series.ts b/packages/sdk-ui/src/chart-options-processor/translations/sunburst/sunburst-series.ts index 784de216..0e2c5b75 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/sunburst/sunburst-series.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/sunburst/sunburst-series.ts @@ -15,7 +15,7 @@ export function prepareSunburstDataItems( ) { const rootDataItem = { id: SUNBURST_ROOT_PARENT_ID, - name: dataOptions.y[0].title ?? dataOptions.y[0].name, + name: dataOptions.y[0]?.title ?? dataOptions.y[0]?.name, custom: { level: 0, levelsCount: chartData.xAxisCount }, }; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/translations-to-highcharts.ts b/packages/sdk-ui/src/chart-options-processor/translations/translations-to-highcharts.ts index a41ed082..9eb3d0cd 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/translations-to-highcharts.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/translations-to-highcharts.ts @@ -20,6 +20,7 @@ import { PolarChartDesignOptions, StackableChartDesignOptions } from './design-o import { AxisMinMax, AxisSettings } from './axis-section'; import { Stacking } from '../chart-options-service'; import { DesignOptions, isPolar } from './types'; +import { colorChineseSilver } from '@/chart-data-options/coloring/consts'; export type LineType = 'straight' | 'smooth'; export type StackType = 'classic' | 'stacked' | 'stack100'; @@ -486,6 +487,11 @@ export const determineYAxisOptions = ( let yTreatNullDataAsZeros = cartesianDataOptions.y.map((y) => !!y.treatNullDataAsZeros); let yConnectNulls = cartesianDataOptions.y.map((y) => !!y.connectNulls); if (cartesianDataOptions.breakBy.length === 0) { + // handle a special case when there is no break by and no y values + if (cartesianDataOptions.y.length === 0) { + return [[0], [undefined], [false], [false]]; + } + // Each Y value has individual axis setting, 0 is on left axis, 1 is on right axis yAxisSide = cartesianDataOptions.y.map((y) => (y.showOnRightAxis ? 1 : 0)); // SeriesChartType is only respected if multiple Y values enabled. @@ -525,6 +531,10 @@ export const getColorSetting = ( key: string, ) => { if (dataOptions.breakBy.length === 0) { + // handle a special case when there is no break by and no y values + if (dataOptions.y.length === 0) { + return colorChineseSilver; + } const colorOpts = dataOptions.y.find((v) => v.name === key)?.color; return legendColor(colorOpts); } else { diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-options.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-options.ts index a6f5a653..a723f29c 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-options.ts @@ -48,7 +48,7 @@ export function prepareTreemapOptions( series: [ { ...DEFAULT_TREEMAP_SERIES, - name: dataOptions.y[0].title ?? dataOptions.y[0].name, + name: dataOptions.y[0]?.title ?? dataOptions.y[0]?.name, data: prepareTreemapDataItems(chartData, dataOptions, themeSettings), levels: prepareTreemapLevels(dataOptions, designOptions, themeSettings), }, diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-series.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-series.ts index d9df02c3..b87e3689 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-series.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-series.ts @@ -37,13 +37,15 @@ export function prepareTreemapDataItems( function createTreemapParents(chartData: CategoricalChartData): SeriesPointStructure[] { const map: { [key: string]: SeriesPointStructure } = {}; chartData.xValues.forEach((value) => { - value.rawValues!.slice(0, -1).forEach((_, index) => { + value.rawValues!.slice(0, -1).forEach((_, index: number) => { const id = value.rawValues!.slice(0, index + 1).join('_'); map[id] = { id, name: value.xValues[index], parent: value.rawValues!.slice(0, index).join('_'), custom: { + xValues: value.xValues.slice(0, index + 1), + rawValues: value.rawValues?.slice(0, index + 1), level: index + 1, levelsCount: chartData.xAxisCount, }, diff --git a/packages/sdk-ui/src/chart/__snapshots__/chart.test.tsx.snap b/packages/sdk-ui/src/chart/__snapshots__/chart.test.tsx.snap index 16e1063a..84d46bfe 100644 --- a/packages/sdk-ui/src/chart/__snapshots__/chart.test.tsx.snap +++ b/packages/sdk-ui/src/chart/__snapshots__/chart.test.tsx.snap @@ -845,7 +845,7 @@ exports[`Chart > change theme of a chart 1`] = ` } `; -exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` +exports[`Chart > funnel chart > render funnel chart with cat and no value 1`] = ` { "accessibility": { "enabled": false, @@ -863,19 +863,16 @@ exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` "events": {}, "polar": false, "spacing": [ - 20, - 20, - 20, - 20, + 30, + 30, + 30, + 30, ], - "type": "pie", + "type": "funnel", }, "drilldown": { "activeDataLabelStyle": { "color": "#000000", - "cursor": "pointer", - "fontWeight": "bold", - "textDecoration": "none", }, "breadcrumbs": { "buttonTheme": { @@ -892,7 +889,6 @@ exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` }, }, }, - "series": [], }, "legend": { "align": "center", @@ -914,22 +910,24 @@ exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` "verticalAlign": "bottom", }, "plotOptions": { - "pie": { + "funnel": { "allowPointSelect": false, + "cursor": "pointer", "dataLabels": { "align": "center", + "color": "#000000", "enabled": true, "formatter": [Function], - "pieMinimumFontSizeToTextLabel": 8, - "showDecimals": false, - "showPercentLabels": true, + "funnelMinimumFontSizeToTextLabel": 8, "style": { - "color": "#000000", "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", }, }, - "innerSize": "0%", + "neckHeight": "0%", + "neckWidth": "20%", + "reversed": false, "showInLegend": true, + "width": "66.6%", }, "series": { "animation": { @@ -956,113 +954,113 @@ exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` { "color": "#00cee6", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2009-01-01T00:00:00.000Z", "xValue": [ "2009-01-01T00:00:00.000Z", ], }, "name": "2009", - "sliced": false, - "y": 6781, + "y": 0.00001, }, { "color": "#9b9bd7", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2010-01-01T00:00:00.000Z", "xValue": [ "2010-01-01T00:00:00.000Z", ], }, "name": "2010", - "sliced": false, - "y": 4471, + "y": 0.00001, }, { "color": "#6eda55", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2011-01-01T00:00:00.000Z", "xValue": [ "2011-01-01T00:00:00.000Z", ], }, "name": "2011", - "sliced": false, - "y": 1812, + "y": 0.00001, }, { "color": "#fc7570", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2012-01-01T00:00:00.000Z", "xValue": [ "2012-01-01T00:00:00.000Z", ], }, "name": "2012", - "sliced": false, - "y": 5001, + "y": 0.00001, }, { "color": "#fbb755", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2013-01-01T00:00:00.000Z", "xValue": [ "2013-01-01T00:00:00.000Z", ], }, "name": "2013", - "sliced": false, - "y": 2045, + "y": 0.00001, }, { "color": "#218a8c", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2014-01-01T00:00:00.000Z", "xValue": [ "2014-01-01T00:00:00.000Z", ], }, "name": "2014", - "sliced": false, - "y": 3010, + "y": 0.00001, }, { "color": "#00cee6", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2015-01-01T00:00:00.000Z", "xValue": [ "2015-01-01T00:00:00.000Z", ], }, "name": "2015", - "sliced": false, - "y": 5447, + "y": 0.00001, }, { "color": "#9b9bd7", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2016-01-01T00:00:00.000Z", "xValue": [ "2016-01-01T00:00:00.000Z", ], }, "name": "2016", - "sliced": false, - "y": 4242, + "y": 0.00001, }, { "color": "#6eda55", "custom": { - "rawValue": undefined, + "number1": 100, + "rawValue": "2018-01-01T00:00:00.000Z", "xValue": [ "2018-01-01T00:00:00.000Z", ], }, "name": "2018", - "sliced": false, - "y": 936, + "y": 0.00001, }, ], - "name": "Quantity", + "name": "", "turboThreshold": 0, }, ], @@ -1086,7 +1084,7 @@ exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` } `; -exports[`Chart > pie chart > render pie chart with two values 1`] = ` +exports[`Chart > funnel chart > render funnel chart with cat and value 1`] = ` { "accessibility": { "enabled": false, @@ -1104,19 +1102,16 @@ exports[`Chart > pie chart > render pie chart with two values 1`] = ` "events": {}, "polar": false, "spacing": [ - 20, - 20, - 20, - 20, + 30, + 30, + 30, + 30, ], - "type": "pie", + "type": "funnel", }, "drilldown": { "activeDataLabelStyle": { "color": "#000000", - "cursor": "pointer", - "fontWeight": "bold", - "textDecoration": "none", }, "breadcrumbs": { "buttonTheme": { @@ -1133,7 +1128,6 @@ exports[`Chart > pie chart > render pie chart with two values 1`] = ` }, }, }, - "series": [], }, "legend": { "align": "center", @@ -1155,22 +1149,24 @@ exports[`Chart > pie chart > render pie chart with two values 1`] = ` "verticalAlign": "bottom", }, "plotOptions": { - "pie": { + "funnel": { "allowPointSelect": false, + "cursor": "pointer", "dataLabels": { "align": "center", + "color": "#000000", "enabled": true, "formatter": [Function], - "pieMinimumFontSizeToTextLabel": 8, - "showDecimals": false, - "showPercentLabels": true, + "funnelMinimumFontSizeToTextLabel": 8, "style": { - "color": "#000000", "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", }, }, - "innerSize": "0%", + "neckHeight": "0%", + "neckWidth": "20%", + "reversed": false, "showInLegend": true, + "width": "66.6%", }, "series": { "animation": { @@ -1197,25 +1193,113 @@ exports[`Chart > pie chart > render pie chart with two values 1`] = ` { "color": "#00cee6", "custom": { + "number1": 100, "rawValue": undefined, - "xValue": [], + "xValue": [ + "2009-01-01T00:00:00.000Z", + ], }, - "name": "Quantity", - "sliced": false, - "y": 33745, + "name": "2009", + "y": 6781, }, { "color": "#9b9bd7", "custom": { + "number1": 80.32738534139507, "rawValue": undefined, - "xValue": [], + "xValue": [ + "2015-01-01T00:00:00.000Z", + ], }, - "name": "Units", - "sliced": false, - "y": 490, + "name": "2015", + "y": 5447, + }, + { + "color": "#6eda55", + "custom": { + "number1": 73.75018433859313, + "rawValue": undefined, + "xValue": [ + "2012-01-01T00:00:00.000Z", + ], + }, + "name": "2012", + "y": 5001, + }, + { + "color": "#fc7570", + "custom": { + "number1": 65.93422798997199, + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + ], + }, + "name": "2010", + "y": 4471, + }, + { + "color": "#fbb755", + "custom": { + "number1": 62.55714496386964, + "rawValue": undefined, + "xValue": [ + "2016-01-01T00:00:00.000Z", + ], + }, + "name": "2016", + "y": 4242, + }, + { + "color": "#218a8c", + "custom": { + "number1": 44.38873322518803, + "rawValue": undefined, + "xValue": [ + "2014-01-01T00:00:00.000Z", + ], + }, + "name": "2014", + "y": 3010, + }, + { + "color": "#00cee6", + "custom": { + "number1": 30.157793835717445, + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + ], + }, + "name": "2013", + "y": 2045, + }, + { + "color": "#9b9bd7", + "custom": { + "number1": 26.721722459814185, + "rawValue": undefined, + "xValue": [ + "2011-01-01T00:00:00.000Z", + ], + }, + "name": "2011", + "y": 1812, + }, + { + "color": "#6eda55", + "custom": { + "number1": 13.80327385341395, + "rawValue": undefined, + "xValue": [ + "2018-01-01T00:00:00.000Z", + ], + }, + "name": "2018", + "y": 936, }, ], - "name": "", + "name": "Quantity", "turboThreshold": 0, }, ], @@ -1239,7 +1323,7 @@ exports[`Chart > pie chart > render pie chart with two values 1`] = ` } `; -exports[`Chart > range charts > render a area range chart two y and two x 1`] = ` +exports[`Chart > funnel chart > render funnel chart with two values 1`] = ` { "accessibility": { "enabled": false, @@ -1254,20 +1338,15 @@ exports[`Chart > range charts > render a area range chart two y and two x 1`] = "duration": 300, }, "backgroundColor": "#FFFFFF", - "events": { - "load": [Function], - }, + "events": {}, "polar": false, "spacing": [ - 20, - 20, - 20, - 20, + 30, + 30, + 30, + 30, ], - "type": "arearange", - }, - "credits": { - "enabled": false, + "type": "funnel", }, "drilldown": { "activeDataLabelStyle": { @@ -1289,9 +1368,6 @@ exports[`Chart > range charts > render a area range chart two y and two x 1`] = }, }, }, - "exporting": { - "enabled": true, - }, "legend": { "align": "center", "backgroundColor": "transparent", @@ -1312,636 +1388,542 @@ exports[`Chart > range charts > render a area range chart two y and two x 1`] = "verticalAlign": "bottom", }, "plotOptions": { - "area": { - "className": "area-series--without-pointer-events", - "states": { - "inactive": { - "enabled": true, - "opacity": 0.3, + "funnel": { + "allowPointSelect": false, + "cursor": "pointer", + "dataLabels": { + "align": "center", + "color": "#000000", + "enabled": true, + "formatter": [Function], + "funnelMinimumFontSizeToTextLabel": 8, + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", }, }, + "neckHeight": "0%", + "neckWidth": "20%", + "reversed": false, + "showInLegend": true, + "width": "66.6%", }, "series": { "animation": { "duration": 600, }, - "connectNulls": false, "dataLabels": { - "crop": false, - "enabled": false, + "enabled": true, "style": { "color": "#000000", "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - }, - }, - "marker": { - "enabled": false, - "fillColor": null, - "fillOpacity": 0.3, - "lineColor": null, - "lineWidth": 2, - "radius": 4, - "states": { - "hover": { - "fillColor": "#FFFFFF", - "lineWidth": 3, - "radius": 6, - }, }, - "symbol": "circle", }, "point": { "events": { "click": [Function], }, }, - "stacking": undefined, - "states": { - "select": { - "borderColor": "transparent", - "color": null, - "opacity": 0.3, - }, - }, - "stickyTracking": false, }, }, "series": [ { "boostThreshold": 0, - "color": "#00cee6", - "connectNulls": false, "data": [ { + "color": "#00cee6", "custom": { + "number1": 100, "rawValue": undefined, - "xValue": [ - "2009-01-01T00:00:00.000Z", - "A", - ], - }, - "high": 9000, - "low": 15, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, + "xValue": [], }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "name": "Quantity", + "y": 33745, }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2010-01-01T00:00:00.000Z", - "A", - ], - }, - "high": 8500, - "low": 65, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, + ], + "name": "", + "turboThreshold": 0, + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + "useHTML": true, + }, + "xAxis": [], + "yAxis": [], +} +`; + +exports[`Chart > pie chart > render pie chart with cat and no value 1`] = ` +{ + "accessibility": { + "enabled": false, + }, + "boost": { + "useGPUTranslations": true, + "usePreAllocated": true, + }, + "chart": { + "alignTicks": false, + "animation": { + "duration": 300, + }, + "backgroundColor": "#FFFFFF", + "events": {}, + "polar": false, + "spacing": [ + 20, + 20, + 20, + 20, + ], + "type": "pie", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + "cursor": "pointer", + "fontWeight": "bold", + "textDecoration": "none", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + "series": [], + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "pieMinimumFontSizeToTextLabel": 8, + "showDecimals": false, + "showPercentLabels": true, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + }, + "innerSize": "0%", + "showInLegend": true, + }, + "series": { + "animation": { + "duration": 600, + }, + "dataLabels": { + "enabled": true, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + }, + "point": { + "events": { + "click": [Function], }, + }, + }, + }, + "series": [ + { + "boostThreshold": 0, + "data": [ { + "color": "#00cee6", "custom": { - "rawValue": undefined, + "rawValue": "2009-01-01T00:00:00.000Z", "xValue": [ - "2011-01-01T00:00:00.000Z", - "C", + "2009-01-01T00:00:00.000Z", ], }, - "high": 1500, - "low": 55, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2009", + "sliced": false, + "y": 0.00001, }, { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "color": "#9b9bd7", + "custom": { + "rawValue": "2010-01-01T00:00:00.000Z", + "xValue": [ + "2010-01-01T00:00:00.000Z", + ], + }, + "name": "2010", + "sliced": false, + "y": 0.00001, }, { + "color": "#6eda55", "custom": { - "rawValue": undefined, + "rawValue": "2011-01-01T00:00:00.000Z", "xValue": [ - "2012-01-01T00:00:00.000Z", - "C", + "2011-01-01T00:00:00.000Z", ], }, - "high": 5300, - "low": 70, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2011", + "sliced": false, + "y": 0.00001, }, { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "color": "#fc7570", + "custom": { + "rawValue": "2012-01-01T00:00:00.000Z", + "xValue": [ + "2012-01-01T00:00:00.000Z", + ], + }, + "name": "2012", + "sliced": false, + "y": 0.00001, }, { + "color": "#fbb755", "custom": { - "rawValue": undefined, + "rawValue": "2013-01-01T00:00:00.000Z", "xValue": [ "2013-01-01T00:00:00.000Z", - "A", ], }, - "high": 2200, - "low": 45, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2013", + "sliced": false, + "y": 0.00001, }, { + "color": "#218a8c", "custom": { - "rawValue": undefined, + "rawValue": "2014-01-01T00:00:00.000Z", "xValue": [ "2014-01-01T00:00:00.000Z", - "A", ], }, - "high": 3200, - "low": 95, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2014", + "sliced": false, + "y": 0.00001, }, { + "color": "#00cee6", "custom": { - "rawValue": undefined, + "rawValue": "2015-01-01T00:00:00.000Z", "xValue": [ "2015-01-01T00:00:00.000Z", - "C", ], }, - "high": 5800, - "low": 85, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2015", + "sliced": false, + "y": 0.00001, }, { + "color": "#9b9bd7", "custom": { - "rawValue": undefined, + "rawValue": "2016-01-01T00:00:00.000Z", "xValue": [ "2016-01-01T00:00:00.000Z", - "C", - ], - }, - "high": 4400, - "low": 75, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2017-01-01T00:00:00.000Z", - "A", ], }, - "high": 2900, - "low": 50, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Cost Lower", - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2016", + "sliced": false, + "y": 0.00001, }, { + "color": "#6eda55", "custom": { - "rawValue": undefined, + "rawValue": "2018-01-01T00:00:00.000Z", "xValue": [ "2018-01-01T00:00:00.000Z", - "C", ], }, - "high": 1100, - "low": 25, - "lowerPointName": "Cost Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Cost Upper", - "y": undefined, + "name": "2018", + "sliced": false, + "y": 0.00001, }, ], - "dataLabels": { - "formatter": [Function], - }, - "lineWidth": 3, - "marker": { - "enabled": false, - "fillColor": null, - "fillOpacity": 0.3, - "lineColor": null, - "lineWidth": 2, - "radius": 4, + "name": "", + "turboThreshold": 0, + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + "useHTML": true, + }, + "xAxis": [], + "yAxis": [], +} +`; + +exports[`Chart > pie chart > render pie chart with cat and value 1`] = ` +{ + "accessibility": { + "enabled": false, + }, + "boost": { + "useGPUTranslations": true, + "usePreAllocated": true, + }, + "chart": { + "alignTicks": false, + "animation": { + "duration": 300, + }, + "backgroundColor": "#FFFFFF", + "events": {}, + "polar": false, + "spacing": [ + 20, + 20, + 20, + 20, + ], + "type": "pie", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + "cursor": "pointer", + "fontWeight": "bold", + "textDecoration": "none", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", "states": { "hover": { - "fillColor": "#FFFFFF", - "lineWidth": 3, - "radius": 6, + "fill": "#f2b900", + "stroke": "#f2b900", }, }, - "symbol": "circle", + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + "series": [], + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "pieMinimumFontSizeToTextLabel": 8, + "showDecimals": false, + "showPercentLabels": true, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + }, + "innerSize": "0%", + "showInLegend": true, + }, + "series": { + "animation": { + "duration": 600, + }, + "dataLabels": { + "enabled": true, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + }, + "point": { + "events": { + "click": [Function], + }, }, - "name": "Revenue", - "showInNavigator": true, - "stickyTracking": false, - "turboThreshold": 0, - "type": "arearange", - "yAxis": 0, }, + }, + "series": [ { "boostThreshold": 0, - "color": "#9b9bd7", - "connectNulls": false, "data": [ { + "color": "#00cee6", "custom": { "rawValue": undefined, "xValue": [ "2009-01-01T00:00:00.000Z", - "A", ], }, - "high": 20000, - "low": 12000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2009", + "sliced": false, + "y": 6781, }, { + "color": "#9b9bd7", "custom": { "rawValue": undefined, "xValue": [ "2010-01-01T00:00:00.000Z", - "A", ], }, - "high": 19000, - "low": 12000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2010", + "sliced": false, + "y": 4471, }, { + "color": "#6eda55", "custom": { "rawValue": undefined, "xValue": [ "2011-01-01T00:00:00.000Z", - "C", ], }, - "high": 18000, - "low": 13000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2011", + "sliced": false, + "y": 1812, }, { + "color": "#fc7570", "custom": { "rawValue": undefined, "xValue": [ "2012-01-01T00:00:00.000Z", - "C", ], }, - "high": 22000, - "low": 13000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2012", + "sliced": false, + "y": 5001, }, { + "color": "#fbb755", "custom": { "rawValue": undefined, "xValue": [ "2013-01-01T00:00:00.000Z", - "A", ], }, - "high": 23000, - "low": 11000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2013", + "sliced": false, + "y": 2045, }, { + "color": "#218a8c", "custom": { "rawValue": undefined, "xValue": [ "2014-01-01T00:00:00.000Z", - "A", ], }, - "high": 24000, - "low": 11000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2014", + "sliced": false, + "y": 3010, }, { + "color": "#00cee6", "custom": { "rawValue": undefined, "xValue": [ "2015-01-01T00:00:00.000Z", - "C", ], }, - "high": 20000, - "low": 15000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2015", + "sliced": false, + "y": 5447, }, { + "color": "#9b9bd7", "custom": { "rawValue": undefined, "xValue": [ "2016-01-01T00:00:00.000Z", - "C", - ], - }, - "high": 19000, - "low": 10000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2017-01-01T00:00:00.000Z", - "A", ], }, - "high": 22000, - "low": 15000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, - }, - { - "high": null, - "low": null, - "lowerPointName": "Qty Lower", - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2016", + "sliced": false, + "y": 4242, }, { + "color": "#6eda55", "custom": { "rawValue": undefined, "xValue": [ "2018-01-01T00:00:00.000Z", - "C", ], }, - "high": 24000, - "low": 14000, - "lowerPointName": "Qty Lower", - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "upperPointName": "Qty Upper", - "y": undefined, + "name": "2018", + "sliced": false, + "y": 936, }, ], - "dataLabels": { - "formatter": [Function], - }, - "lineWidth": 3, - "marker": { - "enabled": false, - "fillColor": null, - "fillOpacity": 0.3, - "lineColor": null, - "lineWidth": 2, - "radius": 4, - "states": { - "hover": { - "fillColor": "#FFFFFF", - "lineWidth": 3, - "radius": 6, - }, - }, - "symbol": "circle", - }, - "name": "Cost", - "showInNavigator": true, - "stickyTracking": false, + "name": "Quantity", "turboThreshold": 0, - "type": "arearange", - "yAxis": 0, }, ], "title": { @@ -1953,431 +1935,171 @@ exports[`Chart > range charts > render a area range chart two y and two x 1`] = "borderColor": "#CCCCCC", "borderRadius": 10, "borderWidth": 1, - "crosshairs": true, "formatter": [Function], "style": { "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", }, "useHTML": true, }, - "xAxis": [ - { - "categories": [ - "A", - " ", - "A", - " ", - "C", - " ", - "C", - " ", - "A", - " ", - "A", - " ", - "C", - " ", - "C", - " ", - "A", - " ", - "C", - ], - "endOnTick": false, - "gridLineColor": "#d1d1d7", - "gridLineDashStyle": "Dot", - "gridLineWidth": 0, - "labels": { - "autoRotation": [ - -10, - -20, - -30, - -40, - -50, - -60, - -70, - -80, - -90, - ], - "enabled": true, - "formatter": [Function], - "overflow": "none", + "xAxis": [], + "yAxis": [], +} +`; + +exports[`Chart > pie chart > render pie chart with two values 1`] = ` +{ + "accessibility": { + "enabled": false, + }, + "boost": { + "useGPUTranslations": true, + "usePreAllocated": true, + }, + "chart": { + "alignTicks": false, + "animation": { + "duration": 300, + }, + "backgroundColor": "#FFFFFF", + "events": {}, + "polar": false, + "spacing": [ + 20, + 20, + 20, + 20, + ], + "type": "pie", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + "cursor": "pointer", + "fontWeight": "bold", + "textDecoration": "none", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + "series": [], + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "pieMinimumFontSizeToTextLabel": 8, + "showDecimals": false, + "showPercentLabels": true, "style": { "color": "#000000", "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", }, }, - "lineColor": "#d1d1d7", - "lineWidth": 1, - "max": null, - "min": null, - "minorGridLineColor": "#d1d1d7", - "minorGridLineWidth": 0, - "minorTickColor": "#d1d1d7", - "plotBands": [ - { - "color": "#FFFFFF", - "from": -0.5, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2009", - "y": -5, - }, - "to": 1, - }, - { - "color": "#FFFFFF", - "from": 1, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2010", - "y": -5, - }, - "to": 3, - }, - { - "color": "#FFFFFF", - "from": 3, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2011", - "y": -5, - }, - "to": 5, + "innerSize": "0%", + "showInLegend": true, + }, + "series": { + "animation": { + "duration": 600, + }, + "dataLabels": { + "enabled": true, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", }, - { - "color": "#FFFFFF", - "from": 5, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2012", - "y": -5, - }, - "to": 7, + }, + "point": { + "events": { + "click": [Function], }, + }, + }, + }, + "series": [ + { + "boostThreshold": 0, + "data": [ { - "color": "#FFFFFF", - "from": 7, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2013", - "y": -5, + "color": "#00cee6", + "custom": { + "rawValue": undefined, + "xValue": [], }, - "to": 9, + "name": "Quantity", + "sliced": false, + "y": 33745, }, { - "color": "#FFFFFF", - "from": 9, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2014", - "y": -5, + "color": "#9b9bd7", + "custom": { + "rawValue": undefined, + "xValue": [], }, - "to": 11, - }, - { - "color": "#FFFFFF", - "from": 11, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2015", - "y": -5, - }, - "to": 13, - }, - { - "color": "#FFFFFF", - "from": 13, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2016", - "y": -5, - }, - "to": 15, - }, - { - "color": "#FFFFFF", - "from": 15, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2017", - "y": -5, - }, - "to": 17, - }, - { - "color": "#FFFFFF", - "from": 17, - "isPlotBand": true, - "label": { - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2018", - "y": -5, - }, - "to": 18.5, - }, - ], - "plotLines": [ - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 1, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 3, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 5, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 7, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 9, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 11, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 13, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 15, - "width": 1, - }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 17, - "width": 1, + "name": "Units", + "sliced": false, + "y": 490, }, ], - "startOnTick": false, - "tickColor": "#d1d1d7", - "tickInterval": null, - "tickWidth": 0, - "tickmarkPlacement": "on", - "title": { - "enabled": false, - "margin": 25, - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - }, - "text": "X Axis title", - }, - "type": "linear", + "name": "", + "turboThreshold": 0, }, ], - "yAxis": [ - { - "endOnTick": true, - "gridLineColor": "#d1d1d7", - "gridLineDashStyle": "Dot", - "gridLineWidth": 1, - "labels": { - "autoRotation": [ - -10, - -20, - -30, - -40, - -50, - -60, - -70, - -80, - -90, - ], - "enabled": true, - "formatter": [Function], - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - }, - }, - "lineColor": "#d1d1d7", - "lineWidth": 1, - "max": 24000, - "min": 15, - "minorGridLineColor": "#d1d1d7", - "minorGridLineDashStyle": "Dot", - "minorGridLineWidth": 0, - "minorTickColor": "#d1d1d7", - "minorTickWidth": 0, - "plotBands": undefined, - "showLastLabel": true, - "stackLabels": { - "allowOverlap": false, - "crop": true, - "enabled": false, - "labelrank": 99999, - "rotation": 0, - "style": { - "color": "#56535b", - "fontFamily": "Open Sans", - "fontSize": "13px", - "fontWeight": "bold", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - }, - }, - "startOnTick": true, - "tickColor": "#d1d1d7", - "tickInterval": null, - "tickWidth": 0, - "tickmarkPlacement": "on", - "title": { - "enabled": false, - "margin": 25, - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - }, - "text": "Y Axis title", - }, - "type": "linear", + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", }, - ], + "useHTML": true, + }, + "xAxis": [], + "yAxis": [], } `; -exports[`Chart > range charts > render a area range chart with break by 1`] = ` +exports[`Chart > range charts > render a area range chart two y and two x 1`] = ` { "accessibility": { "enabled": false, @@ -2511,131 +2233,223 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "series": [ { "boostThreshold": 0, - "color": "red", + "color": "#00cee6", "connectNulls": false, - "custom": { - "rawValue": [ - "A", - ], - }, "data": [ { "custom": { "rawValue": undefined, "xValue": [ "2009-01-01T00:00:00.000Z", + "A", ], }, "high": 9000, "low": 15, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, { - "custom": { - "rawValue": undefined, - "xValue": [ - "2010-01-01T00:00:00.000Z", - ], + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + "A", + ], }, "high": 8500, "low": 65, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2011-01-01T00:00:00.000Z", + "C", ], }, - "high": NaN, - "low": NaN, + "high": 1500, + "low": 55, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2012-01-01T00:00:00.000Z", + "C", ], }, - "high": NaN, - "low": NaN, + "high": 5300, + "low": 70, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2013-01-01T00:00:00.000Z", + "A", ], }, "high": 2200, "low": 45, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2014-01-01T00:00:00.000Z", + "A", ], }, "high": 3200, "low": 95, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2015-01-01T00:00:00.000Z", + "C", ], }, - "high": NaN, - "low": NaN, + "high": 5800, + "low": 85, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2016-01-01T00:00:00.000Z", + "C", ], }, - "high": NaN, - "low": NaN, + "high": 4400, + "low": 75, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2017-01-01T00:00:00.000Z", + "A", ], }, "high": 2900, @@ -2649,16 +2463,28 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "upperPointName": "Cost Upper", "y": undefined, }, + { + "high": null, + "low": null, + "lowerPointName": "Cost Lower", + "upperPointName": "Cost Upper", + "y": undefined, + }, { "custom": { "rawValue": undefined, "xValue": [ "2018-01-01T00:00:00.000Z", + "C", ], }, - "high": NaN, - "low": NaN, + "high": 1100, + "low": 25, "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, "upperPointName": "Cost Upper", "y": undefined, @@ -2684,7 +2510,7 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` }, "symbol": "circle", }, - "name": "A", + "name": "Revenue", "showInNavigator": true, "stickyTracking": false, "turboThreshold": 0, @@ -2693,30 +2519,33 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` }, { "boostThreshold": 0, - "color": "green", + "color": "#9b9bd7", "connectNulls": false, - "custom": { - "rawValue": [ - "C", - ], - }, "data": [ { "custom": { "rawValue": undefined, "xValue": [ "2009-01-01T00:00:00.000Z", + "A", ], }, - "high": NaN, - "low": NaN, - "lowerPointName": "Cost Lower", + "high": 20000, + "low": 12000, + "lowerPointName": "Qty Lower", "marker": { "enabled": true, "isIsolatedPoint": true, }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2724,13 +2553,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2010-01-01T00:00:00.000Z", + "A", ], }, - "high": NaN, - "low": NaN, - "lowerPointName": "Cost Lower", + "high": 19000, + "low": 12000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2738,13 +2579,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2011-01-01T00:00:00.000Z", + "C", ], }, - "high": 1500, - "low": 55, - "lowerPointName": "Cost Lower", + "high": 18000, + "low": 13000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2752,13 +2605,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2012-01-01T00:00:00.000Z", + "C", ], }, - "high": 5300, - "low": 70, - "lowerPointName": "Cost Lower", + "high": 22000, + "low": 13000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2766,13 +2631,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2013-01-01T00:00:00.000Z", + "A", ], }, - "high": NaN, - "low": NaN, - "lowerPointName": "Cost Lower", + "high": 23000, + "low": 11000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2780,13 +2657,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2014-01-01T00:00:00.000Z", + "A", ], }, - "high": NaN, - "low": NaN, - "lowerPointName": "Cost Lower", + "high": 24000, + "low": 11000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2794,13 +2683,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2015-01-01T00:00:00.000Z", + "C", ], }, - "high": 5800, - "low": 85, - "lowerPointName": "Cost Lower", + "high": 20000, + "low": 15000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2808,13 +2709,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2016-01-01T00:00:00.000Z", + "C", ], }, - "high": 4400, - "low": 75, - "lowerPointName": "Cost Lower", + "high": 19000, + "low": 10000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2822,13 +2735,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2017-01-01T00:00:00.000Z", + "A", ], }, - "high": NaN, - "low": NaN, - "lowerPointName": "Cost Lower", + "high": 22000, + "low": 15000, + "lowerPointName": "Qty Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", + "y": undefined, + }, + { + "high": null, + "low": null, + "lowerPointName": "Qty Lower", + "upperPointName": "Qty Upper", "y": undefined, }, { @@ -2836,17 +2761,18 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "rawValue": undefined, "xValue": [ "2018-01-01T00:00:00.000Z", + "C", ], }, - "high": 1100, - "low": 25, - "lowerPointName": "Cost Lower", + "high": 24000, + "low": 14000, + "lowerPointName": "Qty Lower", "marker": { "enabled": true, "isIsolatedPoint": true, }, "selected": false, - "upperPointName": "Cost Upper", + "upperPointName": "Qty Upper", "y": undefined, }, ], @@ -2870,7 +2796,7 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` }, "symbol": "circle", }, - "name": "C", + "name": "Cost", "showInNavigator": true, "stickyTracking": false, "turboThreshold": 0, @@ -2897,16 +2823,25 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "xAxis": [ { "categories": [ - "2009", - "2010", - "2011", - "2012", - "2013", - "2014", - "2015", - "2016", - "2017", - "2018", + "A", + " ", + "A", + " ", + "C", + " ", + "C", + " ", + "A", + " ", + "A", + " ", + "C", + " ", + "C", + " ", + "A", + " ", + "C", ], "endOnTick": false, "gridLineColor": "#d1d1d7", @@ -2943,109 +2878,1034 @@ exports[`Chart > range charts > render a area range chart with break by 1`] = ` "minorGridLineColor": "#d1d1d7", "minorGridLineWidth": 0, "minorTickColor": "#d1d1d7", - "plotBands": [], - "plotLines": [], - "startOnTick": false, - "tickColor": "#d1d1d7", - "tickInterval": null, - "tickWidth": 0, - "tickmarkPlacement": "on", - "title": { - "enabled": false, - "margin": 25, - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - }, - "text": "X Axis title", - }, - "type": "linear", - }, - ], - "yAxis": [ - { - "endOnTick": true, - "gridLineColor": "#d1d1d7", - "gridLineDashStyle": "Dot", - "gridLineWidth": 1, - "labels": { - "autoRotation": [ - -10, - -20, - -30, - -40, - -50, - -60, - -70, - -80, - -90, - ], - "enabled": true, - "formatter": [Function], - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", + "plotBands": [ + { + "color": "#FFFFFF", + "from": -0.5, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2009", + "y": -5, + }, + "to": 1, }, - }, - "lineColor": "#d1d1d7", - "lineWidth": 1, - "max": 9000, - "min": 15, - "minorGridLineColor": "#d1d1d7", - "minorGridLineDashStyle": "Dot", - "minorGridLineWidth": 0, - "minorTickColor": "#d1d1d7", - "minorTickWidth": 0, - "plotBands": undefined, - "showLastLabel": true, - "stackLabels": { - "allowOverlap": false, - "crop": true, - "enabled": false, - "labelrank": 99999, - "rotation": 0, - "style": { - "color": "#56535b", - "fontFamily": "Open Sans", - "fontSize": "13px", - "fontWeight": "bold", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", + { + "color": "#FFFFFF", + "from": 1, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2010", + "y": -5, + }, + "to": 3, }, - }, - "startOnTick": true, - "tickColor": "#d1d1d7", - "tickInterval": null, - "tickWidth": 0, - "tickmarkPlacement": "on", - "title": { - "enabled": false, - "margin": 25, - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", + { + "color": "#FFFFFF", + "from": 3, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2011", + "y": -5, + }, + "to": 5, }, - "text": "Y Axis title", - }, - "type": "linear", - }, - ], -} -`; - + { + "color": "#FFFFFF", + "from": 5, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2012", + "y": -5, + }, + "to": 7, + }, + { + "color": "#FFFFFF", + "from": 7, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2013", + "y": -5, + }, + "to": 9, + }, + { + "color": "#FFFFFF", + "from": 9, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2014", + "y": -5, + }, + "to": 11, + }, + { + "color": "#FFFFFF", + "from": 11, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2015", + "y": -5, + }, + "to": 13, + }, + { + "color": "#FFFFFF", + "from": 13, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2016", + "y": -5, + }, + "to": 15, + }, + { + "color": "#FFFFFF", + "from": 15, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2017", + "y": -5, + }, + "to": 17, + }, + { + "color": "#FFFFFF", + "from": 17, + "isPlotBand": true, + "label": { + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2018", + "y": -5, + }, + "to": 18.5, + }, + ], + "plotLines": [ + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 1, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 3, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 5, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 7, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 9, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 11, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 13, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 15, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 17, + "width": 1, + }, + ], + "startOnTick": false, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "X Axis title", + }, + "type": "linear", + }, + ], + "yAxis": [ + { + "endOnTick": true, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 1, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": 24000, + "min": 15, + "minorGridLineColor": "#d1d1d7", + "minorGridLineDashStyle": "Dot", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "minorTickWidth": 0, + "plotBands": undefined, + "showLastLabel": true, + "stackLabels": { + "allowOverlap": false, + "crop": true, + "enabled": false, + "labelrank": 99999, + "rotation": 0, + "style": { + "color": "#56535b", + "fontFamily": "Open Sans", + "fontSize": "13px", + "fontWeight": "bold", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + }, + }, + "startOnTick": true, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "Y Axis title", + }, + "type": "linear", + }, + ], +} +`; + +exports[`Chart > range charts > render a area range chart with break by 1`] = ` +{ + "accessibility": { + "enabled": false, + }, + "boost": { + "useGPUTranslations": true, + "usePreAllocated": true, + }, + "chart": { + "alignTicks": false, + "animation": { + "duration": 300, + }, + "backgroundColor": "#FFFFFF", + "events": { + "load": [Function], + }, + "polar": false, + "spacing": [ + 20, + 20, + 20, + 20, + ], + "type": "arearange", + }, + "credits": { + "enabled": false, + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "exporting": { + "enabled": true, + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "area": { + "className": "area-series--without-pointer-events", + "states": { + "inactive": { + "enabled": true, + "opacity": 0.3, + }, + }, + }, + "series": { + "animation": { + "duration": 600, + }, + "connectNulls": false, + "dataLabels": { + "crop": false, + "enabled": false, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "point": { + "events": { + "click": [Function], + }, + }, + "stacking": undefined, + "states": { + "select": { + "borderColor": "transparent", + "color": null, + "opacity": 0.3, + }, + }, + "stickyTracking": false, + }, + }, + "series": [ + { + "boostThreshold": 0, + "color": "red", + "connectNulls": false, + "custom": { + "rawValue": [ + "A", + ], + }, + "data": [ + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2009-01-01T00:00:00.000Z", + ], + }, + "high": 9000, + "low": 15, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + ], + }, + "high": 8500, + "low": 65, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2011-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2012-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + ], + }, + "high": 2200, + "low": 45, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2014-01-01T00:00:00.000Z", + ], + }, + "high": 3200, + "low": 95, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2015-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2016-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2017-01-01T00:00:00.000Z", + ], + }, + "high": 2900, + "low": 50, + "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2018-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + ], + "dataLabels": { + "formatter": [Function], + }, + "lineWidth": 3, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "name": "A", + "showInNavigator": true, + "stickyTracking": false, + "turboThreshold": 0, + "type": "arearange", + "yAxis": 0, + }, + { + "boostThreshold": 0, + "color": "green", + "connectNulls": false, + "custom": { + "rawValue": [ + "C", + ], + }, + "data": [ + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2009-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2011-01-01T00:00:00.000Z", + ], + }, + "high": 1500, + "low": 55, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2012-01-01T00:00:00.000Z", + ], + }, + "high": 5300, + "low": 70, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2014-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2015-01-01T00:00:00.000Z", + ], + }, + "high": 5800, + "low": 85, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2016-01-01T00:00:00.000Z", + ], + }, + "high": 4400, + "low": 75, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2017-01-01T00:00:00.000Z", + ], + }, + "high": NaN, + "low": NaN, + "lowerPointName": "Cost Lower", + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2018-01-01T00:00:00.000Z", + ], + }, + "high": 1100, + "low": 25, + "lowerPointName": "Cost Lower", + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "upperPointName": "Cost Upper", + "y": undefined, + }, + ], + "dataLabels": { + "formatter": [Function], + }, + "lineWidth": 3, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "name": "C", + "showInNavigator": true, + "stickyTracking": false, + "turboThreshold": 0, + "type": "arearange", + "yAxis": 0, + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "crosshairs": true, + "formatter": [Function], + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + "useHTML": true, + }, + "xAxis": [ + { + "categories": [ + "2009", + "2010", + "2011", + "2012", + "2013", + "2014", + "2015", + "2016", + "2017", + "2018", + ], + "endOnTick": false, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 0, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "overflow": "none", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": null, + "min": null, + "minorGridLineColor": "#d1d1d7", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "plotBands": [], + "plotLines": [], + "startOnTick": false, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "X Axis title", + }, + "type": "linear", + }, + ], + "yAxis": [ + { + "endOnTick": true, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 1, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": 9000, + "min": 15, + "minorGridLineColor": "#d1d1d7", + "minorGridLineDashStyle": "Dot", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "minorTickWidth": 0, + "plotBands": undefined, + "showLastLabel": true, + "stackLabels": { + "allowOverlap": false, + "crop": true, + "enabled": false, + "labelrank": 99999, + "rotation": 0, + "style": { + "color": "#56535b", + "fontFamily": "Open Sans", + "fontSize": "13px", + "fontWeight": "bold", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + }, + }, + "startOnTick": true, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "Y Axis title", + }, + "type": "linear", + }, + ], +} +`; + exports[`Chart > render Table 1`] = `
render Table 1`] = `
`; -exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` +exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` +{ + "accessibility": { + "enabled": false, + }, + "boost": { + "useGPUTranslations": true, + "usePreAllocated": true, + }, + "chart": { + "alignTicks": false, + "animation": { + "duration": 300, + }, + "backgroundColor": "#FFFFFF", + "events": { + "load": [Function], + }, + "polar": false, + "spacing": [ + 20, + 90, + 20, + 20, + ], + "type": "bar", + }, + "credits": { + "enabled": false, + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "exporting": { + "enabled": true, + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "area": { + "className": "area-series--without-pointer-events", + "states": { + "inactive": { + "enabled": true, + "opacity": 0.3, + }, + }, + }, + "bar": { + "groupPadding": 0.1, + "pointPadding": 0.01, + }, + "series": { + "animation": { + "duration": 600, + }, + "connectNulls": false, + "dataLabels": { + "crop": false, + "enabled": false, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "point": { + "events": { + "click": [Function], + }, + }, + "stacking": undefined, + "states": { + "select": { + "borderColor": "transparent", + "color": null, + "opacity": 0.3, + }, + }, + "stickyTracking": false, + }, + }, + "series": [ + { + "boostThreshold": 0, + "color": "#00cee6", + "connectNulls": false, + "data": [ + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2009-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 6781, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 4471, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2011-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 1812, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2012-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 5001, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 2045, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2014-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 3010, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2015-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 5447, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2016-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 4242, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2018-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 936, + }, + ], + "dataLabels": { + "formatter": [Function], + }, + "lineWidth": 2, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "name": "Quantity", + "showInNavigator": true, + "stickyTracking": false, + "turboThreshold": 0, + "yAxis": 0, + }, + { + "boostThreshold": 0, + "color": "#9b9bd7", + "connectNulls": false, + "data": [ + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2009-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 10, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 70, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2011-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 50, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2012-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 60, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 40, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2014-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 90, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2015-01-01T00:00:00.000Z", + "A", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 80, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2016-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 70, + }, + { + "y": null, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2018-01-01T00:00:00.000Z", + "B", + ], + }, + "marker": { + "enabled": true, + "isIsolatedPoint": true, + }, + "selected": false, + "y": 20, + }, + ], + "dataLabels": { + "formatter": [Function], + }, + "lineWidth": 2, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "name": "Units", + "showInNavigator": true, + "stickyTracking": false, + "turboThreshold": 0, + "yAxis": 0, + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + "useHTML": true, + }, + "xAxis": [ + { + "categories": [ + "A", + " ", + "A", + " ", + "B", + " ", + "B", + " ", + "A", + " ", + "B", + " ", + "A", + " ", + "B", + " ", + "B", + ], + "endOnTick": false, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 0, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "overflow": "none", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": null, + "min": null, + "minorGridLineColor": "#d1d1d7", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "plotBands": [ + { + "color": "#FFFFFF", + "from": -0.5, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2009", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 1, + }, + { + "color": "#FFFFFF", + "from": 1, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2010", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 3, + }, + { + "color": "#FFFFFF", + "from": 3, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2011", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 5, + }, + { + "color": "#FFFFFF", + "from": 5, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2012", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 7, + }, + { + "color": "#FFFFFF", + "from": 7, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2013", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 9, + }, + { + "color": "#FFFFFF", + "from": 9, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2014", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 11, + }, + { + "color": "#FFFFFF", + "from": 11, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2015", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 13, + }, + { + "color": "#FFFFFF", + "from": 13, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2016", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 15, + }, + { + "color": "#FFFFFF", + "from": 15, + "isPlotBand": true, + "label": { + "align": "right", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + "width": "70px", + }, + "text": "2018", + "textAlign": "left", + "x": 5, + "y": 0, + }, + "to": 16.5, + }, + ], + "plotLines": [ + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 1, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 3, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 5, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 7, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 9, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 11, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 13, + "width": 1, + }, + { + "color": "#C0D0E0", + "dashStyle": "shortDot", + "value": 15, + "width": 1, + }, + ], + "startOnTick": false, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "X Axis title", + }, + "type": "linear", + }, + ], + "yAxis": [ + { + "endOnTick": true, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 1, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": 6781, + "min": 0, + "minorGridLineColor": "#d1d1d7", + "minorGridLineDashStyle": "Dot", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "minorTickWidth": 0, + "plotBands": undefined, + "showLastLabel": true, + "stackLabels": { + "allowOverlap": false, + "crop": true, + "enabled": false, + "labelrank": 99999, + "rotation": 0, + "style": { + "color": "#56535b", + "fontFamily": "Open Sans", + "fontSize": "13px", + "fontWeight": "bold", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + }, + }, + "startOnTick": true, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "Y Axis title", + }, + "type": "linear", + }, + ], +} +`; + +exports[`Chart > render a column chart with breakBy 1`] = ` { "accessibility": { "enabled": false, @@ -4245,11 +6055,11 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "polar": false, "spacing": [ 20, - 90, + 20, 20, 20, ], - "type": "bar", + "type": "column", }, "credits": { "enabled": false, @@ -4306,7 +6116,7 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` }, }, }, - "bar": { + "column": { "groupPadding": 0.1, "pointPadding": 0.01, }, @@ -4364,85 +6174,57 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "boostThreshold": 0, "color": "#00cee6", "connectNulls": false, + "custom": { + "rawValue": [ + "A", + ], + }, "data": [ { "custom": { "rawValue": undefined, "xValue": [ "2009-01-01T00:00:00.000Z", - "A", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 6781, - }, - { - "y": null, + "y": 6781, }, { "custom": { "rawValue": undefined, "xValue": [ "2010-01-01T00:00:00.000Z", - "A", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, "y": 4471, }, - { - "y": null, - }, { "custom": { "rawValue": undefined, "xValue": [ "2011-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 1812, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2012-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 5001, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2013-01-01T00:00:00.000Z", - "A", ], }, "marker": { @@ -4452,33 +6234,21 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "selected": false, "y": 2045, }, - { - "y": null, - }, { "custom": { "rawValue": undefined, "xValue": [ "2014-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 3010, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2015-01-01T00:00:00.000Z", - "A", ], }, "marker": { @@ -4488,33 +6258,21 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "selected": false, "y": 5447, }, - { - "y": null, - }, { "custom": { "rawValue": undefined, "xValue": [ "2016-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 4242, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2018-01-01T00:00:00.000Z", - "B", ], }, "marker": { @@ -4522,7 +6280,7 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "isIsolatedPoint": true, }, "selected": false, - "y": 936, + "y": NaN, }, ], "dataLabels": { @@ -4545,7 +6303,7 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` }, "symbol": "circle", }, - "name": "Quantity", + "name": "A", "showInNavigator": true, "stickyTracking": false, "turboThreshold": 0, @@ -4555,13 +6313,17 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "boostThreshold": 0, "color": "#9b9bd7", "connectNulls": false, + "custom": { + "rawValue": [ + "B", + ], + }, "data": [ { "custom": { "rawValue": undefined, "xValue": [ "2009-01-01T00:00:00.000Z", - "A", ], }, "marker": { @@ -4569,89 +6331,53 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "isIsolatedPoint": true, }, "selected": false, - "y": 10, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2010-01-01T00:00:00.000Z", - "A", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 70, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2011-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 50, - }, - { - "y": null, + "y": 1812, }, { "custom": { "rawValue": undefined, "xValue": [ "2012-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 60, - }, - { - "y": null, + "y": 5001, }, { "custom": { "rawValue": undefined, "xValue": [ "2013-01-01T00:00:00.000Z", - "A", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 40, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2014-01-01T00:00:00.000Z", - "B", ], }, "marker": { @@ -4659,61 +6385,37 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "isIsolatedPoint": true, }, "selected": false, - "y": 90, - }, - { - "y": null, + "y": 3010, }, { "custom": { "rawValue": undefined, "xValue": [ "2015-01-01T00:00:00.000Z", - "A", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 80, - }, - { - "y": null, + "y": NaN, }, { "custom": { "rawValue": undefined, "xValue": [ "2016-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 70, - }, - { - "y": null, + "y": 4242, }, { "custom": { "rawValue": undefined, "xValue": [ "2018-01-01T00:00:00.000Z", - "B", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 20, + "y": 936, }, ], "dataLabels": { @@ -4736,7 +6438,7 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` }, "symbol": "circle", }, - "name": "Units", + "name": "B", "showInNavigator": true, "stickyTracking": false, "turboThreshold": 0, @@ -4761,23 +6463,15 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "xAxis": [ { "categories": [ - "A", - " ", - "A", - " ", - "B", - " ", - "B", - " ", - "A", - " ", - "B", - " ", - "A", - " ", - "B", - " ", - "B", + "2009", + "2010", + "2011", + "2012", + "2013", + "2014", + "2015", + "2016", + "2018", ], "endOnTick": false, "gridLineColor": "#d1d1d7", @@ -4807,272 +6501,436 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "textOutline": "none", }, }, - "lineColor": "#d1d1d7", - "lineWidth": 1, - "max": null, - "min": null, - "minorGridLineColor": "#d1d1d7", - "minorGridLineWidth": 0, - "minorTickColor": "#d1d1d7", - "plotBands": [ - { - "color": "#FFFFFF", - "from": -0.5, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2009", - "textAlign": "left", - "x": 5, - "y": 0, - }, - "to": 1, - }, - { - "color": "#FFFFFF", - "from": 1, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2010", - "textAlign": "left", - "x": 5, - "y": 0, - }, - "to": 3, - }, - { - "color": "#FFFFFF", - "from": 3, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2011", - "textAlign": "left", - "x": 5, - "y": 0, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": null, + "min": null, + "minorGridLineColor": "#d1d1d7", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "plotBands": [], + "plotLines": [], + "startOnTick": false, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "X Axis title", + }, + "type": "linear", + }, + ], + "yAxis": [ + { + "endOnTick": true, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 1, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": 6781, + "min": 0, + "minorGridLineColor": "#d1d1d7", + "minorGridLineDashStyle": "Dot", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "minorTickWidth": 0, + "plotBands": undefined, + "showLastLabel": true, + "stackLabels": { + "allowOverlap": false, + "crop": true, + "enabled": false, + "labelrank": 99999, + "rotation": 0, + "style": { + "color": "#56535b", + "fontFamily": "Open Sans", + "fontSize": "13px", + "fontWeight": "bold", + "pointerEvents": "none", + "textOutline": "none", + "textOverflow": "ellipsis", + }, + }, + "startOnTick": true, + "tickColor": "#d1d1d7", + "tickInterval": null, + "tickWidth": 0, + "tickmarkPlacement": "on", + "title": { + "enabled": false, + "margin": 25, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + "text": "Y Axis title", + }, + "type": "linear", + }, + ], +} +`; + +exports[`Chart > render a line chart 1`] = ` +{ + "accessibility": { + "enabled": false, + }, + "boost": { + "useGPUTranslations": true, + "usePreAllocated": true, + }, + "chart": { + "alignTicks": false, + "animation": { + "duration": 300, + }, + "backgroundColor": "#FFFFFF", + "events": { + "load": [Function], + }, + "polar": false, + "spacing": [ + 20, + 20, + 20, + 20, + ], + "type": "line", + }, + "credits": { + "enabled": false, + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", }, - "to": 5, }, - { - "color": "#FFFFFF", - "from": 5, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2012", - "textAlign": "left", - "x": 5, - "y": 0, - }, - "to": 7, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", }, - { - "color": "#FFFFFF", - "from": 7, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2013", - "textAlign": "left", - "x": 5, - "y": 0, - }, - "to": 9, + }, + }, + }, + "exporting": { + "enabled": true, + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "area": { + "className": "area-series--without-pointer-events", + "states": { + "inactive": { + "enabled": true, + "opacity": 0.3, }, - { - "color": "#FFFFFF", - "from": 9, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2014", - "textAlign": "left", - "x": 5, - "y": 0, - }, - "to": 11, + }, + }, + "series": { + "animation": { + "duration": 600, + }, + "connectNulls": false, + "dataLabels": { + "crop": false, + "enabled": false, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", }, - { - "color": "#FFFFFF", - "from": 11, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2015", - "textAlign": "left", - "x": 5, - "y": 0, + }, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, }, - "to": 13, }, + "symbol": "circle", + }, + "point": { + "events": { + "click": [Function], + }, + }, + "stacking": undefined, + "states": { + "select": { + "borderColor": "transparent", + "color": null, + "opacity": 0.3, + }, + }, + "stickyTracking": false, + }, + }, + "series": [ + { + "boostThreshold": 0, + "color": "#00cee6", + "connectNulls": false, + "data": [ { - "color": "#FFFFFF", - "from": 13, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2016", - "textAlign": "left", - "x": 5, - "y": 0, + "custom": { + "rawValue": undefined, + "xValue": [ + "2009-01-01T00:00:00.000Z", + ], }, - "to": 15, + "selected": false, + "y": 6781, }, { - "color": "#FFFFFF", - "from": 15, - "isPlotBand": true, - "label": { - "align": "right", - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - "textOverflow": "ellipsis", - "width": "70px", - }, - "text": "2018", - "textAlign": "left", - "x": 5, - "y": 0, + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + ], }, - "to": 16.5, + "selected": false, + "y": 4471, }, - ], - "plotLines": [ { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 1, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2011-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 1812, }, { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 3, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2012-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 5001, }, { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 5, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 2045, }, { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 7, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2014-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 3010, }, { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 9, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2015-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 5447, }, { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 11, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2016-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 4242, }, { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 13, - "width": 1, + "custom": { + "rawValue": undefined, + "xValue": [ + "2018-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 936, }, - { - "color": "#C0D0E0", - "dashStyle": "shortDot", - "value": 15, - "width": 1, + ], + "dataLabels": { + "formatter": [Function], + }, + "lineWidth": 3, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, }, + "symbol": "circle", + }, + "name": "Quantity", + "showInNavigator": true, + "stickyTracking": false, + "turboThreshold": 0, + "yAxis": 0, + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "style": { + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + }, + "useHTML": true, + }, + "xAxis": [ + { + "categories": [ + "2009", + "2010", + "2011", + "2012", + "2013", + "2014", + "2015", + "2016", + "2018", ], + "endOnTick": false, + "gridLineColor": "#d1d1d7", + "gridLineDashStyle": "Dot", + "gridLineWidth": 0, + "labels": { + "autoRotation": [ + -10, + -20, + -30, + -40, + -50, + -60, + -70, + -80, + -90, + ], + "enabled": true, + "formatter": [Function], + "overflow": "none", + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, + }, + "lineColor": "#d1d1d7", + "lineWidth": 1, + "max": null, + "min": null, + "minorGridLineColor": "#d1d1d7", + "minorGridLineWidth": 0, + "minorTickColor": "#d1d1d7", + "plotBands": [], + "plotLines": [], "startOnTick": false, "tickColor": "#d1d1d7", "tickInterval": null, @@ -5126,7 +6984,7 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` "lineColor": "#d1d1d7", "lineWidth": 1, "max": 6781, - "min": 0, + "min": 936, "minorGridLineColor": "#d1d1d7", "minorGridLineDashStyle": "Dot", "minorGridLineWidth": 0, @@ -5174,7 +7032,7 @@ exports[`Chart > render a bar chart with breakBy and two x-axes 1`] = ` } `; -exports[`Chart > render a column chart with breakBy 1`] = ` +exports[`Chart > render a line chart with only category (x-axis) 1`] = ` { "accessibility": { "enabled": false, @@ -5199,7 +7057,7 @@ exports[`Chart > render a column chart with breakBy 1`] = ` 20, 20, ], - "type": "column", + "type": "line", }, "credits": { "enabled": false, @@ -5211,222 +7069,68 @@ exports[`Chart > render a column chart with breakBy 1`] = ` "breadcrumbs": { "buttonTheme": { "fill": "#ffcb05", - "states": { - "hover": { - "fill": "#f2b900", - "stroke": "#f2b900", - }, - }, - "stroke": "#ffcb05", - "style": { - "color": "#3a4356", - }, - }, - }, - }, - "exporting": { - "enabled": true, - }, - "legend": { - "align": "center", - "backgroundColor": "transparent", - "borderColor": "transparent", - "borderWidth": 0, - "enabled": true, - "itemStyle": { - "color": "#000000", - "cursor": "default", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "auto", - "textOutline": "none", - }, - "layout": "horizontal", - "symbolRadius": 0, - "verticalAlign": "bottom", - }, - "plotOptions": { - "area": { - "className": "area-series--without-pointer-events", - "states": { - "inactive": { - "enabled": true, - "opacity": 0.3, - }, - }, - }, - "column": { - "groupPadding": 0.1, - "pointPadding": 0.01, - }, - "series": { - "animation": { - "duration": 600, - }, - "connectNulls": false, - "dataLabels": { - "crop": false, - "enabled": false, - "style": { - "color": "#000000", - "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", - "fontSize": "13px", - "fontWeight": "normal", - "pointerEvents": "none", - "textOutline": "none", - }, - }, - "marker": { - "enabled": false, - "fillColor": null, - "fillOpacity": 0.3, - "lineColor": null, - "lineWidth": 2, - "radius": 4, - "states": { - "hover": { - "fillColor": "#FFFFFF", - "lineWidth": 3, - "radius": 6, - }, - }, - "symbol": "circle", - }, - "point": { - "events": { - "click": [Function], - }, - }, - "stacking": undefined, - "states": { - "select": { - "borderColor": "transparent", - "color": null, - "opacity": 0.3, - }, - }, - "stickyTracking": false, - }, - }, - "series": [ - { - "boostThreshold": 0, - "color": "#00cee6", - "connectNulls": false, - "custom": { - "rawValue": [ - "A", - ], - }, - "data": [ - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2009-01-01T00:00:00.000Z", - ], - }, - "selected": false, - "y": 6781, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2010-01-01T00:00:00.000Z", - ], - }, - "selected": false, - "y": 4471, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2011-01-01T00:00:00.000Z", - ], - }, - "selected": false, - "y": NaN, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2012-01-01T00:00:00.000Z", - ], - }, - "selected": false, - "y": NaN, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2013-01-01T00:00:00.000Z", - ], - }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "y": 2045, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2014-01-01T00:00:00.000Z", - ], - }, - "selected": false, - "y": NaN, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2015-01-01T00:00:00.000Z", - ], - }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, - "selected": false, - "y": 5447, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2016-01-01T00:00:00.000Z", - ], - }, - "selected": false, - "y": NaN, - }, - { - "custom": { - "rawValue": undefined, - "xValue": [ - "2018-01-01T00:00:00.000Z", - ], - }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", }, - "selected": false, - "y": NaN, }, - ], + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "exporting": { + "enabled": true, + }, + "legend": { + "align": "center", + "backgroundColor": "transparent", + "borderColor": "transparent", + "borderWidth": 0, + "enabled": true, + "itemStyle": { + "color": "#000000", + "cursor": "default", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "auto", + "textOutline": "none", + }, + "layout": "horizontal", + "symbolRadius": 0, + "verticalAlign": "bottom", + }, + "plotOptions": { + "area": { + "className": "area-series--without-pointer-events", + "states": { + "inactive": { + "enabled": true, + "opacity": 0.3, + }, + }, + }, + "series": { + "animation": { + "duration": 600, + }, + "connectNulls": false, "dataLabels": { - "formatter": [Function], + "crop": false, + "enabled": false, + "style": { + "color": "#000000", + "fontFamily": ""Open Sans","Roboto","Helvetica","Arial",sans-serif", + "fontSize": "13px", + "fontWeight": "normal", + "pointerEvents": "none", + "textOutline": "none", + }, }, - "lineWidth": 2, "marker": { "enabled": false, "fillColor": null, @@ -5443,125 +7147,123 @@ exports[`Chart > render a column chart with breakBy 1`] = ` }, "symbol": "circle", }, - "name": "A", - "showInNavigator": true, + "point": { + "events": { + "click": [Function], + }, + }, + "stacking": undefined, + "states": { + "select": { + "borderColor": "transparent", + "color": null, + "opacity": 0.3, + }, + }, "stickyTracking": false, - "turboThreshold": 0, - "yAxis": 0, }, + }, + "series": [ { "boostThreshold": 0, - "color": "#9b9bd7", + "color": "#CCCCCC", "connectNulls": false, - "custom": { - "rawValue": [ - "B", - ], - }, "data": [ { "custom": { - "rawValue": undefined, + "rawValue": "2009-01-01T00:00:00.000Z", "xValue": [ "2009-01-01T00:00:00.000Z", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": NaN, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2010-01-01T00:00:00.000Z", "xValue": [ "2010-01-01T00:00:00.000Z", ], }, "selected": false, - "y": NaN, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2011-01-01T00:00:00.000Z", "xValue": [ "2011-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 1812, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2012-01-01T00:00:00.000Z", "xValue": [ "2012-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 5001, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2013-01-01T00:00:00.000Z", "xValue": [ "2013-01-01T00:00:00.000Z", ], }, "selected": false, - "y": NaN, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2014-01-01T00:00:00.000Z", "xValue": [ "2014-01-01T00:00:00.000Z", ], }, - "marker": { - "enabled": true, - "isIsolatedPoint": true, - }, "selected": false, - "y": 3010, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2015-01-01T00:00:00.000Z", "xValue": [ "2015-01-01T00:00:00.000Z", ], }, "selected": false, - "y": NaN, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2016-01-01T00:00:00.000Z", "xValue": [ "2016-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 4242, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2018-01-01T00:00:00.000Z", "xValue": [ "2018-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 936, + "y": 0.00001, }, ], "dataLabels": { "formatter": [Function], }, - "lineWidth": 2, + "lineWidth": 3, "marker": { "enabled": false, "fillColor": null, @@ -5578,7 +7280,7 @@ exports[`Chart > render a column chart with breakBy 1`] = ` }, "symbol": "circle", }, - "name": "B", + "name": "", "showInNavigator": true, "stickyTracking": false, "turboThreshold": 0, @@ -5702,8 +7404,8 @@ exports[`Chart > render a column chart with breakBy 1`] = ` }, "lineColor": "#d1d1d7", "lineWidth": 1, - "max": 6781, - "min": 0, + "max": 0.00001, + "min": 0.00001, "minorGridLineColor": "#d1d1d7", "minorGridLineDashStyle": "Dot", "minorGridLineWidth": 0, @@ -5751,7 +7453,7 @@ exports[`Chart > render a column chart with breakBy 1`] = ` } `; -exports[`Chart > render a line chart 1`] = ` +exports[`Chart > render a line chart with only category (x-axis) and breakBy 1`] = ` { "accessibility": { "enabled": false, @@ -5886,27 +7588,32 @@ exports[`Chart > render a line chart 1`] = ` { "boostThreshold": 0, "color": "#00cee6", - "connectNulls": false, + "connectNulls": undefined, + "custom": { + "rawValue": [ + "A", + ], + }, "data": [ { "custom": { - "rawValue": undefined, + "rawValue": "2009-01-01T00:00:00.000Z", "xValue": [ "2009-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 6781, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2010-01-01T00:00:00.000Z", "xValue": [ "2010-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 4471, + "y": 0.00001, }, { "custom": { @@ -5916,7 +7623,7 @@ exports[`Chart > render a line chart 1`] = ` ], }, "selected": false, - "y": 1812, + "y": 0.00001, }, { "custom": { @@ -5926,17 +7633,17 @@ exports[`Chart > render a line chart 1`] = ` ], }, "selected": false, - "y": 5001, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2013-01-01T00:00:00.000Z", "xValue": [ "2013-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 2045, + "y": 0.00001, }, { "custom": { @@ -5946,17 +7653,17 @@ exports[`Chart > render a line chart 1`] = ` ], }, "selected": false, - "y": 3010, + "y": 0.00001, }, { "custom": { - "rawValue": undefined, + "rawValue": "2015-01-01T00:00:00.000Z", "xValue": [ "2015-01-01T00:00:00.000Z", ], }, "selected": false, - "y": 5447, + "y": 0.00001, }, { "custom": { @@ -5966,7 +7673,7 @@ exports[`Chart > render a line chart 1`] = ` ], }, "selected": false, - "y": 4242, + "y": 0.00001, }, { "custom": { @@ -5976,7 +7683,7 @@ exports[`Chart > render a line chart 1`] = ` ], }, "selected": false, - "y": 936, + "y": 0.00001, }, ], "dataLabels": { @@ -5999,7 +7706,134 @@ exports[`Chart > render a line chart 1`] = ` }, "symbol": "circle", }, - "name": "Quantity", + "name": "A", + "showInNavigator": true, + "stickyTracking": false, + "turboThreshold": 0, + "yAxis": 0, + }, + { + "boostThreshold": 0, + "color": "#9b9bd7", + "connectNulls": undefined, + "custom": { + "rawValue": [ + "B", + ], + }, + "data": [ + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2009-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2010-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": "2011-01-01T00:00:00.000Z", + "xValue": [ + "2011-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": "2012-01-01T00:00:00.000Z", + "xValue": [ + "2012-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2013-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": "2014-01-01T00:00:00.000Z", + "xValue": [ + "2014-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": undefined, + "xValue": [ + "2015-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": "2016-01-01T00:00:00.000Z", + "xValue": [ + "2016-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + { + "custom": { + "rawValue": "2018-01-01T00:00:00.000Z", + "xValue": [ + "2018-01-01T00:00:00.000Z", + ], + }, + "selected": false, + "y": 0.00001, + }, + ], + "dataLabels": { + "formatter": [Function], + }, + "lineWidth": 3, + "marker": { + "enabled": false, + "fillColor": null, + "fillOpacity": 0.3, + "lineColor": null, + "lineWidth": 2, + "radius": 4, + "states": { + "hover": { + "fillColor": "#FFFFFF", + "lineWidth": 3, + "radius": 6, + }, + }, + "symbol": "circle", + }, + "name": "B", "showInNavigator": true, "stickyTracking": false, "turboThreshold": 0, @@ -6123,8 +7957,8 @@ exports[`Chart > render a line chart 1`] = ` }, "lineColor": "#d1d1d7", "lineWidth": 1, - "max": 6781, - "min": 936, + "max": 0.00001, + "min": 0.00001, "minorGridLineColor": "#d1d1d7", "minorGridLineDashStyle": "Dot", "minorGridLineWidth": 0, diff --git a/packages/sdk-ui/src/chart/chart.test.tsx b/packages/sdk-ui/src/chart/chart.test.tsx index 2c938ad4..fc0f83f7 100644 --- a/packages/sdk-ui/src/chart/chart.test.tsx +++ b/packages/sdk-ui/src/chart/chart.test.tsx @@ -151,6 +151,38 @@ describe('Chart', () => { expect(chart).toBeTruthy(); }); + it('render a line chart with only category (x-axis)', async () => { + const { findByLabelText } = render( + { + expect(options).toMatchSnapshot(); + return options; + }} + />, + ); + const chart = await findByLabelText('chart-root'); + expect(chart).toBeTruthy(); + }); + + it('render a line chart with only category (x-axis) and breakBy', async () => { + const { findByLabelText } = render( + { + expect(options).toMatchSnapshot(); + return options; + }} + />, + ); + const chart = await findByLabelText('chart-root'); + expect(chart).toBeTruthy(); + }); + it('render a column chart with breakBy', async () => { const { findByLabelText } = render( { expect(chart).toBeTruthy(); }); + it('render pie chart with cat and no value', async () => { + const { findByLabelText } = render( + { + expect(options).toMatchSnapshot(); + return {}; + }} + />, + ); + const chart = await findByLabelText('chart-root'); + expect(chart).toBeTruthy(); + }); + it('render pie chart with two values', async () => { const { findByLabelText } = render( { }); }); + describe('funnel chart', () => { + it('render funnel chart with cat and value', async () => { + const { findByLabelText } = render( + { + expect(options).toMatchSnapshot(); + return {}; + }} + />, + ); + const chart = await findByLabelText('chart-root'); + expect(chart).toBeTruthy(); + }); + + it('render funnel chart with cat and no value', async () => { + const { findByLabelText } = render( + { + expect(options).toMatchSnapshot(); + return {}; + }} + />, + ); + const chart = await findByLabelText('chart-root'); + expect(chart).toBeTruthy(); + }); + + it('render funnel chart with two values', async () => { + const { findByLabelText } = render( + { + expect(options).toMatchSnapshot(); + return {}; + }} + />, + ); + const chart = await findByLabelText('chart-root'); + expect(chart).toBeTruthy(); + }); + }); + it('render indicator chart', async () => { const { container, findByLabelText } = render( ; + + if (dataOptions.geo) { + entries.geo = [ + { + ...getDataPointMetadata(`geo.0`, dataOptions.geo), + value: geoDataElement.geoName, + }, + ]; + } + + if (dataOptions.color) { + entries.color = [ + { + ...getDataPointMetadata(`color.0`, dataOptions.color), + value: geoDataElement.originalValue, + }, + ]; + } + + return { + ...geoDataElement, + entries, + }; +} diff --git a/packages/sdk-ui/src/charts/map-charts/areamap/areamap.tsx b/packages/sdk-ui/src/charts/map-charts/areamap/areamap.tsx index 031408fd..44a7ff0d 100644 --- a/packages/sdk-ui/src/charts/map-charts/areamap/areamap.tsx +++ b/packages/sdk-ui/src/charts/map-charts/areamap/areamap.tsx @@ -2,7 +2,7 @@ import { AreamapChartDataOptionsInternal, ChartDataOptionsInternal, } from '../../../chart-data-options/types.js'; -import { AreamapData, ChartData } from '../../../chart-data/types.js'; +import { AreamapData, ChartData, GeoDataElement } from '../../../chart-data/types.js'; import { AreamapChartDesignOptions } from '../../../chart-options-processor/translations/design-options.js'; import { DesignOptions } from '../../../chart-options-processor/translations/types.js'; import { AreamapMap } from './areamap-map.js'; @@ -12,6 +12,8 @@ import { ChartRendererProps } from '@/chart/types.js'; import { useThemeContext } from '@/theme-provider'; import { useMemo } from 'react'; import { getPaletteColor } from '@/chart-data-options/coloring/utils'; +import { useCallback } from 'react'; +import { getAreamapDataPoint } from './areamap-utils.js'; export type AreamapProps = { chartData: AreamapData; @@ -39,6 +41,17 @@ export const Areamap: React.FC = ({ return chartData.geoData; }, [chartData.geoData, dataOptions, themeSettings]); + const onAreaClickHandler = useCallback( + (geoDataElement: GeoDataElement, event: MouseEvent) => { + if (!onDataPointClick) { + return; + } + const areamapDataPoint = getAreamapDataPoint(geoDataElement, dataOptions); + onDataPointClick(areamapDataPoint, event); + }, + [dataOptions, onDataPointClick], + ); + return ( <> {geoJson && ( @@ -47,7 +60,7 @@ export const Areamap: React.FC = ({ geoData={geoData} dataOptions={{ originalValueTitle: dataOptions.color?.title || dataOptions.color?.name || '', - onAreaClick: onDataPointClick, + onAreaClick: onAreaClickHandler, }} mapType={designOptions.mapType} /> diff --git a/packages/sdk-ui/src/charts/map-charts/scattermap/scattermap.tsx b/packages/sdk-ui/src/charts/map-charts/scattermap/scattermap.tsx index 97aeface..b1c1e393 100644 --- a/packages/sdk-ui/src/charts/map-charts/scattermap/scattermap.tsx +++ b/packages/sdk-ui/src/charts/map-charts/scattermap/scattermap.tsx @@ -5,7 +5,7 @@ import { useLocations } from './hooks/use-locations.js'; import { ChartData, ScattermapChartData } from '../../../chart-data/types.js'; import { ScattermapDataPointEventHandler } from '../../../props.js'; import { getLocationsMarkerSizes } from './utils/size.js'; -import { locationToScattermapDataPoint } from './utils/location.js'; +import { getScattermapDataPoint } from './utils/location.js'; import { useGeoSettings } from './hooks/use-settings.js'; import { getLocationsMarkerColors } from './utils/color.js'; import { createMarker, removeMarkers } from './utils/markers.js'; @@ -122,7 +122,7 @@ export const Scattermap = ({ if (onDataPointClick) { marker.on('click', (e) => { onDataPointClick( - locationToScattermapDataPoint(locationWithCoordinates), + getScattermapDataPoint(locationWithCoordinates, dataOptions), e.originalEvent, ); }); @@ -149,6 +149,7 @@ export const Scattermap = ({ markerSizes, designOptions, themeSettings, + dataOptions, tooltipHandler, onDataPointClick, ]); diff --git a/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.test.ts b/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.test.ts index 72c5df1f..38aa12ff 100644 --- a/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.test.ts +++ b/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.test.ts @@ -1,10 +1,11 @@ import { combineLocationNames, getLocationGeoLevel, - locationToScattermapDataPoint, + getScattermapDataPoint, splitLocationName, } from './location'; import { ScattermapChartLocation } from '../../../../chart-data/types'; +import { ScattermapChartDataOptionsInternal } from '@/index'; describe('combineLocationNames', () => { it('should combine location names with delimiter', () => { @@ -44,7 +45,7 @@ describe('getLocationGeoLevel', () => { }); }); -describe('locationToScattermapDataPoint', () => { +describe('getScattermapDataPoint', () => { it('should transform location to data point correctly', () => { const location = { name: 'USA, New York', @@ -53,13 +54,37 @@ describe('locationToScattermapDataPoint', () => { value: 100, } as unknown as ScattermapChartLocation; - const result = locationToScattermapDataPoint(location); + const result = getScattermapDataPoint(location, { + locations: [{ name: 'Country' }, { name: 'City' }], + size: { + name: 'Revenue', + }, + } as ScattermapChartDataOptionsInternal); - expect(result).toEqual({ + expect(result).toMatchObject({ categories: ['USA', 'New York'], displayName: 'USA, New York', coordinates: { lat: 40.7128, lng: -74.006 }, value: 100, + entries: { + geo: [ + { + id: 'geo.0', + dataOption: { name: 'Country' }, + value: 'USA', + }, + { + id: 'geo.1', + dataOption: { name: 'City' }, + value: 'New York', + }, + ], + size: { + id: 'size', + dataOption: { name: 'Revenue' }, + value: 100, + }, + }, }); }); }); diff --git a/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.ts b/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.ts index d9a5c629..a5c3e51f 100644 --- a/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.ts +++ b/packages/sdk-ui/src/charts/map-charts/scattermap/utils/location.ts @@ -1,7 +1,11 @@ import trim from 'lodash-es/trim'; -import { ScattermapLocationLevel } from '@/chart-data-options/types'; -import { ScattermapDataPoint } from '@/types'; +import { + ScattermapLocationLevel, + ScattermapChartDataOptionsInternal, +} from '@/chart-data-options/types'; +import { DataPointEntry, ScattermapDataPoint } from '@/types'; import { ScattermapChartLocation } from '@/chart-data/types'; +import { getDataPointMetadata } from '@/chart-options-processor/data-points'; export const LOCATION_DELIMITER = ','; @@ -26,10 +30,47 @@ export function getLocationGeoLevel(level: ScattermapLocationLevel) { return undefined; } -export function locationToScattermapDataPoint( +export function getScattermapDataPoint( location: ScattermapChartLocation, + dataOptions: ScattermapChartDataOptionsInternal, ): ScattermapDataPoint { - const { name, rawName, coordinates, value } = location; + const { name, rawName, coordinates, value, colorValue, details } = location; + + const geoEntries: DataPointEntry[] = dataOptions.locations.map((item, index) => { + return { + ...getDataPointMetadata(`geo.${index}`, item), + value: rawName[index], + }; + }); + + const entries = { + geo: geoEntries, + } as NonNullable; + + if (dataOptions.size) { + entries.size = { + ...getDataPointMetadata(`size`, dataOptions.size), + value: value, + }; + } + + if (dataOptions.colorBy) { + entries.colorBy = { + ...getDataPointMetadata(`colorBy`, dataOptions.colorBy), + value: colorValue as number, + }; + } + + if (dataOptions.details) { + const metadata = getDataPointMetadata(`details`, dataOptions.details); + // Supports only measure "details" that already part of a map data + if (metadata.measure) { + entries.details = { + ...metadata, + value: details as number, + }; + } + } return { categories: rawName, @@ -39,5 +80,6 @@ export function locationToScattermapDataPoint( lng: coordinates!.lng, }, value, + entries, }; } diff --git a/packages/sdk-ui/src/common-filters/cascading-utils.test.ts b/packages/sdk-ui/src/common-filters/cascading-utils.test.ts index b454863a..8ef656da 100644 --- a/packages/sdk-ui/src/common-filters/cascading-utils.test.ts +++ b/packages/sdk-ui/src/common-filters/cascading-utils.test.ts @@ -1,6 +1,5 @@ -import { isCascadingFilter } from '@/utils/filters'; import * as DM from '@/__test-helpers__/sample-ecommerce'; -import { filterFactory, CascadingFilter, Filter } from '@sisense/sdk-data'; +import { filterFactory, CascadingFilter, Filter, isCascadingFilter } from '@sisense/sdk-data'; import omit from 'lodash-es/omit'; import { flattenCascadingFilters, diff --git a/packages/sdk-ui/src/common-filters/cascading-utils.ts b/packages/sdk-ui/src/common-filters/cascading-utils.ts index 6b183bd5..d7a4538e 100644 --- a/packages/sdk-ui/src/common-filters/cascading-utils.ts +++ b/packages/sdk-ui/src/common-filters/cascading-utils.ts @@ -1,6 +1,6 @@ import { getFilterCompareId } from '@/dashboard-widget/utils'; -import { clearMembersFilter, haveSameAttribute, isCascadingFilter } from '@/utils/filters'; -import { CascadingFilter, Filter } from '@sisense/sdk-data'; +import { clearMembersFilter, haveSameAttribute } from '@/utils/filters'; +import { CascadingFilter, Filter, isCascadingFilter } from '@sisense/sdk-data'; import { FiltersIgnoringRules, PureFilter } from './types'; import { isEqualMembersFilters } from './utils'; diff --git a/packages/sdk-ui/src/common-filters/common-filters-connector.tsx b/packages/sdk-ui/src/common-filters/common-filters-connector.tsx index 65ad1076..b085842f 100644 --- a/packages/sdk-ui/src/common-filters/common-filters-connector.tsx +++ b/packages/sdk-ui/src/common-filters/common-filters-connector.tsx @@ -103,14 +103,14 @@ export function prepareCommonFiltersToWidgetConnectProps( if (normalizedOptions.shouldAffectFilters && selectableAttributes.length) { // registers "onDataPointClick" handler - props.onDataPointClick = (point: DataPoint, nativeEvent: PointerEvent) => { - const selections = getWidgetSelections(widgetType, dataOptions, [point], nativeEvent); + props.onDataPointClick = (point: DataPoint) => { + const selections = getWidgetSelections(widgetType, dataOptions, [point]); const selectedFilters = createCommonFiltersOverSelections(selections, pureFilters); updateFilters(mergeFilters(pureFilters, selectedFilters)); }; // registers "onDataPointsSelected" handler - props.onDataPointsSelected = (points: DataPoint[], nativeEvent: MouseEvent | PointerEvent) => { - const selections = getWidgetSelections(widgetType, dataOptions, points, nativeEvent); + props.onDataPointsSelected = (points: DataPoint[]) => { + const selections = getWidgetSelections(widgetType, dataOptions, points); const selectedFilters = createCommonFiltersOverSelections(selections, pureFilters); updateFilters(mergeFilters(pureFilters, selectedFilters)); }; diff --git a/packages/sdk-ui/src/common-filters/selection-utils.test.ts b/packages/sdk-ui/src/common-filters/selection-utils.test.ts index 96f3a227..223d0750 100644 --- a/packages/sdk-ui/src/common-filters/selection-utils.test.ts +++ b/packages/sdk-ui/src/common-filters/selection-utils.test.ts @@ -5,7 +5,13 @@ import { getSelectableWidgetAttributes, getWidgetSelections, } from './selection-utils'; -import { DataPoint, ScatterDataPoint } from '..'; +import { + AreamapDataPoint, + BoxplotDataPoint, + DataPoint, + ScatterDataPoint, + ScattermapDataPoint, +} from '..'; describe('createCommonFiltersOverSelections()', () => { const filters: MembersFilter[] = [ @@ -125,12 +131,12 @@ describe('getSelectableWidgetAttributes()', () => { describe('getWidgetSelections()', () => { it('should return no selections for "plugin" widget', () => { - const selections = getWidgetSelections('plugin', {}, [], {} as PointerEvent); + const selections = getWidgetSelections('plugin', {}, []); expect(selections).toEqual([]); }); it('should return no selections for "pivot" widget', () => { - const selections = getWidgetSelections('pivot', {}, [], {} as PointerEvent); + const selections = getWidgetSelections('pivot', {}, []); expect(selections).toEqual([]); }); @@ -141,11 +147,18 @@ describe('getWidgetSelections()', () => { }; const points = [ { - value: 123, - categoryValue: '65+', + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '65+', + }, + ], + }, }, - ]; - const selections = getWidgetSelections('column', dataOptions, points, {} as PointerEvent); + ] as DataPoint[]; + const selections = getWidgetSelections('column', dataOptions, points); expect(selections[0].attribute.expression).toEqual(DM.Commerce.AgeRange.expression); expect(selections[0].values).toEqual(['65+']); }); @@ -155,18 +168,20 @@ describe('getWidgetSelections()', () => { category: [DM.Commerce.AgeRange], value: [], }; - const points: DataPoint[] = []; - const event = { - point: { - options: { - custom: { - level: 1, - }, + const points = [ + { + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '65+', + }, + ], }, - name: '65+', }, - } as unknown as PointerEvent; - const selections = getWidgetSelections('treemap', dataOptions, points, event); + ] as DataPoint[]; + const selections = getWidgetSelections('treemap', dataOptions, points); expect(selections[0].attribute.expression).toEqual(DM.Commerce.AgeRange.expression); expect(selections[0].values).toEqual(['65+']); }); @@ -178,24 +193,29 @@ describe('getWidgetSelections()', () => { }; const points = [ { - value: 123, - categoryValue: '65+', + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '65+', + }, + ], + }, }, { - value: 124, - x: 0, - }, - ]; - const event = { - point: { - series: { - xAxis: { - categories: ['0-18'], - }, + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '0-18', + }, + ], }, }, - } as unknown as PointerEvent; - const selections = getWidgetSelections('boxplot', dataOptions, points, event); + ] as BoxplotDataPoint[]; + const selections = getWidgetSelections('boxplot', dataOptions, points); expect(selections[0].attribute.expression).toEqual(DM.Commerce.AgeRange.expression); expect(selections[0].values).toEqual(['65+', '0-18']); }); @@ -207,20 +227,33 @@ describe('getWidgetSelections()', () => { breakByColor: DM.Commerce.Condition, breakByPoint: DM.Commerce.CategoryID, }; - const points: ScatterDataPoint[] = []; - const event = { - point: { - options: { - custom: { - maskedX: '0-18', - maskedY: 'Male', - maskedBreakByColor: 'New', - maskedBreakByPoint: '1', + const points = [ + { + entries: { + x: { + id: 'x', + attribute: DM.Commerce.AgeRange, + value: '0-18', + }, + y: { + id: 'y', + attribute: DM.Commerce.Gender, + value: 'Male', + }, + breakByColor: { + id: 'breakByColor', + attribute: DM.Commerce.Condition, + value: 'New', + }, + breakByPoint: { + id: 'breakByPoint', + attribute: DM.Commerce.CategoryID, + value: '1', }, }, }, - } as unknown as PointerEvent; - const selections = getWidgetSelections('scatter', dataOptions, points, event); + ] as ScatterDataPoint[]; + const selections = getWidgetSelections('scatter', dataOptions, points); expect(selections[0].attribute.expression).toEqual(DM.Commerce.AgeRange.expression); expect(selections[0].values).toEqual(['0-18']); expect(selections[1].attribute.expression).toEqual(DM.Commerce.Gender.expression); @@ -238,11 +271,18 @@ describe('getWidgetSelections()', () => { }; const points = [ { - value: 123, - categories: ['Ukraine'], + entries: { + geo: [ + { + id: 'geo.0', + attribute: DM.Country.Country, + value: 'Ukraine', + }, + ], + }, }, - ]; - const selections = getWidgetSelections('scattermap', dataOptions, points, {} as PointerEvent); + ] as ScattermapDataPoint[]; + const selections = getWidgetSelections('scattermap', dataOptions, points); expect(selections[0].attribute.expression).toEqual(DM.Country.Country.expression); expect(selections[0].values).toEqual(['Ukraine']); }); @@ -254,11 +294,18 @@ describe('getWidgetSelections()', () => { }; const points = [ { - value: 123, - geoName: 'USA', + entries: { + geo: [ + { + id: 'geo.0', + attribute: DM.Country.Country, + value: 'USA', + }, + ], + }, }, - ]; - const selections = getWidgetSelections('areamap', dataOptions, points, {} as PointerEvent); + ] as AreamapDataPoint[]; + const selections = getWidgetSelections('areamap', dataOptions, points); expect(selections[0].attribute.expression).toEqual(DM.Country.Country.expression); expect(selections[0].values).toEqual(['USA']); }); diff --git a/packages/sdk-ui/src/common-filters/selection-utils.ts b/packages/sdk-ui/src/common-filters/selection-utils.ts index 09448dbd..cde84cb3 100644 --- a/packages/sdk-ui/src/common-filters/selection-utils.ts +++ b/packages/sdk-ui/src/common-filters/selection-utils.ts @@ -1,4 +1,3 @@ -import { PointClickEventObject } from '@sisense/sisense-charts'; import { translateColumnToAttribure } from '@/chart-data-options/utils'; import { isAreamap, @@ -11,15 +10,15 @@ import { } from '@/chart-options-processor/translations/types'; import { Column, Attribute, Filter } from '@sisense/sdk-data'; import uniq from 'lodash-es/uniq'; -import isUndefined from 'lodash-es/isUndefined'; +import groupBy from 'lodash-es/groupBy'; import { - AreamapChartDataOptions, AreamapDataPoint, + BoxplotDataPoint, CartesianChartDataOptions, CategoricalChartDataOptions, ChartDataOptions, - ChartDataPoint, DataPoint, + DataPointEntry, isMeasureColumn, PivotTableDataOptions, ScatterChartDataOptions, @@ -28,176 +27,97 @@ import { ScattermapDataPoint, StyledColumn, } from '../index.js'; -import { ScatterCustomPointOptions } from '@/chart-options-processor/translations/scatter-tooltip.js'; import { createCommonFilter, getFilterByAttribute, isEqualMembersFilters } from './utils.js'; import { WidgetTypeInternal } from '@/models/widget/types.js'; import { clearMembersFilter, haveSameAttribute } from '@/utils/filters.js'; -type WidgetSelection = { +type DataSelection = { attribute: Attribute; values: (string | number)[]; }; -type AnyDataPoint = ChartDataPoint | ScattermapDataPoint; +type AbstractDataPointWithEntries = { + entries?: Record; +}; -function prepareSelectionValues

( - points: P[], - convertPointToValueFn: (point: P, index: number) => string | number, +function getSelectionsFromPoints( + points: AbstractDataPointWithEntries[], + selectablePaths: string[], ) { - const validPoints = points.filter((point) => { - const isValidDataPoint = 'value' in point && !isUndefined(point.value); - const isValidScatterDataPoint = - ('x' in point && !isUndefined(point.x)) || ('y' in point && !isUndefined(point.y)); - const isValiedBoxplotDataPoint = 'boxMedian' in point && !isUndefined(point.boxMedian); - const isValidGeoDataPoint = 'geoName' in point && !isUndefined(point.geoName); + const selectableEntriesArray = points.flatMap(({ entries = {} }) => + selectablePaths.flatMap((selectablePath) => { + const entriesByPath = entries[selectablePath]; - return ( - isValidDataPoint || isValidScatterDataPoint || isValiedBoxplotDataPoint || isValidGeoDataPoint - ); - }); + if (!entriesByPath) { + return []; + } - const values = validPoints.map(convertPointToValueFn); + const entriesArray = Array.isArray(entriesByPath) ? entriesByPath : [entriesByPath]; + return entriesArray.filter(({ attribute }) => !!attribute); + }), + ); - return uniq(values); -} + const groupedEntries = groupBy(selectableEntriesArray, ({ id }) => id); -function getCartesianChartSelections( - dataOptions: CartesianChartDataOptions, - points: DataPoint[], -): WidgetSelection[] { - const attributes = dataOptions.category.map(translateColumnToAttribure); - return attributes.map((attribute, index) => { + return Object.values(groupedEntries).map((entries) => { return { - attribute, - values: prepareSelectionValues(points, (point) => - index === 0 ? point.categoryValue! : point.categoryDisplayValue!, - ), - }; + attribute: entries[0].attribute, + values: uniq(entries.map(({ value }) => value)), + } as DataSelection; }); } -function getBoxplotChartSelections( - dataOptions: CartesianChartDataOptions, - points: Array, - nativeEvent: MouseEvent | PointerEvent, -): WidgetSelection[] { - const attribute = dataOptions.category.map(translateColumnToAttribure)[0]; - // todo: replace usage of 'nativeEvent' after 'point' will be improved - const event = nativeEvent as PointClickEventObject; - - if (attribute) { - return [ - { - attribute, - values: prepareSelectionValues(points, (point) => { - const isScatterDataPoint = 'x' in point; - return isScatterDataPoint - ? event.point.series.xAxis.categories[point.x!] - : (point as DataPoint).categoryValue; - }), - }, - ]; - } +function getCartesianChartSelections(points: DataPoint[]): DataSelection[] { + return getSelectionsFromPoints(points, ['category']); +} - return []; +function getBoxplotChartSelections(points: Array): DataSelection[] { + return getSelectionsFromPoints(points, ['category']); } +/** + * Note: treemap selection works differently to other widgets, + * it selects only the currently clicked level while deselects all other levels + */ function getTreemapChartSelections( - dataOptions: CategoricalChartDataOptions, points: DataPoint[], - nativeEvent: MouseEvent | PointerEvent, -): WidgetSelection[] { - // todo: replace usage of 'nativeEvent' after 'points' will be improved - const event = nativeEvent as PointClickEventObject; - const { level: pointLevel } = event.point.options.custom as { level: number }; - const pointLevelIndex = pointLevel - 1; - const attributes = dataOptions.category.map(translateColumnToAttribure); - return attributes.map((attribute, index) => ({ - attribute: attribute, - // select only current level and deselect all other levels - values: pointLevelIndex === index ? [event.point.name] : [], - })); -} - -function getScatterChartSelections( - dataOptions: ScatterChartDataOptions, - points: ScatterDataPoint[], - nativeEvent: MouseEvent | PointerEvent, -): WidgetSelection[] { - const selections: WidgetSelection[] = []; - // todo: replace usage of 'nativeEvent' after extending 'points' - const event = nativeEvent as PointClickEventObject; - const isMultiSelectionEvent = event.type === 'mouseup'; - - // todo: add multi-selection support after extending 'points' - if (isMultiSelectionEvent) { - console.warn('No cross-filtering support for multi-selection in scatter chart'); - return selections; - } - - if (dataOptions.x && !isMeasureColumn(dataOptions.x)) { - selections.push({ - attribute: translateColumnToAttribure(dataOptions.x), - values: [(event.point.options.custom as ScatterCustomPointOptions).maskedX], - }); - } - - if (dataOptions.y && !isMeasureColumn(dataOptions.y)) { - selections.push({ - attribute: translateColumnToAttribure(dataOptions.y), - values: [(event.point.options.custom as ScatterCustomPointOptions).maskedY], - }); - } + dataOptions: CategoricalChartDataOptions, +): DataSelection[] { + const selections = getSelectionsFromPoints(points, ['category']); + const pointLevelIndex = selections.length - 1; - if (dataOptions.breakByColor && !isMeasureColumn(dataOptions.breakByColor)) { - selections.push({ - attribute: translateColumnToAttribure(dataOptions.breakByColor), - values: [(event.point.options.custom as ScatterCustomPointOptions).maskedBreakByColor!], - }); - } + return dataOptions.category.map((dataOption, index) => { + const isPointLevel = pointLevelIndex === index; - if (dataOptions.breakByPoint) { - selections.push({ - attribute: translateColumnToAttribure(dataOptions.breakByPoint), - values: [(event.point.options.custom as ScatterCustomPointOptions).maskedBreakByPoint!], - }); - } + // select only current level + if (isPointLevel) { + return selections[index]; + } - return selections; -} - -function getScattermapChartSelections( - dataOptions: ScattermapChartDataOptions, - points: ScattermapDataPoint[], -): WidgetSelection[] { - const attributes = dataOptions.geo.map(translateColumnToAttribure); - return attributes.map((attribute, index) => { + // deselect all other levels return { - attribute, - values: prepareSelectionValues(points, (point) => point.categories[index]), + attribute: translateColumnToAttribure(dataOption), + values: [], }; }); } -function getAreamapChartSelections( - dataOptions: AreamapChartDataOptions, - points: AreamapDataPoint[], -): WidgetSelection[] { - const attributes = dataOptions.geo.map(translateColumnToAttribure); +function getScatterChartSelections(points: ScatterDataPoint[]): DataSelection[] { + return getSelectionsFromPoints(points, ['x', 'y', 'breakByColor', 'breakByPoint']); +} - return attributes.map((attribute) => { - return { - attribute, - values: prepareSelectionValues(points, (point) => point.geoName), - }; - }); +function getScattermapChartSelections(points: ScattermapDataPoint[]): DataSelection[] { + return getSelectionsFromPoints(points, ['geo']); +} + +function getAreamapChartSelections(points: AreamapDataPoint[]): DataSelection[] { + return getSelectionsFromPoints(points, ['geo']); } export function getWidgetSelections( widgetType: WidgetTypeInternal, dataOptions: ChartDataOptions | PivotTableDataOptions, points: Array, - nativeEvent: MouseEvent | PointerEvent, ) { if (widgetType === 'plugin') { // no plugins support @@ -207,37 +127,19 @@ export function getWidgetSelections( return []; } else if (widgetType === 'treemap' || widgetType === 'sunburst') { return getTreemapChartSelections( - dataOptions as CategoricalChartDataOptions, points as DataPoint[], - nativeEvent, + dataOptions as CategoricalChartDataOptions, ); } else if (isCartesian(widgetType) || widgetType === 'pie' || widgetType === 'funnel') { - return getCartesianChartSelections( - dataOptions as CartesianChartDataOptions, - points as DataPoint[], - ); + return getCartesianChartSelections(points as DataPoint[]); } else if (isBoxplot(widgetType)) { - return getBoxplotChartSelections( - dataOptions as CartesianChartDataOptions, - points as Array, - nativeEvent, - ); + return getBoxplotChartSelections(points as BoxplotDataPoint[]); } else if (isScatter(widgetType)) { - return getScatterChartSelections( - dataOptions as ScatterChartDataOptions, - points as ScatterDataPoint[], - nativeEvent, - ); + return getScatterChartSelections(points as ScatterDataPoint[]); } else if (isScattermap(widgetType)) { - return getScattermapChartSelections( - dataOptions as ScattermapChartDataOptions, - points as ScattermapDataPoint[], - ); + return getScattermapChartSelections(points as ScattermapDataPoint[]); } else if (isAreamap(widgetType)) { - return getAreamapChartSelections( - dataOptions as AreamapChartDataOptions, - points as AreamapDataPoint[], - ); + return getAreamapChartSelections(points as AreamapDataPoint[]); } return []; @@ -278,7 +180,7 @@ export function getSelectableWidgetAttributes( } export function createCommonFiltersOverSelections( - selections: WidgetSelection[], + selections: DataSelection[], existingCommonFilters: Filter[], ) { const commonFiltersFromSelections = selections.map(({ attribute, values }) => diff --git a/packages/sdk-ui/src/common-filters/use-common-filters.test.tsx b/packages/sdk-ui/src/common-filters/use-common-filters.test.tsx index 194f2da0..efe909a9 100644 --- a/packages/sdk-ui/src/common-filters/use-common-filters.test.tsx +++ b/packages/sdk-ui/src/common-filters/use-common-filters.test.tsx @@ -5,6 +5,7 @@ import { useCommonFilters } from './use-common-filters'; import * as DM from '@/__test-helpers__/sample-ecommerce'; import { CartesianChartDataOptions, + DataPoint, DataPointEventHandler, DataPointsEventHandler, RenderToolbarHandler, @@ -172,7 +173,20 @@ describe('useCommonFilters', () => { expect(onDataPointClickHandler).toBeDefined(); act(() => { - onDataPointClickHandler?.({ value: 111, categoryValue: '65+' }, {} as PointerEvent); + onDataPointClickHandler?.( + { + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '65+', + }, + ], + }, + } as DataPoint, + {} as PointerEvent, + ); }); // need to reconnect widget to get the latest changes connectedWidget = result.current.connectToWidgetModel(widgetModelMock, { @@ -202,9 +216,29 @@ describe('useCommonFilters', () => { act(() => { onDataPointsSelectedHandler?.( [ - { value: 111, categoryValue: '19-24' }, - { value: 112, categoryValue: '65+' }, - ], + { + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '19-24', + }, + ], + }, + }, + { + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '65+', + }, + ], + }, + }, + ] as DataPoint[], {} as PointerEvent, ); }); @@ -354,7 +388,20 @@ describe('useCommonFilters', () => { expect(onDataPointClickHandler).toBeDefined(); act(() => { - onDataPointClickHandler?.({ value: 111, categoryValue: '19-24' }, {} as PointerEvent); + onDataPointClickHandler?.( + { + entries: { + category: [ + { + id: 'category.0', + attribute: DM.Commerce.AgeRange, + value: '19-24', + }, + ], + }, + } as DataPoint, + {} as PointerEvent, + ); }); // need to reconnect widget to get the latest changes connectedWidget = result.current.connectToWidgetModel(widgetModelMock, { diff --git a/packages/sdk-ui/src/dashboard-widget/__mocks__/line-chart-widget-dto.ts b/packages/sdk-ui/src/dashboard-widget/__mocks__/line-chart-widget-dto.ts new file mode 100644 index 00000000..ab7ee3e1 --- /dev/null +++ b/packages/sdk-ui/src/dashboard-widget/__mocks__/line-chart-widget-dto.ts @@ -0,0 +1,217 @@ +import { WidgetDto } from '../types'; + +export const lineChartWidgetDTO: WidgetDto = { + _id: '66c35c158b702e002ae41724', + title: '', + type: 'chart/line', + subtype: 'line/basic', + oid: '66c35c158b702e002ae41723', + desc: 'THIS IS LINE CHART!', + source: null, + owner: '662ba7319f04e5001cbc7f58', + userId: '662ba7319f04e5001cbc7f58', + created: '2024-08-19T14:52:05.329Z', + lastUpdated: '2024-08-19T14:52:22.841Z', + instanceType: 'owner', + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'localhost_aSampleIAAaECommerce', + database: 'aSampleIAAaECommerce', + fullname: 'localhost/Sample ECommerce', + live: false, + }, + selection: null, + metadata: { + ignore: { + dimensions: [], + ids: [], + all: false, + }, + panels: [ + { + name: 'x-axis', + items: [ + { + jaql: { + table: 'Commerce', + column: 'Date', + dim: '[Commerce.Date (Calendar)]', + datatype: 'datetime', + merged: true, + level: 'months', + title: 'Months in Date', + }, + instanceid: '5B818-A6A7-D3', + panel: 'rows', + field: { + id: '[Commerce.Date (Calendar)]_years', + index: 0, + }, + format: { + mask: { + years: 'yyyy', + quarters: 'yyyy Q', + months: 'MM/yyyy', + weeks: 'ww yyyy', + days: 'shortDate', + minutes: 'HH:mm', + seconds: 'MM/dd/yyyy HH:mm:ss', + dateAndTime: 'MM/dd/yyyy HH:mm', + isdefault: true, + }, + }, + hierarchies: ['calendar'], + }, + ], + }, + { + name: 'values', + items: [ + { + jaql: { + table: 'Commerce', + column: 'Cost', + dim: '[Commerce.Cost]', + datatype: 'numeric', + agg: 'sum', + title: 'Total Cost', + }, + instanceid: 'E31B8-B218-C7', + panel: 'measures', + format: { + mask: { + type: 'number', + abbreviations: { + t: true, + b: true, + m: true, + k: true, + }, + separated: true, + decimals: 'auto', + abbreviateAll: false, + isdefault: true, + }, + color: { + colorIndex: 0, + type: 'color', + }, + }, + }, + ], + }, + { + name: 'break by', + items: [], + }, + { + name: 'filters', + items: [], + }, + ], + usedFormulasMapping: {}, + }, + tags: [], + style: { + lineWidth: { + width: 'bold', + }, + legend: { + enabled: true, + position: 'bottom', + }, + seriesLabels: { + enabled: false, + rotation: 0, + }, + markers: { + enabled: false, + fill: 'filled', + size: 'small', + }, + xAxis: { + enabled: true, + ticks: true, + labels: { + enabled: true, + rotation: 0, + }, + title: { + enabled: false, + }, + x2Title: { + enabled: false, + }, + gridLines: true, + isIntervalEnabled: false, + }, + yAxis: { + inactive: false, + enabled: true, + ticks: true, + labels: { + enabled: true, + rotation: 0, + }, + title: { + enabled: false, + }, + gridLines: true, + logarithmic: false, + isIntervalEnabled: true, + }, + y2Axis: { + inactive: true, + enabled: true, + ticks: true, + labels: { + enabled: true, + rotation: 0, + }, + title: { + enabled: false, + }, + gridLines: false, + logarithmic: false, + isIntervalEnabled: true, + }, + navigator: { + enabled: true, + }, + dataLimits: { + seriesCapacity: 50, + categoriesCapacity: 100000, + }, + narration: { + enabled: false, + display: 'above', + format: 'bullets', + verbosity: 'medium', + up_sentiment: 'good', + aggregation: 'sum', + labels: [ + { + id: 'years_in_date', + title: 'Years in Date', + singular: 'Years in Date', + plural: 'Years in Date', + }, + ], + }, + }, + instanceid: '3C0D4-3580-B6', + realTimeRefreshing: false, + options: { + dashboardFiltersMode: 'filter', + selector: true, + triggersDomready: true, + autoUpdateOnEveryChange: true, + drillToAnywhere: true, + previousScrollerLocation: { + min: null, + max: null, + }, + }, + dashboardid: '66c35bff8b702e002ae41721', +}; diff --git a/packages/sdk-ui/src/dashboard-widget/__mocks__/text-widget-dto.ts b/packages/sdk-ui/src/dashboard-widget/__mocks__/text-widget-dto.ts new file mode 100644 index 00000000..7c6711a4 --- /dev/null +++ b/packages/sdk-ui/src/dashboard-widget/__mocks__/text-widget-dto.ts @@ -0,0 +1,155 @@ +import { WidgetDto } from '../types'; + +export const textWidgetDTO: WidgetDto = { + _id: '66d9a146ab28a90032b5b495', + title: 'RICHTEXT_MAIN.TITLE', + type: 'richtexteditor', + subtype: 'richtexteditor', + oid: '66d9a146ab28a90032b5b494', + desc: null, + source: null, + owner: '662ba7319f04e5001cbc7f58', + userId: '662ba7319f04e5001cbc7f58', + created: '2024-09-05T12:17:10.314Z', + lastUpdated: '2024-09-10T12:19:14.010Z', + instanceType: 'owner', + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'localhost_aSampleIAAaECommerce', + database: 'aSampleIAAaECommerce', + fullname: 'localhost/Sample ECommerce', + live: false, + }, + selection: null, + metadata: { + ignore: { + dimensions: [], + ids: [], + all: false, + }, + panels: [], + usedFormulasMapping: {}, + }, + tags: [], + style: { + content: { + html: 'fancy text', + vAlign: 'valign-middle', + bgColor: '#FFFFFF', + textAlign: 'center', + }, + }, + instanceid: '2E7CC-1178-BA', + realTimeRefreshing: false, + options: { + triggersDomready: true, + hideFromWidgetList: true, + disableExportToCSV: true, + disableExportToImage: true, + toolbarButton: { + css: 'add-rich-text', + tooltip: 'RICHTEXT_MAIN.TOOLBAR_BUTTON', + }, + selector: false, + disallowSelector: true, + disallowWidgetTitle: true, + supportsHierarchies: false, + dashboardFiltersMode: 'filter', + }, + dashboardid: '66d998d1ab28a90032b5b490', + _dataSourcePermission: 'owner', + userAuth: { + dashboards: { + create: true, + delete: true, + move: true, + rename: true, + duplicate: true, + change_owner: true, + toggle_edit_mode: true, + edit_layout: true, + edit_script: true, + export_dash: true, + export_jpeg: true, + export_image: true, + export_pdf: true, + share: true, + restore: true, + copy_to_server: true, + import: true, + select_palette: true, + replace_datasource: true, + undo_import_dash: true, + toggleDataExploration: true, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + reorder: true, + modify_type: true, + toggle_auto_update: true, + set_defaults: true, + advanced: true, + use_starred: true, + modify_filter_relationship: true, + }, + }, + widgets: { + create: true, + delete: true, + rename: true, + duplicate: true, + copy_to_dashboard: true, + edit: true, + edit_script: true, + change_type: true, + export_csv: true, + export_png: true, + export_svg: true, + export_pdf: true, + modify_selection_attrs: true, + modify_selection_mode: true, + drill_to_anywhere: true, + add_to_pulse: true, + items: { + create: true, + delete: true, + rename: true, + modify: true, + reorder: true, + modify_type: true, + modify_format: true, + on_off: true, + select_hierarchies: true, + }, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + modify_layout: true, + modify_type: true, + modify_dashboard_filters: true, + use_starred: true, + }, + widgetViewOnly: false, + }, + base: { + isConsumer: false, + isContributor: false, + isAdmin: false, + isSuper: true, + }, + }, + _toDisableOptionsList: { + widgets: { + duplicate: false, + }, + }, +}; diff --git a/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx b/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx index 1466ad5f..e490a24b 100644 --- a/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx +++ b/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx @@ -1,29 +1,36 @@ import { useMemo, type FunctionComponent } from 'react'; import { type Filter } from '@sisense/sdk-data'; import { ChartWidget } from '../widgets/chart-widget'; -import { ChartWidgetProps, DashboardWidgetProps } from '../props'; +import { ChartWidgetProps, DashboardWidgetProps, TextWidgetProps } from '../props'; import { useThemeContext } from '../theme-provider'; import { asSisenseComponent } from '../decorators/component-decorators/as-sisense-component'; import { convertFilterRelationsModelToJaql, getFilterRelationsFromJaql, isPivotWidget, + isTextWidget, mergeFilters, mergeFiltersByStrategy, } from './utils'; import { extractDashboardFiltersForWidget } from './translate-dashboard-filters'; import { useFetchWidgetDtoModel } from './use-fetch-widget-dto-model'; import { WidgetModel } from '../models'; -import { PivotTableWidgetProps } from '..'; +import { PivotTableWidgetProps, WidgetType } from '..'; import { PivotTableWidget } from '@/widgets/pivot-table-widget'; import { useSisenseContext } from '@/sisense-context/sisense-context'; +import { isTextWidgetProps, TextWidget } from '@/widgets/text-widget'; -function getWidgetProps(widgetModel: WidgetModel) { +function getWidgetProps(widgetModel: WidgetModel): { + props: TextWidgetProps | ChartWidgetProps | PivotTableWidgetProps; + widgetType: WidgetType; +} { const { widgetType } = widgetModel; let props; if (isPivotWidget(widgetType)) { props = widgetModel.getPivotTableWidgetProps(); + } else if (isTextWidget(widgetType)) { + props = widgetModel.getTextWidgetProps(); } else { props = widgetModel.getChartWidgetProps(); } @@ -84,6 +91,9 @@ export const DashboardWidget: FunctionComponent = asSisens const widgetModel = new WidgetModel(fetchedWidget, themeSettings, app?.settings); const extractedWidgetProps = getWidgetProps(widgetModel); + if (isTextWidgetProps(extractedWidgetProps.props)) { + return { widgetType: 'richtexteditor', props: extractedWidgetProps.props }; + } if (includeDashboardFilters) { const { filters: dashboardFilters, highlights: dashboardHighlights } = extractDashboardFiltersForWidget(fetchedDashboard!, fetchedWidget); @@ -98,23 +108,28 @@ export const DashboardWidget: FunctionComponent = asSisens return extractedWidgetProps; }, [fetchedWidget, fetchedDashboard, themeSettings, includeDashboardFilters, app?.settings]); + if (!fetchedProps) { + return null; + } + // if filter relations are set on dashboard widget, additionally provided filters will be ignored // since there is not enough information how to merge them - const filters = mergeFiltersByStrategy( - fetchedProps?.filters as Filter[], - restProps.filters, - restProps.filtersMergeStrategy, - ); + const filters = isTextWidgetProps(fetchedProps) + ? [] + : mergeFiltersByStrategy( + fetchedProps?.filters as Filter[], + restProps.filters, + restProps.filtersMergeStrategy, + ); - const highlights = mergeFiltersByStrategy( - (fetchedProps as ChartWidgetProps)?.highlights, - restProps.highlights, - restProps.filtersMergeStrategy, - ); + const highlights = isTextWidgetProps(fetchedProps) + ? [] + : mergeFiltersByStrategy( + (fetchedProps as ChartWidgetProps)?.highlights, + restProps.highlights, + restProps.filtersMergeStrategy, + ); - if (!fetchedProps) { - return null; - } const filterRelations = getFilterRelationsFromJaql( filters, highlights, @@ -125,6 +140,9 @@ export const DashboardWidget: FunctionComponent = asSisens ), ); + if (isTextWidgetProps(fetchedProps)) { + return ; + } if (isPivotWidget(widgetType)) { return ( = asSisens /> ); } + return ( ( widgetType: WType, widget: WidgetDto, -): ChartStyleOptions | TableStyleOptions { +): ChartStyleOptions | TableStyleOptions | TextWidgetStyleOptions { const { subtype: widgetSubtype, style, @@ -499,7 +502,10 @@ export function extractStyleOptions( panels, ); if (styleOptions.navigator) { - styleOptions.navigator.scrollerLocation = widget.options?.previousScrollerLocation; + const scrollerLocation = widget.options?.previousScrollerLocation; + styleOptions.navigator.scrollerLocation = isValidScrollerLocation(scrollerLocation) + ? scrollerLocation + : undefined; } return styleOptions; } @@ -534,7 +540,11 @@ export function extractStyleOptions( panels, ); if (boxplotStyleOptions.navigator) { - boxplotStyleOptions.navigator.scrollerLocation = widget.options?.previousScrollerLocation; + boxplotStyleOptions.navigator.scrollerLocation = isValidScrollerLocation( + widget.options?.previousScrollerLocation, + ) + ? widget.options?.previousScrollerLocation + : undefined; } return boxplotStyleOptions; } @@ -542,6 +552,8 @@ export function extractStyleOptions( return extractScattermapChartStyleOptions(widgetSubtype, style as ScattermapWidgetStyle); case 'map/area': return extractAreamapChartStyleOptions(widgetSubtype); + case 'richtexteditor': + return (style as TextWidgetDtoStyle).content; default: throw new TranslatableError('errors.unsupportedWidgetType', { widgetType }); } @@ -554,8 +566,8 @@ export function extractStyleOptions( * @param isWidgetDesignStyleEnabled - The flag to enable the widget design style * @returns The merged widget style */ -export function getStyleWithWigetDesign( - widgetStyle: ChartStyleOptions | TableStyleOptions, +export function getStyleWithWidgetDesign( + widgetStyle: ChartStyleOptions | TableStyleOptions | TextWidgetStyleOptions, widgetDesign?: WidgetDesign, isWidgetDesignStyleEnabled?: boolean, ): WidgetStyleOptions { diff --git a/packages/sdk-ui/src/dashboard-widget/types.ts b/packages/sdk-ui/src/dashboard-widget/types.ts index 297ce120..bf0e8206 100644 --- a/packages/sdk-ui/src/dashboard-widget/types.ts +++ b/packages/sdk-ui/src/dashboard-widget/types.ts @@ -22,6 +22,11 @@ export type CategoricalWidgetType = 'chart/pie' | 'chart/funnel' | 'treemap' | ' */ export type TabularWidgetType = 'tablewidget' | 'tablewidgetagg' | 'pivot' | 'pivot2'; +/** + * The type of a widget on a dashboard that is a variant of text widget. + */ +export type TextWidgetType = 'richtexteditor'; + /** * The type of a widget on a dashboard. */ @@ -34,6 +39,7 @@ export type WidgetType = | 'chart/boxplot' | 'map/scatter' | 'map/area' + | TextWidgetType | 'plugin'; export type WidgetSubtype = @@ -66,7 +72,8 @@ export type WidgetSubtype = | 'boxplot/hollow' | 'map/scatter' | 'areamap/world' - | 'areamap/usa'; + | 'areamap/usa' + | 'richtexteditor'; export enum WidgetDashboardFilterMode { FILTER = 'filter', @@ -99,6 +106,7 @@ export interface WidgetDto { ignore?: FiltersIgnoringRules; panels: Panel[]; drillHistory?: PanelItem[]; + usedFormulasMapping?: any; }; style: WidgetStyle; title: string; @@ -107,8 +115,34 @@ export interface WidgetDto { dashboardFiltersMode: `${WidgetDashboardFilterMode}`; selector: boolean; drillToAnywhere?: boolean; - previousScrollerLocation?: AutoZoomNavigatorScrollerLocation; + previousScrollerLocation?: + | AutoZoomNavigatorScrollerLocation + | EmptyAutoZoomNavigatorScrollerLocation; + triggersDomready?: boolean; + autoUpdateOnEveryChange?: boolean; + hideFromWidgetList?: boolean; + disableExportToCSV?: boolean; + disableExportToImage?: boolean; + toolbarButton?: any; + disallowSelector?: boolean; + disallowWidgetTitle?: boolean; + supportsHierarchies?: boolean; }; + source?: any; + owner?: string; + userId?: string; + created?: string; + lastUpdated?: string; + instanceType?: string; + selection?: any; + tags?: any; + instanceid?: string; + realTimeRefreshing?: boolean; + dashboardid?: string; + _dataSourcePermission?: string; + userAuth?: any; + _toDisableOptionsList?: any; + _id?: string; } /** * @description the scroll location of the navigator scroller / auto zoom feature @@ -118,6 +152,18 @@ export type AutoZoomNavigatorScrollerLocation = { max: number; }; +/** @internal sometimes Fusion widgets contain dumb scroller location with both locations empty */ +type EmptyAutoZoomNavigatorScrollerLocation = { + min: null; + max: null; +}; + +export function isValidScrollerLocation( + scrollerLocation?: AutoZoomNavigatorScrollerLocation | EmptyAutoZoomNavigatorScrollerLocation, +): scrollerLocation is AutoZoomNavigatorScrollerLocation { + return !!scrollerLocation && scrollerLocation.min !== null && scrollerLocation.max !== null; +} + export type WidgetDesign = { widgetBackgroundColor: string; widgetSpacing: keyof typeof LEGACY_DESIGN_TYPES; @@ -166,6 +212,7 @@ export type NumericMask = { number?: { separated: boolean }; separated?: boolean; type?: string; + abbreviateAll?: boolean; }; export type DatetimeMask = { @@ -175,6 +222,7 @@ export type DatetimeMask = { months: string; weeks: string; minutes: string; + seconds: string; days: string; type: string; dateAndTime?: string; @@ -246,6 +294,8 @@ export type PanelItem = { id: string; index: number; }; + panel?: string; + hierarchies?: any; }; export type PanelColorFormat = @@ -320,6 +370,7 @@ type AxisTitleStyle = { }; export type AxisStyle = { + inactive?: boolean; enabled: boolean; ticks: boolean; labels: LabelsStyle; @@ -354,9 +405,10 @@ export type CartesianWidgetStyle = BaseWidgetStyle & }; markers?: { enabled: boolean; - size: number; + size: number | string; fill: string; }; + dataLimits?: any; }; export type PolarWidgetStyle = BaseWidgetStyle & @@ -507,7 +559,7 @@ export type ScattermapWidgetStyle = WidgetContainerStyleOptions & { /** Currently, WidgetStyle for areamap is an empty object */ export type AreamapWidgetStyle = {}; -export type WidgetStyle = { widgetDesign?: WidgetDesign } & ( +export type WidgetStyle = { widgetDesign?: WidgetDesign; narration?: any } & ( | CartesianWidgetStyle | PolarWidgetStyle | FunnelWidgetStyle @@ -520,6 +572,7 @@ export type WidgetStyle = { widgetDesign?: WidgetDesign } & ( | ScattermapWidgetStyle | AreamapWidgetStyle | PivotWidgetStyle + | TextWidgetDtoStyle ); export enum FiltersMergeStrategyEnum { @@ -544,3 +597,12 @@ export type PivotWidgetStyle = { rowHeight?: number; automaticHeight?: boolean; }; + +export type TextWidgetDtoStyle = { + content: { + html: string; + vAlign: `valign-${'middle' | 'top' | 'bottom'}`; + bgColor: string; + textAlign: 'center'; + }; +}; diff --git a/packages/sdk-ui/src/dashboard-widget/utils.test.ts b/packages/sdk-ui/src/dashboard-widget/utils.test.ts index 17bb9c75..1d612266 100644 --- a/packages/sdk-ui/src/dashboard-widget/utils.test.ts +++ b/packages/sdk-ui/src/dashboard-widget/utils.test.ts @@ -4,8 +4,11 @@ import { getFilterRelationsFromJaql, mergeFilters, applyWidgetFiltersToRelations, + isTextWidgetDtoStyle, } from './utils'; import { PanelItem } from './types'; +import { lineChartWidgetDTO } from './__mocks__/line-chart-widget-dto'; +import { textWidgetDTO } from './__mocks__/text-widget-dto'; const mockFilter1 = { guid: 'mockFilter1', @@ -205,3 +208,13 @@ describe('applyWidgetFiltersToRelations', () => { expect(updatedFilterRelations).toStrictEqual(filterRelationsJaql); }); }); + +describe('isTextWidgetDtoStyle', () => { + it('should return true if widget is a TextWidget style', () => { + expect(isTextWidgetDtoStyle(textWidgetDTO.style)).toBe(true); + }); + + it('should return false if widget type is not a TextWidget style', () => { + expect(isTextWidgetDtoStyle(lineChartWidgetDTO.style)).toBe(false); + }); +}); diff --git a/packages/sdk-ui/src/dashboard-widget/utils.ts b/packages/sdk-ui/src/dashboard-widget/utils.ts index b88de3ad..abb081eb 100644 --- a/packages/sdk-ui/src/dashboard-widget/utils.ts +++ b/packages/sdk-ui/src/dashboard-widget/utils.ts @@ -8,6 +8,7 @@ import { FilterRelationsModel, FilterRelationsJaql, FilterRelationsJaqlNode, + isCascadingFilter, } from '@sisense/sdk-data'; import { ChartSubtype } from '../chart-options-processor/subtype-to-design-options'; import { ChartType, type SortDirection } from '../types'; @@ -16,12 +17,13 @@ import { FiltersMergeStrategyEnum, Panel, PanelItem, + TextWidgetDtoStyle, + WidgetStyle, WidgetSubtype, WidgetType, } from './types'; import cloneDeep from 'lodash-es/cloneDeep'; import { TranslatableError } from '../translation/translatable-error'; -import { isCascadingFilter } from '@/utils/filters'; export function getChartType(widgetType: WidgetType) { const widgetTypeToChartType = >{ @@ -101,6 +103,7 @@ export function isSupportedWidgetType(widgetType: WidgetTypeOrString): widgetTyp 'chart/boxplot', 'map/scatter', 'map/area', + 'richtexteditor', ]; return supportedWidgetTypes.includes(widgetType as WidgetType); } @@ -113,8 +116,16 @@ export function isPivotWidget(widgetType: WidgetTypeOrString) { return widgetType === 'pivot' || widgetType === 'pivot2'; } +export function isTextWidget(widgetType: WidgetTypeOrString) { + return widgetType === 'richtexteditor'; +} + +export function isTextWidgetDtoStyle(widgetStyle: WidgetStyle): widgetStyle is TextWidgetDtoStyle { + return 'content' in widgetStyle && 'html' in widgetStyle.content; +} + export function isChartWidget(widgetType: WidgetTypeOrString) { - return !isPivotWidget(widgetType); + return !isPivotWidget(widgetType) && !isTextWidget(widgetType); } export function getEnabledPanelItems(panels: Panel[], panelName: string) { diff --git a/packages/sdk-ui/src/dashboard/components/content-panel.tsx b/packages/sdk-ui/src/dashboard/components/content-panel.tsx index 31cd9a36..23728a2c 100644 --- a/packages/sdk-ui/src/dashboard/components/content-panel.tsx +++ b/packages/sdk-ui/src/dashboard/components/content-panel.tsx @@ -1,15 +1,23 @@ -import { isPivotWidget, isTableWidget } from '@/dashboard-widget/utils'; +import { isPivotWidget, isTableWidget, isTextWidget } from '@/dashboard-widget/utils'; import { getDividerStyle } from '@/dashboard/utils'; import { DynamicSizeContainer, getWidgetDefaultSize } from '@/dynamic-size-container'; import { CompleteThemeSettings, useThemeContext } from '@/index'; import { Layout, WidgetModel } from '@/models'; -import { ChartWidgetProps, PivotTableWidgetProps, TableWidgetProps } from '@/props'; +import { + ChartWidgetProps, + PivotTableWidgetProps, + TableWidgetProps, + TextWidgetProps, +} from '@/props'; import { ChartWidget } from '@/widgets/chart-widget'; import { WidgetContainer } from '@/widgets/common/widget-container'; import { PivotTableWidget } from '@/widgets/pivot-table-widget'; import { TableWidget } from '@/widgets/table-widget'; +import { TextWidget } from '@/widgets/text-widget'; import styled from '@emotion/styled'; -import { PluginService } from './plugin-service'; +import { usePlugins } from '@/plugins-provider'; +import { WidgetPlugin } from '@/plugins-provider/types'; +import ErrorBoundaryBox from '@/error-boundary/error-boundary-box'; const Row = styled.div<{ widths: number[] }>` display: grid; @@ -43,23 +51,34 @@ function getWidgetProps(widgetModel: WidgetModel) { return widgetModel.getTableWidgetProps(); } else if (isPivotWidget(widgetType)) { return widgetModel.getPivotTableWidgetProps(); + } else if (isTextWidget(widgetType)) { + return widgetModel.getTextWidgetProps(); } else { return widgetModel.getChartWidgetProps(); } } -const renderWidgetModel = (w: WidgetModel | undefined, theme: CompleteThemeSettings) => { +const renderWidgetModel = ( + w: WidgetModel | undefined, + theme: CompleteThemeSettings, + plugins: Map, +) => { if (!w) { return null; } if (w.widgetType === 'plugin') { - const plugin = PluginService.get(w.pluginType); + const plugin = plugins.get(w.pluginType); if (!plugin) { - console.error(`Unknown plugin type: ${w.pluginType}`); - return; + return ( + + ); } + const { component: PluginComponent } = plugin; const pluginChartProps = plugin.createChartProps(w, theme); + return ( console.log('DEBUG refresh')} > - + ); @@ -81,6 +100,8 @@ const renderWidgetModel = (w: WidgetModel | undefined, theme: CompleteThemeSetti return ; } else if (isPivotWidget(w.widgetType)) { return ; + } else if (isTextWidget(w.widgetType)) { + return ; } else { return ; } @@ -129,6 +150,7 @@ export interface ContentPanelProps { */ export const ContentPanel = ({ layout, widgets }: ContentPanelProps) => { const { themeSettings } = useThemeContext(); + const { plugins } = usePlugins(); return ( c.widthPercentage)}> {layout.columns.map((column, columnIndex) => ( @@ -152,6 +174,7 @@ export const ContentPanel = ({ layout, widgets }: ContentPanelProps) => { {renderWidgetModel( widgets.find((w) => w.oid === subcell.widgetId), themeSettings, + plugins, )} ))} diff --git a/packages/sdk-ui/src/dashboard/components/plugin-service.tsx b/packages/sdk-ui/src/dashboard/components/plugin-service.tsx deleted file mode 100644 index abc6695e..00000000 --- a/packages/sdk-ui/src/dashboard/components/plugin-service.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { WidgetModel } from '@/models'; -import { CompleteThemeSettings } from '@/types'; - -/** - * @internal - */ -export type ReactWidgetPlugin

= { - name: string; - Plugin: any; - createChartProps(w: WidgetModel, themeSettings: CompleteThemeSettings): P; -}; - -/** - * POC - singleton plugin store. A widget from a Fusion dashboard can use this - * store to look up and render a chart from a third-party plugin that matches its type. - * - * @internal - */ -export class PluginService { - static pluginMap = new Map(); - - static get(pluginType: string): ReactWidgetPlugin | undefined { - return PluginService.pluginMap.get(pluginType); - } - - static register(pluginType: string, plugin: ReactWidgetPlugin): void { - PluginService.pluginMap.set(pluginType, plugin); - } -} diff --git a/packages/sdk-ui/src/dashboard/dashboard.tsx b/packages/sdk-ui/src/dashboard/dashboard.tsx index 286a089b..095712d0 100644 --- a/packages/sdk-ui/src/dashboard/dashboard.tsx +++ b/packages/sdk-ui/src/dashboard/dashboard.tsx @@ -1,7 +1,6 @@ import { DashboardProps } from '@/dashboard/types'; import { DashboardContainer } from '@/dashboard/components/dashboard-container'; import { useEffect, useMemo, useState } from 'react'; -import { isSupportedWidgetTypeByDashboard } from '@/dashboard/utils'; import { WidgetModel } from '@/models'; import { useCommonFilters } from '@/common-filters/use-common-filters'; import { ThemeProvider, useThemeContext } from '@/theme-provider'; @@ -72,9 +71,9 @@ export const Dashboard = asSisenseComponent({ const { palette, ...restDashboardStyles } = styleOptions; const widgetsWithCommonFilters = useMemo(() => { - return innerWidgets - .filter((widget) => isSupportedWidgetTypeByDashboard(widget.widgetType)) - .map((widget) => connectToWidgetModel(widget, widgetFilterOptions?.[widget.oid])); + return innerWidgets.map((widget) => + connectToWidgetModel(widget, widgetFilterOptions?.[widget.oid]), + ); }, [innerWidgets, widgetFilterOptions, connectToWidgetModel]); useEffect(() => { diff --git a/packages/sdk-ui/src/dashboard/utils.ts b/packages/sdk-ui/src/dashboard/utils.ts index 5b3bbe2d..232c3256 100644 --- a/packages/sdk-ui/src/dashboard/utils.ts +++ b/packages/sdk-ui/src/dashboard/utils.ts @@ -1,5 +1 @@ -export function isSupportedWidgetTypeByDashboard(widgetType: string) { - return widgetType !== 'plugin'; -} - export const getDividerStyle = (color: string, width: number) => `${width}px solid ${color}`; diff --git a/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-level-filter.tsx b/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-level-filter.tsx index 440bf349..051a2984 100644 --- a/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-level-filter.tsx +++ b/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-level-filter.tsx @@ -1,15 +1,14 @@ import { DataSource, - CustomFilter, - DateRangeFilter, Filter, LevelAttribute, - MeasureFilter, - MembersFilter, - NumericFilter, - RankingFilter, - RelativeDateFilter, - TextFilter, + isMembersFilter, + isDateRangeFilter, + isRelativeDateFilter, + isMeasureFilter, + isTextFilter, + isRankingFilter, + isCustomFilter, } from '@sisense/sdk-data'; import { MemberFilterTile } from '../member-filter-tile/index.js'; import { CriteriaFilterTile } from '../criteria-filter-tile/index.js'; @@ -85,35 +84,29 @@ export const CascadingLevelFilterTile = ({ tileDesignOptions: cascadingLevelTileDesign, }; - const filterTile = - filter instanceof MembersFilter ? ( - - ) : filter instanceof DateRangeFilter ? ( - - ) : filter instanceof RelativeDateFilter ? ( - - ) : filter instanceof MeasureFilter || - filter instanceof NumericFilter || - filter instanceof TextFilter || - filter instanceof RankingFilter ? ( - - ) : filter instanceof CustomFilter ? ( - - ) : ( - ( -

{t('unsupportedFilter.message')}

- )} - design={cascadingLevelTileDesign} - locked={filter.locked} - /> - ); + const filterTile = isMembersFilter(filter) ? ( + + ) : isDateRangeFilter(filter) ? ( + + ) : isRelativeDateFilter(filter) ? ( + + ) : isMeasureFilter(filter) || + isMembersFilter(filter) || + isTextFilter(filter) || + isRankingFilter(filter) ? ( + + ) : isCustomFilter(filter) ? ( + + ) : ( + ( +

{t('unsupportedFilter.message')}

+ )} + design={cascadingLevelTileDesign} + locked={filter.locked} + /> + ); return (
{ it('should render collapsed display text by default when vertical', () => { const props = { title: 'Test Title', - filter: filters.dateRelativeTo(mockAttributeDays, 0, 2) as RelativeDateFilter, + filter: filterFactory.dateRelativeTo(mockAttributeDays, 0, 2) as RelativeDateFilter, arrangement: 'vertical' as FilterVariant, onUpdate: vi.fn(), }; @@ -46,7 +46,7 @@ describe('RelativeDateFilterTile tests', () => { it('should render input fields when vertical and expanded', async () => { const props = { title: 'Test Title', - filter: filters.dateRelativeTo(mockAttributeDays, 0, 2) as RelativeDateFilter, + filter: filterFactory.dateRelativeTo(mockAttributeDays, 0, 2) as RelativeDateFilter, arrangement: 'vertical' as FilterVariant, onUpdate: vi.fn(), }; @@ -67,7 +67,7 @@ describe('RelativeDateFilterTile tests', () => { it('should render input fields when horizontal', async () => { const props = { title: 'Test Title', - filter: filters.dateRelativeFrom(mockAttributeYears, 0, 1) as RelativeDateFilter, + filter: filterFactory.dateRelativeFrom(mockAttributeYears, 0, 1) as RelativeDateFilter, onUpdate: vi.fn(), }; const { user } = setup( diff --git a/packages/sdk-ui/src/filters/components/filters-panel/__snapshots__/filters-panel-tile.test.tsx.snap b/packages/sdk-ui/src/filters/components/filters-panel/__snapshots__/filters-panel-tile.test.tsx.snap index c6d9de83..1ece8012 100644 --- a/packages/sdk-ui/src/filters/components/filters-panel/__snapshots__/filters-panel-tile.test.tsx.snap +++ b/packages/sdk-ui/src/filters/components/filters-panel/__snapshots__/filters-panel-tile.test.tsx.snap @@ -32,7 +32,7 @@ exports[`FiltersPanelTile > renders CriteriaFilterTile for NumericFilter 1`] = ` class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
renders CriteriaFilterTile for RankingFilter 1`] = ` class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
renders CriteriaFilterTile for TextFilter 1`] = ` class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
renders CustomFilterTile for advnced filter type 1`] class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
renders RelativeDateFilterTile for RelativeDateFilte class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
renders locked CriteriaFilterTile 1`] = ` class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
renders locked RelativeDateFilter component 1`] = ` class="csdk-text-[13px] csdk-mt-[6px] csdk-mb-[4px] csdk-ml-[7px] csdk-leading-[16px]" style="color: rgb(91, 99, 114);" > - TestRevenue + Test Revenue
; } - if (filter instanceof MembersFilter) { + if (isMembersFilter(filter)) { return ; } - if (filter instanceof DateRangeFilter) { + if (isDateRangeFilter(filter)) { return ( ; } if ( - filter instanceof MeasureFilter || - filter instanceof NumericFilter || - filter instanceof TextFilter || - filter instanceof RankingFilter + isMeasureFilter(filter) || + isNumericFilter(filter) || + isTextFilter(filter) || + isRankingFilter(filter) ) { return ; } - if (filter instanceof CascadingFilter) { + if (isCascadingFilter(filter)) { return ; } diff --git a/packages/sdk-ui/src/index.ts b/packages/sdk-ui/src/index.ts index 112fa346..7ee64082 100644 --- a/packages/sdk-ui/src/index.ts +++ b/packages/sdk-ui/src/index.ts @@ -13,6 +13,7 @@ export { type CartesianWidgetType, type CategoricalWidgetType, type TabularWidgetType, + type TextWidgetType, } from './dashboard-widget/types'; export * from './query-execution'; export { executeQuery } from './query/execute-query'; @@ -42,6 +43,8 @@ export * from './areamap-chart'; export * from './area-range-chart'; export * from './sisense-context/custom-sisense-context-provider'; export * from './theme-provider/custom-theme-provider'; +export * from './plugins-provider/custom-plugins-provider'; +export * from './plugins-provider/types'; export { getThemeSettingsByOid } from './themes/theme-loader'; export { getDefaultThemeSettings } from './theme-provider/default-theme-settings'; export { @@ -98,3 +101,4 @@ export { useThemeContext } from './theme-provider'; export { LoadingIndicator } from './common/components/loading-indicator'; export { LoadingOverlay } from './common/components/loading-overlay'; export { useFetch, type RequestConfig, type UseQueryResult } from './common/hooks/use-fetch'; +export type { EmptyObject } from './utils/utility-types'; diff --git a/packages/sdk-ui/src/models/__mocks__/dashboard-with-text-widget.ts b/packages/sdk-ui/src/models/__mocks__/dashboard-with-text-widget.ts new file mode 100644 index 00000000..fa897410 --- /dev/null +++ b/packages/sdk-ui/src/models/__mocks__/dashboard-with-text-widget.ts @@ -0,0 +1,720 @@ +import { DashboardDto } from '../../api/types/dashboard-dto'; + +export const dashboardWithTextWidget = { + _id: '66d998d1ab28a90032b5b491', + title: 'default text widget', + oid: '66d998d1ab28a90032b5b490', + desc: '', + source: null, + type: 'dashboard', + shares: [ + { + shareId: '662ba7319f04e5001cbc7f58', + type: 'user', + }, + ], + style: { + palette: { + _id: '662ba7319f04e5001cbc7f59', + colors: ['#00cee6', '#9b9bd7', '#6EDA55', '#fc7570', '#fbb755', '#218A8C'], + name: 'Vivid', + isDefault: true, + sortOrder: 10, + isSystem: true, + systemDefault: true, + }, + }, + owner: '662ba7319f04e5001cbc7f58', + userId: '662ba7319f04e5001cbc7f58', + created: '2024-09-05T11:41:05.127Z', + lastUpdated: '2024-09-10T14:40:22.119Z', + lastUsed: '2024-09-10T14:40:22.119Z', + usageCount: 1, + layout: { + instanceid: 'D2CA0-910D-C8', + type: 'columnar', + columns: [ + { + width: 100, + cells: [ + { + subcells: [ + { + elements: [ + { + minHeight: 96, + maxHeight: 2048, + minWidth: 128, + maxWidth: 2048, + height: 384, + defaultWidth: 512, + widgetid: '66e02b59ab28a90032b5b4d3', + }, + ], + width: 100, + stretchable: false, + pxlWidth: 1380, + index: 0, + }, + ], + }, + { + subcells: [ + { + elements: [ + { + minHeight: 64, + maxHeight: 2048, + minWidth: 64, + maxWidth: 2048, + height: '476px', + defaultWidth: 128, + widgetid: '66d9a146ab28a90032b5b494', + }, + ], + width: 100, + stretchable: false, + pxlWidth: 1383, + index: 0, + }, + ], + }, + ], + pxlWidth: 1383, + index: 0, + }, + ], + container: {}, + }, + instanceType: 'owner', + original: null, + dataExploration: false, + tenantId: '662ba7329f04e5001cbc7f65', + lastOpened: '2024-09-10T14:02:47.380Z', + previewLayout: [], + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'localhost_aSampleIAAaECommerce', + database: 'aSampleIAAaECommerce', + fullname: 'localhost/Sample ECommerce', + live: false, + }, + filters: [ + { + jaql: { + table: 'Category', + column: 'Category', + dim: '[Category.Category]', + datatype: 'text', + merged: true, + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'localhost_aSampleIAAaECommerce', + database: 'aSampleIAAaECommerce', + fullname: 'localhost/Sample ECommerce', + live: false, + }, + firstday: 'mon', + locale: 'en-gb', + filter: { + explicit: true, + multiSelection: true, + members: [ + 'Camcorders', + 'Camera Flashes', + 'Car Amplifiers', + 'Car Speakers and Subwoofers', + ], + }, + title: 'Category', + collapsed: true, + isDashboardFilter: true, + }, + instanceid: '7D7BD-E7C4-FB', + isCascading: false, + }, + { + jaql: { + table: 'Commerce', + column: 'Gender', + dim: '[Commerce.Gender]', + datatype: 'text', + merged: true, + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'localhost_aSampleIAAaECommerce', + database: 'aSampleIAAaECommerce', + fullname: 'localhost/Sample ECommerce', + live: false, + }, + firstday: 'mon', + locale: 'en-gb', + title: 'Gender', + collapsed: true, + isDashboardFilter: true, + filter: { + explicit: true, + multiSelection: true, + members: ['Female'], + }, + }, + instanceid: '9A2F2-F785-36', + isCascading: false, + disabled: false, + }, + ], + editing: true, + settings: { + autoUpdateOnFiltersChange: true, + }, + filterRelations: [], + filterToDatasourceMapping: {}, + widgets: [ + { + _id: '66d9a146ab28a90032b5b495', + title: 'RICHTEXT_MAIN.TITLE', + type: 'richtexteditor', + subtype: 'richtexteditor', + oid: '66d9a146ab28a90032b5b494', + desc: null, + source: null, + owner: '662ba7319f04e5001cbc7f58', + userId: '662ba7319f04e5001cbc7f58', + created: '2024-09-05T12:17:10.314Z', + lastUpdated: '2024-09-10T12:19:14.010Z', + instanceType: 'owner', + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'localhost_aSampleIAAaECommerce', + database: 'aSampleIAAaECommerce', + fullname: 'localhost/Sample ECommerce', + live: false, + }, + selection: null, + metadata: { + ignore: { + dimensions: [], + ids: [], + all: false, + }, + panels: [], + usedFormulasMapping: {}, + }, + tags: [], + style: { + content: { + html: 'fancy text', + vAlign: 'valign-middle', + bgColor: '#FFFFFF', + textAlign: 'center', + }, + }, + instanceid: '2E7CC-1178-BA', + realTimeRefreshing: false, + options: { + triggersDomready: true, + hideFromWidgetList: true, + disableExportToCSV: true, + disableExportToImage: true, + toolbarButton: { + css: 'add-rich-text', + tooltip: 'RICHTEXT_MAIN.TOOLBAR_BUTTON', + }, + selector: false, + disallowSelector: true, + disallowWidgetTitle: true, + supportsHierarchies: false, + dashboardFiltersMode: 'filter', + }, + dashboardid: '66d998d1ab28a90032b5b490', + _dataSourcePermission: 'owner', + userAuth: { + dashboards: { + create: true, + delete: true, + move: true, + rename: true, + duplicate: true, + change_owner: true, + toggle_edit_mode: true, + edit_layout: true, + edit_script: true, + export_dash: true, + export_jpeg: true, + export_image: true, + export_pdf: true, + share: true, + restore: true, + copy_to_server: true, + import: true, + select_palette: true, + replace_datasource: true, + undo_import_dash: true, + toggleDataExploration: true, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + reorder: true, + modify_type: true, + toggle_auto_update: true, + set_defaults: true, + advanced: true, + use_starred: true, + modify_filter_relationship: true, + }, + }, + widgets: { + create: true, + delete: true, + rename: true, + duplicate: true, + copy_to_dashboard: true, + edit: true, + edit_script: true, + change_type: true, + export_csv: true, + export_png: true, + export_svg: true, + export_pdf: true, + modify_selection_attrs: true, + modify_selection_mode: true, + drill_to_anywhere: true, + add_to_pulse: true, + items: { + create: true, + delete: true, + rename: true, + modify: true, + reorder: true, + modify_type: true, + modify_format: true, + on_off: true, + select_hierarchies: true, + }, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + modify_layout: true, + modify_type: true, + modify_dashboard_filters: true, + use_starred: true, + }, + widgetViewOnly: false, + }, + base: { + isConsumer: false, + isContributor: false, + isAdmin: false, + isSuper: true, + }, + }, + _toDisableOptionsList: { + widgets: { + duplicate: false, + }, + }, + }, + { + _id: '66e02b59ab28a90032b5b4d4', + title: '', + type: 'chart/pie', + subtype: 'pie/classic', + oid: '66e02b59ab28a90032b5b4d3', + desc: null, + source: null, + owner: '662ba7319f04e5001cbc7f58', + userId: '662ba7319f04e5001cbc7f58', + created: '2024-09-10T11:19:53.948Z', + lastUpdated: '2024-09-10T14:40:12.469Z', + instanceType: 'owner', + datasource: { + address: 'LocalHost', + title: 'Sample ECommerce', + id: 'aLOCALHOST_aSAMPLEIAAaECOMMERCE', + database: 'aSampleIAAaECommerce', + fullname: 'LocalHost/Sample ECommerce', + }, + selection: null, + metadata: { + ignore: { + dimensions: [], + ids: [], + all: false, + }, + panels: [ + { + name: 'categories', + items: [ + { + jaql: { + table: 'Commerce', + column: 'Gender', + dim: '[Commerce.Gender]', + datatype: 'text', + merged: true, + title: 'Gender', + }, + instanceid: '7FFC2-6334-12', + format: { + members: {}, + }, + }, + ], + }, + { + name: 'values', + items: [ + { + jaql: { + table: 'Commerce', + column: 'Cost', + dim: '[Commerce.Cost]', + datatype: 'numeric', + agg: 'sum', + title: 'Total Cost', + }, + instanceid: '75F04-7F38-F0', + format: { + mask: { + type: 'number', + abbreviations: { + t: true, + b: true, + m: true, + k: true, + }, + separated: true, + decimals: 'auto', + abbreviateAll: false, + isdefault: true, + }, + }, + }, + ], + }, + { + name: 'filters', + items: [], + }, + ], + usedFormulasMapping: {}, + }, + tags: [], + style: { + legend: { + enabled: true, + position: 'bottom', + }, + labels: { + enabled: true, + categories: true, + value: false, + percent: true, + decimals: false, + fontFamily: 'Open Sans', + color: 'red', + }, + convolution: { + enabled: true, + selectedConvolutionType: 'byPercentage', + minimalIndependentSlicePercentage: 3, + independentSlicesCount: 7, + }, + dataLimits: { + seriesCapacity: 100000, + }, + lineWidth: { + width: 'bold', + }, + seriesLabels: { + enabled: false, + rotation: 0, + }, + markers: { + enabled: false, + fill: 'filled', + size: 'small', + }, + xAxis: { + enabled: true, + ticks: true, + labels: { + enabled: true, + rotation: 0, + }, + title: { + enabled: false, + }, + x2Title: { + enabled: false, + }, + gridLines: true, + isIntervalEnabled: true, + }, + yAxis: { + inactive: true, + enabled: true, + ticks: true, + labels: { + enabled: true, + rotation: 0, + }, + title: { + enabled: false, + }, + gridLines: true, + logarithmic: false, + isIntervalEnabled: true, + }, + y2Axis: { + inactive: true, + enabled: true, + ticks: true, + labels: { + enabled: true, + rotation: 0, + }, + title: { + enabled: false, + }, + gridLines: false, + logarithmic: false, + isIntervalEnabled: true, + }, + navigator: { + enabled: true, + }, + narration: { + enabled: false, + display: 'above', + format: 'bullets', + verbosity: 'medium', + up_sentiment: 'good', + aggregation: 'sum', + labels: [ + { + id: 'gender', + title: 'Gender', + singular: 'Gender', + plural: 'Gender', + }, + ], + }, + automaticHeight: false, + }, + instanceid: '64D07-9BFD-DB', + realTimeRefreshing: false, + options: { + dashboardFiltersMode: 'select', + selector: true, + triggersDomready: true, + autoUpdateOnEveryChange: true, + drillToAnywhere: true, + selectorLocked: false, + }, + dashboardid: '66d998d1ab28a90032b5b490', + _dataSourcePermission: 'owner', + userAuth: { + dashboards: { + create: true, + delete: true, + move: true, + rename: true, + duplicate: true, + change_owner: true, + toggle_edit_mode: true, + edit_layout: true, + edit_script: true, + export_dash: true, + export_jpeg: true, + export_image: true, + export_pdf: true, + share: true, + restore: true, + copy_to_server: true, + import: true, + select_palette: true, + replace_datasource: true, + undo_import_dash: true, + toggleDataExploration: true, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + reorder: true, + modify_type: true, + toggle_auto_update: true, + set_defaults: true, + advanced: true, + use_starred: true, + modify_filter_relationship: true, + }, + }, + widgets: { + create: true, + delete: true, + rename: true, + duplicate: true, + copy_to_dashboard: true, + edit: true, + edit_script: true, + change_type: true, + export_csv: true, + export_png: true, + export_svg: true, + export_pdf: true, + modify_selection_attrs: true, + modify_selection_mode: true, + drill_to_anywhere: true, + add_to_pulse: true, + items: { + create: true, + delete: true, + rename: true, + modify: true, + reorder: true, + modify_type: true, + modify_format: true, + on_off: true, + select_hierarchies: true, + }, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + modify_layout: true, + modify_type: true, + modify_dashboard_filters: true, + use_starred: true, + }, + widgetViewOnly: false, + }, + base: { + isConsumer: false, + isContributor: false, + isAdmin: false, + isSuper: true, + }, + }, + _toDisableOptionsList: { + widgets: { + duplicate: false, + }, + }, + }, + ], + isDatasourceBeingReplaced: false, + _dataSourcePermission: 'owner', + userAuth: { + dashboards: { + create: true, + delete: true, + move: true, + rename: true, + duplicate: true, + change_owner: true, + toggle_edit_mode: true, + edit_layout: true, + edit_script: true, + export_dash: true, + export_jpeg: true, + export_image: true, + export_pdf: true, + share: true, + restore: true, + copy_to_server: true, + import: true, + select_palette: true, + replace_datasource: true, + undo_import_dash: true, + toggleDataExploration: true, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + reorder: true, + modify_type: true, + toggle_auto_update: true, + set_defaults: true, + advanced: true, + use_starred: true, + modify_filter_relationship: true, + }, + }, + widgets: { + create: true, + delete: true, + rename: true, + duplicate: true, + copy_to_dashboard: true, + edit: true, + edit_script: true, + change_type: true, + export_csv: true, + export_png: true, + export_svg: true, + export_pdf: true, + modify_selection_attrs: true, + modify_selection_mode: true, + drill_to_anywhere: true, + add_to_pulse: true, + items: { + create: true, + delete: true, + rename: true, + modify: true, + reorder: true, + modify_type: true, + modify_format: true, + on_off: true, + select_hierarchies: true, + }, + filters: { + create: true, + delete: true, + save: true, + on_off: true, + toggle_expansion: true, + modify: true, + modify_layout: true, + modify_type: true, + modify_dashboard_filters: true, + use_starred: true, + }, + widgetViewOnly: false, + }, + base: { + isConsumer: false, + isContributor: false, + isAdmin: false, + isSuper: true, + }, + }, + _toDisableOptionsList: { + dashboards: { + duplicate: false, + export_dash: false, + }, + }, +} as DashboardDto; diff --git a/packages/sdk-ui/src/models/dashboard/__snapshots__/dashboard-model.test.ts.snap b/packages/sdk-ui/src/models/dashboard/__snapshots__/dashboard-model.test.ts.snap index 20b2c68e..bfcde932 100644 --- a/packages/sdk-ui/src/models/dashboard/__snapshots__/dashboard-model.test.ts.snap +++ b/packages/sdk-ui/src/models/dashboard/__snapshots__/dashboard-model.test.ts.snap @@ -13,7 +13,7 @@ DashboardModel { "__serializable": "DimensionalElement", "desc": "", "expression": "dim", - "name": "column", + "name": "title", "type": "text-attribute", }, "desc": "", @@ -21,7 +21,7 @@ DashboardModel { "members": [ "member", ], - "name": "e8e9681675b", + "name": "8cbfe2c92d", "type": "filter", }, ], diff --git a/packages/sdk-ui/src/models/widget/__snapshots__/widget-model.test.ts.snap b/packages/sdk-ui/src/models/widget/__snapshots__/widget-model.test.ts.snap index 55385b8a..bad4aa63 100644 --- a/packages/sdk-ui/src/models/widget/__snapshots__/widget-model.test.ts.snap +++ b/packages/sdk-ui/src/models/widget/__snapshots__/widget-model.test.ts.snap @@ -24,7 +24,7 @@ exports[`WidgetModel > getExecutePivotQueryParams > getChartProps > should retur "__serializable": "DimensionalElement", "desc": "", "expression": "[Admissions.Patient_ID]", - "name": "PATIENTS", + "name": "# PATIENTS", "type": "numeric-attribute", }, "desc": "", @@ -54,7 +54,7 @@ exports[`WidgetModel > getExecutePivotQueryParams > getChartProps > should retur "__serializable": "DimensionalElement", "desc": "", "expression": "[Admissions.Cost_of_admission]", - "name": "AVGCOST", + "name": "AVG COST", "type": "numeric-attribute", }, "desc": "", @@ -86,7 +86,7 @@ exports[`WidgetModel > getExecutePivotQueryParams > getChartProps > should retur "__serializable": "DimensionalElement", "desc": "", "expression": "[Diagnosis.Description]", - "name": "Description", + "name": "DESCRIPTION", "type": "text-attribute", }, "count": 10, @@ -107,7 +107,7 @@ exports[`WidgetModel > getExecutePivotQueryParams > getChartProps > should retur "sort": 0, "type": "basemeasure", }, - "name": "f1b3d268f61", + "name": "d259e15eba1", "operator": "top", "type": "filter", }, diff --git a/packages/sdk-ui/src/models/widget/widget-model.test.ts b/packages/sdk-ui/src/models/widget/widget-model.test.ts index 0d59fd25..814a1b1f 100644 --- a/packages/sdk-ui/src/models/widget/widget-model.test.ts +++ b/packages/sdk-ui/src/models/widget/widget-model.test.ts @@ -4,6 +4,7 @@ import { WidgetDto, WidgetType } from '../../dashboard-widget/types'; import { TranslatableError } from '../../translation/translatable-error'; import { sampleEcommerceDashboard as dashboardMock } from '../__mocks__/sample-ecommerce-dashboard'; import { sampleHealthcareDashboard } from '../__mocks__/sample-healthcare-dashboard'; +import { dashboardWithTextWidget } from '../__mocks__/dashboard-with-text-widget'; describe('WidgetModel', () => { let mockWidgetDto: WidgetDto; @@ -179,9 +180,14 @@ describe('WidgetModel', () => { const pivotWidgetModel = new WidgetModel( sampleHealthcareDashboard.widgets!.find((widget) => widget.type === 'pivot')!, ); - expect(() => pivotWidgetModel.getChartProps()).toThrow(TranslatableError); }); + it('should throw an error for text widget', () => { + const textWidgetModel = new WidgetModel( + dashboardWithTextWidget.widgets!.find((widget) => widget.type === 'richtexteditor')!, + ); + expect(() => textWidgetModel.getChartProps()).toThrow(TranslatableError); + }); it('should return chart props for chart widgets', () => { const widget = new WidgetModel(mockWidgetDto); const chartProps = widget.getChartProps(); @@ -387,6 +393,14 @@ describe('WidgetModel', () => { expect(() => { tableWidgetModel.getChartWidgetProps(); }).toThrow(TranslatableError); + + const textWidgetModel = new WidgetModel( + dashboardWithTextWidget.widgets!.find((widget) => widget.type === 'richtexteditor')!, + ); + + expect(() => { + textWidgetModel.getChartWidgetProps(); + }).toThrow(TranslatableError); }); }); }); @@ -439,6 +453,11 @@ describe('WidgetModel', () => { it('should throw an error for non-table widgets', () => { const nonTableWidgetModel = new WidgetModel(mockWidgetDto); expect(() => nonTableWidgetModel.getTableWidgetProps()).toThrow(TranslatableError); + + const textWidgetModel = new WidgetModel( + dashboardWithTextWidget.widgets!.find((widget) => widget.type === 'richtexteditor')!, + ); + expect(() => textWidgetModel.getTableWidgetProps()).toThrow(TranslatableError); }); }); @@ -446,6 +465,11 @@ describe('WidgetModel', () => { it('should throw an error for non-pivot widgets', () => { const nonPivotWidgetModel = new WidgetModel(mockWidgetDto); expect(() => nonPivotWidgetModel.getPivotTableWidgetProps()).toThrow(TranslatableError); + + const textWidgetModel = new WidgetModel( + dashboardWithTextWidget.widgets!.find((widget) => widget.type === 'richtexteditor')!, + ); + expect(() => textWidgetModel.getPivotTableWidgetProps()).toThrow(TranslatableError); }); it('should return PivotTableWidgetProps for pivot widgets', () => { const pivotWidgetModel = new WidgetModel( @@ -495,4 +519,26 @@ describe('WidgetModel', () => { }); }); }); + + describe('getTextWidgetProps', () => { + it('should return text widget props correctly for text widget', () => { + const textWidgetModel = new WidgetModel( + dashboardWithTextWidget.widgets!.find((widget) => widget.type === 'richtexteditor')!, + ); + const textWidgetProps = textWidgetModel.getTextWidgetProps(); + + expect(textWidgetProps).toMatchObject({ + styleOptions: { + bgColor: '#FFFFFF', + html: 'fancy text', + textAlign: 'center', + vAlign: 'valign-middle', + }, + }); + }); + it('should throw an error for non-text widgets', () => { + const nonTextWidgetModel = new WidgetModel(mockWidgetDto); + expect(() => nonTextWidgetModel.getTextWidgetProps()).toThrow(TranslatableError); + }); + }); }); diff --git a/packages/sdk-ui/src/models/widget/widget-model.ts b/packages/sdk-ui/src/models/widget/widget-model.ts index f9de1106..391f4d34 100644 --- a/packages/sdk-ui/src/models/widget/widget-model.ts +++ b/packages/sdk-ui/src/models/widget/widget-model.ts @@ -16,7 +16,7 @@ import { extractDrilldownOptions } from '../../dashboard-widget/translate-widget import { extractWidgetFilters } from '../../dashboard-widget/translate-widget-filters'; import { extractStyleOptions, - getStyleWithWigetDesign, + getStyleWithWidgetDesign, } from '../../dashboard-widget/translate-widget-style-options'; import { Panel, WidgetDto, WidgetType } from '../../dashboard-widget/types'; import { @@ -25,6 +25,7 @@ import { isPivotWidget, isSupportedWidgetType, isTableWidget, + isTextWidget, } from '../../dashboard-widget/utils'; import { ChartProps, @@ -33,6 +34,7 @@ import { TableProps, TableWidgetProps, PivotTableWidgetProps, + TextWidgetProps, } from '../../props'; import { ExecutePivotQueryParams, ExecuteQueryParams } from '../../query-execution'; import { getTableAttributesAndMeasures } from '../../table/hooks/use-table-data'; @@ -48,13 +50,15 @@ import { RenderToolbarHandler, WidgetContainerStyleOptions, WidgetStyleOptions, + TextWidgetStyleOptions, } from '../../types'; import { AppSettings } from '@/app/settings/settings'; +import { EmptyObject } from '@/utils/utility-types'; /** * Widget data options. */ -export type WidgetDataOptions = ChartDataOptions | PivotTableDataOptions; +export type WidgetDataOptions = ChartDataOptions | PivotTableDataOptions | EmptyObject; /** * Model of Sisense widget defined in the abstractions of Compose SDK. @@ -178,15 +182,15 @@ export class WidgetModel { const styleOptions = extractStyleOptions(widgetType, widgetDto); - // take into account widget design style feature flag const isWidgetDesignStyleEnabled = appSettings?.serverFeatures?.widgetDesignStyle?.active ?? true; - this.styleOptions = getStyleWithWigetDesign( + this.styleOptions = getStyleWithWidgetDesign( styleOptions, widgetDto.style.widgetDesign, isWidgetDesignStyleEnabled, ); + // } } // does not handle widget type plugin @@ -293,6 +297,9 @@ export class WidgetModel { if (isPivotWidget(this.widgetType)) { throw new PivotNotSupportedMethodError('getChartProps'); } + if (isTextWidget(this.widgetType)) { + throw new TextWidgetNotSupportedMethodError('getChartProps'); + } if (isTableWidget(this.widgetType)) { return { chartType: this.chartType!, @@ -302,7 +309,7 @@ export class WidgetModel { return { chartType: this.chartType!, dataOptions: this.dataOptions as ChartDataOptions, - styleOptions: this.styleOptions, + styleOptions: this.styleOptions as ChartStyleOptions, dataSet: this.dataSource, filters: this.filters, highlights: this.highlights, @@ -355,7 +362,7 @@ export class WidgetModel { } return { dataOptions: this.dataOptions as PivotTableDataOptions, - styleOptions: this.styleOptions, + styleOptions: this.styleOptions as PivotTableWidgetStyleOptions, dataSet: this.dataSource, filters: this.filters, highlights: this.highlights, @@ -376,10 +383,13 @@ export class WidgetModel { if (isPivotWidget(this.widgetType)) { throw new PivotNotSupportedMethodError('getChartWidgetProps'); } + if (isTextWidget(this.widgetType)) { + throw new TextWidgetNotSupportedMethodError('getChartWidgetProps'); + } return { chartType: this.chartType!, dataOptions: this.dataOptions as ChartDataOptions, - styleOptions: this.styleOptions, + styleOptions: this.styleOptions as ChartStyleOptions, dataSource: this.dataSource, filters: this.filters, highlights: this.highlights, @@ -449,6 +459,29 @@ export class WidgetModel { }; } + /** + * Returns the props to be used for rendering a text widget. + * + * @example + * ```tsx + * + * ``` + * + * Note: this method is not supported for chart, table, or pivot widgets. + * Use {@link getChartWidgetProps} instead for getting props for the component. + * Use {@link getTableWidgetProps} instead for getting props for the component. + * Use {@link getPivotTableWidgetProps} instead for getting props for the component. + * + */ + getTextWidgetProps(): TextWidgetProps { + if (!isTextWidget(this.widgetType)) { + throw new TranslatableError('errors.widgetModel.onlyTextWidgetSupported', { + methodName: 'getTextWidgetProps', + }); + } + return { styleOptions: this.styleOptions as TextWidgetStyleOptions }; + } + /** * Registers new "onDataPointClick" handler for the constructed component * @@ -503,3 +536,9 @@ class PivotNotSupportedMethodError extends TranslatableError { super('errors.widgetModel.pivotWidgetNotSupported', { methodName }); } } + +class TextWidgetNotSupportedMethodError extends TranslatableError { + constructor(methodName: string) { + super('errors.widgetModel.textWidgetNotSupported', { methodName }); + } +} diff --git a/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.test.ts b/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.test.ts index 8fe67029..415f11fd 100644 --- a/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.test.ts +++ b/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.test.ts @@ -147,4 +147,34 @@ describe('createHeaderCellValueFormatter', () => { expect(cell.content).toBe('N\\A'); }); + + it('should format datetime cell with invalid date as original value', () => { + const dataOptions = { + rows: [ + { + dateFormat: 'YYYY', + column: { + type: 'datetime', + }, + }, + ], + } as PivotTableDataOptions; + const cell = { + value: 'Some non-date string', + content: null, + } as unknown as PivotTreeNode; + const jaqlPanelItem = { + jaql: { + datatype: 'datetime', + }, + field: { + index: 0, + }, + } as JaqlPanel; + const formatter = createHeaderCellValueFormatter(dataOptions, dateFormatterMock); + + formatter(cell, jaqlPanelItem, jaqlMock); + + expect(cell.content).toBe('Some non-date string'); + }); }); diff --git a/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.ts b/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.ts index 29066d19..a504e68a 100644 --- a/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.ts +++ b/packages/sdk-ui/src/pivot-table/formatters/header-cell-formatters/header-cell-value-formatter.ts @@ -36,7 +36,7 @@ export const createHeaderCellValueFormatter = ( ); break; case 'datetime': - cell.content = dateFormat ? dateFormatter(parseISO(cell.value!), dateFormat) : cell.value; + cell.content = formatDateTimeString(cell.value!, dateFormatter, dateFormat); break; default: cell.content = cell.value; @@ -47,3 +47,29 @@ export const createHeaderCellValueFormatter = ( } }; }; + +/** + * Formats the date time string. + * If the date is invalid, it returns the original value. + */ +function formatDateTimeString( + value: string, + dateFormatter: DateFormatter, + dateFormat?: string, +): string { + if (!dateFormat) { + return value; + } + const date = parseISO(value); + if (isInvalidDate(date)) { + return value; + } + return dateFormatter(date, dateFormat); +} + +/** + * Checks if the date is invalid. + */ +function isInvalidDate(date: Date): boolean { + return date.toString() === 'Invalid Date'; +} diff --git a/packages/sdk-ui/src/plugins-provider/custom-plugins-provider.tsx b/packages/sdk-ui/src/plugins-provider/custom-plugins-provider.tsx new file mode 100644 index 00000000..ad195b4d --- /dev/null +++ b/packages/sdk-ui/src/plugins-provider/custom-plugins-provider.tsx @@ -0,0 +1,36 @@ +import { ReactNode } from 'react'; +import { PluginsContext } from './plugins-context'; +import { WidgetPlugin } from './types'; + +/** @internal */ +export type CustomPluginsProviderProps = { + context: CustomPluginsContext; + error?: Error; +}; + +/** @internal */ +export type CustomPluginsContext = { + pluginMap: Map; + registerPlugin: (pluginType: string, plugin: WidgetPlugin) => void; + getPlugin: (pluginType: string) => WidgetPlugin | undefined; +}; + +/** + * Custom Plugin Provider component that allows passing external plugins context. + * + * Note: it is designed to serve as a bridge for passing pre-initialized plugin data between an external wrapper and child React components. + * + * @internal + */ +export const CustomPluginsProvider: React.FC<{ + context: CustomPluginsContext; + children: ReactNode; +}> = ({ context, children }) => { + const { pluginMap, registerPlugin, getPlugin } = context; + + return ( + + {children} + + ); +}; diff --git a/packages/sdk-ui/src/plugins-provider/index.ts b/packages/sdk-ui/src/plugins-provider/index.ts new file mode 100644 index 00000000..219407f2 --- /dev/null +++ b/packages/sdk-ui/src/plugins-provider/index.ts @@ -0,0 +1,2 @@ +export * from './plugins-provider'; +export * from './plugins-context'; diff --git a/packages/sdk-ui/src/plugins-provider/plugins-context.tsx b/packages/sdk-ui/src/plugins-provider/plugins-context.tsx new file mode 100644 index 00000000..3266c529 --- /dev/null +++ b/packages/sdk-ui/src/plugins-provider/plugins-context.tsx @@ -0,0 +1,16 @@ +import { createContext } from 'react'; +import { WidgetPlugin } from './types'; + +type PluginsContextType = { + plugins: Map; + registerPlugin: (pluginType: string, plugin: WidgetPlugin) => void; + getPlugin: (pluginType: string) => WidgetPlugin | undefined; +}; + +const map = new Map(); + +export const PluginsContext = createContext({ + plugins: map, + registerPlugin: () => {}, + getPlugin: () => undefined, +}); diff --git a/packages/sdk-ui/src/plugins-provider/plugins-provider.tsx b/packages/sdk-ui/src/plugins-provider/plugins-provider.tsx new file mode 100644 index 00000000..a9b1d18a --- /dev/null +++ b/packages/sdk-ui/src/plugins-provider/plugins-provider.tsx @@ -0,0 +1,32 @@ +import { ReactNode, useCallback, useContext, useMemo, useRef } from 'react'; +import { PluginsContext } from './plugins-context'; +import { WidgetPlugin } from './types'; + +/** + * Plugin Provider component that allows registering and accessing plugins. + * + * @internal + */ +export const PluginsProvider: React.FC<{ children: ReactNode }> = ({ children }) => { + const pluginMapRef = useRef(new Map()); + + const registerPlugin = useCallback((pluginType: string, plugin: WidgetPlugin) => { + if (!pluginMapRef.current.has(pluginType)) { + pluginMapRef.current.set(pluginType, plugin); + } + }, []); + + const getPlugin = useCallback((pluginType: string) => { + return pluginMapRef.current.get(pluginType); + }, []); + + const plugins = useMemo(() => pluginMapRef.current, []); + + return ( + + {children} + + ); +}; + +export const usePlugins = () => useContext(PluginsContext); diff --git a/packages/sdk-ui/src/plugins-provider/types.ts b/packages/sdk-ui/src/plugins-provider/types.ts new file mode 100644 index 00000000..becf8fbd --- /dev/null +++ b/packages/sdk-ui/src/plugins-provider/types.ts @@ -0,0 +1,9 @@ +import { WidgetModel } from '@/models'; +import { CompleteThemeSettings } from '../types'; + +/** @internal */ +export type WidgetPlugin

= { + name: string; + component: (props: any) => any; + createChartProps(w: WidgetModel, themeSettings: CompleteThemeSettings): P; +}; diff --git a/packages/sdk-ui/src/props.tsx b/packages/sdk-ui/src/props.tsx index 3e407c1c..fe35eb39 100644 --- a/packages/sdk-ui/src/props.tsx +++ b/packages/sdk-ui/src/props.tsx @@ -50,6 +50,7 @@ import { TableStyleOptions, AreaRangeStyleOptions, DrilldownSelection, + TextWidgetStyleOptions, } from './types'; import { HighchartsOptions } from './chart-options-processor/chart-options-service'; import { ComponentType, PropsWithChildren, ReactNode } from 'react'; @@ -1607,3 +1608,13 @@ export interface UseGetSharedFormulaParams extends HookEnableParam { */ dataSource?: DataSource; } + +/** + * Props for the TextWidget component. + */ +export type TextWidgetProps = { + /** + * Style options for the text widget. + */ + styleOptions: TextWidgetStyleOptions; +}; diff --git a/packages/sdk-ui/src/sisense-chart/sisense-chart.tsx b/packages/sdk-ui/src/sisense-chart/sisense-chart.tsx index 68b2eedf..ead10305 100644 --- a/packages/sdk-ui/src/sisense-chart/sisense-chart.tsx +++ b/packages/sdk-ui/src/sisense-chart/sisense-chart.tsx @@ -95,6 +95,7 @@ export const SisenseChart = ({ const highchartsOptionsWithEventHandlers = applyEventHandlersToChart( highchartsOptionsWithCommonOptions, + dataOptions, { onDataPointClick, onDataPointContextMenu, diff --git a/packages/sdk-ui/src/sisense-chart/types.ts b/packages/sdk-ui/src/sisense-chart/types.ts index 5cf95d87..adc1f5a2 100644 --- a/packages/sdk-ui/src/sisense-chart/types.ts +++ b/packages/sdk-ui/src/sisense-chart/types.ts @@ -1,9 +1,9 @@ -import { DataPointsEventHandler, ScatterDataPointsEventHandler } from '../props.js'; import { BoxplotDataPoint, DataPoint, ScatterDataPoint } from '../types.js'; -export type SisenseChartDataPointsEventHandler = - | DataPointsEventHandler - | ScatterDataPointsEventHandler; +export type SisenseChartDataPointsEventHandler = ( + points: SisenseChartDataPoint[], + nativeEvent: MouseEvent, +) => void; export type SisenseChartDataPoint = DataPoint | ScatterDataPoint | BoxplotDataPoint; diff --git a/packages/sdk-ui/src/sisense-context/sisense-context-provider.tsx b/packages/sdk-ui/src/sisense-context/sisense-context-provider.tsx index 2e328c2f..d84cd1a8 100644 --- a/packages/sdk-ui/src/sisense-context/sisense-context-provider.tsx +++ b/packages/sdk-ui/src/sisense-context/sisense-context-provider.tsx @@ -7,6 +7,7 @@ import { SisenseContext } from './sisense-context'; import { I18nProvider } from '../translation/i18n-provider'; import { SisenseQueryClientProvider } from './sisense-query-client-provider'; import { isAuthTokenPending } from '@sisense/sdk-rest-client'; +import { PluginsProvider } from '@/plugins-provider'; /** * Sisense Context Provider Component allowing you to connect to @@ -123,7 +124,9 @@ export const SisenseContextProvider: FunctionComponent< - {children} + + {children} + diff --git a/packages/sdk-ui/src/theme-provider/fonts-loader/__snapshots__/font-loader.test.tsx.snap b/packages/sdk-ui/src/theme-provider/fonts-loader/__snapshots__/font-loader.test.tsx.snap new file mode 100644 index 00000000..906f93c6 --- /dev/null +++ b/packages/sdk-ui/src/theme-provider/fonts-loader/__snapshots__/font-loader.test.tsx.snap @@ -0,0 +1,60 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`FontLoader > should avoid duplication on multiple instance 1`] = ` + + + +`; + +exports[`FontLoader > should load different fonts on multiple instance 1`] = ` + + + + +`; + +exports[`FontLoader > should load font correctly 1`] = ` + + + +`; diff --git a/packages/sdk-ui/src/theme-provider/fonts-loader/__snapshots__/fonts-loader.test.tsx.snap b/packages/sdk-ui/src/theme-provider/fonts-loader/__snapshots__/fonts-loader.test.tsx.snap new file mode 100644 index 00000000..906f93c6 --- /dev/null +++ b/packages/sdk-ui/src/theme-provider/fonts-loader/__snapshots__/fonts-loader.test.tsx.snap @@ -0,0 +1,60 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`FontLoader > should avoid duplication on multiple instance 1`] = ` + + + +`; + +exports[`FontLoader > should load different fonts on multiple instance 1`] = ` + + + + +`; + +exports[`FontLoader > should load font correctly 1`] = ` + + + +`; diff --git a/packages/sdk-ui/src/theme-provider/fonts-loader/fonts-loader.test.tsx b/packages/sdk-ui/src/theme-provider/fonts-loader/fonts-loader.test.tsx new file mode 100644 index 00000000..f05bf9f5 --- /dev/null +++ b/packages/sdk-ui/src/theme-provider/fonts-loader/fonts-loader.test.tsx @@ -0,0 +1,59 @@ +import { describe } from 'vitest'; +import { FontsLoader } from '@/theme-provider/fonts-loader/fonts-loader'; +import { render, waitFor } from '@testing-library/react'; + +const FONT_MOCK = { + fontFamily: 'FontTest1', + fontWeight: 'bold', + fontStyle: 'normal', + src: [ + { + url: `FontTest1-Bold.eot`, + }, + { + local: `FontTest1-Bold`, + }, + { + url: `FontTest1-Bold.eot?#iefix`, + format: 'embedded-opentype', + }, + { + url: `FontTest1-Bold.ttf`, + format: 'truetype', + }, + ], +}; + +describe('FontLoader', () => { + it('should load font correctly', async () => { + render(Test); + + await waitFor(() => { + expect(document.querySelector('head')).toMatchSnapshot(); + }); + }); + + it('should avoid duplication on multiple instance', async () => { + render( + + Test + , + ); + + await waitFor(() => { + expect(document.querySelector('head')).toMatchSnapshot(); + }); + }); + + it('should load different fonts on multiple instance', async () => { + render( + + Test + , + ); + + await waitFor(() => { + expect(document.querySelector('head')).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/sdk-ui/src/theme-provider/fonts-loader/fonts-loader.tsx b/packages/sdk-ui/src/theme-provider/fonts-loader/fonts-loader.tsx new file mode 100644 index 00000000..ca3b1603 --- /dev/null +++ b/packages/sdk-ui/src/theme-provider/fonts-loader/fonts-loader.tsx @@ -0,0 +1,31 @@ +import { ThemeSettingsFont } from '@/types'; +import { useFontsLoader } from '@/theme-provider/fonts-loader/use-fonts-loader'; +import { useThemeContext } from '@/theme-provider'; +import { createContext, useContext } from 'react'; + +const FontLoaderContext = createContext<{ + loadedFonts: string[]; +}>({ + loadedFonts: [], +}); + +export const FontsLoader = ({ + fonts, + children, +}: { + fonts?: ThemeSettingsFont[]; + children?: any; +}) => { + const { loadedFonts: prevLoadedFonts } = useContext(FontLoaderContext); + const { themeSettings } = useThemeContext(); + const loadedFonts = useFontsLoader( + fonts || themeSettings.typography.fontsLoader?.fonts || [], + prevLoadedFonts, + ); + + return ( + + {children} + + ); +}; diff --git a/packages/sdk-ui/src/theme-provider/fonts-loader/use-fonts-loader.tsx b/packages/sdk-ui/src/theme-provider/fonts-loader/use-fonts-loader.tsx new file mode 100644 index 00000000..9cc6de3f --- /dev/null +++ b/packages/sdk-ui/src/theme-provider/fonts-loader/use-fonts-loader.tsx @@ -0,0 +1,50 @@ +/* eslint-disable sonarjs/no-nested-template-literals */ +import { ThemeSettingsFont } from '@/types'; +import { useEffect, useMemo, useRef, useState } from 'react'; + +export const useFontsLoader = (fonts: ThemeSettingsFont[], prevLoadedFonts: string[]) => { + const styleElement = useRef(document.createElement('style')); + const [loadedFonts, setLoadedFonts] = useState([]); + + const notLoadedFonts = useMemo( + () => fonts.filter((font) => !prevLoadedFonts.includes(getFontInditifier(font))), + [fonts, prevLoadedFonts], + ); + + useEffect(() => { + if (notLoadedFonts.length) { + styleElement.current = document.createElement('style'); + const fontFaces = notLoadedFonts.map(prepareFontFaceString); + styleElement.current.innerHTML = fontFaces.join('\n'); + + document.head.appendChild(styleElement.current); + setLoadedFonts(notLoadedFonts.map(getFontInditifier)); + } + + return () => { + styleElement.current?.remove(); + }; + }, [notLoadedFonts]); + + return loadedFonts; +}; + +function getFontInditifier(font: ThemeSettingsFont) { + return `${font.fontFamily}|${font.fontWeight}|${font.fontStyle}`; +} + +function prepareFontFaceString(font: ThemeSettingsFont) { + return `@font-face { + font-family: "${font.fontFamily}"; + font-weight: ${font.fontWeight}; + font-style: ${font.fontStyle}; + ${font.src + .map( + (src) => + `src: ${Object.entries(src) + .map(([key, value]) => `${key}('${value}')`) + .join(' ')};`, + ) + .join('\n')} + }`; +} diff --git a/packages/sdk-ui/src/theme-provider/theme-provider.tsx b/packages/sdk-ui/src/theme-provider/theme-provider.tsx index db0994f5..cabba1d7 100644 --- a/packages/sdk-ui/src/theme-provider/theme-provider.tsx +++ b/packages/sdk-ui/src/theme-provider/theme-provider.tsx @@ -2,6 +2,7 @@ import { ThemeProviderProps } from '../props'; import { asSisenseComponent } from '../decorators/component-decorators/as-sisense-component'; import { useThemeSettings } from './use-theme-settings'; import { ThemeContext } from './theme-context'; +import { FontsLoader } from '@/theme-provider/fonts-loader/fonts-loader'; /** * Theme provider, which allows you to adjust the look and feel of child components. @@ -51,6 +52,7 @@ export const ThemeProvider = asSisenseComponent({ })((props: ThemeProviderProps) => { const { theme, children } = props; const [themeSettings, error] = useThemeSettings(theme); + if (error) { throw error; } @@ -58,7 +60,7 @@ export const ThemeProvider = asSisenseComponent({ <> {themeSettings && ( - {children} + {children} )} diff --git a/packages/sdk-ui/src/themes/__mocks__/legacy-design-settings.mock.ts b/packages/sdk-ui/src/themes/__mocks__/legacy-design-settings.mock.ts index ca4bbc80..19855e51 100644 --- a/packages/sdk-ui/src/themes/__mocks__/legacy-design-settings.mock.ts +++ b/packages/sdk-ui/src/themes/__mocks__/legacy-design-settings.mock.ts @@ -74,6 +74,73 @@ export const redThemeSettings: CompleteThemeSettings = { fontFamily: 'Open Sans', primaryTextColor: '#ff0000', secondaryTextColor: '#f9a8a8', + fontsLoader: { + fonts: [ + { + fontFamily: 'Open Sans', + fontStyle: 'normal', + fontWeight: 'normal', + src: [ + { + url: 'http://test.com/resources/base/fonts/Open Sans-Regular.eot', + }, + { + local: 'Open Sans-Regular', + }, + { + format: 'embedded-opentype', + url: 'http://test.com/resources/base/fonts/Open Sans-Regular.eot?#iefix', + }, + { + format: 'truetype', + url: 'http://test.com/resources/base/fonts/Open Sans-Regular.ttf', + }, + ], + }, + { + fontFamily: 'Open Sans', + fontStyle: 'normal', + fontWeight: 600, + src: [ + { + url: 'http://test.com/resources/base/fonts/Open Sans-SemiBold.eot', + }, + { + local: 'Open Sans-SemiBold', + }, + { + format: 'embedded-opentype', + url: 'http://test.com/resources/base/fonts/Open Sans-SemiBold.eot?#iefix', + }, + { + format: 'truetype', + url: 'http://test.com/resources/base/fonts/Open Sans-SemiBold.ttf', + }, + ], + }, + { + fontFamily: 'Open Sans', + fontStyle: 'normal', + fontWeight: 'bold', + src: [ + { + url: 'http://test.com/resources/base/fonts/Open Sans-Bold.eot', + }, + { + local: 'Open Sans-Bold', + }, + { + format: 'embedded-opentype', + url: 'http://test.com/resources/base/fonts/Open Sans-Bold.eot?#iefix', + }, + { + format: 'truetype', + url: 'http://test.com/resources/base/fonts/Open Sans-Bold.ttf', + }, + ], + }, + ], + }, }, palette: { variantColors: ['#779fa8', '#bf1e1d', '#787070'], diff --git a/packages/sdk-ui/src/themes/legacy-design-settings.test.ts b/packages/sdk-ui/src/themes/legacy-design-settings.test.ts index 841da604..2d83df8a 100644 --- a/packages/sdk-ui/src/themes/legacy-design-settings.test.ts +++ b/packages/sdk-ui/src/themes/legacy-design-settings.test.ts @@ -8,7 +8,11 @@ import { convertToThemeSettings, getPaletteName } from './legacy-design-settings describe('legacy-design-settings', () => { describe('convertToThemeSettings', () => { it('should convert LegacyDesignSettings and LegacyPalette to ThemeSettings', () => { - const themeSettings = convertToThemeSettings(redLegacyDesignSettings, corporatePalette); + const themeSettings = convertToThemeSettings( + redLegacyDesignSettings, + corporatePalette, + 'http://test.com/', + ); expect(themeSettings).toEqual(redThemeSettings); }); }); diff --git a/packages/sdk-ui/src/themes/legacy-design-settings.ts b/packages/sdk-ui/src/themes/legacy-design-settings.ts index 1002efa4..72433a02 100644 --- a/packages/sdk-ui/src/themes/legacy-design-settings.ts +++ b/packages/sdk-ui/src/themes/legacy-design-settings.ts @@ -11,6 +11,7 @@ import { RadiusSizes, ShadowsTypes, AlignmentTypes, + ThemeSettingsFont, } from '../types.js'; /** @@ -117,6 +118,7 @@ export const LEGACY_DESIGN_TYPES = { export function convertToThemeSettings( legacyDesignSettings: LegacyDesignSettings, legacyPalette: LegacyPalette, + domainUrl: string, ): CompleteThemeSettings { const themeSettings: Omit = { chart: { @@ -137,6 +139,13 @@ export function convertToThemeSettings( fontFamily: legacyDesignSettings.typography.fontFamily, primaryTextColor: legacyDesignSettings.typography.primaryTextColor, secondaryTextColor: legacyDesignSettings.typography.secondaryTextColor, + fontsLoader: { + fonts: prepareLegacyThemeSettingsFonts( + legacyDesignSettings.typography.fontFamily, + domainUrl, + legacyDesignSettings.typography.customFontSelected, + ), + }, }, palette: { variantColors: legacyPalette.colors, @@ -183,3 +192,80 @@ export function convertToThemeSettings( export function getPaletteName(legacyDesignSettings: LegacyDesignSettings): string { return legacyDesignSettings.dashboards.colorPaletteName; } + +function prepareLegacyThemeSettingsFonts( + fontFamily: string, + domainUrl: string, + isCustomFont: boolean, +): ThemeSettingsFont[] { + const BASE_FONTS_PATH = 'resources/base/fonts/'; + const CUSTOM_FONTS_PATH = 'fonts/'; + const path = isCustomFont ? CUSTOM_FONTS_PATH : BASE_FONTS_PATH; + + return [ + { + fontFamily: fontFamily, + fontWeight: 'normal', + fontStyle: 'normal', + src: [ + { + url: `${domainUrl}${path}${fontFamily}-Regular.eot`, + }, + { + local: `${fontFamily}-Regular`, + }, + { + url: `${domainUrl}${path}${fontFamily}-Regular.eot?#iefix`, + // eslint-disable-next-line sonarjs/no-duplicate-string + format: 'embedded-opentype', + }, + { + url: `${domainUrl}${path}${fontFamily}-Regular.ttf`, + format: 'truetype', + }, + ], + }, + { + fontFamily: fontFamily, + fontWeight: 600, + fontStyle: 'normal', + src: [ + { + url: `${domainUrl}${path}${fontFamily}-SemiBold.eot`, + }, + { + local: `${fontFamily}-SemiBold`, + }, + { + url: `${domainUrl}${path}${fontFamily}-SemiBold.eot?#iefix`, + format: 'embedded-opentype', + }, + { + url: `${domainUrl}${path}${fontFamily}-SemiBold.ttf`, + format: 'truetype', + }, + ], + }, + { + fontFamily: fontFamily, + fontWeight: 'bold', + fontStyle: 'normal', + src: [ + { + url: `${domainUrl}${path}${fontFamily}-Bold.eot`, + }, + { + local: `${fontFamily}-Bold`, + }, + { + url: `${domainUrl}${path}${fontFamily}-Bold.eot?#iefix`, + format: 'embedded-opentype', + }, + { + url: `${domainUrl}${path}${fontFamily}-Bold.ttf`, + format: 'truetype', + }, + ], + }, + ]; +} diff --git a/packages/sdk-ui/src/themes/theme-loader.test.ts b/packages/sdk-ui/src/themes/theme-loader.test.ts index 30efa89d..e3c18730 100644 --- a/packages/sdk-ui/src/themes/theme-loader.test.ts +++ b/packages/sdk-ui/src/themes/theme-loader.test.ts @@ -10,8 +10,9 @@ import { ThemeOid, ThemeSettings } from '../types'; import { Mocked } from 'vitest'; describe('getThemeSettingsByOid', () => { - const httpClientMock: Mocked> = { + const httpClientMock: Mocked> = { get: vi.fn().mockImplementation(() => {}), + url: 'http://test.com/', }; afterEach(() => { diff --git a/packages/sdk-ui/src/themes/theme-loader.ts b/packages/sdk-ui/src/themes/theme-loader.ts index 4b3dd898..a482ba7f 100644 --- a/packages/sdk-ui/src/themes/theme-loader.ts +++ b/packages/sdk-ui/src/themes/theme-loader.ts @@ -19,7 +19,7 @@ import { */ export async function getThemeSettingsByOid( themeOid: ThemeOid, - httpClient: Pick, + httpClient: Pick, ): Promise { const legacyDesignSettings = await getLegacyDesignSettings(themeOid, httpClient); @@ -29,7 +29,7 @@ export async function getThemeSettingsByOid( const paletteName = getPaletteName(legacyDesignSettings); const legacyPalette = await getLegacyPalette(paletteName, httpClient); - return convertToThemeSettings(legacyDesignSettings, legacyPalette); + return convertToThemeSettings(legacyDesignSettings, legacyPalette, httpClient.url); } async function getLegacyDesignSettings(themeOid: ThemeOid, httpClient: Pick) { diff --git a/packages/sdk-ui/src/translation/resources/en.ts b/packages/sdk-ui/src/translation/resources/en.ts index e890890d..fecad5fd 100644 --- a/packages/sdk-ui/src/translation/resources/en.ts +++ b/packages/sdk-ui/src/translation/resources/en.ts @@ -17,7 +17,6 @@ export const translation = { 'Sisense Context for query execution not found. To fix, wrap the component inside a Sisense context provider.', executeQueryNoDataSource: 'No dataSource provided to execute query', dataOptions: { - emptyValueArray: 'Invalid dataOptions – Array "value" is empty', noDimensionsAndMeasures: 'Neither dimensions nor measures found. Data options should have at least one dimension or measure.', attributeNotFound: 'Attribute "{{attributeName}}" not found in the data', @@ -40,8 +39,10 @@ export const translation = { }, widgetModel: { pivotWidgetNotSupported: 'Pivot widget is not supported for method {{methodName}}', + textWidgetNotSupported: 'Text widget is not supported for method {{methodName}}', onlyTableWidgetSupported: 'Only table widget is supported for method {{methodName}}', onlyPivotWidgetSupported: 'Only pivot widget is supported for method {{methodName}}', + onlyTextWidgetSupported: 'Only text widget is supported for method {{methodName}}', }, unknownFilterInFilterRelations: 'Filter relations contain unknown filter', filterRelationsNotSupported: 'Filter relations not supported yet', diff --git a/packages/sdk-ui/src/translation/resources/uk.ts b/packages/sdk-ui/src/translation/resources/uk.ts index 373f0694..4eddd38f 100644 --- a/packages/sdk-ui/src/translation/resources/uk.ts +++ b/packages/sdk-ui/src/translation/resources/uk.ts @@ -17,7 +17,6 @@ export const translation: TranslationDictionary = { 'Контекст Sisense для виконання запиту не знайдено. Щоб виправити, оберніть компонент у SisenseContextProvider.', executeQueryNoDataSource: 'Не надано dataSource для виконання запиту', dataOptions: { - emptyValueArray: 'Недійсні dataOptions - Масив "value" порожній', noDimensionsAndMeasures: 'Не знайдено ні dimension-ів, ні measure-ів. Параметри даних повинні мати щонайменше один dimension або measure.', attributeNotFound: 'Атрибут "{{attributeName}}" не знайдено в даних', @@ -41,8 +40,10 @@ export const translation: TranslationDictionary = { }, widgetModel: { pivotWidgetNotSupported: 'Метод {{methodName}} не підтримується для півот віджету', - onlyTableWidgetSupported: 'Метод {{methodName}} підтримуються тільки для табличним віджетом', - onlyPivotWidgetSupported: 'Метод {{methodName}} підтримуються тільки для півот віджетом', + textWidgetNotSupported: 'Метод {{methodName}} не підтримується для текстового віджету', + onlyTableWidgetSupported: 'Метод {{methodName}} підтримується тільки для табличних віджетів', + onlyPivotWidgetSupported: 'Метод {{methodName}} підтримується тільки для півот віджетів', + onlyTextWidgetSupported: 'Метод {{methodName}} підтримується тільки для текстових віджетів', }, unknownFilterInFilterRelations: 'Логічні відношення фільтрів містять невідомий фільтр', filterRelationsNotSupported: 'Відносини фільтрів ще не підтримуються', diff --git a/packages/sdk-ui/src/types.ts b/packages/sdk-ui/src/types.ts index 3bee4909..29337806 100644 --- a/packages/sdk-ui/src/types.ts +++ b/packages/sdk-ui/src/types.ts @@ -1,6 +1,12 @@ -import { AutoZoomNavigatorScrollerLocation } from './dashboard-widget/types'; /* eslint-disable max-lines */ -import type { Attribute, MembersFilter } from '@sisense/sdk-data'; +import type { + Attribute, + CalculatedMeasureColumn, + Column, + Measure, + MeasureColumn, + MembersFilter, +} from '@sisense/sdk-data'; import { DeepRequired } from 'ts-essentials'; import { AreaSubtype, @@ -37,6 +43,8 @@ import { DataPointsEventHandler } from './props'; import { LegendPosition } from './chart-options-processor/translations/legend-section'; import { GeoDataElement, RawGeoDataElement } from './chart-data/types'; import { Coordinates } from '@/charts/map-charts/scattermap/types'; +import { StyledColumn, StyledMeasureColumn } from '.'; +import { HighchartsOptionsInternal } from './chart-options-processor/chart-options-service'; export type { SortDirection, PivotRowsSort } from '@sisense/sdk-data'; export type { AppConfig } from './app/client-application'; @@ -101,7 +109,8 @@ export type Components = { export type Navigator = { /** Boolean flag that defines if navigator should be shown on the chart */ enabled: boolean; - scrollerLocation?: AutoZoomNavigatorScrollerLocation; + /** The scroll location of the navigator scroller / auto zoom feature */ + scrollerLocation?: { min: number; max: number }; }; /** Configuration that defines line width */ @@ -1011,6 +1020,32 @@ export interface AiChatThemeSettings { }; } +export type ThemeSettingsFontSource = + | { + local: string; + } + | { + url: string; + } + | { + format: string; + url: string; + }; + +/** Loading font details */ +export interface ThemeSettingsFont { + fontFamily: string; + fontWeight: string | number; + fontStyle: string; + src: ThemeSettingsFontSource[]; +} + +/** Settings for fonts loading */ +export interface FontsLoaderSettings { + /** List of fonts */ + fonts: ThemeSettingsFont[]; +} + /** Text theme settings */ export interface TypographyThemeSettings { /** Font family name to style component text */ @@ -1019,6 +1054,8 @@ export interface TypographyThemeSettings { primaryTextColor?: string; /** Secondary text color */ secondaryTextColor?: string; + /** Settings for font loading */ + fontsLoader?: FontsLoaderSettings; } /** General theme settings */ @@ -1137,11 +1174,15 @@ export interface ThemeSettings { * * @internal */ -export type CompleteThemeSettings = DeepRequired; +export type CompleteThemeSettings = DeepRequired> & { + typography: DeepRequired> & { + fontsLoader?: FontsLoaderSettings; + }; +}; /** Complete set of configuration options that define functional style of the various elements of the charts as well as the look and feel of widget itself and widget header. */ -export type WidgetStyleOptions = (ChartStyleOptions | TableStyleOptions) & - WidgetContainerStyleOptions; +export type WidgetStyleOptions = + | (ChartStyleOptions | TableStyleOptions | TextWidgetStyleOptions) & WidgetContainerStyleOptions; /** Style settings defining the look and feel of widget itself and widget header */ export interface WidgetContainerStyleOptions { @@ -1232,6 +1273,15 @@ export type TableWidgetStyleOptions = TableStyleOptions & WidgetContainerStyleOp */ export type PivotTableWidgetStyleOptions = PivotTableStyleOptions & WidgetContainerStyleOptions; +/** + * Style settings defining the look and feel of TextWidget + */ +export type TextWidgetStyleOptions = { + html: string; + vAlign: `valign-${'middle' | 'top' | 'bottom'}`; + bgColor: string; +}; + /** * Runs type guard check for ThemeOid. * @@ -1273,12 +1323,18 @@ export type ChartDataPoints = | DataPoint[] | ScatterDataPoint[] | BoxplotDataPoint[] - | AreamapDataPoint[]; + | AreamapDataPoint[] + | ScattermapDataPoint[]; /** * Abstract data point in a chart - union of all types of data points. */ -export type ChartDataPoint = DataPoint | ScatterDataPoint | BoxplotDataPoint | AreamapDataPoint; +export type ChartDataPoint = + | DataPoint + | ScatterDataPoint + | BoxplotDataPoint + | AreamapDataPoint + | ScattermapDataPoint; /** * Abstract data point in a chart that based on Highcharts. @@ -1307,6 +1363,39 @@ export type DataPoint = { categoryDisplayValue?: string; /** Series associated with the data point */ seriesValue?: string | number; + /** + * A collection of data point entries that represents values for all related `dataOptions`. + * + * @internal + */ + entries?: { + category: DataPointEntry[]; + value: DataPointEntry[]; + breakBy?: DataPointEntry[]; + }; +}; + +/** + * A data point entry that represents a single dimension within a multi-dimensional data point. + * + * @internal + */ +export type DataPointEntry = { + /** + * The unique identifier of the data point entry. + * It represents the path within the `dataOptions` object that identifies the related option. + */ + readonly id: string; + /** The data option associated with this entry */ + dataOption: Column | StyledColumn | MeasureColumn | CalculatedMeasureColumn | StyledMeasureColumn; + /** The attribute associated with this data point entry */ + attribute?: Attribute; + /** The measure associated with this data point entry */ + measure?: Measure; + /** The raw value of the data point */ + value: string | number; + /** The formated value of the data point */ + displayValue?: string; }; /** Data point in a Scatter chart. */ @@ -1316,30 +1405,64 @@ export type ScatterDataPoint = { size?: number; breakByPoint?: string; breakByColor?: string; + /** + * A collection of data point entries that represents values for all related `dataOptions`. + * + * @internal + */ + entries?: { + x?: DataPointEntry; + y?: DataPointEntry; + size?: DataPointEntry; + breakByPoint?: DataPointEntry; + breakByColor?: DataPointEntry; + }; }; /** Data point in a Boxplot chart. */ export type BoxplotDataPoint = { /** Value of the box minimum */ - boxMin: number; + boxMin?: number; /** Value of the box median */ - boxMedian: number; + boxMedian?: number; /** Value of the box maximum */ - boxMax: number; + boxMax?: number; /** Value of the box minimal whisker */ - whiskerMin: number; + whiskerMin?: number; /** Value of the box maximal whisker */ - whiskerMax: number; + whiskerMax?: number; /** Value of the category for the data point */ categoryValue?: string | number; /** Display value of category of the data point */ categoryDisplayValue?: string; + /** Value of the outlier */ + outlier?: number; + /** + * A collection of data point entries that represents values for all related `dataOptions`. + * + * @internal + */ + entries?: { + category: DataPointEntry[]; + value: DataPointEntry[]; + outliers: DataPointEntry[]; + }; }; /** * Data point in an Areamap chart. */ -export type AreamapDataPoint = GeoDataElement; +export type AreamapDataPoint = GeoDataElement & { + /** + * A collection of data point entries that represents values for all related `dataOptions`. + * + * @internal + */ + entries?: { + geo: DataPointEntry[]; + color: DataPointEntry[]; + }; +}; /** * Data point in an Scattermap chart. @@ -1353,6 +1476,17 @@ export type ScattermapDataPoint = { value: number; /** Location coordinates */ coordinates: Coordinates; + /** + * A collection of data point entries that represents values for all related `dataOptions`. + * + * @internal + */ + entries?: { + geo: DataPointEntry[]; + size?: DataPointEntry; + colorBy?: DataPointEntry; + details?: DataPointEntry; + }; }; /** @@ -1401,18 +1535,27 @@ export type HighchartsPoint = { name: string; custom: { number1?: number; + level?: number; + levelsCount?: number; }; q1?: number; median?: number; q3?: number; low?: number; high?: number; + y?: number; }; custom: { + maskedX?: string; + maskedY?: string; maskedBreakByPoint?: string; maskedBreakByColor?: string; + maskedSize?: string; rawValue?: string | number; xValue?: (string | number)[]; + xDisplayValue?: string[]; + rawValues?: (string | number)[]; + xValues?: string[]; }; series: { initialType: string; @@ -1420,6 +1563,11 @@ export type HighchartsPoint = { options: { custom?: { rawValue?: string | number[] }; }; + index: number; + chart: { + options: HighchartsOptionsInternal; + }; + name: string; }; graphic?: { on: (eventType: string, callback: (event: PointerEvent) => void) => HighchartsPoint['graphic']; @@ -1427,6 +1575,8 @@ export type HighchartsPoint = { x: number; y: number; z: number; + index: number; + value?: number; }; /** diff --git a/packages/sdk-ui/src/utils/filters.ts b/packages/sdk-ui/src/utils/filters.ts index 917d3c81..8850f0ed 100644 --- a/packages/sdk-ui/src/utils/filters.ts +++ b/packages/sdk-ui/src/utils/filters.ts @@ -1,17 +1,13 @@ import { Attribute, - CascadingFilter, DimensionalLevelAttribute, Filter, filterFactory, + isMembersFilter, MembersFilter, } from '@sisense/sdk-data'; import cloneDeep from 'lodash-es/cloneDeep.js'; -export function isCascadingFilter(filter: Filter): filter is CascadingFilter { - return filter instanceof CascadingFilter; -} - /** * Clones a filter with a toggled 'disabled' state. * @@ -41,10 +37,6 @@ export function clearMembersFilter(filter: Filter) { return createIncludeAllFilter(attribute, backgroundFilter, guid); } -export function isMembersFilter(filter: Filter): filter is MembersFilter { - return filter instanceof MembersFilter; -} - export function isIncludeAllFilter(filter: Filter) { return 'members' in filter && (filter as MembersFilter).members.length === 0; } diff --git a/packages/sdk-ui/src/utils/utility-types.ts b/packages/sdk-ui/src/utils/utility-types.ts index 6843bc56..da6bcab4 100644 --- a/packages/sdk-ui/src/utils/utility-types.ts +++ b/packages/sdk-ui/src/utils/utility-types.ts @@ -48,6 +48,11 @@ type PickTypeOf = K extends AllKeys */ export type AnyObject = Record; +/** + * Empty object with no properties + */ +export type EmptyObject = Record; + /** * Allows you to make a property of an object required. * diff --git a/packages/sdk-ui/src/widgets/text-widget.test.tsx b/packages/sdk-ui/src/widgets/text-widget.test.tsx new file mode 100644 index 00000000..2858d63c --- /dev/null +++ b/packages/sdk-ui/src/widgets/text-widget.test.tsx @@ -0,0 +1,72 @@ +/** @vitest-environment jsdom */ +import { describe, it, expect } from 'vitest'; +import { render } from '@testing-library/react'; +import { isTextWidgetProps, TextWidget } from './text-widget'; +import { TextWidgetProps } from '@/props'; + +vi.mock('@/decorators/component-decorators/as-sisense-component', () => ({ + asSisenseComponent: () => (Component: any) => Component, +})); + +describe('TextWidget', () => { + describe('isTextWidgetProps', () => { + it('should return true for valid TextWidgetProps', () => { + const validProps: TextWidgetProps = { + styleOptions: { + html: '

Sample Text

', + bgColor: '#ffffff', + vAlign: 'valign-top', + }, + }; + expect(isTextWidgetProps(validProps)).toBe(true); + }); + + it('should return false for invalid TextWidgetProps (missing properties)', () => { + const invalidProps = { + styleOptions: { + html: '

Sample Text

', + bgColor: '#ffffff', + }, + }; + expect(isTextWidgetProps(invalidProps)).toBe(false); + }); + + it('should return false for invalid TextWidgetProps (wrong types)', () => { + const invalidProps = { + styleOptions: { + html: 123, + bgColor: '#ffffff', + vAlign: 'valign-top', + }, + }; + expect(isTextWidgetProps(invalidProps)).toBe(false); + }); + + it('should return false for completely invalid objects', () => { + const invalidProps = { + someRandomKey: 'someRandomValue', + }; + expect(isTextWidgetProps(invalidProps)).toBe(false); + }); + + it('should return false for null or undefined', () => { + expect(isTextWidgetProps(null)).toBe(false); + expect(isTextWidgetProps(undefined)).toBe(false); + }); + }); + + describe('TextWidget component', () => { + it('should render TextWidget with provided HTML content', async () => { + const props: TextWidgetProps = { + styleOptions: { + html: '

Sample Text

', + bgColor: '#ffffff', + vAlign: 'valign-top', + }, + }; + const { findByText } = render(); + + expect(await findByText('Sample Text')).toBeInTheDocument(); + }); + }); +}); diff --git a/packages/sdk-ui/src/widgets/text-widget.tsx b/packages/sdk-ui/src/widgets/text-widget.tsx new file mode 100644 index 00000000..fdb51545 --- /dev/null +++ b/packages/sdk-ui/src/widgets/text-widget.tsx @@ -0,0 +1,53 @@ +import styled from '@emotion/styled'; +import { FunctionComponent } from 'react'; +import DOMPurify from 'dompurify'; +import { asSisenseComponent } from '@/decorators/component-decorators/as-sisense-component'; +import { TextWidgetStyleOptions } from '@/types'; +import { TextWidgetProps } from '@/props'; + +export function isTextWidgetProps(props: any): props is TextWidgetProps { + return ( + props !== null && + typeof props === 'object' && + typeof props.styleOptions === 'object' && + typeof props.styleOptions.html === 'string' && + typeof props.styleOptions.bgColor === 'string' && + typeof props.styleOptions.vAlign === 'string' + ); +} + +type Stylable = { + styleOptions: TextWidgetStyleOptions; +}; + +const VERTICAL_ALIGNMENT_DICTIONARY = { + 'valign-top': 'flex-start', + 'valign-middle': 'center', + 'valign-bottom': 'flex-end', +} as const; + +const TextWidgetContainer = styled.div` + background-color: ${(props) => props.styleOptions.bgColor}; + display: flex; + align-items: ${(props) => VERTICAL_ALIGNMENT_DICTIONARY[props.styleOptions.vAlign]}; + text-align: center; + height: 100%; + width: 100%; + padding: 10px; + box-sizing: border-box; +`; + +const InnerHtml = styled.div` + width: 100%; +`; + +export const TextWidget: FunctionComponent = asSisenseComponent({ + componentName: 'TextWidget', +})((props) => { + const sanitizedHtml = DOMPurify.sanitize(props.styleOptions.html); + return ( + + + + ); +}); diff --git a/yarn.lock b/yarn.lock index e0362cc5..c1d56cad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5513,12 +5513,12 @@ __metadata: resolution: "@sisense/sdk-cli@workspace:packages/sdk-cli" dependencies: "@babel/preset-env": ^7.20.2 - "@sisense/sdk-common": ^1.18.1 - "@sisense/sdk-data": ^1.18.1 - "@sisense/sdk-modeling": ^1.18.1 - "@sisense/sdk-query-client": ^1.18.1 - "@sisense/sdk-rest-client": ^1.18.1 - "@sisense/sdk-tracking": ^1.18.1 + "@sisense/sdk-common": ^1.19.0 + "@sisense/sdk-data": ^1.19.0 + "@sisense/sdk-modeling": ^1.19.0 + "@sisense/sdk-query-client": ^1.19.0 + "@sisense/sdk-rest-client": ^1.19.0 + "@sisense/sdk-tracking": ^1.19.0 "@types/inquirer": 8.2.6 "@types/js-levenshtein": ^1.1.3 "@types/yargs": ^17.0.22 @@ -5536,7 +5536,7 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-common@^1.18.1, @sisense/sdk-common@workspace:packages/sdk-common": +"@sisense/sdk-common@^1.19.0, @sisense/sdk-common@workspace:packages/sdk-common": version: 0.0.0-use.local resolution: "@sisense/sdk-common@workspace:packages/sdk-common" dependencies: @@ -5546,13 +5546,13 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-data@^1.18.1, @sisense/sdk-data@workspace:^, @sisense/sdk-data@workspace:packages/sdk-data": +"@sisense/sdk-data@^1.19.0, @sisense/sdk-data@workspace:^, @sisense/sdk-data@workspace:packages/sdk-data": version: 0.0.0-use.local resolution: "@sisense/sdk-data@workspace:packages/sdk-data" dependencies: "@babel/preset-env": ^7.20.2 - "@sisense/sdk-common": ^1.18.1 - "@sisense/sdk-rest-client": ^1.18.1 + "@sisense/sdk-common": ^1.19.0 + "@sisense/sdk-rest-client": ^1.19.0 "@types/lodash": ^4.14.201 "@types/numeral": 2.0.2 eslint: ^8.40.0 @@ -5565,19 +5565,19 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-modeling@^1.18.1, @sisense/sdk-modeling@workspace:packages/sdk-modeling": +"@sisense/sdk-modeling@^1.19.0, @sisense/sdk-modeling@workspace:packages/sdk-modeling": version: 0.0.0-use.local resolution: "@sisense/sdk-modeling@workspace:packages/sdk-modeling" dependencies: "@babel/preset-env": ^7.20.2 - "@sisense/sdk-data": ^1.18.1 + "@sisense/sdk-data": ^1.19.0 eslint: ^8.40.0 prettier: ^3.2.5 typescript: 4.8.4 languageName: unknown linkType: soft -"@sisense/sdk-pivot-client@^1.18.1, @sisense/sdk-pivot-client@workspace:packages/sdk-pivot-client": +"@sisense/sdk-pivot-client@^1.19.0, @sisense/sdk-pivot-client@workspace:packages/sdk-pivot-client": version: 0.0.0-use.local resolution: "@sisense/sdk-pivot-client@workspace:packages/sdk-pivot-client" dependencies: @@ -5585,8 +5585,8 @@ __metadata: "@emotion/react": ^11.11.4 "@emotion/styled": ^11.11.5 "@mui/material": ^5.11.6 - "@sisense/sdk-data": ^1.18.1 - "@sisense/sdk-rest-client": ^1.18.1 + "@sisense/sdk-data": ^1.19.0 + "@sisense/sdk-rest-client": ^1.19.0 "@types/lodash-es": ^4.17.12 "@types/react": ^18.3.1 "@types/react-custom-scrollbars": ^4.0.13 @@ -5621,14 +5621,14 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-query-client@^1.18.1, @sisense/sdk-query-client@workspace:packages/sdk-query-client": +"@sisense/sdk-query-client@^1.19.0, @sisense/sdk-query-client@workspace:packages/sdk-query-client": version: 0.0.0-use.local resolution: "@sisense/sdk-query-client@workspace:packages/sdk-query-client" dependencies: - "@sisense/sdk-common": ^1.18.1 - "@sisense/sdk-data": ^1.18.1 - "@sisense/sdk-pivot-client": ^1.18.1 - "@sisense/sdk-rest-client": ^1.18.1 + "@sisense/sdk-common": ^1.19.0 + "@sisense/sdk-data": ^1.19.0 + "@sisense/sdk-pivot-client": ^1.19.0 + "@sisense/sdk-rest-client": ^1.19.0 "@sisense/task-manager": ^0.1.0 "@types/tar": ^6.1.4 "@types/uuid": ^9.0.0 @@ -5645,12 +5645,12 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-rest-client@^1.18.1, @sisense/sdk-rest-client@workspace:^, @sisense/sdk-rest-client@workspace:packages/sdk-rest-client": +"@sisense/sdk-rest-client@^1.19.0, @sisense/sdk-rest-client@workspace:^, @sisense/sdk-rest-client@workspace:packages/sdk-rest-client": version: 0.0.0-use.local resolution: "@sisense/sdk-rest-client@workspace:packages/sdk-rest-client" dependencies: "@babel/preset-env": ^7.20.2 - "@sisense/sdk-common": ^1.18.1 + "@sisense/sdk-common": ^1.19.0 eslint: ^8.40.0 fetch-intercept: ^2.4.0 prettier: 2.8.4 @@ -5658,7 +5658,7 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-tracking@^1.18.1, @sisense/sdk-tracking@workspace:^, @sisense/sdk-tracking@workspace:packages/sdk-tracking": +"@sisense/sdk-tracking@^1.19.0, @sisense/sdk-tracking@workspace:^, @sisense/sdk-tracking@workspace:packages/sdk-tracking": version: 0.0.0-use.local resolution: "@sisense/sdk-tracking@workspace:packages/sdk-tracking" dependencies: @@ -5703,7 +5703,7 @@ __metadata: dependencies: "@preact/preset-vite": 2.5.0 "@sisense/sdk-data": "workspace:^" - "@sisense/sdk-ui": ^1.18.1 + "@sisense/sdk-ui": ^1.19.0 "@types/node": ^18.16.0 eslint: ^8.40.0 preact: ^10.13.2 @@ -5741,7 +5741,7 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-ui@^1.18.1, @sisense/sdk-ui@workspace:^, @sisense/sdk-ui@workspace:packages/sdk-ui": +"@sisense/sdk-ui@^1.19.0, @sisense/sdk-ui@workspace:^, @sisense/sdk-ui@workspace:packages/sdk-ui": version: 0.0.0-use.local resolution: "@sisense/sdk-ui@workspace:packages/sdk-ui" dependencies: @@ -5752,12 +5752,12 @@ __metadata: "@mui/material": ^5.15.16 "@mui/system": ^5.15.15 "@mui/x-data-grid": ^6.16.0 - "@sisense/sdk-common": ^1.18.1 - "@sisense/sdk-data": ^1.18.1 - "@sisense/sdk-pivot-client": ^1.18.1 - "@sisense/sdk-query-client": ^1.18.1 - "@sisense/sdk-rest-client": ^1.18.1 - "@sisense/sdk-tracking": ^1.18.1 + "@sisense/sdk-common": ^1.19.0 + "@sisense/sdk-data": ^1.19.0 + "@sisense/sdk-pivot-client": ^1.19.0 + "@sisense/sdk-query-client": ^1.19.0 + "@sisense/sdk-rest-client": ^1.19.0 + "@sisense/sdk-tracking": ^1.19.0 "@sisense/sisense-charts": 5.1.1 "@storybook/addon-actions": 7.0.24 "@storybook/addon-docs": 7.0.24 @@ -5772,6 +5772,7 @@ __metadata: "@tanstack/react-query": 4.36.1 "@testing-library/jest-dom": ^6.4.2 "@testing-library/react": ^14.0.0 + "@types/dompurify": ^3.0.5 "@types/fixed-data-table-2": ^1.0.0 "@types/leaflet": ^1.9.8 "@types/lodash": ^4.14.194 @@ -5789,6 +5790,7 @@ __metadata: date-fns: ^2.29.3 date-fns-tz: ^2.0.0 dayjs: ^1.11.7 + dompurify: ^3.1.6 eslint: ^8.40.0 fixed-data-table-2: ^1.2.18 geojson: ^0.5.0 @@ -7337,6 +7339,15 @@ __metadata: languageName: node linkType: hard +"@types/dompurify@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/dompurify@npm:3.0.5" + dependencies: + "@types/trusted-types": "*" + checksum: ffc34eca6a4536e1c8c16a47cce2623c5a118a9785492e71230052d92933ff096d14326ff449031e8dfaac509413222372d8f2b28786a13159de6241df716185 + languageName: node + linkType: hard + "@types/ejs@npm:^3.1.1": version: 3.1.5 resolution: "@types/ejs@npm:3.1.5" @@ -7908,6 +7919,13 @@ __metadata: languageName: node linkType: hard +"@types/trusted-types@npm:*": + version: 2.0.7 + resolution: "@types/trusted-types@npm:2.0.7" + checksum: 8e4202766a65877efcf5d5a41b7dd458480b36195e580a3b1085ad21e948bc417d55d6f8af1fd2a7ad008015d4117d5fdfe432731157da3c68678487174e4ba3 + languageName: node + linkType: hard + "@types/unist@npm:^2, @types/unist@npm:^2.0.0": version: 2.0.10 resolution: "@types/unist@npm:2.0.10" @@ -11927,6 +11945,13 @@ __metadata: languageName: node linkType: hard +"dompurify@npm:^3.1.6": + version: 3.1.6 + resolution: "dompurify@npm:3.1.6" + checksum: cc4fc4ccd9261fbceb2a1627a985c70af231274a26ddd3f643fd0616a0a44099bd9e4480940ce3655612063be4a1fe9f5e9309967526f8c0a99f931602323866 + languageName: node + linkType: hard + "domutils@npm:^2.8.0": version: 2.8.0 resolution: "domutils@npm:2.8.0"