diff --git a/.gitignore b/.gitignore index 38b9ce89..8e697921 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ lerna-debug.log* docs/ docs-internal/ e2e/results.xml + +# generated from storybook build +storybook-static/ diff --git a/CHANGELOG.md b/CHANGELOG.md index cc47cf14..8c152c8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## [0.11.0] - 2023-09-28 + +### Added + +- Add component `TreemapChart` + and support Treemap chart type in components `Chart`, `ChartWidget`, and `DashboardWidget` +- Add component `DrilldownWidget`, which allows adding drilldown functionality to any type of chart + +### Changed +- Refactor `HttpClient` to return raw response – in addition to JSON +- Support internationalization for numbers and improve tooltip consistency +- Make `dataSource` optional in `ChartWidgetProps` and `TableWidgetProps` +- Extend component `ExecuteQueryByWidgetId` and hook `useExecuteQueryByWidgetId` + to support `filters`, `highlights`, and `filtersMergeStrategy` +- Extend hook `useExecuteQuery` to support boolean flag `enabled` +- Extend component `DashboardWidget` to support `filtersMergeStrategy` +- Move `markers`, `navigator`, `xAxis`, `yAxis`, and `yAxis2` out of `BaseStyleOptions` + and into `BaseAxisStyleOptions` +- Bump `sisense-charts` version after fixing chart freeze on navigator update +- Improve styling of the Drilldown Breadcrumbs + ## [0.10.0] - 2023-09-15 ### Added diff --git a/docs-md/sdk/img/treemap-chart-example-1.png b/docs-md/sdk/img/treemap-chart-example-1.png new file mode 100644 index 00000000..315a8ae7 Binary files /dev/null and b/docs-md/sdk/img/treemap-chart-example-1.png differ diff --git a/docs-md/sdk/modules/sdk-ui/functions/function.ChartWidget.md b/docs-md/sdk/modules/sdk-ui/functions/function.ChartWidget.md index f8c3ca44..ae21836e 100644 --- a/docs-md/sdk/modules/sdk-ui/functions/function.ChartWidget.md +++ b/docs-md/sdk/modules/sdk-ui/functions/function.ChartWidget.md @@ -37,7 +37,7 @@ Drill-down capability is enabled. breakBy: [], }} drilldownOptions={{ - drilldownCategories: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], + drilldownDimensions: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], }} /> ``` diff --git a/docs-md/sdk/modules/sdk-ui/functions/function.ContextMenu.md b/docs-md/sdk/modules/sdk-ui/functions/function.ContextMenu.md new file mode 100644 index 00000000..e54338d1 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/functions/function.ContextMenu.md @@ -0,0 +1,17 @@ +--- +title: ContextMenu +--- + +# Function ContextMenu + +> **ContextMenu**(`__namedParameters`): `Element` + +## Parameters + +| Parameter | Type | +| :------ | :------ | +| `__namedParameters` | [`ContextMenuProps`](../type-aliases/type-alias.ContextMenuProps.md) | + +## Returns + +`Element` diff --git a/docs-md/sdk/modules/sdk-ui/functions/function.DrilldownBreadcrumbs.md b/docs-md/sdk/modules/sdk-ui/functions/function.DrilldownBreadcrumbs.md new file mode 100644 index 00000000..531bc419 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/functions/function.DrilldownBreadcrumbs.md @@ -0,0 +1,18 @@ +--- +title: DrilldownBreadcrumbs +--- + +# Function DrilldownBreadcrumbs + +> **DrilldownBreadcrumbs**(`props`, `context`?): `null` \| `ReactElement`\< `any`, `any` \> + +## Parameters + +| Parameter | Type | +| :------ | :------ | +| `props` | [`DrilldownBreadcrumbsProps`](../type-aliases/type-alias.DrilldownBreadcrumbsProps.md) | +| `context`? | `any` | + +## Returns + +`null` \| `ReactElement`\< `any`, `any` \> diff --git a/docs-md/sdk/modules/sdk-ui/functions/function.DrilldownWidget.md b/docs-md/sdk/modules/sdk-ui/functions/function.DrilldownWidget.md new file mode 100644 index 00000000..641e0115 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/functions/function.DrilldownWidget.md @@ -0,0 +1,63 @@ +--- +title: DrilldownWidget +--- + +# Function DrilldownWidget + +> **DrilldownWidget**(`props`): `Element` + +React component designed to add drilldown functionality to any type of chart + +It acts as a wrapper around a given chart component, enhancing it with drilldown capabilities + +The widget offers several features including: +- A context menu for initiating drilldown actions (can be provided as a custom component) +- Breadcrumbs that not only allow for drilldown selection slicing but also +provide an option to clear the selection (can be provided as a custom component) +- Filters specifically created for drilldown operation +- An option to navigate to the next drilldown dimension + +When an `initialDimension` is specified, the `drilldownDimension` will automatically inherit its value, +even before any points on the chart are selected. +This allows for complete control over the chart's dimensions to be handed over to the DrilldownWidget + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `props` | [`DrilldownWidgetProps`](../type-aliases/type-alias.DrilldownWidgetProps.md) | DrilldownWidget properties | + +## Returns + +`Element` + +DrilldownWidget wrapper component + +## Example + +Example of using the `DrilldownWidget` component to +plot a custom React component that uses the `ExecuteQuery` component to +query the `Sample ECommerce` data source hosted in a Sisense instance. +```ts + + {({ drilldownFilters, drilldownDimension, onDataPointsSelected, onContextMenu }) => ( + + {(data) => ( + + )} + + )} + +``` diff --git a/docs-md/sdk/modules/sdk-ui/functions/function.TreemapChart.md b/docs-md/sdk/modules/sdk-ui/functions/function.TreemapChart.md new file mode 100644 index 00000000..454d3142 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/functions/function.TreemapChart.md @@ -0,0 +1,49 @@ +--- +title: TreemapChart +--- + +# Function TreemapChart + +> **TreemapChart**(`props`, `context`?): `null` \| `ReactElement`\< `any`, `any` \> + +A React component displaying hierarchical data in the form of nested rectangles. +This type of chart can be used in different scenarios, for example, +instead of a column chart if you have to compare too many categories and sub-categories. +See [Treemap Chart](https://docs.sisense.com/main/SisenseLinux/treemap.htm) for more information. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `props` | [`TreemapChartProps`](../interfaces/interface.TreemapChartProps.md) | Treemap chart properties | +| `context`? | `any` | - | + +## Returns + +`null` \| `ReactElement`\< `any`, `any` \> + +Treemap Chart component + +## Example + +An example of using the component to visualize the `Sample ECommerce` data source: +```ts + { + console.log('clicked', point, nativeEvent); + }} +/> +``` +### + diff --git a/docs-md/sdk/modules/sdk-ui/functions/function.useExecuteQueryByWidgetId.md b/docs-md/sdk/modules/sdk-ui/functions/function.useExecuteQueryByWidgetId.md index 38cafe76..d761c923 100644 --- a/docs-md/sdk/modules/sdk-ui/functions/function.useExecuteQueryByWidgetId.md +++ b/docs-md/sdk/modules/sdk-ui/functions/function.useExecuteQueryByWidgetId.md @@ -14,7 +14,7 @@ This approach, which offers an alternative to [ExecuteQueryByWidgetId](function. | Parameter | Type | Description | | :------ | :------ | :------ | -| `params` | [`ExecuteQueryByWidgetIdParams`](../type-aliases/type-alias.ExecuteQueryByWidgetIdParams.md) | Parameters to identify the target widget | +| `params` | [`ExecuteQueryByWidgetIdParams`](../interfaces/interface.ExecuteQueryByWidgetIdParams.md) | Parameters to identify the target widget | ## Returns diff --git a/docs-md/sdk/modules/sdk-ui/functions/index.md b/docs-md/sdk/modules/sdk-ui/functions/index.md index f1dad53a..b9aaf86c 100644 --- a/docs-md/sdk/modules/sdk-ui/functions/index.md +++ b/docs-md/sdk/modules/sdk-ui/functions/index.md @@ -9,8 +9,11 @@ title: Functions - [Chart](function.Chart.md) - [ChartWidget](function.ChartWidget.md) - [ColumnChart](function.ColumnChart.md) +- [ContextMenu](function.ContextMenu.md) - [DashboardWidget](function.DashboardWidget.md) - [DateRangeFilterTile](function.DateRangeFilterTile.md) +- [DrilldownBreadcrumbs](function.DrilldownBreadcrumbs.md) +- [DrilldownWidget](function.DrilldownWidget.md) - [ExecuteQuery](function.ExecuteQuery.md) - [ExecuteQueryByWidgetId](function.ExecuteQueryByWidgetId.md) - [FunnelChart](function.FunnelChart.md) @@ -23,5 +26,6 @@ title: Functions - [SisenseContextProvider](function.SisenseContextProvider.md) - [Table](function.Table.md) - [ThemeProvider](function.ThemeProvider.md) +- [TreemapChart](function.TreemapChart.md) - [useExecuteQuery](function.useExecuteQuery.md) - [useExecuteQueryByWidgetId](function.useExecuteQueryByWidgetId.md) diff --git a/docs-md/sdk/modules/sdk-ui/index.md b/docs-md/sdk/modules/sdk-ui/index.md index ea1127fb..0cf647a1 100644 --- a/docs-md/sdk/modules/sdk-ui/index.md +++ b/docs-md/sdk/modules/sdk-ui/index.md @@ -17,6 +17,7 @@ title: sdk-ui - [DashboardWidgetProps](interfaces/interface.DashboardWidgetProps.md) - [DataLimits](interfaces/interface.DataLimits.md) - [DateRangeFilterTileProps](interfaces/interface.DateRangeFilterTileProps.md) +- [ExecuteQueryByWidgetIdParams](interfaces/interface.ExecuteQueryByWidgetIdParams.md) - [ExecuteQueryByWidgetIdProps](interfaces/interface.ExecuteQueryByWidgetIdProps.md) - [ExecuteQueryProps](interfaces/interface.ExecuteQueryProps.md) - [FunnelChartProps](interfaces/interface.FunnelChartProps.md) @@ -44,6 +45,8 @@ title: sdk-ui - [TableProps](interfaces/interface.TableProps.md) - [TableStyleOptions](interfaces/interface.TableStyleOptions.md) - [ThemeSettings](interfaces/interface.ThemeSettings.md) +- [TreemapChartProps](interfaces/interface.TreemapChartProps.md) +- [TreemapStyleOptions](interfaces/interface.TreemapStyleOptions.md) - [WidgetStyleOptions](interfaces/interface.WidgetStyleOptions.md) ## Type Aliases @@ -59,7 +62,9 @@ title: sdk-ui - [Color](type-aliases/type-alias.Color.md) - [ColorPaletteTheme](type-aliases/type-alias.ColorPaletteTheme.md) - [ConditionalDataColorOptions](type-aliases/type-alias.ConditionalDataColorOptions.md) +- [ContextMenuProps](type-aliases/type-alias.ContextMenuProps.md) - [Convolution](type-aliases/type-alias.Convolution.md) +- [CustomDrilldownResult](type-aliases/type-alias.CustomDrilldownResult.md) - [DataColorCondition](type-aliases/type-alias.DataColorCondition.md) - [DataColorOptions](type-aliases/type-alias.DataColorOptions.md) - [DataPoint](type-aliases/type-alias.DataPoint.md) @@ -69,9 +74,10 @@ title: sdk-ui - [DateLevel](type-aliases/type-alias.DateLevel.md) - [DayOfWeek](type-aliases/type-alias.DayOfWeek.md) - [DecimalScale](type-aliases/type-alias.DecimalScale.md) +- [DrilldownBreadcrumbsProps](type-aliases/type-alias.DrilldownBreadcrumbsProps.md) - [DrilldownOptions](type-aliases/type-alias.DrilldownOptions.md) - [DrilldownSelection](type-aliases/type-alias.DrilldownSelection.md) -- [ExecuteQueryByWidgetIdParams](type-aliases/type-alias.ExecuteQueryByWidgetIdParams.md) +- [DrilldownWidgetProps](type-aliases/type-alias.DrilldownWidgetProps.md) - [ExecuteQueryParams](type-aliases/type-alias.ExecuteQueryParams.md) - [IndicatorChartType](type-aliases/type-alias.IndicatorChartType.md) - [IndicatorComponents](type-aliases/type-alias.IndicatorComponents.md) @@ -82,6 +88,7 @@ title: sdk-ui - [LineWidth](type-aliases/type-alias.LineWidth.md) - [Markers](type-aliases/type-alias.Markers.md) - [MenuItemSection](type-aliases/type-alias.MenuItemSection.md) +- [MenuPosition](type-aliases/type-alias.MenuPosition.md) - [MonthOfYear](type-aliases/type-alias.MonthOfYear.md) - [Navigator](type-aliases/type-alias.Navigator.md) - [NumberFormatConfig](type-aliases/type-alias.NumberFormatConfig.md) @@ -115,8 +122,11 @@ title: sdk-ui - [Chart](functions/function.Chart.md) - [ChartWidget](functions/function.ChartWidget.md) - [ColumnChart](functions/function.ColumnChart.md) +- [ContextMenu](functions/function.ContextMenu.md) - [DashboardWidget](functions/function.DashboardWidget.md) - [DateRangeFilterTile](functions/function.DateRangeFilterTile.md) +- [DrilldownBreadcrumbs](functions/function.DrilldownBreadcrumbs.md) +- [DrilldownWidget](functions/function.DrilldownWidget.md) - [ExecuteQuery](functions/function.ExecuteQuery.md) - [ExecuteQueryByWidgetId](functions/function.ExecuteQueryByWidgetId.md) - [FunnelChart](functions/function.FunnelChart.md) @@ -129,5 +139,6 @@ title: sdk-ui - [SisenseContextProvider](functions/function.SisenseContextProvider.md) - [Table](functions/function.Table.md) - [ThemeProvider](functions/function.ThemeProvider.md) +- [TreemapChart](functions/function.TreemapChart.md) - [useExecuteQuery](functions/function.useExecuteQuery.md) - [useExecuteQueryByWidgetId](functions/function.useExecuteQueryByWidgetId.md) diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/index.md b/docs-md/sdk/modules/sdk-ui/interfaces/index.md index a9754f69..cdbae4c4 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/index.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/index.md @@ -15,6 +15,7 @@ title: Interfaces - [DashboardWidgetProps](interface.DashboardWidgetProps.md) - [DataLimits](interface.DataLimits.md) - [DateRangeFilterTileProps](interface.DateRangeFilterTileProps.md) +- [ExecuteQueryByWidgetIdParams](interface.ExecuteQueryByWidgetIdParams.md) - [ExecuteQueryByWidgetIdProps](interface.ExecuteQueryByWidgetIdProps.md) - [ExecuteQueryProps](interface.ExecuteQueryProps.md) - [FunnelChartProps](interface.FunnelChartProps.md) @@ -42,4 +43,6 @@ title: Interfaces - [TableProps](interface.TableProps.md) - [TableStyleOptions](interface.TableStyleOptions.md) - [ThemeSettings](interface.ThemeSettings.md) +- [TreemapChartProps](interface.TreemapChartProps.md) +- [TreemapStyleOptions](interface.TreemapStyleOptions.md) - [WidgetStyleOptions](interface.WidgetStyleOptions.md) diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.AreaStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.AreaStyleOptions.md index d1bdb8cb..3afe3282 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.AreaStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.AreaStyleOptions.md @@ -8,7 +8,7 @@ Configuration options that define functional style of the various elements of [A ## Extends -- `BaseStyleOptions` +- `BaseStyleOptions`.`BaseAxisStyleOptions` ## Properties @@ -68,7 +68,7 @@ Configuration for markers - symbols or data points that highlight specific value #### Inherited from -BaseStyleOptions.markers +BaseAxisStyleOptions.markers *** @@ -80,7 +80,7 @@ Configuration for navigator - zoom/pan tool for large datasets in a chart #### Inherited from -BaseStyleOptions.navigator +BaseAxisStyleOptions.navigator *** @@ -116,7 +116,7 @@ Configuration for X axis #### Inherited from -BaseStyleOptions.xAxis +BaseAxisStyleOptions.xAxis *** @@ -128,7 +128,7 @@ Configuration for second Y axis #### Inherited from -BaseStyleOptions.y2Axis +BaseAxisStyleOptions.y2Axis *** @@ -140,4 +140,4 @@ Configuration for Y axis #### Inherited from -BaseStyleOptions.yAxis +BaseAxisStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ChartWidgetProps.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ChartWidgetProps.md index 7fa48b8e..6d08b47f 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ChartWidgetProps.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ChartWidgetProps.md @@ -16,7 +16,7 @@ Props for the [ChartWidget](../functions/function.ChartWidget.md) component #### dataSource -> **dataSource**: `string` +> **dataSource**?: `string` Data source the query is run against - e.g. `Sample ECommerce` diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.DashboardWidgetProps.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.DashboardWidgetProps.md index ce06c077..6580bad6 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.DashboardWidgetProps.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.DashboardWidgetProps.md @@ -28,6 +28,20 @@ Omit.filters *** +#### filtersMergeStrategy + +> **filtersMergeStrategy**?: `"widgetFirst"` \| `"codeFirst"` \| `"codeOnly"` + +Strategy for merging the existing widget filters with the filters provided via the `filters` prop: + +- `widgetFirst` - prioritizes the widget filters over the provided filters in case of filter conflicts by certain attributes. +- `codeFirst` - prioritizes the provided filters over the widget filters in case of filter conflicts by certain attributes. +- `codeOnly` - applies only the provided filters and completely ignores the widget filters. + +If not specified, the default strategy is `widgetFirst`. + +*** + #### highlights > **highlights**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdParams.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdParams.md new file mode 100644 index 00000000..8b4c6713 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdParams.md @@ -0,0 +1,55 @@ +--- +title: ExecuteQueryByWidgetIdParams +--- + +# Interface ExecuteQueryByWidgetIdParams + +Parameters for [useExecuteQueryByWidgetId](../functions/function.useExecuteQueryByWidgetId.md) hook. + +## Properties + +### dashboardOid + +> **dashboardOid**: `string` + +Identifier of the dashboard that contains the widget + +*** + +### filters + +> **filters**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] + +Filters that will slice query results. + +The provided filters will be merged with the existing widget filters based on `filtersMergeStrategy` + +*** + +### filtersMergeStrategy + +> **filtersMergeStrategy**?: `"widgetFirst"` \| `"codeFirst"` \| `"codeOnly"` + +Strategy for merging the existing widget filters with the filters provided via the `filters` prop: + +- `widgetFirst` - prioritizes the widget filters over the provided filters in case of filter conflicts by certain attributes. +- `codeFirst` - prioritizes the provided filters over the widget filters in case of filter conflicts by certain attributes. +- `codeOnly` - applies only the provided filters and completely ignores the widget filters. + +If not specified, the default strategy is `widgetFirst`. + +*** + +### highlights + +> **highlights**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] + +Highlight filters that will highlight results that pass filter criteria + +*** + +### widgetOid + +> **widgetOid**: `string` + +Identifier of the widget diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdProps.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdProps.md index 3543cfd6..04f0edc3 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdProps.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ExecuteQueryByWidgetIdProps.md @@ -35,6 +35,38 @@ Identifier of the dashboard that contains the widget *** +### filters + +> **filters**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] + +Filters that will slice query results. + +The provided filters will be merged with the existing widget filters based on `filtersMergeStrategy` + +*** + +### filtersMergeStrategy + +> **filtersMergeStrategy**?: `"widgetFirst"` \| `"codeFirst"` \| `"codeOnly"` + +Strategy for merging the existing widget filters with the filters provided via the `filters` prop: + +- `widgetFirst` - prioritizes the widget filters over the provided filters in case of filter conflicts by certain attributes. +- `codeFirst` - prioritizes the provided filters over the widget filters in case of filter conflicts by certain attributes. +- `codeOnly` - applies only the provided filters and completely ignores the widget filters. + +If not specified, the default strategy is `widgetFirst`. + +*** + +### highlights + +> **highlights**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] + +Highlight filters that will highlight results that pass filter criteria + +*** + ### onDataChanged > **onDataChanged**?: (`data`, `queryParams`) => `void` diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.FunnelStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.FunnelStyleOptions.md index 72995464..3c76fbef 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.FunnelStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.FunnelStyleOptions.md @@ -84,30 +84,6 @@ BaseStyleOptions.legend *** -### markers - -> **markers**?: [`Markers`](../type-aliases/type-alias.Markers.md) - -Configuration for markers - symbols or data points that highlight specific values - -#### Inherited from - -BaseStyleOptions.markers - -*** - -### navigator - -> **navigator**?: [`Navigator`](../type-aliases/type-alias.Navigator.md) - -Configuration for navigator - zoom/pan tool for large datasets in a chart - -#### Inherited from - -BaseStyleOptions.navigator - -*** - ### subtype > **subtype**?: `undefined` @@ -129,39 +105,3 @@ Total width of the component, which is considered in the following order of prio #### Inherited from BaseStyleOptions.width - -*** - -### xAxis - -> **xAxis**?: [`AxisLabel`](../type-aliases/type-alias.AxisLabel.md) - -Configuration for X axis - -#### Inherited from - -BaseStyleOptions.xAxis - -*** - -### y2Axis - -> **y2Axis**?: [`AxisLabel`](../type-aliases/type-alias.AxisLabel.md) - -Configuration for second Y axis - -#### Inherited from - -BaseStyleOptions.y2Axis - -*** - -### yAxis - -> **yAxis**?: [`AxisLabel`](../type-aliases/type-alias.AxisLabel.md) - -Configuration for Y axis - -#### Inherited from - -BaseStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.LineStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.LineStyleOptions.md index bab1e7d4..973b44b1 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.LineStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.LineStyleOptions.md @@ -8,7 +8,7 @@ Configuration options that define functional style of the various elements of [L ## Extends -- `BaseStyleOptions` +- `BaseStyleOptions`.`BaseAxisStyleOptions` ## Properties @@ -68,7 +68,7 @@ Configuration for markers - symbols or data points that highlight specific value #### Inherited from -BaseStyleOptions.markers +BaseAxisStyleOptions.markers *** @@ -80,7 +80,7 @@ Configuration for navigator - zoom/pan tool for large datasets in a chart #### Inherited from -BaseStyleOptions.navigator +BaseAxisStyleOptions.navigator *** @@ -116,7 +116,7 @@ Configuration for X axis #### Inherited from -BaseStyleOptions.xAxis +BaseAxisStyleOptions.xAxis *** @@ -128,7 +128,7 @@ Configuration for second Y axis #### Inherited from -BaseStyleOptions.y2Axis +BaseAxisStyleOptions.y2Axis *** @@ -140,4 +140,4 @@ Configuration for Y axis #### Inherited from -BaseStyleOptions.yAxis +BaseAxisStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.PieStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.PieStyleOptions.md index 7ffa0dc5..82e486e6 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.PieStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.PieStyleOptions.md @@ -69,30 +69,6 @@ BaseStyleOptions.legend *** -### markers - -> **markers**?: [`Markers`](../type-aliases/type-alias.Markers.md) - -Configuration for markers - symbols or data points that highlight specific values - -#### Inherited from - -BaseStyleOptions.markers - -*** - -### navigator - -> **navigator**?: [`Navigator`](../type-aliases/type-alias.Navigator.md) - -Configuration for navigator - zoom/pan tool for large datasets in a chart - -#### Inherited from - -BaseStyleOptions.navigator - -*** - ### subtype > **subtype**?: [`PieSubtype`](../type-aliases/type-alias.PieSubtype.md) @@ -114,39 +90,3 @@ Total width of the component, which is considered in the following order of prio #### Inherited from BaseStyleOptions.width - -*** - -### xAxis - -> **xAxis**?: [`AxisLabel`](../type-aliases/type-alias.AxisLabel.md) - -Configuration for X axis - -#### Inherited from - -BaseStyleOptions.xAxis - -*** - -### y2Axis - -> **y2Axis**?: [`AxisLabel`](../type-aliases/type-alias.AxisLabel.md) - -Configuration for second Y axis - -#### Inherited from - -BaseStyleOptions.y2Axis - -*** - -### yAxis - -> **yAxis**?: [`AxisLabel`](../type-aliases/type-alias.AxisLabel.md) - -Configuration for Y axis - -#### Inherited from - -BaseStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.PolarStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.PolarStyleOptions.md index c7918ba2..62a53b97 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.PolarStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.PolarStyleOptions.md @@ -8,7 +8,7 @@ Configuration options that define functional style of the various elements of [P ## Extends -- `BaseStyleOptions` +- `BaseStyleOptions`.`BaseAxisStyleOptions` ## Properties @@ -60,7 +60,7 @@ Configuration for markers - symbols or data points that highlight specific value #### Inherited from -BaseStyleOptions.markers +BaseAxisStyleOptions.markers *** @@ -72,7 +72,7 @@ Configuration for navigator - zoom/pan tool for large datasets in a chart #### Inherited from -BaseStyleOptions.navigator +BaseAxisStyleOptions.navigator *** @@ -108,7 +108,7 @@ Configuration for X axis #### Inherited from -BaseStyleOptions.xAxis +BaseAxisStyleOptions.xAxis *** @@ -120,7 +120,7 @@ Configuration for second Y axis #### Inherited from -BaseStyleOptions.y2Axis +BaseAxisStyleOptions.y2Axis *** @@ -132,4 +132,4 @@ Configuration for Y axis #### Inherited from -BaseStyleOptions.yAxis +BaseAxisStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ScatterStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ScatterStyleOptions.md index d2cf7704..514c309a 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ScatterStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ScatterStyleOptions.md @@ -8,7 +8,7 @@ Configuration options that define functional style of the various elements of [S ## Extends -- `BaseStyleOptions` +- `BaseStyleOptions`.`BaseAxisStyleOptions` ## Properties @@ -66,7 +66,7 @@ Configuration for markers - symbols or data points that highlight specific value #### Inherited from -BaseStyleOptions.markers +BaseAxisStyleOptions.markers *** @@ -78,7 +78,7 @@ Configuration for navigator - zoom/pan tool for large datasets in a chart #### Inherited from -BaseStyleOptions.navigator +BaseAxisStyleOptions.navigator *** @@ -114,7 +114,7 @@ Configuration for X axis #### Inherited from -BaseStyleOptions.xAxis +BaseAxisStyleOptions.xAxis *** @@ -126,7 +126,7 @@ Configuration for second Y axis #### Inherited from -BaseStyleOptions.y2Axis +BaseAxisStyleOptions.y2Axis *** @@ -138,4 +138,4 @@ Configuration for Y axis #### Inherited from -BaseStyleOptions.yAxis +BaseAxisStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.StackableStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.StackableStyleOptions.md index ecaae1b4..73c0ef4a 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.StackableStyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.StackableStyleOptions.md @@ -8,7 +8,7 @@ Configuration options that define functional style of the various elements of st ## Extends -- `BaseStyleOptions` +- `BaseStyleOptions`.`BaseAxisStyleOptions` ## Properties @@ -60,7 +60,7 @@ Configuration for markers - symbols or data points that highlight specific value #### Inherited from -BaseStyleOptions.markers +BaseAxisStyleOptions.markers *** @@ -72,7 +72,7 @@ Configuration for navigator - zoom/pan tool for large datasets in a chart #### Inherited from -BaseStyleOptions.navigator +BaseAxisStyleOptions.navigator *** @@ -108,7 +108,7 @@ Configuration for X axis #### Inherited from -BaseStyleOptions.xAxis +BaseAxisStyleOptions.xAxis *** @@ -120,7 +120,7 @@ Configuration for second Y axis #### Inherited from -BaseStyleOptions.y2Axis +BaseAxisStyleOptions.y2Axis *** @@ -132,4 +132,4 @@ Configuration for Y axis #### Inherited from -BaseStyleOptions.yAxis +BaseAxisStyleOptions.yAxis diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.StyledColumn.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.StyledColumn.md index 99a0918e..e23a545c 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.StyledColumn.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.StyledColumn.md @@ -92,6 +92,16 @@ CategoryStyle.granularity *** +### isColored + +> **isColored**?: `boolean` + +#### Inherited from + +CategoryStyle.isColored + +*** + ### numberFormatConfig > **numberFormatConfig**?: [`NumberFormatConfig`](../type-aliases/type-alias.NumberFormatConfig.md) diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettings.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettings.md index 161229bd..bab88537 100644 --- a/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettings.md +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.ThemeSettings.md @@ -22,6 +22,12 @@ Chart theme settings > > Background color > +> ##### `chart.panelBackgroundColor` +> +> **panelBackgroundColor**?: `string` +> +> Toolbar Background color, can be used as a secondary background color +> > ##### `chart.secondaryTextColor` > > **secondaryTextColor**?: `string` diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.TreemapChartProps.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.TreemapChartProps.md new file mode 100644 index 00000000..107eca52 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.TreemapChartProps.md @@ -0,0 +1,131 @@ +--- +title: TreemapChartProps +--- + +# Interface TreemapChartProps + +Props of the [TreemapChart](../functions/function.TreemapChart.md) component. + +## Extends + +- `BaseChartProps` + +## Properties + +### Data + +#### dataSet + +> **dataSet**?: `string` \| [`Data`](../../sdk-data/interfaces/interface.Data.md) + +Data set for this chart, which supports two options: + +(1) Data source name (as a `string`) - e.g. `Sample ECommerce`. Under the hood, +the chart will have an internal [ExecuteQuery](../functions/function.ExecuteQuery.md) connect to the data source +and load the data as specified in [dataOptions](interface.TreemapChartProps.md#dataoptions), [filters](interface.TreemapChartProps.md#filters), and [highlights](interface.TreemapChartProps.md#highlights). + +OR + +(2) Explicit [Data](../../sdk-data/interfaces/interface.Data.md), which is made up of +an array of [columns](../../sdk-data/interfaces/interface.Column.md) +and a two-dimensional array of data [cells](../../sdk-data/interfaces/interface.Cell.md). +This allows the chart component to be used +with user-provided data. + +If neither option is specified, +the chart will use the `defaultDataSource` specified in the parent [SisenseContextProvider](../functions/function.SisenseContextProvider.md) component. + +##### Inherited from + +BaseChartProps.dataSet + +*** + +#### filters + +> **filters**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] + +Filters that will slice query results + +##### Inherited from + +BaseChartProps.filters + +*** + +#### highlights + +> **highlights**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] + +Highlight filters that will highlight results that pass filter criteria + +##### Inherited from + +BaseChartProps.highlights + +### Chart + +#### dataOptions + +> **dataOptions**: [`CategoricalChartDataOptions`](interface.CategoricalChartDataOptions.md) + +Configurations for how to interpret and present the data passed to the chart + +*** + +#### styleOptions + +> **styleOptions**?: [`TreemapStyleOptions`](interface.TreemapStyleOptions.md) + +Configuration that define functional style of the various chart elements + +### Callbacks + +#### onBeforeRender + +> **onBeforeRender**?: [`BeforeRenderHandler`](../type-aliases/type-alias.BeforeRenderHandler.md) + +Before render handler callback that allows adjusting +detail chart options prior to render + +This callback is not yet supported for [IndicatorChart](../functions/function.IndicatorChart.md) + +##### Inherited from + +BaseChartProps.onBeforeRender + +*** + +#### onDataPointClick + +> **onDataPointClick**?: [`DataPointEventHandler`](../type-aliases/type-alias.DataPointEventHandler.md) + +Click handler callback for a data point + +##### Inherited from + +BaseChartProps.onDataPointClick + +*** + +#### onDataPointContextMenu + +> **onDataPointContextMenu**?: [`DataPointEventHandler`](../type-aliases/type-alias.DataPointEventHandler.md) + +Context menu handler callback for a data point + +##### Inherited from + +BaseChartProps.onDataPointContextMenu + +*** + +#### onDataPointsSelected + +> **onDataPointsSelected**?: [`DataPointsEventHandler`](../type-aliases/type-alias.DataPointsEventHandler.md) + +Handler callback for selection of multiple data points + +##### Inherited from + +BaseChartProps.onDataPointsSelected diff --git a/docs-md/sdk/modules/sdk-ui/interfaces/interface.TreemapStyleOptions.md b/docs-md/sdk/modules/sdk-ui/interfaces/interface.TreemapStyleOptions.md new file mode 100644 index 00000000..cf4ab5a6 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/interfaces/interface.TreemapStyleOptions.md @@ -0,0 +1,105 @@ +--- +title: TreemapStyleOptions +--- + +# Interface TreemapStyleOptions + +Configuration options that define functional style of the various elements of [TreemapChart](../functions/function.TreemapChart.md) + +## Extends + +- `BaseStyleOptions` + +## Properties + +### dataLimits + +> **dataLimits**?: [`DataLimits`](interface.DataLimits.md) + +Data limit for series or categories that will be plotted + +#### Inherited from + +BaseStyleOptions.dataLimits + +*** + +### height + +> **height**?: `number` + +Total height of the component, which is considered in the following order of priority: + +1. Value passed to this property (in pixels). +2. Height of the container wrapping this component +3. Default value of 400px (for component without header) or 425px (for component with header). + +#### Inherited from + +BaseStyleOptions.height + +*** + +### labels + +> **labels**?: `object` + +Labels options object + +#### Type declaration + +> ##### `labels.category` +> +> **category**?: \{ +> `enabled`: `boolean`; +> }[] +> +> Array with single label options objects (order of items relative to dataOptions.category) +> +> + +*** + +### legend + +> **legend**?: [`Legend`](../type-aliases/type-alias.Legend.md) + +Configuration for legend - a key that provides information about the data series or colors used in chart + +#### Inherited from + +BaseStyleOptions.legend + +*** + +### tooltip + +> **tooltip**?: `object` + +Tooltip options object + +#### Type declaration + +> ##### `tooltip.mode` +> +> **mode**?: `"value"` \| `"contribution"` +> +> Define mode of data showing +> +> + +*** + +### width + +> **width**?: `number` + +Total width of the component, which is considered in the following order of priority: + +1. Value passed to this property (in pixels) +2. Width of the container wrapping this component +3. Default value of 400px + +#### Inherited from + +BaseStyleOptions.width 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 5e8b4d09..68172ea0 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/index.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/index.md @@ -15,7 +15,9 @@ title: Type Aliases - [Color](type-alias.Color.md) - [ColorPaletteTheme](type-alias.ColorPaletteTheme.md) - [ConditionalDataColorOptions](type-alias.ConditionalDataColorOptions.md) +- [ContextMenuProps](type-alias.ContextMenuProps.md) - [Convolution](type-alias.Convolution.md) +- [CustomDrilldownResult](type-alias.CustomDrilldownResult.md) - [DataColorCondition](type-alias.DataColorCondition.md) - [DataColorOptions](type-alias.DataColorOptions.md) - [DataPoint](type-alias.DataPoint.md) @@ -25,9 +27,10 @@ title: Type Aliases - [DateLevel](type-alias.DateLevel.md) - [DayOfWeek](type-alias.DayOfWeek.md) - [DecimalScale](type-alias.DecimalScale.md) +- [DrilldownBreadcrumbsProps](type-alias.DrilldownBreadcrumbsProps.md) - [DrilldownOptions](type-alias.DrilldownOptions.md) - [DrilldownSelection](type-alias.DrilldownSelection.md) -- [ExecuteQueryByWidgetIdParams](type-alias.ExecuteQueryByWidgetIdParams.md) +- [DrilldownWidgetProps](type-alias.DrilldownWidgetProps.md) - [ExecuteQueryParams](type-alias.ExecuteQueryParams.md) - [IndicatorChartType](type-alias.IndicatorChartType.md) - [IndicatorComponents](type-alias.IndicatorComponents.md) @@ -38,6 +41,7 @@ title: Type Aliases - [LineWidth](type-alias.LineWidth.md) - [Markers](type-alias.Markers.md) - [MenuItemSection](type-alias.MenuItemSection.md) +- [MenuPosition](type-alias.MenuPosition.md) - [MonthOfYear](type-alias.MonthOfYear.md) - [Navigator](type-alias.Navigator.md) - [NumberFormatConfig](type-alias.NumberFormatConfig.md) 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 48ad3a29..6746b473 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**: `"pie" | "funnel"` +> **CategoricalChartType**: `"pie" | "funnel" | "treemap"` Categorical family of chart types diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ContextMenuProps.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ContextMenuProps.md new file mode 100644 index 00000000..28391797 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ContextMenuProps.md @@ -0,0 +1,45 @@ +--- +title: ContextMenuProps +--- + +# Type alias ContextMenuProps + +> **ContextMenuProps**: `object` + +Props for [ContextMenu](../functions/function.ContextMenu.md) component. + +## Type declaration + +### `children` + +**children**?: `React.ReactNode` + +React nodes to be rendered at the bottom of the context menu + +*** + +### `closeContextMenu` + +**closeContextMenu**: () => `void` + +Callback function that is evaluated when context menu is closed + +#### Returns + +`void` + +*** + +### `itemSections` + +**itemSections**?: [`MenuItemSection`](type-alias.MenuItemSection.md)[] + +Sections of menu items + +*** + +### `position` + +**position**?: [`MenuPosition`](type-alias.MenuPosition.md) \| `null` + +Position of the context menu diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CustomDrilldownResult.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CustomDrilldownResult.md new file mode 100644 index 00000000..9b513935 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.CustomDrilldownResult.md @@ -0,0 +1,54 @@ +--- +title: CustomDrilldownResult +--- + +# Type alias CustomDrilldownResult + +> **CustomDrilldownResult**: `object` + +Result of custom drilldown execution + +User provides selected points and desired category to drilldown to +and receives set of filters to apply and new category to display + +## Type declaration + +### `drilldownDimension` + +**drilldownDimension**: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md) + +New dimension that should replace the current dimension + +*** + +### `drilldownFilters` + +**drilldownFilters**: `MembersFilter`[] + +The drilldown filters that should be applied to the next drilldown + +*** + +### `onContextMenu` + +**onContextMenu**: (`menuPosition`) => `void` + +Callback to open context menu + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `menuPosition` | [`MenuPosition`](type-alias.MenuPosition.md) | + +#### Returns + +`void` + +*** + +### `onDataPointsSelected` + +**onDataPointsSelected**: [`DataPointsEventHandler`](type-alias.DataPointsEventHandler.md) + +Callback to provide next points to drilldown to diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownBreadcrumbsProps.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownBreadcrumbsProps.md new file mode 100644 index 00000000..db674a8e --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownBreadcrumbsProps.md @@ -0,0 +1,53 @@ +--- +title: DrilldownBreadcrumbsProps +--- + +# Type alias DrilldownBreadcrumbsProps + +> **DrilldownBreadcrumbsProps**: `object` + +## Type declaration + +### `clearDrilldownSelections` + +**clearDrilldownSelections**: () => `void` + +Callback function that is evaluated when X button is clicked + +#### Returns + +`void` + +*** + +### `currentDimension` + +**currentDimension**: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md) + +Currently selected drilldown dimension + +*** + +### `filtersDisplayValues` + +**filtersDisplayValues**: `string`[][] + +List of drilldown filters formatted to be displayed as breadcrumbs + +*** + +### `sliceDrilldownSelections` + +**sliceDrilldownSelections**: (`i`) => `void` + +Callback function that is evaluated when a breadcrumb is clicked + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `i` | `number` | + +#### Returns + +`void` diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownOptions.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownOptions.md index 63a20eef..2870e66e 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownOptions.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownOptions.md @@ -6,14 +6,20 @@ title: DrilldownOptions > **DrilldownOptions**: `object` +Configuration for the drilldown + ## Type declaration -### `drilldownCategories` +### `drilldownDimensions` + +**drilldownDimensions**?: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md)[] -**drilldownCategories**?: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md)[] +Dimensions that can be used for drilldown *** ### `drilldownSelections` **drilldownSelections**?: [`DrilldownSelection`](type-alias.DrilldownSelection.md)[] + +Current selections for multiple drilldowns diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownSelection.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownSelection.md index a52935f9..a202fe84 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownSelection.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownSelection.md @@ -6,14 +6,20 @@ title: DrilldownSelection > **DrilldownSelection**: `object` +Selection for the drilldown + ## Type declaration -### `nextCategory` +### `nextDimension` + +**nextDimension**: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md) -**nextCategory**: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md) +Dimension to drilldown to *** ### `points` **points**: [`DataPoint`](type-alias.DataPoint.md)[] + +Points selected for drilldown diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownWidgetProps.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownWidgetProps.md new file mode 100644 index 00000000..5f41bdd2 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.DrilldownWidgetProps.md @@ -0,0 +1,84 @@ +--- +title: DrilldownWidgetProps +--- + +# Type alias DrilldownWidgetProps + +> **DrilldownWidgetProps**: `object` + +Props for the [DrilldownWidget](../functions/function.DrilldownWidget.md) component + +## Type declaration + +### `breadcrumbsComponent` + +**breadcrumbsComponent**?: (`drilldownBreadcrumbProps`) => `JSX.Element` + +React component to be rendered as breadcrumbs + +[DrilldownBreadcrumbs](../functions/function.DrilldownBreadcrumbs.md) will be used if not provided + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `drilldownBreadcrumbProps` | [`DrilldownBreadcrumbsProps`](type-alias.DrilldownBreadcrumbsProps.md) | + +#### Returns + +`JSX.Element` + +*** + +### `children` + +**children**: (`customDrilldownResult`) => `ReactNode` + +A function that allows to pass calculated drilldown filters +and new dimension to a ReactNode to be rendered (custom chart) + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `customDrilldownResult` | [`CustomDrilldownResult`](type-alias.CustomDrilldownResult.md) | + +#### Returns + +`ReactNode` + +*** + +### `contextMenuComponent` + +**contextMenuComponent**?: (`contextMenuProps`) => `JSX.Element` + +React component to be rendered as context menu + +[ContextMenu](../functions/function.ContextMenu.md) will be used if not provided + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `contextMenuProps` | [`ContextMenuProps`](type-alias.ContextMenuProps.md) | + +#### Returns + +`JSX.Element` + +*** + +### `drilldownDimensions` + +**drilldownDimensions**: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md)[] + +List of dimensions to allow drilldowns on + +*** + +### `initialDimension` + +**initialDimension**: [`Attribute`](../../sdk-data/interfaces/interface.Attribute.md) + +Initial dimension to apply first set of filters to diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryByWidgetIdParams.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryByWidgetIdParams.md deleted file mode 100644 index 01064776..00000000 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryByWidgetIdParams.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: ExecuteQueryByWidgetIdParams ---- - -# Type alias ExecuteQueryByWidgetIdParams - -> **ExecuteQueryByWidgetIdParams**: `object` - -Parameters for [useExecuteQueryByWidgetId](../functions/function.useExecuteQueryByWidgetId.md) hook. - -## Type declaration - -### `dashboardOid` - -**dashboardOid**: `string` - -Identifier of the dashboard - -*** - -### `widgetOid` - -**widgetOid**: `string` - -Identifier of the widget diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryParams.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryParams.md index 49fa1623..827fbf4d 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryParams.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.ExecuteQueryParams.md @@ -28,6 +28,16 @@ Dimensions of the query *** +### `enabled` + +**enabled**?: `boolean` + +Boolean flag to control if query is executed + +If not specified, the default value is `true` + +*** + ### `filters` **filters**?: [`Filter`](../../sdk-data/interfaces/interface.Filter.md)[] diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuItemSection.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuItemSection.md index 8a00446b..b1342662 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuItemSection.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuItemSection.md @@ -6,6 +6,9 @@ title: MenuItemSection > **MenuItemSection**: `object` +Context menu section +Used in [ContextMenu](../functions/function.ContextMenu.md) component + ## Type declaration ### `items` diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuPosition.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuPosition.md new file mode 100644 index 00000000..feb22716 --- /dev/null +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.MenuPosition.md @@ -0,0 +1,26 @@ +--- +title: MenuPosition +--- + +# Type alias MenuPosition + +> **MenuPosition**: `object` + +Context menu position coordinates +Used in [ContextMenu](../functions/function.ContextMenu.md) component + +## Type declaration + +### `left` + +**left**: `number` + +Horizontal position + +*** + +### `top` + +**top**: `number` + +Vertical position diff --git a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.StyleOptions.md b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.StyleOptions.md index eecb95fa..731956fd 100644 --- a/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.StyleOptions.md +++ b/docs-md/sdk/modules/sdk-ui/type-aliases/type-alias.StyleOptions.md @@ -4,6 +4,6 @@ title: StyleOptions # Type alias StyleOptions -> **StyleOptions**: [`LineStyleOptions`](../interfaces/interface.LineStyleOptions.md) \| [`AreaStyleOptions`](../interfaces/interface.AreaStyleOptions.md) \| [`StackableStyleOptions`](../interfaces/interface.StackableStyleOptions.md) \| [`PieStyleOptions`](../interfaces/interface.PieStyleOptions.md) \| [`FunnelStyleOptions`](../interfaces/interface.FunnelStyleOptions.md) \| [`PolarStyleOptions`](../interfaces/interface.PolarStyleOptions.md) \| [`IndicatorStyleOptions`](type-alias.IndicatorStyleOptions.md) \| [`ScatterStyleOptions`](../interfaces/interface.ScatterStyleOptions.md) +> **StyleOptions**: [`LineStyleOptions`](../interfaces/interface.LineStyleOptions.md) \| [`AreaStyleOptions`](../interfaces/interface.AreaStyleOptions.md) \| [`StackableStyleOptions`](../interfaces/interface.StackableStyleOptions.md) \| [`PieStyleOptions`](../interfaces/interface.PieStyleOptions.md) \| [`FunnelStyleOptions`](../interfaces/interface.FunnelStyleOptions.md) \| [`PolarStyleOptions`](../interfaces/interface.PolarStyleOptions.md) \| [`IndicatorStyleOptions`](type-alias.IndicatorStyleOptions.md) \| [`ScatterStyleOptions`](../interfaces/interface.ScatterStyleOptions.md) \| [`TreemapStyleOptions`](../interfaces/interface.TreemapStyleOptions.md) Configuration options that define functional style of the various elements of chart. diff --git a/e2e/tests/DrilldownBreadcrumbs.spec.tsx b/e2e/tests/DrilldownBreadcrumbs.spec.tsx new file mode 100644 index 00000000..a1e94666 --- /dev/null +++ b/e2e/tests/DrilldownBreadcrumbs.spec.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { test, expect } from '@playwright/experimental-ct-react'; +import { DrilldownBreadcrumbs } from '../../packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs'; + +test.describe('DrilldownBreadcrumbs Component', () => { + const filtersDisplayValues = [['Apple Macbooks'], ['Category'], ['Gender']]; + const currentDimension = { + name: 'AgeRange', + type: 'text-attribute', + desc: '', + __serializable: 'DimensionalElement', + expression: '[Commerce.Age Range]', + }; + + const clearDrilldownSelections = () => filtersDisplayValues.slice(0, 2); + const sliceDrilldownSelections = (i: any) => + filtersDisplayValues.filter((item) => item[0] !== item[i]); + + test('should render without errors', async ({mount}) => { + const component = await mount( + + ); + expect(component).not.toBeNull(); + }); + + test('should display first active drill', async ({mount}) => { + const component = await mount( + + ); + + const firstActiveDrill = component.getByRole('button', {name: filtersDisplayValues[0][0]}); + await expect(firstActiveDrill).toHaveText(filtersDisplayValues[0][0]); + }); + + test('should display second active drill', async ({mount}) => { + const component = await mount( + + ); + + const secondActiveDrill = component.getByRole('button', {name: filtersDisplayValues[1][0]}); + await expect(secondActiveDrill).toHaveText(filtersDisplayValues[1][0]); + }); + + test('should display third drill', async ({mount}) => { + const component = await mount( + + ); + + const thirdActiveDrill = component.getByRole('button', {name: filtersDisplayValues[2][0]}); + await expect(thirdActiveDrill).toHaveText(filtersDisplayValues[2][0]); + }); + + test('should display the current category with "(All)" being added ', async ({mount}) => { + const currentDrillText= currentDimension.expression.split('.')[1].slice(0, -1); + const component = await mount( + + ); + const currentDrill = component.locator('li').filter({ hasText: currentDrillText }) + await expect(currentDrill).toHaveText(`${currentDrillText} (All)`); + }) +}) diff --git a/media/treemap-chart-example-1.png b/media/treemap-chart-example-1.png new file mode 100644 index 00000000..315a8ae7 Binary files /dev/null and b/media/treemap-chart-example-1.png differ diff --git a/package.json b/package.json index f55017f2..275a0889 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.10.0", + "version": "0.11.0", "type": "module", "license": "SEE LICENSE IN LICENSE.md", "private": true, @@ -12,6 +12,7 @@ "dev": "yarn workspace @sisense/sdk-ui dev", "demo": "yarn workspace react-ts-demo dev", "build": "yarn workspaces foreach --no-private --verbose --topological run build", + "storybook": "yarn workspace @sisense/sdk-ui storybook", "build:prod": "yarn workspaces foreach --no-private --verbose --topological --exclude @sisense/sdk-ui-angular --exclude @sisense/sdk-ui-preact --exclude @sisense/sdk-ui-vue run build:prod", "clean": "yarn workspaces foreach run clean && rm -rf ./coverage && rm -rf ./.nyc_output", "reset": "yarn clean && rm -rf ./node_modules", diff --git a/packages/sdk-cli/package.json b/packages/sdk-cli/package.json index 30ec33a0..847891d1 100644 --- a/packages/sdk-cli/package.json +++ b/packages/sdk-cli/package.json @@ -1,7 +1,7 @@ { "name": "@sisense/sdk-cli", "description": "CLI for generating programmatic interface from Sisense data model", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -10,11 +10,11 @@ "license": "SEE LICENSE IN LICENSE.md", "bin": "./dist/index.js", "dependencies": { - "@sisense/sdk-common": "^0.10.0", - "@sisense/sdk-data": "^0.10.0", - "@sisense/sdk-modeling": "^0.10.0", - "@sisense/sdk-query-client": "^0.10.0", - "@sisense/sdk-rest-client": "^0.10.0", + "@sisense/sdk-common": "^0.11.0", + "@sisense/sdk-data": "^0.11.0", + "@sisense/sdk-modeling": "^0.11.0", + "@sisense/sdk-query-client": "^0.11.0", + "@sisense/sdk-rest-client": "^0.11.0", "cross-fetch": "^4.0.0", "inquirer": "^8.1.2", "yargs": "17.7.1" diff --git a/packages/sdk-common/package.json b/packages/sdk-common/package.json index b32ea8d2..c0825045 100644 --- a/packages/sdk-common/package.json +++ b/packages/sdk-common/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-common", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": { "types": "./dist/index.d.ts", diff --git a/packages/sdk-data/package.json b/packages/sdk-data/package.json index 05bf484b..c8e0f105 100644 --- a/packages/sdk-data/package.json +++ b/packages/sdk-data/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-data", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": { ".": "./dist/index.js", @@ -12,7 +12,7 @@ "author": "Sisense ", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-rest-client": "^0.10.0", + "@sisense/sdk-rest-client": "^0.11.0", "guid-typescript": "^1.0.9", "numeral": "^2.0.6" }, diff --git a/packages/sdk-modeling/package.json b/packages/sdk-modeling/package.json index 5190c8a2..859392ee 100644 --- a/packages/sdk-modeling/package.json +++ b/packages/sdk-modeling/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-modeling", - "version": "0.10.0", + "version": "0.11.0", "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "type": "module", @@ -9,7 +9,7 @@ "module": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "@sisense/sdk-data": "^0.10.0", + "@sisense/sdk-data": "^0.11.0", "typescript": "4.8.4" }, "scripts": { diff --git a/packages/sdk-query-client/package.json b/packages/sdk-query-client/package.json index d05028ad..5f4546c3 100644 --- a/packages/sdk-query-client/package.json +++ b/packages/sdk-query-client/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-query-client", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -9,8 +9,8 @@ "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-data": "^0.10.0", - "@sisense/sdk-rest-client": "^0.10.0", + "@sisense/sdk-data": "^0.11.0", + "@sisense/sdk-rest-client": "^0.11.0", "@sisense/task-manager": "^0.1.0", "numeral": "^2.0.6", "uuid": "^9.0.0" diff --git a/packages/sdk-rest-client/package.json b/packages/sdk-rest-client/package.json index b8cfc859..81c3e45f 100644 --- a/packages/sdk-rest-client/package.json +++ b/packages/sdk-rest-client/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-rest-client", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", diff --git a/packages/sdk-rest-client/src/http-client.ts b/packages/sdk-rest-client/src/http-client.ts index 238345b0..f9cd9dae 100644 --- a/packages/sdk-rest-client/src/http-client.ts +++ b/packages/sdk-rest-client/src/http-client.ts @@ -51,7 +51,7 @@ export class HttpClient { return this.auth.authenticate(); } - async call(url: string, config: RequestInit): Promise { + async call(url: string, config: RequestInit): Promise { if (this.auth.isAuthenticating()) { return new Promise((res) => { const retry = () => { @@ -61,7 +61,7 @@ export class HttpClient { return; } - void this.call(url, config).then((r) => res(r as T)); + void this.call(url, config).then((r) => res(r)); }; retry(); @@ -82,7 +82,7 @@ export class HttpClient { trc: this.env, }); - return fetch(trackedUrl, config).then((response) => response.json()) as T; + return fetch(trackedUrl, config); } // eslint-disable-next-line max-params @@ -103,12 +103,20 @@ export class HttpClient { ...options, }; - return this.call(this.url + endpoint, request); + const res = await this.call(this.url + endpoint, request); + return res.json() as T; } - async get(endpoint: string, request: RequestInit = {}): Promise { + async get(endpoint: string, request: RequestInit = {}): Promise { request.method = 'GET'; + const res = await this.call(this.url + endpoint, request); + return res.json() as T; + } + + async delete(endpoint: string, request: RequestInit = {}): Promise { + request.method = 'DELETE'; + return this.call(this.url + endpoint, request); } } diff --git a/packages/sdk-ui-angular/package.json b/packages/sdk-ui-angular/package.json index 461a3664..1832dfc9 100644 --- a/packages/sdk-ui-angular/package.json +++ b/packages/sdk-ui-angular/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-ui-angular", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "main": "./dist/index.d.ts", "module": "./dist/index.d.ts", diff --git a/packages/sdk-ui-preact/package.json b/packages/sdk-ui-preact/package.json index 4b10701f..39bf2aa6 100644 --- a/packages/sdk-ui-preact/package.json +++ b/packages/sdk-ui-preact/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-ui-preact", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": { ".": { @@ -14,7 +14,7 @@ "author": "Sisense", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@sisense/sdk-ui": "^0.10.0", + "@sisense/sdk-ui": "^0.11.0", "preact": "^10.13.2" }, "scripts": { diff --git a/packages/sdk-ui-vue/package.json b/packages/sdk-ui-vue/package.json index 6ba332b7..8d4fad35 100644 --- a/packages/sdk-ui-vue/package.json +++ b/packages/sdk-ui-vue/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-ui-vue", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/packages/sdk-ui/.storybook/global.css b/packages/sdk-ui/.storybook/global.css index b5c61c95..1ea7e5ef 100644 --- a/packages/sdk-ui/.storybook/global.css +++ b/packages/sdk-ui/.storybook/global.css @@ -1,3 +1,7 @@ @tailwind base; @tailwind components; @tailwind utilities; + +body { + padding: 0 !important; +} diff --git a/packages/sdk-ui/.storybook/main.ts b/packages/sdk-ui/.storybook/main.ts index 7cd613ce..f77b762a 100644 --- a/packages/sdk-ui/.storybook/main.ts +++ b/packages/sdk-ui/.storybook/main.ts @@ -1,4 +1,5 @@ import type { StorybookConfig } from '@storybook/react-vite'; +import { withoutVitePlugins } from '@storybook/builder-vite'; const config: StorybookConfig = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], @@ -12,6 +13,16 @@ const config: StorybookConfig = { name: '@storybook/react-vite', options: {}, }, + async viteFinal(config) { + // We get "Unable to preload CSS for ___" errors when trying to render a + // story from a storybook build (not in development). This seems to work + // correctly when not forcing an injection of CSS into the JS, which is + // really only needed when building sdk-ui in library mode anyway. + // + // This is inspired by https://krzysztofzuraw.com/blog/2023/storybook-vite-config/. + config.plugins = await withoutVitePlugins(config.plugins, ['vite-plugin-css-injected-by-js']); + return config; + }, }; export default config; diff --git a/packages/sdk-ui/package.json b/packages/sdk-ui/package.json index 3c27f799..b7ea6e6c 100644 --- a/packages/sdk-ui/package.json +++ b/packages/sdk-ui/package.json @@ -1,6 +1,6 @@ { "name": "@sisense/sdk-ui", - "version": "0.10.0", + "version": "0.11.0", "type": "module", "exports": "./dist/index.js", "main": "./dist/index.js", @@ -13,10 +13,10 @@ "@emotion/styled": "^11.10.5", "@mui/material": "^5.11.6", "@sisense/sdk-common": "workspace:^", - "@sisense/sdk-data": "^0.10.0", - "@sisense/sdk-query-client": "^0.10.0", - "@sisense/sdk-rest-client": "^0.10.0", - "@sisense/sisense-charts": "5.1.0-alpha-812d1e70.0", + "@sisense/sdk-data": "^0.11.0", + "@sisense/sdk-query-client": "^0.11.0", + "@sisense/sdk-rest-client": "^0.11.0", + "@sisense/sisense-charts": "5.1.0-alpha-04052758.0", "classnames": "^2.3.2", "colorjs.io": "^0.4.3", "date-fns": "^2.29.3", @@ -73,14 +73,17 @@ "@types/react": "18.2.0", "@types/react-datepicker": "^4.11.2", "@types/react-dom": "18.2.0", + "@types/react-plotly.js": "^2.6.0", "@vitejs/plugin-react-swc": "^3.3.0", "autoprefixer": "^10.4.14", "eslint": "^8.40.0", "jsdom": "^22.1.0", + "plotly.js": "^2.25.2", "postcss": "^8.4.22", "prettier": "2.8.4", "react": "18.2.0", "react-dom": "^18.2.0", + "react-plotly.js": "^2.6.0", "sass": "1.58.3", "storybook": "7.0.24", "tailwindcss": "^3.3.1", diff --git a/packages/sdk-ui/src/__demo__/app.tsx b/packages/sdk-ui/src/__demo__/app.tsx index 6eb6706d..7c12014b 100644 --- a/packages/sdk-ui/src/__demo__/app.tsx +++ b/packages/sdk-ui/src/__demo__/app.tsx @@ -1,13 +1,19 @@ +/* eslint-disable complexity */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ import { Alert, Tab, Tabs } from '@mui/material'; import { Box } from '@mui/system'; -import { ComponentType, Suspense, useEffect, useState } from 'react'; +import { ComponentType, Suspense, useState } from 'react'; import { SisenseContextProvider } from '../components/sisense-context/sisense-context-provider'; -import { SisenseContextProviderProps } from '../props'; import { loadAdditionalPages } from './load-additional-pages'; import { ChartsFromExampleApp } from './pages/charts-from-example-app'; import { ECommerceDemo } from './pages/ecommerce-demo'; import { MiscDemo } from './pages/misc-demo'; import { WidgetDemo } from './pages/widget-demo'; +import { NumberFormating } from './pages/NumberFormating'; +import { DrilldownWidgetDemo } from './pages/drilldown-widget-demo'; // This page is meant to enable faster iterations during development than // using react-ts-demo or other demo apps that require a built sdk-ui @@ -16,32 +22,45 @@ import { WidgetDemo } from './pages/widget-demo'; // if this becomes popular const pages: ComponentType[] = [ WidgetDemo, + NumberFormating, ECommerceDemo, ChartsFromExampleApp, MiscDemo, + DrilldownWidgetDemo, ...loadAdditionalPages(), ]; -const { VITE_APP_SISENSE_URL, VITE_APP_SISENSE_TOKEN } = import.meta.env; +const { + VITE_APP_SISENSE_URL, + VITE_APP_SISENSE_TOKEN, + VITE_APP_SISENSE_WAT, + VITE_APP_SISENSE_SSO_ENABLED, +} = import.meta.env; -const selectedTabIndexKey = 'selectedTabIndex'; - -export function App() { - const [selectedTabIndex, setSelectedTabIndex] = useState( - Math.min(Number(sessionStorage.getItem(selectedTabIndexKey)) || 0, pages.length - 1), - ); - - const shouldShowAlert = !VITE_APP_SISENSE_URL || !VITE_APP_SISENSE_TOKEN; - - const sisenseContextProps: SisenseContextProviderProps = { - url: VITE_APP_SISENSE_URL ?? '', - token: VITE_APP_SISENSE_TOKEN, +const sisenseContextProviderProps = () => { + const baseOptions = { + url: VITE_APP_SISENSE_URL || '', defaultDataSource: 'Sample ECommerce', }; + const wat = VITE_APP_SISENSE_WAT; + const token = VITE_APP_SISENSE_TOKEN; + const ssoEnabled = VITE_APP_SISENSE_SSO_ENABLED; + + if (ssoEnabled) { + return { ...baseOptions, ssoEnabled: ssoEnabled?.toLowercase() === 'true' }; + } else if (wat) { + return { ...baseOptions, wat }; + } else if (token) { + return { ...baseOptions, token }; + } else { + return baseOptions; + } +}; + +export function App() { + const [selectedTabIndex, setSelectedTabIndex] = useState(0); - useEffect(() => { - sessionStorage.setItem(selectedTabIndexKey, selectedTabIndex.toString()); - }, [selectedTabIndex]); + const shouldShowAlert = !VITE_APP_SISENSE_URL; return ( Loading...}> @@ -51,7 +70,7 @@ export function App() { .env.local file. )} - + - , + , ); diff --git a/packages/sdk-ui/src/__demo__/pages/NumberFormating.tsx b/packages/sdk-ui/src/__demo__/pages/NumberFormating.tsx new file mode 100644 index 00000000..90acd116 --- /dev/null +++ b/packages/sdk-ui/src/__demo__/pages/NumberFormating.tsx @@ -0,0 +1,115 @@ +import { Filter, filters as filtersFactory, measures as measureFactory } from '@sisense/sdk-data'; +import { ChartWidget } from '../../widgets/chart-widget'; +import * as DM from '../sample-ecommerce'; +import { defaultConfig } from '../../chart-options-processor/translations/number-format-config'; +import { CartesianChartDataOptions, NumberFormatConfig } from '../../types'; +import { TableWidget } from '../../widgets/table-widget'; +import { getIndicatorStyleOptions } from './ecommerce-demo'; + +const format1: NumberFormatConfig = { ...defaultConfig, name: 'Currency', decimalScale: 2 }; +const format2: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + decimalScale: 2, + symbol: '@', +}; +const format3: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + kilo: false, + decimalScale: 2, + symbol: '#', +}; +const format4: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + decimalScale: 2, + symbol: '!', +}; +const format5: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + decimalScale: 2, + symbol: '^', +}; + +const dataOptions: CartesianChartDataOptions = { + category: [ + { column: DM.Category.CategoryID, numberFormatConfig: format1 }, + { column: DM.Commerce.CountryID, numberFormatConfig: format2 }, + ], + value: [ + { + column: measureFactory.sum(DM.Commerce.Revenue, 'Revenue'), + numberFormatConfig: format3, + }, + ], + breakBy: [{ column: DM.Commerce.BrandID, numberFormatConfig: format4 }], +}; + +const filters: Filter[] = [ + filtersFactory.members(DM.Commerce.BrandID, ['1', '2']), + filtersFactory.members(DM.Commerce.CountryID, ['1', '2']), +]; + +export const NumberFormating = () => ( +
+ Number Formatting + + + + + +
+); diff --git a/packages/sdk-ui/src/__demo__/pages/dashboard-widget-demo.tsx b/packages/sdk-ui/src/__demo__/pages/dashboard-widget-demo.tsx index 74d610b0..78826b5a 100644 --- a/packages/sdk-ui/src/__demo__/pages/dashboard-widget-demo.tsx +++ b/packages/sdk-ui/src/__demo__/pages/dashboard-widget-demo.tsx @@ -9,7 +9,7 @@ const dashboardOid = '642314fe48cbdd002900ccca'; const filters: Filter[] = []; const drilldownOptions = { - drilldownCategories: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], + drilldownDimensions: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], }; export const DashboardWidgetDemo = () => ( diff --git a/packages/sdk-ui/src/__demo__/pages/drilldown-widget-demo.tsx b/packages/sdk-ui/src/__demo__/pages/drilldown-widget-demo.tsx new file mode 100644 index 00000000..985140c3 --- /dev/null +++ b/packages/sdk-ui/src/__demo__/pages/drilldown-widget-demo.tsx @@ -0,0 +1,86 @@ +/* eslint-disable max-lines-per-function */ +import { measures as measureFactory } from '@sisense/sdk-data'; +import * as DM from '../sample-ecommerce-autogenerated'; +import { DrilldownWidget } from '../../widgets/drilldown-widget'; +import { ExecuteQuery } from '../../components/query-execution/execute-query'; +import { DataPoint } from '../../types'; +import { Chart } from '../../components/chart'; +import { PlotlyDotChart } from './plotly-dot-chart'; + +const dataOptions = { + category: [DM.Category.Category], + value: [measureFactory.sum(DM.Commerce.Revenue)], + breakBy: [], +}; + +export const DrilldownWidgetDemo = () => ( +
+
+
+ With native charting library (Compose SDK) +

Right click on a bar to see the context menu or rubberband select multiple bars

+ + {({ drilldownFilters, drilldownDimension, onDataPointsSelected, onContextMenu }) => { + const onPointsSelected = (points: DataPoint[], nativeEvent: MouseEvent) => { + onDataPointsSelected(points, nativeEvent); + onContextMenu({ + left: nativeEvent.clientX, + top: nativeEvent.clientY, + }); + }; + + const onPointClick = (point: DataPoint, event: MouseEvent) => { + onDataPointsSelected([point], event); + onContextMenu({ + left: event.clientX, + top: event.clientY, + }); + }; + + return ( + + ); + }} + +
+
+
+ With third-party charting library (Plotly) +

Select points with left click, then right click to see the context menu

+ + {({ drilldownFilters, drilldownDimension, onDataPointsSelected, onContextMenu }) => ( + + {(data) => ( + + )} + + )} + +
+
+
+); diff --git a/packages/sdk-ui/src/__demo__/pages/ecommerce-demo.tsx b/packages/sdk-ui/src/__demo__/pages/ecommerce-demo.tsx index 1dc74466..97eaa896 100644 --- a/packages/sdk-ui/src/__demo__/pages/ecommerce-demo.tsx +++ b/packages/sdk-ui/src/__demo__/pages/ecommerce-demo.tsx @@ -20,7 +20,10 @@ const seriesToColorMap = { Unspecified: '#6eda55', }; -const getIndicatorStyleOptions = (title: string, secondaryTitle = ''): IndicatorStyleOptions => { +export const getIndicatorStyleOptions = ( + title: string, + secondaryTitle = '', +): IndicatorStyleOptions => { return { indicatorComponents: { title: { diff --git a/packages/sdk-ui/src/__demo__/pages/misc-demo.tsx b/packages/sdk-ui/src/__demo__/pages/misc-demo.tsx index 4ec0d66f..a122b0cc 100644 --- a/packages/sdk-ui/src/__demo__/pages/misc-demo.tsx +++ b/packages/sdk-ui/src/__demo__/pages/misc-demo.tsx @@ -181,6 +181,7 @@ export const MiscDemo = () => { backgroundColor: '#333333', textColor: 'orange', secondaryTextColor: 'purple', + panelBackgroundColor: '#F6F6F6', }, typography: { fontFamily: 'impact', diff --git a/packages/sdk-ui/src/__demo__/pages/plotly-dot-chart.tsx b/packages/sdk-ui/src/__demo__/pages/plotly-dot-chart.tsx new file mode 100644 index 00000000..52ce6c26 --- /dev/null +++ b/packages/sdk-ui/src/__demo__/pages/plotly-dot-chart.tsx @@ -0,0 +1,117 @@ +import React, { useEffect, useState } from 'react'; +import Plot from 'react-plotly.js'; +import { QueryResultData } from '@sisense/sdk-data'; +import { Datum } from 'plotly.js'; +import { DataPointsEventHandler } from '../../props'; +import { MenuPosition } from '../../types'; + +type Props = { + rawData: QueryResultData; + onDataPointsSelected: DataPointsEventHandler; + onContextMenu: (menuPosition: MenuPosition) => void; +}; + +const generateTrace = ( + data: { [key: string]: Datum }[], + name: string, + markerColor: string, +): Partial => ({ + type: 'scatter', + x: data.map((d) => d.revenue), + y: data.map((d) => d.category), + mode: 'markers', + name: name, + marker: { + color: markerColor, + line: { + width: 1, + }, + symbol: 'circle', + size: 16, + }, +}); + +export const PlotlyDotChart: React.FC = ({ + rawData, + onDataPointsSelected: onSelected, + onContextMenu, +}) => { + const [selectedColumns, setSelectedColumns] = useState([]); + + useEffect(() => { + const filteredCountries = selectedColumns.filter((category) => + rawData.rows.some((row) => row[0].data === category), + ); + + if (filteredCountries.length !== selectedColumns.length) { + setSelectedColumns(filteredCountries); + } + }, [selectedColumns, rawData]); + + const data = rawData.rows.map(([category, revenue]) => ({ + category: category.data as string, + revenue: revenue.data as string | number, + })); + + const getColorForCountry = (category: string) => { + return selectedColumns.includes(category) ? 'orange' : 'lightgreen'; + }; + + const trace = generateTrace(data, 'Revenue', 'lightgreen'); + + const coloredTrace = { + ...trace, + marker: { + ...trace.marker, + color: data.map((d) => getColorForCountry(d.category)), + }, + }; + + const layout = { + title: `Revenue by ${rawData.columns[0].name}`, + // ... (other layout properties as needed) + }; + + const handlePlotClick = (eventData: Plotly.PlotMouseEvent) => { + const clickedIndex = eventData.points[0].pointNumber; + const selectedCountry = data[clickedIndex].category; + const newselectedColumns = selectedColumns.includes(selectedCountry) + ? selectedColumns.filter((country) => country !== selectedCountry) + : [...selectedColumns, selectedCountry]; + + setSelectedColumns(newselectedColumns); + + onSelected( + newselectedColumns.map((category) => ({ + value: undefined, + categoryValue: category, + categoryDisplayValue: category, + seriesValue: undefined, + })), + eventData.event, + ); + }; + + useEffect(() => { + const handleContextMenu = (event: MouseEvent) => { + if (!selectedColumns.length) return; + event.preventDefault(); + onContextMenu({ left: event.clientX, top: event.clientY }); + }; + + document.addEventListener('contextmenu', handleContextMenu); + + return () => { + document.removeEventListener('contextmenu', handleContextMenu); + }; + }, [selectedColumns, onSelected, onContextMenu]); + + return ( + + ); +}; diff --git a/packages/sdk-ui/src/__demo__/pages/widget-demo.tsx b/packages/sdk-ui/src/__demo__/pages/widget-demo.tsx index 17c2c75d..caf97a07 100644 --- a/packages/sdk-ui/src/__demo__/pages/widget-demo.tsx +++ b/packages/sdk-ui/src/__demo__/pages/widget-demo.tsx @@ -12,14 +12,13 @@ const styleOptions = {}; const filters: Filter[] = []; const drilldownOptions = { - drilldownCategories: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], + drilldownDimensions: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], }; export const WidgetDemo = () => (
With Drilldown ( /> No Drilldown { const mockData: DataTable = { @@ -27,7 +28,7 @@ describe('Scatter Chart Data', () => { displayValue: 'S2', }, { - displayValue: '34', + displayValue: '34.001234', }, ], ], @@ -88,7 +89,7 @@ describe('Scatter Chart Data', () => { it('should correct fill break by / point', () => { const dataOptions = { - breakByPoint: { name: 'col_1' }, + breakByPoint: { name: 'col_1', type: 'string' }, } as ScatterChartDataOptionsInternal; const groupedData = groupData(dataOptions, mockData); @@ -108,7 +109,7 @@ describe('Scatter Chart Data', () => { const dataOptions = { x: { name: 'col_1' }, y: { name: 'col_2' }, - breakByPoint: { name: 'col_3' }, + breakByPoint: { name: 'col_3', type: 'string' }, } as ScatterChartDataOptionsInternal; const groupedData = groupData(dataOptions, mockData); @@ -124,9 +125,39 @@ describe('Scatter Chart Data', () => { expect(groupedData).toMatchObject(expected); }); + it('should correct fill x-axis, y-axis, point with numeric break by', () => { + const dataOptions = { + x: { name: 'col_1' }, + y: { name: 'col_2' }, + breakByPoint: { + name: 'col_5', + type: 'number', + numberFormatConfig: { ...defaultConfig, decimalScale: 1 }, + }, + breakByColor: { + name: 'col_5', + type: 'number', + numberFormatConfig: { ...defaultConfig, decimalScale: 2 }, + }, + } as ScatterChartDataOptionsInternal; + + const groupedData = groupData(dataOptions, mockData); + + const expected = [ + { + xAxis: { displayValue: '7' }, + yAxis: { displayValue: '14' }, + breakByPoint: { displayValue: '34.0' }, + breakByColor: { displayValue: '34.00' }, + }, + ]; + + expect(groupedData).toMatchObject(expected); + }); + it('should correct fill break by / color', () => { const dataOptions = { - breakByColor: { name: 'col_1' }, + breakByColor: { name: 'col_1', type: 'string' }, } as ScatterChartDataOptionsInternal; const groupedData = groupData(dataOptions, mockData); @@ -146,7 +177,7 @@ describe('Scatter Chart Data', () => { const dataOptions = { x: { name: 'col_1' }, y: { name: 'col_2' }, - breakByColor: { name: 'col_3' }, + breakByColor: { name: 'col_3', type: 'string' }, } as ScatterChartDataOptionsInternal; const groupedData = groupData(dataOptions, mockData); @@ -173,7 +204,7 @@ describe('Scatter Chart Data', () => { { xAxis: defaultScatterDataValue, yAxis: defaultScatterDataValue, - size: { displayValue: '34' }, + size: { displayValue: '34.001234' }, }, ]; @@ -184,7 +215,7 @@ describe('Scatter Chart Data', () => { const dataOptions = { x: { name: 'col_1' }, y: { name: 'col_2' }, - breakByPoint: { name: 'col_3' }, + breakByPoint: { name: 'col_3', type: 'string' }, size: { name: 'col_5' }, } as ScatterChartDataOptionsInternal; @@ -195,7 +226,7 @@ describe('Scatter Chart Data', () => { xAxis: { displayValue: '7' }, yAxis: { displayValue: '14' }, breakByPoint: { displayValue: 'S1' }, - size: { displayValue: '34' }, + size: { displayValue: '34.001234' }, }, ]; diff --git a/packages/sdk-ui/src/chart-data/scatter-data.ts b/packages/sdk-ui/src/chart-data/scatter-data.ts index af9d3771..10b218fa 100644 --- a/packages/sdk-ui/src/chart-data/scatter-data.ts +++ b/packages/sdk-ui/src/chart-data/scatter-data.ts @@ -12,6 +12,8 @@ import { Value, isCategory, } from '../chart-data-options/types'; +import { isNumber } from '@sisense/sdk-data'; +import { applyFormatPlainText } from '../chart-options-processor/translations/number-format-config'; export const defaultScatterDataValue: ComparableData = { displayValue: '0' }; @@ -96,13 +98,42 @@ export const groupData = ( dataTable: DataTable, ): ScatterDataTable => { const indexes = defineIndexes(chartDataOptions, dataTable); - return dataTable.rows.map((row) => ({ - xAxis: defineValue(indexes.x, row), - yAxis: defineValue(indexes.y, row), - breakByPoint: row[indexes.breakByPoint], - breakByColor: row[indexes.breakByColor], - size: row[indexes.size], - })); + const pointNumFormatConfig = + chartDataOptions?.breakByPoint && isNumber(chartDataOptions.breakByPoint.type) + ? chartDataOptions.breakByPoint?.numberFormatConfig + : undefined; + const colorNumFormatConfig = + chartDataOptions?.breakByColor && + (!isCategory(chartDataOptions.breakByColor) || isNumber(chartDataOptions.breakByColor.type)) + ? chartDataOptions.breakByColor?.numberFormatConfig + : undefined; + + return dataTable.rows.map((row) => { + const byPointData = { ...row[indexes.breakByPoint] }; + if (pointNumFormatConfig) + byPointData.displayValue = applyFormatPlainText( + pointNumFormatConfig, + byPointData.compareValue + ? (byPointData.compareValue.value as number) + : parseFloat(byPointData.displayValue), + ); + const byColorData = { ...row[indexes.breakByColor] }; + if (colorNumFormatConfig) + byColorData.displayValue = applyFormatPlainText( + colorNumFormatConfig, + byColorData.compareValue + ? (byColorData.compareValue.value as number) + : parseFloat(byColorData.displayValue), + ); + + return { + xAxis: defineValue(indexes.x, row), + yAxis: defineValue(indexes.y, row), + breakByPoint: byPointData, + breakByColor: byColorData, + size: row[indexes.size], + }; + }); }; /** diff --git a/packages/sdk-ui/src/chart-data/types.ts b/packages/sdk-ui/src/chart-data/types.ts index 1ce19b60..15fec9b9 100644 --- a/packages/sdk-ui/src/chart-data/types.ts +++ b/packages/sdk-ui/src/chart-data/types.ts @@ -17,6 +17,7 @@ export type SeriesValueData = { xValue?: (string | number)[]; xDisplayValue?: string[]; xCompareValue?: (string | number)[]; + parent?: string; }; export type CategoricalSeriesValues = { name: string; diff --git a/packages/sdk-ui/src/chart-options-processor/cartesian-chart-options.ts b/packages/sdk-ui/src/chart-options-processor/cartesian-chart-options.ts index e2d082c5..cd362717 100644 --- a/packages/sdk-ui/src/chart-options-processor/cartesian-chart-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/cartesian-chart-options.ts @@ -32,7 +32,7 @@ import { getColorSetting, formatSeriesContinuousXAxis, } from './translations/translations-to-highcharts'; -import { getTooltipSettings } from './tooltip'; +import { getTooltipSettings } from './translations/tooltip'; import merge from 'deepmerge'; import { chartOptionsDefaults } from './defaults/cartesian'; import { onlyY } from '../chart-data/utils'; diff --git a/packages/sdk-ui/src/chart-options-processor/category-chart-options.ts b/packages/sdk-ui/src/chart-options-processor/category-chart-options.ts index 555e8019..cae10248 100644 --- a/packages/sdk-ui/src/chart-options-processor/category-chart-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/category-chart-options.ts @@ -4,7 +4,11 @@ import type { SeriesPieOptions } from '@sisense/sisense-charts'; import { ChartDesignOptions } from './translations/types'; import { getLegendSettings } from './translations/legend-section'; -import { PieChartDesignOptions, FunnelChartDesignOptions } from './translations/design-options'; +import { + PieChartDesignOptions, + FunnelChartDesignOptions, + TreemapChartDesignOptions, +} from './translations/design-options'; import { determineHighchartsChartType } from './translations/translations-to-highcharts'; import { getTooltipSettings } from './tooltip'; import { getPiePlotOptions } from './translations/pie-plot-options'; @@ -18,6 +22,7 @@ import { ChartDataOptionsInternal, CategoricalChartDataOptionsInternal, } from '../chart-data-options/types'; +import { prepareTreemapOptions } from './translations/treemap/treemap-options'; /** * Convert intermediate chart data, data options, and design options @@ -115,6 +120,16 @@ export const getCategoricalChartOptions = ( tooltip: getTooltipSettings(funnelDesignOptions.funnelLabels?.showDecimals, dataOptions), }; return { options: funnelOptions, alerts }; + case 'treemap': + return { + options: prepareTreemapOptions( + chartData, + dataOptions as CategoricalChartDataOptionsInternal, + chartDesignOptions as TreemapChartDesignOptions, + themeSettings, + ), + alerts, + }; default: throw new Error('Unexpected chart type'); } 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 dd8eb808..8bae5065 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 @@ -339,7 +339,7 @@ it('for cartesian data, limit series to 50 and categories to 100', () => { }, TestChartDataOptions, ); - expect(chartOptions?.xAxis[0].categories?.length).toBe(100); + expect(chartOptions?.xAxis?.[0].categories?.length).toBe(100); expect(chartOptions?.series.length).toBe(50); }); @@ -653,9 +653,9 @@ describe('cartesianData', () => { ); // x-axis values are formatted when the chart is rendered, // for the test we check that the formatter method is properly defined - const formatterNoFormat = chartOptionsNoFormat.xAxis[0].labels?.formatter; + const formatterNoFormat = chartOptionsNoFormat.xAxis?.[0].labels?.formatter; expect( - chartOptionsNoFormat.xAxis[0].categories?.map((value) => { + chartOptionsNoFormat.xAxis?.[0].categories?.map((value) => { if (!formatterNoFormat) return 'no formatter defined'; const point = { @@ -665,7 +665,7 @@ describe('cartesianData', () => { return point.formatter.call({ value, - axis: { categories: chartOptionsNoFormat.xAxis[0].categories || [] }, + axis: { categories: chartOptionsNoFormat.xAxis?.[0].categories || [] }, }); }), ).toEqual(['15', '20', '25']); @@ -690,9 +690,9 @@ describe('cartesianData', () => { ); // x-axis values are formatted when the chart is rendered, // for the test we check that the formatter method is properly defined - const formatter = chartOptions.xAxis[0].labels?.formatter; + const formatter = chartOptions.xAxis?.[0].labels?.formatter; expect( - chartOptions.xAxis[0].categories?.map((value) => { + chartOptions.xAxis?.[0].categories?.map((value) => { if (!formatter) return 'no formatter defined'; const point = { @@ -702,7 +702,7 @@ describe('cartesianData', () => { return point.formatter.call({ value, - axis: { categories: chartOptionsNoFormat.xAxis[0].categories || [] }, + axis: { categories: chartOptionsNoFormat.xAxis?.[0].categories || [] }, }); }), ).toEqual(['15.0', '20.0', '25.0']); @@ -759,7 +759,7 @@ describe('cartesianData', () => { TestChartDataOptions, ); - expect(chartOptions.xAxis[0].categories).toEqual(['Pies', 'Wine', 'Pasta']); + expect(chartOptions.xAxis?.[0].categories).toEqual(['Pies', 'Wine', 'Pasta']); expect(chartOptions.series[0].data).toMatchObject([ { selected: false }, { selected: true, marker: { enabled: false } }, @@ -803,7 +803,7 @@ describe('cartesianData', () => { expect(chartData.series).toHaveLength(2); expect(chartData.xValues.map((x) => x.key)).toHaveLength(3); expect(chartOptions.series).toHaveLength(1); - expect(chartOptions.xAxis[0].categories ?? []).toHaveLength(2); + expect(chartOptions.xAxis?.[0].categories ?? []).toHaveLength(2); }); }); diff --git a/packages/sdk-ui/src/chart-options-processor/chart-options-service.ts b/packages/sdk-ui/src/chart-options-processor/chart-options-service.ts index 98f3e859..92a8ef8c 100644 --- a/packages/sdk-ui/src/chart-options-processor/chart-options-service.ts +++ b/packages/sdk-ui/src/chart-options-processor/chart-options-service.ts @@ -192,9 +192,9 @@ export type HighchartsOptionsInternal = { text: string | null; }; series: SeriesType[]; - xAxis: AxisSettings[]; + xAxis?: AxisSettings[]; yAxis?: AxisSettings[]; - legend: LegendSettings; + legend?: LegendSettings; plotOptions?: PlotOptions; navigator?: Navigator | { enabled: boolean }; tooltip?: TooltipSettings; diff --git a/packages/sdk-ui/src/chart-options-processor/scatter-chart-options.test.ts b/packages/sdk-ui/src/chart-options-processor/scatter-chart-options.test.ts index 98fa0f64..925358c0 100644 --- a/packages/sdk-ui/src/chart-options-processor/scatter-chart-options.test.ts +++ b/packages/sdk-ui/src/chart-options-processor/scatter-chart-options.test.ts @@ -132,7 +132,7 @@ describe('getScatterChartOptions', () => { it('should apply data limits to axes', () => { expect(chartData.xCategories?.length).toBeGreaterThan(customCategoriesCapacity); expect(chartData.yCategories?.length).toBeGreaterThan(customCategoriesCapacity); - expect(options.xAxis[0].categories).toHaveLength(customCategoriesCapacity); + expect(options.xAxis![0].categories).toHaveLength(customCategoriesCapacity); expect(options.yAxis![0].categories).toHaveLength(customCategoriesCapacity); }); diff --git a/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-style-to-design-options.ts b/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-style-to-design-options.ts index d5388241..96fb8f0a 100644 --- a/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-style-to-design-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-style-to-design-options.ts @@ -11,6 +11,7 @@ import { IndicatorStyleOptions, ScatterStyleOptions, AreaStyleOptions, + TreemapStyleOptions, } from '../../types'; import { ChartDesignOptions } from '../translations/types'; import { chartSubtypeToDesignOptions } from '../subtype-to-design-options'; @@ -24,6 +25,7 @@ import { getPolarChartDesignOptions, getScatterChartDesignOptions, getAreaChartDesignOptions, + getTreemapChartDesignOptions, } from './translate-to-highcharts-options'; export const translateStyleOptionsToDesignOptions = ( @@ -63,6 +65,9 @@ export const translateStyleOptionsToDesignOptions = ( case 'funnel': intermediateDesignOptions = getFunnelChartDesignOptions(styleOptions as FunnelStyleOptions); break; + case 'treemap': + intermediateDesignOptions = getTreemapChartDesignOptions(styleOptions as TreemapStyleOptions); + break; case 'polar': intermediateDesignOptions = getPolarChartDesignOptions(styleOptions as PolarStyleOptions); break; diff --git a/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-to-highcharts-options.ts b/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-to-highcharts-options.ts index c54ec027..c62c1810 100644 --- a/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-to-highcharts-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/style-to-design-options-translator/translate-to-highcharts-options.ts @@ -16,6 +16,7 @@ import { FunnelStyleOptions, ScatterStyleOptions, BaseStyleOptions, + TreemapStyleOptions, } from '../../types'; import { Axis } from '../translations/axis-section'; import { @@ -33,6 +34,7 @@ import { PolarType, ScatterChartDesignOptions, AreaChartDesignOptions, + TreemapChartDesignOptions, } from '../translations/design-options'; import { LegendPosition } from '../translations/legend-section'; import { Marker } from '../translations/marker-section'; @@ -307,6 +309,12 @@ export const getFunnelChartDesignOptions = ( }; }; +export const getTreemapChartDesignOptions = ( + styleOptions: TreemapStyleOptions, +): TreemapChartDesignOptions => { + return styleOptions as TreemapChartDesignOptions; +}; + const DefaultPolarType: PolarType = 'column'; export const getPolarChartDesignOptions = ( styleOptions: PolarStyleOptions, diff --git a/packages/sdk-ui/src/chart-options-processor/subtype-to-design-options.ts b/packages/sdk-ui/src/chart-options-processor/subtype-to-design-options.ts index 5feb7893..99c1b61c 100644 --- a/packages/sdk-ui/src/chart-options-processor/subtype-to-design-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/subtype-to-design-options.ts @@ -98,13 +98,24 @@ export type PolarSubtype = 'polar/column' | 'polar/area' | 'polar/line'; */ export type IndicatorSubtype = 'indicator/numeric' | 'indicator/gauge'; +/** + * + * Subtype of {@link TreemapChart} + * + * **Values** + * + * - `treemap` - default treemap. + */ +export type TreemapSubtype = 'treemap'; + export type ChartSubtype = | LineSubtype | AreaSubtype | StackableSubtype | PieSubtype | PolarSubtype - | IndicatorSubtype; + | IndicatorSubtype + | TreemapSubtype; export const chartSubtypeToDesignOptions = Object.freeze< Record< @@ -140,4 +151,5 @@ export const chartSubtypeToDesignOptions = Object.freeze< 'polar/line': { polarType: 'line' }, 'indicator/numeric': { indicatorType: 'numeric' }, 'indicator/gauge': { indicatorType: 'gauge' }, + treemap: {}, }); diff --git a/packages/sdk-ui/src/chart-options-processor/theme-option-service.ts b/packages/sdk-ui/src/chart-options-processor/theme-option-service.ts index ebb272a9..023d1234 100644 --- a/packages/sdk-ui/src/chart-options-processor/theme-option-service.ts +++ b/packages/sdk-ui/src/chart-options-processor/theme-option-service.ts @@ -5,12 +5,14 @@ import merge from 'ts-deepmerge'; import { CompleteThemeSettings } from '../types'; import { HighchartsOptionsInternal } from './chart-options-service'; import cloneDeep from 'lodash/cloneDeep'; +import { LegendSettings } from './translations/legend-section'; const DEFAULT_THEME_SETTINGS: CompleteThemeSettings = { chart: { backgroundColor: '#FFFFFF', textColor: '#000000', secondaryTextColor: '#E4E4E4', + panelBackgroundColor: '#F6F6F6', }, typography: { fontFamily: '"Open Sans","Roboto","Helvetica","Arial",sans-serif', @@ -66,7 +68,7 @@ export const applyThemeToChart = ( color: themeSettings.chart.textColor, fontFamily: themeSettings.typography.fontFamily, }, - }; + } as LegendSettings; const seriesDataLabelsStyle = { style: { @@ -137,7 +139,7 @@ export const applyThemeToChart = ( const mergedOptions = merge(chartOptions, basicOptions); - mergedOptions.xAxis = mergedOptions.xAxis.map((axis) => { + mergedOptions.xAxis = mergedOptions.xAxis?.map((axis) => { axis.plotBands = axis.plotBands?.map((plotBand) => { return merge(plotBand, plotBandOptions); }); diff --git a/packages/sdk-ui/src/chart-options-processor/tooltip.ts b/packages/sdk-ui/src/chart-options-processor/tooltip.ts index 3c20462f..78c42546 100644 --- a/packages/sdk-ui/src/chart-options-processor/tooltip.ts +++ b/packages/sdk-ui/src/chart-options-processor/tooltip.ts @@ -6,19 +6,14 @@ import { } from '../chart-data-options/types'; import { colorChineseSilver, colorWhite } from './chart-options-service'; import { applyFormat, defaultConfig } from './translations/number-format-config'; +import { TooltipOptions } from '@sisense/sisense-charts'; -export type TooltipSettings = { - enabled?: boolean; - animation?: boolean; - backgroundColor?: string; - borderColor?: string; - borderRadius?: number; - borderWidth?: number; - useHTML?: boolean; - formatter?: () => string; - style?: { - fontFamily?: string; - }; +export type TooltipSettings = TooltipOptions; + +export type InternalSeriesNode = { + val: number; + name: string; + parentNode?: InternalSeriesNode; }; export type InternalSeries = { @@ -29,8 +24,10 @@ export type InternalSeries = { name: string; color: string; custom?: { number1?: number; string1?: string; xDisplayValue?: string }; + node?: InternalSeriesNode; }; percentage?: number; + color?: string; }; export const getTooltipSettings = ( diff --git a/packages/sdk-ui/src/chart-options-processor/translations/__snapshots__/scatter-tooltip.test.ts.snap b/packages/sdk-ui/src/chart-options-processor/translations/__snapshots__/scatter-tooltip.test.ts.snap new file mode 100644 index 00000000..d41e9fed --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/__snapshots__/scatter-tooltip.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Format numbers when x-axis, y-axis, break by / point, color, and size 1`] = `"x
$22.1
y
!2.2
p
13.57976
c
3.1456
x
@12.3"`; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/__snapshots__/tooltip.test.tsx.snap b/packages/sdk-ui/src/chart-options-processor/translations/__snapshots__/tooltip.test.tsx.snap new file mode 100644 index 00000000..40d2452b --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/__snapshots__/tooltip.test.tsx.snap @@ -0,0 +1,29 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`should display cartesian tooltip for point 1`] = ` +"
+ 3.14 +
+ + @42.0009 + + +
!9.877 +
$1.26 +
" +`; + +exports[`should display pie tooltip for point 1`] = ` +"
+ 3.14 +
+ + @42.0009 + / 20% + + + +
" +`; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/design-options.ts b/packages/sdk-ui/src/chart-options-processor/translations/design-options.ts index fc373764..5222fbcf 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/design-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/design-options.ts @@ -5,7 +5,7 @@ import { LegendPosition } from './legend-section'; import { LineType, StackType } from './translations-to-highcharts'; import { PieType, PieLabels } from './pie-plot-options'; import { FunnelSize, FunnelType, FunnelDirection, FunnelLabels } from './funnel-plot-options'; -import { Convolution } from '../../types'; +import { Convolution, TreemapStyleOptions } from '../../types'; import { ScatterMarkerSize } from './scatter-plot-options'; type DataLimits = { @@ -53,6 +53,8 @@ export type FunnelChartDesignOptions = BaseDesignOptionsType & { funnelLabels?: FunnelLabels; }; +export type TreemapChartDesignOptions = BaseDesignOptionsType & TreemapStyleOptions; + export type ScatterChartDesignOptions = BaseDesignOptionsType & { markerSize?: ScatterMarkerSize; }; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/funnel-plot-options.ts b/packages/sdk-ui/src/chart-options-processor/translations/funnel-plot-options.ts index f27037b1..73807e44 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/funnel-plot-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/funnel-plot-options.ts @@ -5,7 +5,7 @@ import { fontStyleDefault } from '../defaults/cartesian'; import { ValueLabelSettings } from './value-label-section'; import { defaultConfig, applyFormatPlainText } from './number-format-config'; import { NumberFormatConfig } from '../../types'; -import { InternalSeries } from '../tooltip'; +import { InternalSeries } from './tooltip-utils'; import { FunnelChartDesignOptions } from './design-options'; import { withPercentSign, fraction, fromFraction } from '../../chart-data/utils'; import { diff --git a/packages/sdk-ui/src/chart-options-processor/translations/number-format-config.ts b/packages/sdk-ui/src/chart-options-processor/translations/number-format-config.ts index 629147eb..62e2cf7e 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/number-format-config.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/number-format-config.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines-per-function */ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable complexity */ /* eslint-disable sonarjs/cognitive-complexity */ @@ -27,6 +28,9 @@ const oneKilo = 1000; const oneMillion = oneKilo * 1000; const oneBillion = oneMillion * 1000; const oneTrillion = oneBillion * 1000; +const localeNumericSep = (1000.1).toLocaleString().replace(/\d/g, ''); +const thousandSep = localeNumericSep[0]; +const decimalSep = localeNumericSep[1]; export const defaultConfig: NumberFormatConfig = { name: 'Numbers', @@ -125,9 +129,10 @@ export const applyFormat = (config: NumberFormatConfig, value: number) => { // while `numericFormatter` simply truncates the decimal portion beyond `decimalScale`. return numericFormatter(`${roundNumber(newValue, decimalScale)}`, { displayType: 'text', - thousandSeparator: thousandSeparator, + thousandSeparator: thousandSeparator ? thousandSep : undefined, fixedDecimalScale: fixedDecimalScale, decimalScale: decimalScale, + decimalSeparator: decimalSep, prefix: prefix, suffix: suffix, }); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/pie-plot-options.ts b/packages/sdk-ui/src/chart-options-processor/translations/pie-plot-options.ts index 8c706a35..490d451e 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/pie-plot-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/pie-plot-options.ts @@ -7,7 +7,7 @@ import { ChartDataOptionsInternal, CategoricalChartDataOptionsInternal, } from '../../chart-data-options/types'; -import { InternalSeries } from '../tooltip'; +import { InternalSeries } from './tooltip-utils'; export const DefaultPieLabels: PieLabels = { enabled: true, diff --git a/packages/sdk-ui/src/chart-options-processor/translations/scatter-plot-options.ts b/packages/sdk-ui/src/chart-options-processor/translations/scatter-plot-options.ts index ef637f75..23974cea 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/scatter-plot-options.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/scatter-plot-options.ts @@ -3,7 +3,7 @@ import { isValue, ScatterChartDataOptionsInternal } from '../../chart-data-optio import { PlotOptions } from '../chart-options-service'; import { ValueLabel, ValueLabelSettings } from './value-label-section'; import { ScatterChartDesignOptions } from './design-options'; -import { InternalSeries } from '../tooltip'; +import { InternalSeries } from './tooltip-utils'; import { ScatterCustomPointOptions } from './scatter-tooltip'; import { applyFormatPlainText, diff --git a/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.test.ts b/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.test.ts index 567f3cef..e762eaa4 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.test.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.test.ts @@ -1,6 +1,8 @@ import { getScatterTooltipSettings, tooltipFormatter } from './scatter-tooltip'; import { ScatterChartDataOptionsInternal } from '../../chart-data-options/types'; -import { InternalSeries } from '../tooltip'; +import { InternalSeries } from './tooltip-utils'; +import { NumberFormatConfig, defaultConfig } from './number-format-config'; +import { TooltipFormatterContextObject } from '@sisense/sisense-charts'; describe('Scatter tooltip', () => { it('should be enabled', () => { @@ -49,7 +51,7 @@ describe('Scatter tooltip', () => { maskedY: 'Apple', }, }, - } as InternalSeries; + } as unknown as TooltipFormatterContextObject; const dataOptions = { x: { @@ -293,3 +295,72 @@ describe('Scatter tooltip', () => { expect(tooltip).toEqual(expected); }); }); + +it('Format numbers when x-axis, y-axis, break by / point, color, and size', () => { + const format1: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + symbol: '$', + decimalScale: 1, + }; + const format2: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + symbol: '!', + decimalScale: 1, + }; + const format3: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + symbol: '@', + decimalScale: 1, + }; + + const tooltipContext = { + series: { name: '3.14', color: '#FFF' }, + x: '22.10009', + y: 2.234567, + point: { + name: '3.14', + color: '#FFF', + x: '22.10009', + y: 2.234567, + z: 12.345678, + custom: { + maskedX: '10M', + maskedY: 'Apple', + maskedBreakByPoint: '13.57976', + maskedBreakByColor: '3.1456', + maskedSize: '12.345678', + }, + }, + } as InternalSeries; + + const dataOptions: ScatterChartDataOptionsInternal = { + x: { + name: 'x', + type: 'number', + numberFormatConfig: format1, + }, + y: { + name: 'y', + numberFormatConfig: format2, + }, + breakByPoint: { + name: 'p', + type: 'number', + numberFormatConfig: format3, + }, + breakByColor: { + name: 'c', + type: 'number', + numberFormatConfig: format3, + }, + size: { + name: 'x', + numberFormatConfig: format3, + }, + } as ScatterChartDataOptionsInternal; + const tooltip = tooltipFormatter(tooltipContext, dataOptions); + expect(tooltip).toMatchSnapshot(); +}); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.ts b/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.ts index 576f5727..c03f068a 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/scatter-tooltip.ts @@ -1,4 +1,9 @@ -import { InternalSeries, TooltipSettings } from '../tooltip'; +import { + InternalSeries, + TooltipSettings, + formatTooltipValue, + formatTooltipXValue, +} from './tooltip-utils'; import { ScatterChartDataOptionsInternal } from '../../chart-data-options/types'; import { getDataOptionTitle } from '../../chart-data-options/utils'; @@ -26,14 +31,22 @@ const block = (element: string, title?: string): string => `${title || ''}
const buildTooltip = (blocks: string[]): string => blocks.reduce((tooltip, value) => tooltip + (value !== '
' ? `
${value}` : '')); -const buildSpans = (ctx: InternalSeries): ScatterTooltipElements => { +const buildSpans = ( + ctx: InternalSeries, + dataOptions: ScatterChartDataOptionsInternal, +): ScatterTooltipElements => { const { maskedX, maskedY, maskedBreakByPoint, maskedSize, maskedBreakByColor } = ctx.point .custom as ScatterCustomPointOptions; - const x = spanSegment(maskedX, ctx.point.color); - const y = spanSegment(maskedY, ctx.point.color); + + const formatedX = formatTooltipXValue(dataOptions.x, ctx.point.x, maskedX); + const formatedY = formatTooltipValue(dataOptions.y, ctx.point.y, maskedY); + const formatedSize = formatTooltipValue(dataOptions.size, ctx.point.z, maskedSize || ''); + + const x = spanSegment(formatedX, ctx.point.color); + const y = spanSegment(formatedY, ctx.point.color); const breakByPoint = spanSegment(maskedBreakByPoint || '', ctx.point.color); const breakByColor = spanSegment(maskedBreakByColor || '', ctx.point.color); - const size = spanSegment(maskedSize || '', ctx.point.color); + const size = spanSegment(formatedSize, ctx.point.color); return { x, @@ -73,7 +86,7 @@ export const tooltipFormatter = ( ctx: InternalSeries, dataOptions: ScatterChartDataOptionsInternal, ): string => { - const spans = buildSpans(ctx); + const spans = buildSpans(ctx, dataOptions); const { x, y, breakByPoint, breakByColor, size } = buildBlocks(spans, dataOptions); return buildTooltip([x, y, breakByPoint, breakByColor, size]); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/tooltip-utils.ts b/packages/sdk-ui/src/chart-options-processor/translations/tooltip-utils.ts new file mode 100644 index 00000000..7f526951 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/tooltip-utils.ts @@ -0,0 +1,64 @@ +import { isNumber } from '@sisense/sdk-data'; +import { Category, Value, isValue } from '../../chart-data-options/types.js'; +import { applyFormat, defaultConfig } from './number-format-config.js'; + +export const isXValueNumeric = (dataOptionX: Value | Category | undefined) => + dataOptionX ? isValue(dataOptionX) || (dataOptionX.type && isNumber(dataOptionX.type)) : false; + +export const formatTooltipValue = ( + dataOption: Value | Category | undefined, + value: number | undefined, + displayValue: string, +) => { + if (!dataOption || value === undefined || isNaN(value)) return displayValue; + + return dataOption.numberFormatConfig + ? applyFormat(dataOption.numberFormatConfig, value) + : applyFormat(defaultConfig, value); +}; + +export const formatTooltipXValue = ( + dataOption: Value | Category | undefined, + value: number | string | undefined, + displayValue: string, +) => { + const isNumeric = isXValueNumeric(dataOption); + + return isNumeric + ? formatTooltipValue(dataOption, parseFloat(`${value}`), displayValue) + : displayValue; +}; + +export type TooltipSettings = { + enabled?: boolean; + animation?: boolean; + backgroundColor?: string; + borderColor?: string; + borderRadius?: number; + borderWidth?: number; + useHTML?: boolean; + formatter?: () => string; + style?: { + fontFamily?: string; + }; +}; + +export type InternalSeries = { + series: { name: string; color: string }; + x: string; + y: number; + point: { + x?: number | string; + y?: number; + z?: number; + name: string; + color: string; + custom?: { + number1?: number; + string1?: string; + xDisplayValue?: string; + xValue?: (number | string)[]; + }; + }; + percentage?: number; +}; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/tooltip.test.tsx b/packages/sdk-ui/src/chart-options-processor/translations/tooltip.test.tsx new file mode 100644 index 00000000..d7d3847d --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/tooltip.test.tsx @@ -0,0 +1,73 @@ +import { CartesianChartDataOptionsInternal } from '../../chart-data-options/types'; +import { NumberFormatConfig, defaultConfig } from './number-format-config'; +import { getTooltipSettings } from './tooltip'; +import { InternalSeries } from './tooltip-utils'; + +const format1: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + symbol: '$', + decimalScale: 2, +}; +const format2: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + symbol: '!', + decimalScale: 3, +}; +const format3: NumberFormatConfig = { + ...defaultConfig, + name: 'Currency', + symbol: '@', + decimalScale: 4, +}; + +const dataOptions: CartesianChartDataOptionsInternal = { + x: [ + { name: 'x1', type: 'number', numberFormatConfig: format1 }, + { name: 'x2', type: 'number', numberFormatConfig: format2 }, + ], + y: [{ title: 'v', name: 'v', numberFormatConfig: format3, enabled: true }], + breakBy: [{ name: 'b', type: 'number' }], +}; + +it('should display cartesian tooltip for point', () => { + const point: InternalSeries = { + series: { name: '3.14', color: 'red' }, + x: '1.25905', + y: 42.0009, + point: { + x: 1, + y: 42.0009, + name: '3.14', + color: 'red', + custom: { xValue: [9.8765, 1.25905] }, + }, + }; + + const seriesPoint = { ...point, ...getTooltipSettings(false, dataOptions) }; + const tooltip = seriesPoint.formatter ? seriesPoint.formatter() : null; + expect(tooltip).toMatchSnapshot(); +}); + +it('should display pie tooltip for point', () => { + const point: InternalSeries = { + series: { name: '3.14', color: 'red' }, + x: '', + y: 42.0009, + percentage: 20, + point: { + y: 42.0009, + name: '3.14', + color: 'red', + custom: {}, + }, + }; + + const seriesPoint = { + ...point, + ...getTooltipSettings(false, { ...dataOptions, breakBy: [dataOptions.x[0]] }), + }; + const tooltip = seriesPoint.formatter ? seriesPoint.formatter() : null; + expect(tooltip).toMatchSnapshot(); +}); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/tooltip.ts b/packages/sdk-ui/src/chart-options-processor/translations/tooltip.ts new file mode 100644 index 00000000..02533762 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/tooltip.ts @@ -0,0 +1,73 @@ +/* eslint-disable max-lines-per-function */ +/* eslint-disable complexity */ +import { + CartesianChartDataOptionsInternal, + ChartDataOptionsInternal, +} from '../../chart-data-options/types'; +import { colorChineseSilver, colorWhite } from '../chart-options-service'; +import { + InternalSeries, + TooltipSettings, + formatTooltipValue, + formatTooltipXValue, +} from './tooltip-utils'; + +export const getTooltipSettings = ( + showDecimals: boolean | undefined, + chartDataOptions: ChartDataOptionsInternal, +): TooltipSettings => { + return { + animation: false, + backgroundColor: colorWhite, + borderColor: colorChineseSilver, + borderRadius: 10, + borderWidth: 1, + useHTML: true, + formatter: function () { + const that: InternalSeries = this as InternalSeries; + + // Applicable only to pie and funnel charts + let percentage: string | undefined; + if (that.percentage) { + percentage = showDecimals ? that.percentage.toFixed(1) : `${Math.round(that.percentage)}`; + } + + const cartesianChartDataOptions: CartesianChartDataOptionsInternal = + chartDataOptions as CartesianChartDataOptionsInternal; + + const dataOptionY = + cartesianChartDataOptions.breakBy.length > 0 + ? cartesianChartDataOptions.y?.find((y) => y.enabled) + : cartesianChartDataOptions.y?.find((y) => y.title === that.series.name); + + const yValue = formatTooltipValue(dataOptionY, that.point.y, ''); + + const maskedX = that.point?.custom?.xDisplayValue ?? that.x; + const x1Value = cartesianChartDataOptions.x + ? formatTooltipXValue(cartesianChartDataOptions.x[0], that.x, maskedX) + : maskedX; + + let x2Value = undefined; + if ( + that.point.custom?.xValue && + cartesianChartDataOptions?.x && + cartesianChartDataOptions.x.length === 2 + ) { + const maskedX1 = `${that.point.custom.xValue[0]}`; // X2 is in position xValue[0] + x2Value = formatTooltipXValue(cartesianChartDataOptions.x[1], maskedX1, maskedX1); + } + + return `
+ ${that.point.name || that.series.name} +
+ + ${yValue} + ${percentage ? ` / ${percentage}%` : ''} + + ${x2Value ? `
${x2Value}` : ''} + ${x1Value ? `
${x1Value}` : ''} +
`; + }, + }; +}; 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 8dc12a27..a8fb21fd 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 @@ -32,18 +32,32 @@ export type HighchartsType = ChartType | 'spline' | 'areaspline' | 'bubble'; export type HighchartsSeriesValues = { name: string; data: SeriesPointStructure[]; + levels?: any; }; export type SeriesPointStructure = { name?: string; - y: number | null; + y?: number | null; x?: number | null; z?: number | null; color?: string; - marker?: { enabled: boolean; isIsolatedPoint: boolean }; + marker?: { + enabled?: boolean; + isIsolatedPoint?: boolean; + lineColor?: string; + lineWidth?: number; + }; selected?: boolean; - custom?: { number1?: number; string1?: string; [k: string]: unknown }; + custom?: { + number1?: number; + string1?: string; + level?: number; + [k: string]: unknown; + }; + value?: number | null; + id?: string; drilldown?: string; + parent?: string; }; /** diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/__snapshots__/treemap-labels.test.ts.snap b/packages/sdk-ui/src/chart-options-processor/translations/treemap/__snapshots__/treemap-labels.test.ts.snap new file mode 100644 index 00000000..b5b78860 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/__snapshots__/treemap-labels.test.ts.snap @@ -0,0 +1,27 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Treemap Chart labels formatter > should prepare big label 1`] = ` +"
Test
" +`; + +exports[`Treemap Chart labels formatter > should prepare small label 1`] = `"
Test
"`; + +exports[`Treemap Chart labels formatter > should prepare small label with light label text 1`] = `"
Test
"`; + +exports[`Treemap Chart labels formatter > should skip big label in case of point small size 1`] = `""`; + +exports[`Treemap Chart labels formatter > should skip small label in case of point small size 1`] = `""`; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/__snapshots__/treemap-tooltip.test.ts.snap b/packages/sdk-ui/src/chart-options-processor/translations/treemap/__snapshots__/treemap-tooltip.test.ts.snap new file mode 100644 index 00000000..2f051fcd --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/__snapshots__/treemap-tooltip.test.ts.snap @@ -0,0 +1,85 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Treemap Chart tooltip formatter > contribution mode 1`] = ` +" +
+ +
+ Three + 75.0% +
+
+ +
+ Two + 50.0% +
+
+ +
+ One + 25.0% +
+
+ +
+ 25.0% of test +
+
+ 50.0%% of Two +
+
" +`; + +exports[`Treemap Chart tooltip formatter > single category tooltip 1`] = ` +" +
+ +
+ One + 1 +
+
+ +
+ 1 of test +
+
+ +
+
" +`; + +exports[`Treemap Chart tooltip formatter > three categories tooltip 1`] = ` +" +
+ +
+ Three + 3 +
+
+ +
+ Two + 2 +
+
+ +
+ One + 1 +
+
+ +
+ 1 of test +
+
+ 50.0%% of Two +
+
" +`; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-labels.test.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-labels.test.ts new file mode 100644 index 00000000..518480e6 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-labels.test.ts @@ -0,0 +1,111 @@ +import { treemapLabelFormatter } from './treemap-labels'; +import { PointLabelObject } from '@sisense/sisense-charts'; + +describe('Treemap Chart labels formatter', () => { + it('should prepare small label', () => { + const point = { + color: 'white', + key: 'Test', + point: { + shapeArgs: { + width: 100, + height: 100, + }, + options: { + custom: { + level: 3, + levelsCount: 3, + }, + }, + }, + } as unknown as PointLabelObject; + + expect(treemapLabelFormatter.call(point)).toMatchSnapshot(); + }); + + it('should prepare small label with light label text', () => { + const point = { + color: 'black', + key: 'Test', + point: { + shapeArgs: { + width: 100, + height: 100, + }, + options: { + custom: { + level: 3, + levelsCount: 3, + }, + }, + }, + } as unknown as PointLabelObject; + + expect(treemapLabelFormatter.call(point)).toMatchSnapshot(); + }); + + it('should prepare big label', () => { + const point = { + color: 'white', + key: 'Test', + point: { + shapeArgs: { + width: 100, + height: 100, + }, + options: { + custom: { + level: 1, + levelsCount: 3, + bigLabelSpacing: true, + }, + }, + }, + } as unknown as PointLabelObject; + + expect(treemapLabelFormatter.call(point)).toMatchSnapshot(); + }); + + it('should skip big label in case of point small size', () => { + const point = { + color: 'white', + key: 'Test', + point: { + shapeArgs: { + width: 20, + height: 20, + }, + options: { + custom: { + level: 1, + levelsCount: 3, + bigLabelSpacing: false, + }, + }, + }, + } as unknown as PointLabelObject; + + expect(treemapLabelFormatter.call(point)).toMatchSnapshot(); + }); + + it('should skip small label in case of point small size', () => { + const point = { + color: 'white', + key: 'Test', + point: { + shapeArgs: { + width: 10, + height: 10, + }, + options: { + custom: { + level: 3, + levelsCount: 3, + }, + }, + }, + } as unknown as PointLabelObject; + + expect(treemapLabelFormatter.call(point)).toMatchSnapshot(); + }); +}); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-labels.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-labels.ts new file mode 100644 index 00000000..e5245f2c --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-labels.ts @@ -0,0 +1,213 @@ +/* eslint-disable max-lines-per-function */ +/* eslint-disable max-lines */ +import { CategoricalChartDataOptionsInternal } from '../../../chart-data-options/types'; +import { TreemapChartDesignOptions } from '../design-options'; +import { CompleteThemeSettings } from '../../../types'; +import Highcharts, { + OptionsLayoutAlgorithmValue, + PlotTreegraphLevelsDataLabelsOptions, + PointLabelObject, + PlotTreegraphLevelsOptions, + PlotTreemapOptions, + PlotTreemapLevelsDataLabelsOptions, + PlotTreegraphLevelsColorVariationOptions, + Chart, + Point, +} from '@sisense/sisense-charts'; +import { getDarkFactor, toColor } from '../../../utils/color'; +import { LayoutPointResult, ParentValues, TreemapLayoutAlgorithmContext } from './types'; + +const LIGHT_COLOR = 'rgb(255, 255, 255)'; +const DARK_COLOR = 'rgb(43, 51, 66)'; +const BIG_LABEL_HEIGHT = 20; +const BIG_SPACING = 4; +const MIDDLE_SPACING = 2; +const SMALL_SPACING = 1; +const MIN_POINT_HEIGHT_FOR_BIG_LABEL = BIG_LABEL_HEIGHT * 2; +const MIN_POINT_HEIGHT_FOR_MIDDLE_LABEL = 26; +const MIN_POINT_HEIGHT_FOR_SMALL_LABEL = 20; +const MIN_POINT_WIDTH_FOR_LABEL = 35; +const BIG_LABEL_TOP_SPACING = BIG_LABEL_HEIGHT + BIG_SPACING - 2; +const DEFAULT_COLOR_VARIATION = { + key: 'brightness', + to: 0.15, +} as PlotTreegraphLevelsColorVariationOptions; + +// eslint-disable-next-line +Highcharts.Series.types.treemap.prototype['squarifiedWithTopSpacing'] = function ( + this: TreemapLayoutAlgorithmContext, + parent: ParentValues, + children: PointLabelObject[], +) { + const pxToLayoutHeight = transformPxToLayoutVertical(parent.height, this.chart.plotHeight); + const result: LayoutPointResult[] = this.squarified(parent, children); + const topLabelSpace = pxToLayoutHeight(BIG_LABEL_TOP_SPACING); + + return isBigLabelEnabled(this.chart) + ? result.map((item, index) => { + const enoughHeightForLabel = + item.height >= pxToLayoutHeight(MIN_POINT_HEIGHT_FOR_BIG_LABEL); + children[index].point.options.custom!.bigLabelSpacing = enoughHeightForLabel; + + if (enoughHeightForLabel) { + item.height = item.height - topLabelSpace; + item.y = item.y + topLabelSpace; + } + return item; + }) + : result; +}; + +export function prepareTreemapLevels( + dataOptions: CategoricalChartDataOptionsInternal, + chartDesignOptions: TreemapChartDesignOptions, + themeSettings?: CompleteThemeSettings, +) { + const levels = createDefaultTreemapLevels(); + + levels.forEach((level, index) => { + const datalabels = level.dataLabels as PlotTreegraphLevelsDataLabelsOptions; + if (chartDesignOptions?.labels?.category) { + datalabels.enabled = chartDesignOptions.labels?.category?.[index]?.enabled ?? true; + } + if (themeSettings?.typography?.fontFamily) { + datalabels.style!.fontFamily = themeSettings?.typography?.fontFamily; + } + }); + + if (dataOptions.breakBy.length === 1) { + levels[0].borderWidth = SMALL_SPACING; + levels[0].borderColor = 'black'; + levels[0].layoutAlgorithm = 'strip'; + levels[0].dataLabels = levels[1].dataLabels; + } + if (dataOptions.breakBy.length === 2) { + levels[1].borderWidth = SMALL_SPACING; + levels[1].borderColor = 'black'; + } + + if (dataOptions.breakBy.some(({ isColored }) => isColored)) { + levels[1].colorVariation = DEFAULT_COLOR_VARIATION; + levels[2].colorVariation = DEFAULT_COLOR_VARIATION; + } + + return levels; +} + +export function treemapLabelFormatter(this: PointLabelObject): string { + const isDarkBG = getDarkFactor(toColor(this.color as string)) > 0.4; + const { width } = getPointSize(this.point); + + if (!isEnoughSpaceForLabel(this.point)) { + return ''; + } + + if (isBigLabelCase(this.point)) { + return `
${this.key}
`; + } + + return `
${this.key}
`; +} + +function createDefaultTreemapLevels(): PlotTreegraphLevelsOptions[] { + return [ + { + level: 1, + borderWidth: BIG_SPACING, + borderColor: 'white', + layoutAlgorithm: 'squarifiedWithTopSpacing' as OptionsLayoutAlgorithmValue, + dataLabels: { + useHTML: true, + enabled: true, + align: 'left', + verticalAlign: 'top', + allowOverlap: true, + padding: 0, + style: { + fontSize: '14px', + }, + formatter: treemapLabelFormatter, + }, + }, + { + level: 2, + borderWidth: MIDDLE_SPACING, + borderColor: 'white', + dataLabels: { + enabled: true, + align: 'left', + verticalAlign: 'top', + style: { + fontSize: '14px', + }, + formatter: treemapLabelFormatter, + }, + }, + { + level: 3, + borderColor: 'black', + borderWidth: SMALL_SPACING, + dataLabels: { + enabled: true, + align: 'center', + verticalAlign: 'middle', + style: { + fontSize: '13px', + }, + formatter: treemapLabelFormatter, + }, + }, + ]; +} + +function isBigLabelCase(point: Point): boolean { + return point.options?.custom?.levelsCount !== 1 && point.options?.custom?.level === 1; +} + +function isEnoughSpaceForLabel(point: Point): boolean { + const { height, width } = getPointSize(point); + const { level } = point.options.custom!; + + if (isBigLabelCase(point)) { + return Boolean(point.options.custom!.bigLabelSpacing); + } + if (level !== 3) { + return height >= MIN_POINT_HEIGHT_FOR_MIDDLE_LABEL && width >= MIN_POINT_WIDTH_FOR_LABEL; + } + + return height >= MIN_POINT_HEIGHT_FOR_SMALL_LABEL && width >= MIN_POINT_WIDTH_FOR_LABEL; +} + +function transformPxToLayoutVertical(layoutHeight: number, plotBoxHeightInPx: number) { + return (pixels: number) => { + const ratio = plotBoxHeightInPx / layoutHeight; + return pixels / ratio; + }; +} + +function isBigLabelEnabled(chart: Chart) { + const series = (chart.options.series?.[0] ?? {}) as PlotTreemapOptions; + const dataLabel = (series?.levels?.[0]?.dataLabels ?? {}) as PlotTreemapLevelsDataLabelsOptions; + return dataLabel.enabled ?? true; +} + +function getPointSize(point: Point) { + return { + width: (point.shapeArgs?.width ?? 0) as number, + height: (point.shapeArgs?.height ?? 0) as number, + }; +} 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 new file mode 100644 index 00000000..a6f5a653 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-options.ts @@ -0,0 +1,58 @@ +/* eslint-disable max-params */ +import { CategoricalChartData } from '../../../chart-data/types'; +import { HighchartsOptionsInternal } from '../../chart-options-service'; +import { CategoricalChartDataOptionsInternal } from '../../../chart-data-options/types'; +import { CompleteThemeSettings } from '../../../types'; +import { TreemapChartDesignOptions } from '../design-options'; +import { getTreemapTooltipSettings } from './treemap-tooltip'; +import { prepareTreemapLevels } from './treemap-labels'; +import { prepareTreemapDataItems } from './treemap-series'; + +const DEFAULT_TREEMAP_SERIES_COLOR = 'rgb(0, 206, 230)'; + +const DEFAULT_TREEMAP_SERIES = { + type: 'treemap', + layoutAlgorithm: 'strip', + layoutStartingDirection: 'horizontal', + clip: false, + color: DEFAULT_TREEMAP_SERIES_COLOR, + dataLabels: { + style: { + textOutline: 'none', + }, + }, +}; + +const DEFAULT_TREEMAP_OPTIONS: HighchartsOptionsInternal = { + title: { text: null }, + chart: { + type: 'treemap', + spacing: [20, 20, 20, 20], + alignTicks: false, + polar: false, + animation: { + duration: 300, + }, + }, + series: [], +}; + +export function prepareTreemapOptions( + chartData: CategoricalChartData, + dataOptions: CategoricalChartDataOptionsInternal, + designOptions: TreemapChartDesignOptions, + themeSettings?: CompleteThemeSettings, +): HighchartsOptionsInternal { + return { + ...DEFAULT_TREEMAP_OPTIONS, + series: [ + { + ...DEFAULT_TREEMAP_SERIES, + name: dataOptions.y[0].title ?? dataOptions.y[0].name, + data: prepareTreemapDataItems(chartData, dataOptions, themeSettings), + levels: prepareTreemapLevels(dataOptions, designOptions, themeSettings), + }, + ], + tooltip: getTreemapTooltipSettings(dataOptions, designOptions), + }; +} 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 new file mode 100644 index 00000000..3467e75d --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-series.ts @@ -0,0 +1,82 @@ +import { CategoricalChartData } from '../../../chart-data/types'; +import { getColorSetting, SeriesPointStructure } from '../translations-to-highcharts'; +import { CategoricalChartDataOptionsInternal } from '../../../chart-data-options/types'; +import { CompleteThemeSettings } from '../../../types'; +import { getAPaletteColor } from '../pie-series'; + +export function prepareTreemapDataItems( + chartData: CategoricalChartData, + dataOptions: CategoricalChartDataOptionsInternal, + themeSettings?: CompleteThemeSettings, +): SeriesPointStructure[] { + if (!chartData.series[0]) { + return []; + } + + const parentDataItems = createTreemapParents(chartData); + const childDataItems = chartData.series[0].data.map((item) => { + return { + value: item.value, + name: item.xDisplayValue?.slice(-1).toString(), + parent: item.xValue?.slice(0, -1).join('_'), + custom: { + level: chartData.xAxisCount, + levelsCount: chartData.xAxisCount, + }, + }; + }); + + return handleTreemapSeriesColor( + [...parentDataItems, ...childDataItems], + dataOptions, + themeSettings, + ); +} + +function createTreemapParents(chartData: CategoricalChartData): SeriesPointStructure[] { + const map: { [key: string]: SeriesPointStructure } = {}; + chartData.xValues.forEach((value) => { + value.rawValues!.slice(0, -1).forEach((name, index) => { + const id = value.xValues.slice(0, index + 1).join('_'); + map[id] = { + id, + name: name as string, + parent: value.rawValues!.slice(0, index).join('_'), + custom: { + level: index + 1, + levelsCount: chartData.xAxisCount, + }, + }; + }); + }); + + return Object.values(map); +} + +function handleTreemapSeriesColor( + series: SeriesPointStructure[], + dataOptions: CategoricalChartDataOptionsInternal, + themeSettings?: CompleteThemeSettings, +) { + const coloringLevel = dataOptions.breakBy.map((item) => item.isColored).indexOf(true) + 1; + const coloringSeriesIndexMap = new Map(); + + return series.map((item) => { + if (item.custom!.level === coloringLevel) { + if (!coloringSeriesIndexMap.has(item.name)) { + coloringSeriesIndexMap.set(item.name, coloringSeriesIndexMap.size); + } + + return { + ...item, + color: + getColorSetting(dataOptions, item.name as string) ?? + getAPaletteColor( + themeSettings?.palette.variantColors, + coloringSeriesIndexMap.get(item.name) as number, + ), + }; + } + return item; + }); +} diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-tooltip.test.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-tooltip.test.ts new file mode 100644 index 00000000..92028a76 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-tooltip.test.ts @@ -0,0 +1,92 @@ +import { CategoricalChartDataOptionsInternal } from '../../../chart-data-options/types'; +import { TooltipFormatterContextObject } from '@sisense/sisense-charts'; +import { TreemapChartDesignOptions } from '../design-options'; +import { treemapTooltipFormatter } from './treemap-tooltip'; + +describe('Treemap Chart tooltip formatter', () => { + const dataOptions = { + y: [{ title: 'test' }], + } as CategoricalChartDataOptionsInternal; + + const designOptions = {} as TreemapChartDesignOptions; + + const node1 = { + val: 1, + name: 'One', + }; + const node2 = { + val: 2, + name: 'Two', + }; + const node3 = { + val: 3, + name: 'Three', + }; + const node4 = { + val: 4, + name: 'Four', + }; + + it('single category tooltip', () => { + const context = { + color: 'red', + point: { + node: { + ...node1, + parentNode: node2, + }, + }, + } as unknown as TooltipFormatterContextObject; + + expect(treemapTooltipFormatter(context, dataOptions, designOptions)).toMatchSnapshot(); + }); + + it('three categories tooltip', () => { + const context = { + color: 'blue', + point: { + node: { + ...node1, + parentNode: { + ...node2, + parentNode: { + ...node3, + parentNode: { + ...node4, + }, + }, + }, + }, + }, + } as unknown as TooltipFormatterContextObject; + + expect(treemapTooltipFormatter(context, dataOptions, designOptions)).toMatchSnapshot(); + }); + + it('contribution mode', () => { + const context = { + color: 'blue', + point: { + node: { + ...node1, + parentNode: { + ...node2, + parentNode: { + ...node3, + parentNode: { + ...node4, + }, + }, + }, + }, + }, + } as unknown as TooltipFormatterContextObject; + const designOptionsWithContribution = { + tooltip: { mode: 'contribution' }, + } as TreemapChartDesignOptions; + + expect( + treemapTooltipFormatter(context, dataOptions, designOptionsWithContribution), + ).toMatchSnapshot(); + }); +}); diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-tooltip.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-tooltip.ts new file mode 100644 index 00000000..17f2fa3f --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/treemap-tooltip.ts @@ -0,0 +1,94 @@ +/* eslint-disable max-lines-per-function */ +import { CategoricalChartDataOptionsInternal } from '../../../chart-data-options/types'; +import { TreemapChartDesignOptions } from '../design-options'; +import { InternalSeriesNode, TooltipSettings } from '../../tooltip'; +import { colorChineseSilver, colorWhite } from '../../chart-options-service'; +import { applyFormat, defaultConfig } from '../number-format-config'; +import { TooltipFormatterContextObject } from '@sisense/sisense-charts'; + +export const getTreemapTooltipSettings = ( + chartDataOptions: CategoricalChartDataOptionsInternal, + designOptions: TreemapChartDesignOptions, +): TooltipSettings => ({ + animation: false, + backgroundColor: colorWhite, + borderColor: colorChineseSilver, + borderRadius: 10, + borderWidth: 1, + useHTML: true, + outside: true, + formatter: function (this) { + return treemapTooltipFormatter(this, chartDataOptions, designOptions); + }, +}); + +function getContribution(value: number, total: number) { + return value / (total / 100); +} + +function getFormattedContribution(value: number, total: number) { + return `${getContribution(value, total).toPrecision(3)}%`; +} + +export function treemapTooltipFormatter( + context: TooltipFormatterContextObject, + chartDataOptions: CategoricalChartDataOptionsInternal, + designOptions: TreemapChartDesignOptions, +) { + const numberFormatConfig = chartDataOptions.y?.[0]?.numberFormatConfig ?? defaultConfig; + const isContributionMode = designOptions?.tooltip?.mode === 'contribution'; + const valueTitle = chartDataOptions.y?.[0]?.title ?? chartDataOptions.y?.[0]?.name; + const color = context.color as string; + + let rootValue = 0; + const nodesToShow: InternalSeriesNode[] = []; + const handleNode = (node: InternalSeriesNode) => { + if (node.parentNode) { + nodesToShow.push(node); + } else { + rootValue = node.val; + return; + } + handleNode(node.parentNode); + }; + // eslint-disable-next-line + handleNode(context.point['node'] as InternalSeriesNode); + + return ` +
+ ${[...nodesToShow] + .reverse() + .map( + (node) => ` +
+ ${node.name} + ${ + isContributionMode + ? getFormattedContribution(node.val, rootValue) + : applyFormat(numberFormatConfig, node.val) + } +
+
+ `, + ) + .join('')} +
+ ${ + isContributionMode + ? getFormattedContribution(nodesToShow[0].val, rootValue) + : applyFormat(numberFormatConfig, nodesToShow[0]?.val) + } of ${valueTitle} +
+
+ ${ + nodesToShow[1] + ? `${getFormattedContribution( + nodesToShow[0]?.val, + nodesToShow[1]?.val, + )}% of ${nodesToShow[1]?.name}` + : '' + } +
+
`; +} diff --git a/packages/sdk-ui/src/chart-options-processor/translations/treemap/types.ts b/packages/sdk-ui/src/chart-options-processor/translations/treemap/types.ts new file mode 100644 index 00000000..d11d5096 --- /dev/null +++ b/packages/sdk-ui/src/chart-options-processor/translations/treemap/types.ts @@ -0,0 +1,22 @@ +import { Chart, PointLabelObject } from '@sisense/sisense-charts'; + +export type ParentValues = { + direction: number; + height: number; + val: number; + width: number; + x: number; + y: number; +}; + +export type LayoutPointResult = { + x: number; + y: number; + width: number; + height: number; +}; + +export type TreemapLayoutAlgorithmContext = { + chart: Chart; + squarified: (parent: ParentValues, children: PointLabelObject[]) => LayoutPointResult[]; +}; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/types.ts b/packages/sdk-ui/src/chart-options-processor/translations/types.ts index 748398ca..8e286651 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/types.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/types.ts @@ -10,6 +10,7 @@ import { IndicatorChartDesignOptions, PolarChartDesignOptions, ScatterChartDesignOptions, + TreemapChartDesignOptions, } from './design-options'; export const POLAR_CHART_TYPES = ['polar'] as const; @@ -25,7 +26,7 @@ export const CARTESIAN_CHART_TYPES = [ /** Cartesian family of chart types @expandType */ export type CartesianChartType = (typeof CARTESIAN_CHART_TYPES)[number]; -export const CATEGORICAL_CHART_TYPES = ['pie', 'funnel'] as const; +export const CATEGORICAL_CHART_TYPES = ['pie', 'funnel', 'treemap'] as const; /** Categorical family of chart types @expandType */ export type CategoricalChartType = (typeof CATEGORICAL_CHART_TYPES)[number]; @@ -58,7 +59,8 @@ export type ChartDesignOptions = | FunnelChartDesignOptions | PolarChartDesignOptions | IndicatorChartDesignOptions - | ScatterChartDesignOptions; + | ScatterChartDesignOptions + | TreemapChartDesignOptions; export type ChartConfig = { chartType: ChartType; diff --git a/packages/sdk-ui/src/chart-options-processor/translations/value-label-section.ts b/packages/sdk-ui/src/chart-options-processor/translations/value-label-section.ts index d2da1edc..983a0c02 100644 --- a/packages/sdk-ui/src/chart-options-processor/translations/value-label-section.ts +++ b/packages/sdk-ui/src/chart-options-processor/translations/value-label-section.ts @@ -4,7 +4,7 @@ import { Style } from '../chart-options-service'; import { defaultConfig, applyFormatPlainText, NumberFormatConfig } from './number-format-config'; import { AxisOrientation } from './axis-section'; -import { InternalSeries } from '../tooltip'; +import { InternalSeries } from './tooltip-utils'; import { PolarType } from './design-options'; export type ValueLabel = 'horizontal' | 'diagonal' | 'vertical' | null; diff --git a/packages/sdk-ui/src/charts/indicator/indicator-legacy-chart-options/__mocks__/theme-settings.ts b/packages/sdk-ui/src/charts/indicator/indicator-legacy-chart-options/__mocks__/theme-settings.ts index 64290260..8c7175da 100644 --- a/packages/sdk-ui/src/charts/indicator/indicator-legacy-chart-options/__mocks__/theme-settings.ts +++ b/packages/sdk-ui/src/charts/indicator/indicator-legacy-chart-options/__mocks__/theme-settings.ts @@ -4,6 +4,7 @@ export const darkThemeSettings: ThemeSettings = { chart: { backgroundColor: '#333333', textColor: '#FFFFFF', + panelBackgroundColor: '#F6F6F6', }, typography: { fontFamily: 'impact', diff --git a/packages/sdk-ui/src/charts/table/helpers/format-numbers.test.ts b/packages/sdk-ui/src/charts/table/helpers/format-numbers.test.ts index a232c26d..c59d5273 100644 --- a/packages/sdk-ui/src/charts/table/helpers/format-numbers.test.ts +++ b/packages/sdk-ui/src/charts/table/helpers/format-numbers.test.ts @@ -8,9 +8,12 @@ describe('formatNumbers', () => { const table: DataTable = { columns: [ { name: 'item', type: 'string', index: 0, direction: 0 }, - { name: 'price', type: 'int', index: 1, direction: 0 }, + { name: 'price', type: 'number', index: 1, direction: 0 }, + { name: 'revenue', type: 'number', index: 1, direction: 0 }, + ], + rows: [ + [{ displayValue: 'abc' }, { displayValue: '54321.54321' }, { displayValue: '12345.12345' }], ], - rows: [[{ displayValue: 'abc' }, { displayValue: '1000' }]], }; const chartDataOptions: TableDataOptions = { @@ -22,9 +25,14 @@ describe('formatNumbers', () => { }, { name: 'price', - type: 'int', + type: 'number', + enabled: true, + }, + { + name: 'revenue', + type: 'number', enabled: true, - numberFormatConfig: defaultConfig, + numberFormatConfig: { ...defaultConfig, name: 'Currency' }, }, ], }; @@ -41,7 +49,13 @@ describe('formatNumbers', () => { direction: 0, index: 1, name: 'price', - type: 'int', + type: 'number', + }, + { + direction: 0, + index: 1, + name: 'revenue', + type: 'number', }, ], rows: [ @@ -51,11 +65,19 @@ describe('formatNumbers', () => { }, { compareValue: { - value: 1000, + value: 54321.54321, + valueIsNaN: false, + valueUndefined: false, + }, + displayValue: '54.32K', + }, + { + compareValue: { + value: 12345.12345, valueIsNaN: false, valueUndefined: false, }, - displayValue: '1K', + displayValue: '$12.35K', }, ], ], diff --git a/packages/sdk-ui/src/charts/table/helpers/format-numbers.ts b/packages/sdk-ui/src/charts/table/helpers/format-numbers.ts index f276dc48..c8ca1883 100644 --- a/packages/sdk-ui/src/charts/table/helpers/format-numbers.ts +++ b/packages/sdk-ui/src/charts/table/helpers/format-numbers.ts @@ -2,14 +2,17 @@ import { DataTable } from '../../../chart-data-processor/table-processor'; import { TableDataOptionsInternal } from '../../../chart-data-options/types'; import { isNumber } from '@sisense/sdk-data'; import { createCompareValue } from '../../../chart-data-processor/row-comparator'; -import { applyFormatPlainText } from '../../../chart-options-processor/translations/number-format-config'; +import { + applyFormatPlainText, + defaultConfig, +} from '../../../chart-options-processor/translations/number-format-config'; export const formatNumbers = ( table: DataTable, chartDataOptions: TableDataOptionsInternal, ): DataTable => { // If there are no numberFormatConfigs, there is no formatting to be done - if (!chartDataOptions.columns.some((c) => c.numberFormatConfig)) return table; + if (!table.columns.some((c) => isNumber(c.type))) return table; // This reads the number format config from chartDataOptions, // and apply the format to display value @@ -20,7 +23,7 @@ export const formatNumbers = ( return row.map((r, index) => { const columnType = columns[index].type; - const numberConfig = chartDataOptions.columns[index].numberFormatConfig; + const numberConfig = chartDataOptions.columns[index].numberFormatConfig || defaultConfig; if (isNumber(columnType) && numberConfig) { const compareValue = createCompareValue(r.displayValue, columnType); return { diff --git a/packages/sdk-ui/src/components/__snapshots__/treemap-chart.test.tsx.snap b/packages/sdk-ui/src/components/__snapshots__/treemap-chart.test.tsx.snap new file mode 100644 index 00000000..cd8e79f8 --- /dev/null +++ b/packages/sdk-ui/src/components/__snapshots__/treemap-chart.test.tsx.snap @@ -0,0 +1,1492 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Treemap Chart > render a treemap with coloring 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": "treemap", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "legend": { + "itemStyle": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "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": { + "style": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "point": { + "events": {}, + }, + }, + }, + "series": [ + { + "clip": false, + "color": "rgb(0, 206, 230)", + "data": [ + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2009", + "name": "2009-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2010", + "name": "2010-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2011", + "name": "2011-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2012", + "name": "2012-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2013", + "name": "2013-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2014", + "name": "2014-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2015", + "name": "2015-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2016", + "name": "2016-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2018", + "name": "2018-01-01T00:00:00.000Z", + "parent": "", + }, + { + "color": "#00cee6", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2009_A", + "name": "A", + "parent": "2009-01-01T00:00:00.000Z", + }, + { + "color": "#00cee6", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2010_A", + "name": "A", + "parent": "2010-01-01T00:00:00.000Z", + }, + { + "color": "#9b9bd7", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2011_B", + "name": "B", + "parent": "2011-01-01T00:00:00.000Z", + }, + { + "color": "#9b9bd7", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2012_B", + "name": "B", + "parent": "2012-01-01T00:00:00.000Z", + }, + { + "color": "#00cee6", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2013_A", + "name": "A", + "parent": "2013-01-01T00:00:00.000Z", + }, + { + "color": "#9b9bd7", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2014_B", + "name": "B", + "parent": "2014-01-01T00:00:00.000Z", + }, + { + "color": "#00cee6", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2015_A", + "name": "A", + "parent": "2015-01-01T00:00:00.000Z", + }, + { + "color": "#9b9bd7", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2016_B", + "name": "B", + "parent": "2016-01-01T00:00:00.000Z", + }, + { + "color": "#9b9bd7", + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2018_B", + "name": "B", + "parent": "2018-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2009-01-01T00:00:00.000Z_A", + "value": 1322, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2009-01-01T00:00:00.000Z_A", + "value": 6781, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2010-01-01T00:00:00.000Z_A", + "value": 2343, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2010-01-01T00:00:00.000Z_A", + "value": 4471, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2011-01-01T00:00:00.000Z_B", + "value": 1244, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2011-01-01T00:00:00.000Z_B", + "value": 1812, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2012-01-01T00:00:00.000Z_B", + "value": 3422, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2012-01-01T00:00:00.000Z_B", + "value": 5001, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2013-01-01T00:00:00.000Z_A", + "value": 2045, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2014-01-01T00:00:00.000Z_B", + "value": 3010, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2015-01-01T00:00:00.000Z_A", + "value": 5447, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2016-01-01T00:00:00.000Z_B", + "value": 4242, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2018-01-01T00:00:00.000Z_B", + "value": 936, + }, + ], + "dataLabels": { + "style": { + "textOutline": "none", + }, + }, + "layoutAlgorithm": "strip", + "layoutStartingDirection": "horizontal", + "levels": [ + { + "borderColor": "white", + "borderWidth": 4, + "dataLabels": { + "align": "left", + "allowOverlap": true, + "enabled": true, + "formatter": [Function], + "padding": 0, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "useHTML": true, + "verticalAlign": "top", + }, + "layoutAlgorithm": "squarifiedWithTopSpacing", + "level": 1, + }, + { + "borderColor": "white", + "borderWidth": 2, + "colorVariation": { + "key": "brightness", + "to": 0.15, + }, + "dataLabels": { + "align": "left", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "verticalAlign": "top", + }, + "level": 2, + }, + { + "borderColor": "black", + "borderWidth": 1, + "colorVariation": { + "key": "brightness", + "to": 0.15, + }, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "13px", + }, + "verticalAlign": "middle", + }, + "level": 3, + }, + ], + "name": "Quantity", + "type": "treemap", + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "outside": true, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + "useHTML": true, + }, + "xAxis": undefined, +} +`; + +exports[`Treemap Chart > render a treemap with single category 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": "treemap", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "legend": { + "itemStyle": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "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": { + "style": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "point": { + "events": {}, + }, + }, + }, + "series": [ + { + "clip": false, + "color": "rgb(0, 206, 230)", + "data": [ + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2009", + "parent": "", + "value": 8103, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2010", + "parent": "", + "value": 6814, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2011", + "parent": "", + "value": 3056, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2012", + "parent": "", + "value": 8423, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2013", + "parent": "", + "value": 2045, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2014", + "parent": "", + "value": 3010, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2015", + "parent": "", + "value": 5447, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2016", + "parent": "", + "value": 4242, + }, + { + "custom": { + "level": 1, + "levelsCount": 1, + }, + "name": "2018", + "parent": "", + "value": 936, + }, + ], + "dataLabels": { + "style": { + "textOutline": "none", + }, + }, + "layoutAlgorithm": "strip", + "layoutStartingDirection": "horizontal", + "levels": [ + { + "borderColor": "black", + "borderWidth": 1, + "dataLabels": { + "align": "left", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "verticalAlign": "top", + }, + "layoutAlgorithm": "strip", + "level": 1, + }, + { + "borderColor": "white", + "borderWidth": 2, + "dataLabels": { + "align": "left", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "verticalAlign": "top", + }, + "level": 2, + }, + { + "borderColor": "black", + "borderWidth": 1, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "13px", + }, + "verticalAlign": "middle", + }, + "level": 3, + }, + ], + "name": "Quantity", + "type": "treemap", + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "outside": true, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + "useHTML": true, + }, + "xAxis": undefined, +} +`; + +exports[`Treemap Chart > render a treemap with three categories 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": "treemap", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "legend": { + "itemStyle": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "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": { + "style": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "point": { + "events": {}, + }, + }, + }, + "series": [ + { + "clip": false, + "color": "rgb(0, 206, 230)", + "data": [ + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2009", + "name": "2009-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2010", + "name": "2010-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2011", + "name": "2011-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2012", + "name": "2012-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2013", + "name": "2013-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2014", + "name": "2014-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2015", + "name": "2015-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2016", + "name": "2016-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 3, + }, + "id": "2018", + "name": "2018-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2009_A", + "name": "A", + "parent": "2009-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2010_A", + "name": "A", + "parent": "2010-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2011_B", + "name": "B", + "parent": "2011-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2012_B", + "name": "B", + "parent": "2012-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2013_A", + "name": "A", + "parent": "2013-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2014_B", + "name": "B", + "parent": "2014-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2015_A", + "name": "A", + "parent": "2015-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2016_B", + "name": "B", + "parent": "2016-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 2, + "levelsCount": 3, + }, + "id": "2018_B", + "name": "B", + "parent": "2018-01-01T00:00:00.000Z", + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2009-01-01T00:00:00.000Z_A", + "value": 1322, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2009-01-01T00:00:00.000Z_A", + "value": 6781, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2010-01-01T00:00:00.000Z_A", + "value": 2343, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2010-01-01T00:00:00.000Z_A", + "value": 4471, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2011-01-01T00:00:00.000Z_B", + "value": 1244, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2011-01-01T00:00:00.000Z_B", + "value": 1812, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Female", + "parent": "2012-01-01T00:00:00.000Z_B", + "value": 3422, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2012-01-01T00:00:00.000Z_B", + "value": 5001, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2013-01-01T00:00:00.000Z_A", + "value": 2045, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2014-01-01T00:00:00.000Z_B", + "value": 3010, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2015-01-01T00:00:00.000Z_A", + "value": 5447, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2016-01-01T00:00:00.000Z_B", + "value": 4242, + }, + { + "custom": { + "level": 3, + "levelsCount": 3, + }, + "name": "Male", + "parent": "2018-01-01T00:00:00.000Z_B", + "value": 936, + }, + ], + "dataLabels": { + "style": { + "textOutline": "none", + }, + }, + "layoutAlgorithm": "strip", + "layoutStartingDirection": "horizontal", + "levels": [ + { + "borderColor": "white", + "borderWidth": 4, + "dataLabels": { + "align": "left", + "allowOverlap": true, + "enabled": true, + "formatter": [Function], + "padding": 0, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "useHTML": true, + "verticalAlign": "top", + }, + "layoutAlgorithm": "squarifiedWithTopSpacing", + "level": 1, + }, + { + "borderColor": "white", + "borderWidth": 2, + "dataLabels": { + "align": "left", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "verticalAlign": "top", + }, + "level": 2, + }, + { + "borderColor": "black", + "borderWidth": 1, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "13px", + }, + "verticalAlign": "middle", + }, + "level": 3, + }, + ], + "name": "Quantity", + "type": "treemap", + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "outside": true, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + "useHTML": true, + }, + "xAxis": undefined, +} +`; + +exports[`Treemap Chart > render a treemap with two categories 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": "treemap", + }, + "drilldown": { + "activeDataLabelStyle": { + "color": "#000000", + }, + "breadcrumbs": { + "buttonTheme": { + "fill": "#ffcb05", + "states": { + "hover": { + "fill": "#f2b900", + "stroke": "#f2b900", + }, + }, + "stroke": "#ffcb05", + "style": { + "color": "#3a4356", + }, + }, + }, + }, + "legend": { + "itemStyle": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "plotOptions": { + "pie": { + "allowPointSelect": false, + "dataLabels": { + "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": { + "style": { + "color": "#000000", + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + }, + "point": { + "events": {}, + }, + }, + }, + "series": [ + { + "clip": false, + "color": "rgb(0, 206, 230)", + "data": [ + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2009", + "name": "2009-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2010", + "name": "2010-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2011", + "name": "2011-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2012", + "name": "2012-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2013", + "name": "2013-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2014", + "name": "2014-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2015", + "name": "2015-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2016", + "name": "2016-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 1, + "levelsCount": 2, + }, + "id": "2018", + "name": "2018-01-01T00:00:00.000Z", + "parent": "", + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "A", + "parent": "2009-01-01T00:00:00.000Z", + "value": 8103, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "A", + "parent": "2010-01-01T00:00:00.000Z", + "value": 6814, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "B", + "parent": "2011-01-01T00:00:00.000Z", + "value": 3056, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "B", + "parent": "2012-01-01T00:00:00.000Z", + "value": 8423, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "A", + "parent": "2013-01-01T00:00:00.000Z", + "value": 2045, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "B", + "parent": "2014-01-01T00:00:00.000Z", + "value": 3010, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "A", + "parent": "2015-01-01T00:00:00.000Z", + "value": 5447, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "B", + "parent": "2016-01-01T00:00:00.000Z", + "value": 4242, + }, + { + "custom": { + "level": 2, + "levelsCount": 2, + }, + "name": "B", + "parent": "2018-01-01T00:00:00.000Z", + "value": 936, + }, + ], + "dataLabels": { + "style": { + "textOutline": "none", + }, + }, + "layoutAlgorithm": "strip", + "layoutStartingDirection": "horizontal", + "levels": [ + { + "borderColor": "white", + "borderWidth": 4, + "dataLabels": { + "align": "left", + "allowOverlap": true, + "enabled": true, + "formatter": [Function], + "padding": 0, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "useHTML": true, + "verticalAlign": "top", + }, + "layoutAlgorithm": "squarifiedWithTopSpacing", + "level": 1, + }, + { + "borderColor": "black", + "borderWidth": 1, + "dataLabels": { + "align": "left", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "14px", + }, + "verticalAlign": "top", + }, + "level": 2, + }, + { + "borderColor": "black", + "borderWidth": 1, + "dataLabels": { + "align": "center", + "enabled": true, + "formatter": [Function], + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + "fontSize": "13px", + }, + "verticalAlign": "middle", + }, + "level": 3, + }, + ], + "name": "Quantity", + "type": "treemap", + }, + ], + "title": { + "text": null, + }, + "tooltip": { + "animation": false, + "backgroundColor": "#FFFFFF", + "borderColor": "#CCCCCC", + "borderRadius": 10, + "borderWidth": 1, + "formatter": [Function], + "outside": true, + "style": { + "fontFamily": "\\"Open Sans\\",\\"Roboto\\",\\"Helvetica\\",\\"Arial\\",sans-serif", + }, + "useHTML": true, + }, + "xAxis": undefined, +} +`; diff --git a/packages/sdk-ui/src/components/chart.test.tsx b/packages/sdk-ui/src/components/chart.test.tsx index 4b1bf719..72efe6ce 100644 --- a/packages/sdk-ui/src/components/chart.test.tsx +++ b/packages/sdk-ui/src/components/chart.test.tsx @@ -95,6 +95,7 @@ it('change theme of a chart', () => { textColor: 'red', secondaryTextColor: 'green', backgroundColor: 'blue', + panelBackgroundColor: '#F6F6F6', }, }} > diff --git a/packages/sdk-ui/src/components/highcharts-wrapper.tsx b/packages/sdk-ui/src/components/highcharts-wrapper.tsx index ff565f9c..e9d1e233 100644 --- a/packages/sdk-ui/src/components/highcharts-wrapper.tsx +++ b/packages/sdk-ui/src/components/highcharts-wrapper.tsx @@ -67,6 +67,7 @@ export const HighchartsWrapper: FunctionComponent = ({ }) => { const chartRef = useRef(null); const chartContainerRef = useRef(null); + const isFirstRender = useRef(true); const chartContainerDefaultStyles = { // Container should inherit parent size for correct chart size calculation by Highcharts height: '100%', @@ -112,13 +113,15 @@ export const HighchartsWrapper: FunctionComponent = ({ }, []); useEffect(() => { - if (allowChartUpdate) { + if (allowChartUpdate && !isFirstRender.current) { if (immutable || !chartRef.current) { createChart(); } else { chartRef.current.update(options, ...(updateArgs || [true, true])); } } + + isFirstRender.current = false; }, [allowChartUpdate, immutable, options]); return
; diff --git a/packages/sdk-ui/src/components/no-results-overlay/images/index.ts b/packages/sdk-ui/src/components/no-results-overlay/images/index.ts index a18211bf..3186cd33 100644 --- a/packages/sdk-ui/src/components/no-results-overlay/images/index.ts +++ b/packages/sdk-ui/src/components/no-results-overlay/images/index.ts @@ -8,8 +8,10 @@ import pieChartNoResultsImage from './pie-no-results-small.svg'; import scatterChartNoResultsImage from './scatter-no-results-small.svg'; import indicatorChartNoResultsImage from './indicator-no-results-small.svg'; import tableNoResultsImage from './table-no-results-small.svg'; +import treemapChartNoResultsImage from './treemap-no-results-small.svg'; +import { ChartType, TableType } from '../../../types'; -export const noResultOverlayImages = { +const noResultOverlayImages = { area: areaChartNoResultsImage, line: lineChartNoResultsImage, bar: barChartNoResultsImage, @@ -20,4 +22,10 @@ export const noResultOverlayImages = { scatter: scatterChartNoResultsImage, indicator: indicatorChartNoResultsImage, table: tableNoResultsImage, + treemap: treemapChartNoResultsImage, }; + +export function getNoResultOverlayImage(type: ChartType | TableType) { + const defaultTypeFallback = 'bar'; + return noResultOverlayImages[type] ?? noResultOverlayImages[defaultTypeFallback]; +} diff --git a/packages/sdk-ui/src/components/no-results-overlay/images/treemap-no-results-small.svg b/packages/sdk-ui/src/components/no-results-overlay/images/treemap-no-results-small.svg new file mode 100644 index 00000000..fbe23854 --- /dev/null +++ b/packages/sdk-ui/src/components/no-results-overlay/images/treemap-no-results-small.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/packages/sdk-ui/src/components/no-results-overlay/no-results-overlay.tsx b/packages/sdk-ui/src/components/no-results-overlay/no-results-overlay.tsx index 74a51d16..73822d6d 100644 --- a/packages/sdk-ui/src/components/no-results-overlay/no-results-overlay.tsx +++ b/packages/sdk-ui/src/components/no-results-overlay/no-results-overlay.tsx @@ -2,7 +2,7 @@ import styles from './no-results-overlay.module.scss'; import { useEffect, useRef, useState } from 'react'; import { useThemeContext } from '../theme-provider'; import { ChartType, TableType } from '../../types'; -import { noResultOverlayImages } from './images'; +import { getNoResultOverlayImage } from './images'; import { translation } from '../../locales/en'; /** @@ -30,7 +30,7 @@ export const NoResultsOverlay = ({ iconType }: { iconType: ChartType | TableType } }, []); - const icon = noResultOverlayImages[iconType]; + const icon = getNoResultOverlayImage(iconType); return (
diff --git a/packages/sdk-ui/src/components/query-execution/execute-query-by-widget-id.tsx b/packages/sdk-ui/src/components/query-execution/execute-query-by-widget-id.tsx index 1266f988..5487e0c0 100644 --- a/packages/sdk-ui/src/components/query-execution/execute-query-by-widget-id.tsx +++ b/packages/sdk-ui/src/components/query-execution/execute-query-by-widget-id.tsx @@ -32,23 +32,36 @@ import { useExecuteQueryByWidgetId } from './use-execute-query-by-widget-id'; export const ExecuteQueryByWidgetId: FunctionComponent = asSisenseComponent({ componentName: 'ExecuteQueryByWidgetId', - })(({ widgetOid, dashboardOid, children, onDataChanged }) => { - const { data, query, error } = useExecuteQueryByWidgetId({ + })( + ({ widgetOid, dashboardOid, - }); + children, + onDataChanged, + filters, + highlights, + filtersMergeStrategy, + }) => { + const { data, query, error } = useExecuteQueryByWidgetId({ + widgetOid, + dashboardOid, + filters, + highlights, + filtersMergeStrategy, + }); - const [prevData, setPrevData] = useState(data); - if (prevData !== data) { - setPrevData(data); - if (data && query) { - onDataChanged?.(data, query); + const [prevData, setPrevData] = useState(data); + if (prevData !== data) { + setPrevData(data); + if (data && query) { + onDataChanged?.(data, query); + } } - } - if (error) { - throw error; - } + if (error) { + throw error; + } - return <>{data && query && children?.(data, query)}; - }); + return <>{data && query && children?.(data, query)}; + }, + ); diff --git a/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.test.ts b/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.test.ts index 1b1c545a..aae47bce 100644 --- a/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.test.ts +++ b/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.test.ts @@ -1,6 +1,10 @@ import { renderHook, waitFor } from '@testing-library/react'; import type { Mock } from 'vitest'; -import { QueryResultData } from '@sisense/sdk-data'; +import { + QueryResultData, + filters as filtersFactory, + DimensionalAttribute, +} from '@sisense/sdk-data'; import { useExecuteQueryByWidgetId, ExecuteQueryByWidgetIdParams, @@ -9,7 +13,12 @@ import { executeQuery } from '../../query/execute-query.js'; import { ClientApplication } from '../../app/client-application.js'; import { useSisenseContext } from '../sisense-context/sisense-context.js'; import { fetchWidget } from '../../dashboard-widget/fetch-widget'; -import { BaseJaql, FilterJaql, WidgetDto } from '../../dashboard-widget/types.js'; +import { + BaseJaql, + FilterJaql, + IncludeMembersFilter, + WidgetDto, +} from '../../dashboard-widget/types.js'; vi.mock('../../query/execute-query', () => ({ executeQuery: vi.fn(), @@ -50,6 +59,51 @@ const mockWidget = { }, } as unknown as WidgetDto; +const mockWidgetWithMetadataItems = { + ...mockWidget, + metadata: { + panels: [ + { + name: 'some panel with dimensions', + items: [ + { + jaql: { + title: 'some dimension title', + dim: 'some dimension', + } as unknown as BaseJaql, + }, + ], + }, + { + name: 'some panel with measures', + items: [ + { + jaql: { + title: 'some measure title', + dim: 'some measure', + agg: 'sum', + } as unknown as BaseJaql, + }, + ], + }, + { + name: 'some panel with filters', + items: [ + { + jaql: { + title: 'some fitler title', + dim: 'some filter', + filter: { + members: ['some member'], + }, + } as unknown as FilterJaql, + }, + ], + }, + ], + }, +}; + describe('useExecuteQueryByWidgetId', () => { const params: ExecuteQueryByWidgetIdParams = { widgetOid: '64473e07dac1920034bce77f', @@ -84,50 +138,7 @@ describe('useExecuteQueryByWidgetId', () => { it('should correctly generate query over the widget', async () => { const mockData: QueryResultData = { columns: [], rows: [] }; - const mockWidgetWithMetadataItems = { - ...mockWidget, - metadata: { - panels: [ - { - name: 'some panel with dimensions', - items: [ - { - jaql: { - title: 'some dimension title', - dim: 'some dimension', - } as unknown as BaseJaql, - }, - ], - }, - { - name: 'some panel with measures', - items: [ - { - jaql: { - title: 'some measure title', - dim: 'some measure', - agg: 'sum', - } as unknown as BaseJaql, - }, - ], - }, - { - name: 'some panel with filters', - items: [ - { - jaql: { - title: 'some fitler title', - dim: 'some filter', - filter: { - members: ['some member'], - }, - } as unknown as FilterJaql, - }, - ], - }, - ], - }, - }; + executeQueryMock.mockResolvedValue(mockData); fetchWidgetMock.mockResolvedValue(mockWidgetWithMetadataItems); @@ -153,6 +164,166 @@ describe('useExecuteQueryByWidgetId', () => { }); }); + it('should add provided "filters" and "highlights" to the query', async () => { + const mockData: QueryResultData = { columns: [], rows: [] }; + const filters = [ + filtersFactory.members(new DimensionalAttribute('some name', 'some new filter attribute'), [ + 'some value', + ]), + ]; + const highlights = [ + filtersFactory.members( + new DimensionalAttribute('some name', 'some new highlight filter attribute'), + ['some value'], + ), + ]; + + executeQueryMock.mockResolvedValue(mockData); + fetchWidgetMock.mockResolvedValue(mockWidgetWithMetadataItems); + + const { result } = renderHook(() => + useExecuteQueryByWidgetId({ + ...params, + filters, + highlights, + }), + ); + + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + // verifies query filters + expect(result.current.query?.filters?.length).toBe(2); // one widget filter + one provided filter via props + expect( + result.current.query?.filters?.find( + (filter) => (filter.jaql(true) as FilterJaql).dim === filters[0].attribute.expression, + ), + ).toBeDefined(); + + // verifies highlight filters + expect(result.current.query?.highlights?.length).toBe(1); // one provided highlight filter via props + expect( + result.current.query?.highlights?.find( + (filter) => (filter.jaql(true) as FilterJaql).dim === highlights[0].attribute.expression, + ), + ).toBeDefined(); + }); + }); + + it('should merge provided "filters" with existing widget filters using default `widgetFirst` strategy', async () => { + const mockData: QueryResultData = { columns: [], rows: [] }; + const filters = [ + // filter with the same target attribure as already exist in widget + filtersFactory.members( + new DimensionalAttribute( + 'some name', + mockWidgetWithMetadataItems.metadata.panels[2].items[0].jaql.dim, + ), + ['some value of provided filter'], + ), + ]; + + executeQueryMock.mockResolvedValue(mockData); + fetchWidgetMock.mockResolvedValue(mockWidgetWithMetadataItems); + + const { result } = renderHook(() => + useExecuteQueryByWidgetId({ + ...params, + filters, + }), + ); + + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + // verifies that query contain only widget filter, while provided filter was ignored due to the lower priority + expect(result.current.query?.filters?.length).toBe(1); + expect( + ( + (result.current.query?.filters?.[0].jaql(true) as FilterJaql) + .filter as IncludeMembersFilter + ).members, + ).toStrictEqual( + ( + (mockWidgetWithMetadataItems.metadata.panels[2].items[0].jaql as FilterJaql) + .filter as IncludeMembersFilter + ).members, + ); + }); + }); + + it('should merge provided "filters" with existing widget filters using `codeFirst` strategy', async () => { + const mockData: QueryResultData = { columns: [], rows: [] }; + const filters = [ + // filter with the same target attribure as already exist in widget + filtersFactory.members( + new DimensionalAttribute( + 'some name', + mockWidgetWithMetadataItems.metadata.panels[2].items[0].jaql.dim, + ), + ['some value of provided filter'], + ), + ]; + + executeQueryMock.mockResolvedValue(mockData); + fetchWidgetMock.mockResolvedValue(mockWidgetWithMetadataItems); + + const { result } = renderHook(() => + useExecuteQueryByWidgetId({ + ...params, + filters, + filtersMergeStrategy: 'codeFirst', + }), + ); + + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + // verifies that query contain only provided filter, while widget filter was ignored due to the lower priority + expect(result.current.query?.filters?.length).toBe(1); + expect( + ( + (result.current.query?.filters?.[0].jaql(true) as FilterJaql) + .filter as IncludeMembersFilter + ).members, + ).toStrictEqual( + ((filters[0].jaql(true) as FilterJaql).filter as IncludeMembersFilter).members, + ); + }); + }); + + it('should merge provided "filters" with existing widget filters using `codeOnly` strategy', async () => { + const mockData: QueryResultData = { columns: [], rows: [] }; + const filters = [ + // filter with the new target attribure that not exist in widget + filtersFactory.members(new DimensionalAttribute('some name', 'some new filter attribute'), [ + 'some value of provided filter', + ]), + ]; + + executeQueryMock.mockResolvedValue(mockData); + fetchWidgetMock.mockResolvedValue(mockWidgetWithMetadataItems); + + const { result } = renderHook(() => + useExecuteQueryByWidgetId({ + ...params, + filters, + filtersMergeStrategy: 'codeOnly', + }), + ); + + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + // verifies that query contain only provided filter, while widget filter was fully ignored + expect(result.current.query?.filters?.length).toBe(1); + expect( + ( + (result.current.query?.filters?.[0].jaql(true) as FilterJaql) + .filter as IncludeMembersFilter + ).members, + ).toStrictEqual( + ((filters[0].jaql(true) as FilterJaql).filter as IncludeMembersFilter).members, + ); + }); + }); + it('should handle widget fetch error', async () => { const mockError = new Error('Widget fetch error'); fetchWidgetMock.mockRejectedValueOnce(mockError); diff --git a/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.ts b/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.ts index 1efa26c2..d6aa0e11 100644 --- a/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.ts +++ b/packages/sdk-ui/src/components/query-execution/use-execute-query-by-widget-id.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines-per-function */ import { useEffect, useReducer, useRef, useState } from 'react'; import { Attribute, Measure, Filter, MetadataTypes } from '@sisense/sdk-data'; import { ExecuteQueryParams } from './index.js'; @@ -7,20 +8,35 @@ import { translation } from '../../locales/en.js'; import { fetchWidget } from '../../dashboard-widget/fetch-widget'; import { createDimensionalElementFromJaql } from '../../dashboard-widget/translate-widget-data-options'; import { executeQuery } from '../../query/execute-query.js'; -import { getRootPanelItem } from '../../dashboard-widget/utils.js'; -import { WidgetDto } from '../../dashboard-widget/types.js'; +import { + getRootPanelItem, + mergeFilters, + mergeFiltersByStrategy, +} from '../../dashboard-widget/utils.js'; +import { FiltersMergeStrategy, WidgetDto } from '../../dashboard-widget/types.js'; import { usePrevious } from './use-execute-query.js'; import { isEqual } from 'lodash'; +import { isFiltersChanged } from '../../utils/filters-comparator.js'; /** * Parameters for {@link useExecuteQueryByWidgetId} hook. */ -export type ExecuteQueryByWidgetIdParams = { - /** Identifier of the widget */ +export interface ExecuteQueryByWidgetIdParams { + /** {@inheritDoc ExecuteQueryByWidgetIdProps.widgetOid} */ widgetOid: string; - /** Identifier of the dashboard */ + + /** {@inheritDoc ExecuteQueryByWidgetIdProps.dashboardOid} */ dashboardOid: string; -}; + + /** {@inheritDoc ExecuteQueryByWidgetIdProps.filters} */ + filters?: Filter[]; + + /** {@inheritDoc ExecuteQueryByWidgetIdProps.highlights} */ + highlights?: Filter[]; + + /** {@inheritDoc ExecuteQueryByWidgetIdProps.filtersMergeStrategy} */ + filtersMergeStrategy?: FiltersMergeStrategy; +} export type QueryByWidgetIdState = QueryState & { /** Query parameters constructed over the widget */ @@ -91,8 +107,19 @@ export const useExecuteQueryByWidgetId = (params: ExecuteQueryByWidgetIdParams) void fetchWidget(widgetOid, dashboardOid, app) .then((fetchedWidget: WidgetDto) => { - const { dataSource, dimensions, measures, filters, highlights } = - extractQueryFromWidget(fetchedWidget); + const { + dataSource, + dimensions, + measures, + filters: widgetFilters, + highlights: widgetHighlights, + } = extractQueryFromWidget(fetchedWidget); + const filters = mergeFiltersByStrategy( + widgetFilters, + params.filters, + params.filtersMergeStrategy, + ); + const highlights = mergeFilters(params.highlights, widgetHighlights); query.current = { dataSource, dimensions, measures, filters, highlights }; return executeQuery(dataSource, dimensions, measures, filters, highlights, app); }) @@ -121,8 +148,16 @@ function isParamsChanged( if (!prevParams && newParams) { return true; } - return ['widgetOid', 'dashboardOid'].some( - (paramName) => !isEqual(prevParams?.[paramName], newParams[paramName]), + + const isRegularFiltersChanged = isFiltersChanged(prevParams!.filters, newParams.filters); + const isHighlightFiltersChanged = isFiltersChanged(prevParams!.highlights, newParams.highlights); + + return ( + ['widgetOid', 'dashboardOid'].some( + (paramName) => !isEqual(prevParams?.[paramName], newParams[paramName]), + ) || + isRegularFiltersChanged || + isHighlightFiltersChanged ); } diff --git a/packages/sdk-ui/src/components/query-execution/use-execute-query.test.ts b/packages/sdk-ui/src/components/query-execution/use-execute-query.test.ts index cf02903d..02421ce9 100644 --- a/packages/sdk-ui/src/components/query-execution/use-execute-query.test.ts +++ b/packages/sdk-ui/src/components/query-execution/use-execute-query.test.ts @@ -62,6 +62,21 @@ describe('useExecuteQuery', () => { }); }); + it('if enabled is set to false, should return initial state', async () => { + const mockData: QueryResultData = { columns: [], rows: [] }; + executeQueryMock.mockResolvedValue(mockData); + + const { result } = renderHook(() => useExecuteQuery({ ...params, enabled: false })); + + expect(result.current.isLoading).toBe(true); + + await waitFor(() => { + expect(result.current.isLoading).toBe(true); + expect(result.current.isSuccess).toBe(false); + expect(result.current.data).toBeUndefined(); + }); + }); + it('should handle query error', async () => { const mockError = new Error('Test error'); executeQueryMock.mockRejectedValue(mockError); diff --git a/packages/sdk-ui/src/components/query-execution/use-execute-query.ts b/packages/sdk-ui/src/components/query-execution/use-execute-query.ts index 8b5c3c49..4df10b1d 100644 --- a/packages/sdk-ui/src/components/query-execution/use-execute-query.ts +++ b/packages/sdk-ui/src/components/query-execution/use-execute-query.ts @@ -29,6 +29,13 @@ export type ExecuteQueryParams = { /** Highlight filters that will highlight results that pass filter criteria */ highlights?: Filter[]; + + /** + * Boolean flag to control if query is executed + * + * If not specified, the default value is `true` + */ + enabled?: boolean; }; /** @@ -81,6 +88,9 @@ export const useExecuteQuery = (params: ExecuteQueryParams): QueryState => { if (!app) { return; } + if (params?.enabled === false) { + return; + } if (isNeverExecuted || isQueryParamsChanged(prevParams, params)) { if (isNeverExecuted) { setIsNeverExecuted(false); diff --git a/packages/sdk-ui/src/components/table/__snapshots__/table.test.tsx.snap b/packages/sdk-ui/src/components/table/__snapshots__/table.test.tsx.snap index 02817641..99cef2ea 100644 --- a/packages/sdk-ui/src/components/table/__snapshots__/table.test.tsx.snap +++ b/packages/sdk-ui/src/components/table/__snapshots__/table.test.tsx.snap @@ -256,7 +256,7 @@ exports[`Table > should render Table 1`] = ` style="max-width: 102px;" >
- 1000 + 1K
@@ -366,7 +366,7 @@ exports[`Table > should render Table 1`] = ` style="max-width: 102px;" >
- 19.123 + 19.12
diff --git a/packages/sdk-ui/src/components/treemap-chart.test.tsx b/packages/sdk-ui/src/components/treemap-chart.test.tsx new file mode 100644 index 00000000..bf16ce00 --- /dev/null +++ b/packages/sdk-ui/src/components/treemap-chart.test.tsx @@ -0,0 +1,145 @@ +import { render } from '@testing-library/react'; +import { HighchartsOptions } from '../chart-options-processor/chart-options-service'; +import { useSisenseContext } from './sisense-context/sisense-context'; +import { DAYS, JAN, MON } from '../query/date-formats/apply-date-format'; +import { getDefaultThemeSettings } from '../chart-options-processor/theme-option-service'; +import { getBaseDateFnsLocale } from '../chart-data-processor/data-table-date-period'; +import { ClientApplication } from '../app/client-application'; +import { TreemapChart } from './treemap-chart'; + +vi.mock('./HighchartsWrapper', () => { + return { + HighchartsWrapper: ({ options }: { options: object }) => { + return
{JSON.stringify(options)}
; + }, + }; +}); + +vi.mock('./sisense-context/sisense-context', async () => { + const actual: typeof import('./sisense-context/sisense-context') = await vi.importActual( + './sisense-context/sisense-context', + ); + + const useSisenseContextMock: typeof useSisenseContext = () => ({ + app: { + settings: { + dateConfig: { + weekFirstDay: MON, + isFiscalOn: false, + fiscalMonth: JAN, + selectedDateLevel: DAYS, + timeZone: 'UTC', + }, + serverThemeSettings: getDefaultThemeSettings(), + locale: getBaseDateFnsLocale(), + }, + } as ClientApplication, + + isInitialized: true, + enableTracking: true, + }); + + return { + ...actual, + useSisenseContext: useSisenseContextMock, + }; +}); + +const dataSet = { + columns: [ + { name: 'Gender', type: 'string' }, + { name: 'Years', type: 'date' }, + { name: 'Group', type: 'string' }, + { name: 'Quantity', type: 'number' }, + { name: 'Units', type: 'number' }, + ], + rows: [ + ['Male', '2009', 'A', 6781, 10], + ['Male', '2010', 'A', 4471, 70], + ['Male', '2011', 'B', 1812, 50], + ['Male', '2012', 'B', 5001, 60], + ['Female', '2009', 'A', 1322, 10], + ['Female', '2010', 'A', 2343, 70], + ['Female', '2011', 'B', 1244, 50], + ['Female', '2012', 'B', 3422, 60], + ['Male', '2013', 'A', 2045, 40], + ['Male', '2014', 'B', 3010, 90], + ['Male', '2015', 'A', 5447, 80], + ['Male', '2016', 'B', 4242, 70], + ['Male', '2018', 'B', 936, 20], + ], +}; + +const cat1 = { + name: 'Years', + type: 'date', +}; + +const cat2 = { + name: 'Group', + type: 'string', +}; + +const cat3 = { + name: 'Gender', + type: 'string', +}; + +const meas1 = { + column: { name: 'Quantity', aggregation: 'sum' }, + showOnRightAxis: false, +}; + +describe('Treemap Chart', () => { + it('render a treemap with single category', () => { + render( + { + expect(options).toMatchSnapshot(); + return options; + }} + />, + ); + }); + + it('render a treemap with two categories', () => { + render( + { + expect(options).toMatchSnapshot(); + return options; + }} + />, + ); + }); + + it('render a treemap with three categories', () => { + render( + { + expect(options).toMatchSnapshot(); + return options; + }} + />, + ); + }); + + it('render a treemap with coloring', () => { + render( + { + expect(options).toMatchSnapshot(); + return options; + }} + />, + ); + }); +}); diff --git a/packages/sdk-ui/src/components/treemap-chart.tsx b/packages/sdk-ui/src/components/treemap-chart.tsx new file mode 100644 index 00000000..0b23afae --- /dev/null +++ b/packages/sdk-ui/src/components/treemap-chart.tsx @@ -0,0 +1,41 @@ +import { TreemapChartProps } from '../props'; +import { Chart, shouldSkipSisenseContextWaiting } from './chart'; +import { asSisenseComponent } from './decorators/as-sisense-component'; + +/** + * A React component displaying hierarchical data in the form of nested rectangles. + * This type of chart can be used in different scenarios, for example, + * instead of a column chart if you have to compare too many categories and sub-categories. + * See [Treemap Chart](https://docs.sisense.com/main/SisenseLinux/treemap.htm) for more information. + * + * @example + * An example of using the component to visualize the `Sample ECommerce` data source: + * ```tsx + * { + * console.log('clicked', point, nativeEvent); + * }} + * /> + * ``` + * ### + * + * @param props - Treemap chart properties + * @returns Treemap Chart component + */ +export const TreemapChart = asSisenseComponent({ + componentName: 'TreemapChart', + shouldSkipSisenseContextWaiting, +})((props: TreemapChartProps) => { + return ; +}); diff --git a/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx b/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx index cd07952e..8539868e 100644 --- a/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx +++ b/packages/sdk-ui/src/dashboard-widget/dashboard-widget.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useMemo, useState, type FunctionComponent } from 'react'; -import unionBy from 'lodash/unionBy'; import { ChartWidget } from '../widgets/chart-widget'; import { TableWidget } from '../widgets/table-widget'; import { extractWidgetProps } from './translate-widget'; @@ -10,6 +9,7 @@ import { useSisenseContext } from '../components/sisense-context/sisense-context import { useThemeContext } from '../components/theme-provider'; import { translation } from '../locales/en'; import { asSisenseComponent } from '../components/decorators/as-sisense-component'; +import { mergeFiltersByStrategy } from './utils'; /** * The Dashboard Widget component, which is a thin wrapper on the {@link ChartWidget} component, @@ -64,12 +64,10 @@ export const DashboardWidget: FunctionComponent = asSisens [fetchedWidget, themeSettings], ); - const filters = unionBy( + const filters = mergeFiltersByStrategy( fetchedProps?.filters, restProps.filters, - // TODO: remove fallback on 'filter.jaql()' after removing temporal 'jaql()' workaround from filter translation layer - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - (filter) => filter.attribute?.expression ?? filter.jaql().jaql.dim, + restProps.filtersMergeStrategy, ); if (!fetchedProps) { diff --git a/packages/sdk-ui/src/dashboard-widget/translate-widget-data-options.ts b/packages/sdk-ui/src/dashboard-widget/translate-widget-data-options.ts index d7f05aa1..dfa3a7f9 100644 --- a/packages/sdk-ui/src/dashboard-widget/translate-widget-data-options.ts +++ b/packages/sdk-ui/src/dashboard-widget/translate-widget-data-options.ts @@ -136,6 +136,7 @@ export function createDataColumn(item: PanelItem, themeSettings?: CompleteThemeS return { column: element, + isColored: item.isColored ?? false, ...(sortType && { sortType }), ...(numberFormatConfig && { numberFormatConfig }), } as StyledColumn; @@ -179,12 +180,18 @@ function extractCategoricalChartDataOptions( ): CategoricalChartDataOptions { const category = createColumnsFromPanelItems(panels, 'categories', themeSettings); const value = createColumnsFromPanelItems(panels, 'values', themeSettings); - const membersFormat = getEnabledPanelItems(panels, 'categories')[0]?.format?.members; + const size = createColumnsFromPanelItems(panels, 'size', themeSettings); + let membersFormat = getEnabledPanelItems(panels, 'categories')[0]?.format?.members; + + if (getEnabledPanelItems(panels, 'color').length) { + membersFormat = getEnabledPanelItems(panels, 'color')[0]?.format?.members; + } + const seriesToColorMap = membersFormat && createValueToColorMap(membersFormat); return { category: category as StyledColumn[], - value, + value: [...value, ...size], ...(seriesToColorMap && { seriesToColorMap }), }; } @@ -251,6 +258,7 @@ export function extractDataOptions( return extractCartesianChartDataOptions(panels, widgetType, themeSettings); case WidgetType.PieChart: case WidgetType.FunnelChart: + case WidgetType.TreemapChart: return extractCategoricalChartDataOptions(panels, themeSettings); case WidgetType.ScatterChart: return extractScatterChartDataOptions(panels, themeSettings); diff --git a/packages/sdk-ui/src/dashboard-widget/translate-widget-drilldown-options.ts b/packages/sdk-ui/src/dashboard-widget/translate-widget-drilldown-options.ts index ffd27a7c..e98f2363 100644 --- a/packages/sdk-ui/src/dashboard-widget/translate-widget-drilldown-options.ts +++ b/packages/sdk-ui/src/dashboard-widget/translate-widget-drilldown-options.ts @@ -13,9 +13,9 @@ const getAvailableDrilldowns = (item: PanelItem): Attribute[] => /* eslint complexity: ['error', 9] */ const getDrilldownSelections = ( item?: PanelItem, -): { nextCategory: Attribute; points: DataPoint[] }[] => { +): { nextDimension: Attribute; points: DataPoint[] }[] => { if (item?.parent && item.through && 'filter' in item.through.jaql) { - const nextCategory = createDataColumn(item).column as Attribute; + const nextDimension = createDataColumn(item).column as Attribute; const { jaql, format: { mask } = {} } = item.parent; const dateFormat = 'level' in jaql && jaql.level && mask && (mask as DatetimeMask)[jaql.level]; @@ -29,7 +29,7 @@ const getDrilldownSelections = ( : (member) => ({ categoryValue: member }), ) ?? []; - return [...getDrilldownSelections(item.parent), { nextCategory, points }]; + return [...getDrilldownSelections(item.parent), { nextDimension, points }]; } return []; }; @@ -44,9 +44,9 @@ export const extractDrilldownOptions = ( const item = getEnabledPanelItems(panels, categoriesPanelName)[0]; const drilldownSelections = getDrilldownSelections(item); - const drilldownCategories = getAvailableDrilldowns(item); + const drilldownDimensions = getAvailableDrilldowns(item); return { - drilldownCategories, + drilldownDimensions, drilldownSelections, }; }; diff --git a/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.test.ts b/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.test.ts index 165aca4e..ceb5db05 100644 --- a/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.test.ts +++ b/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.test.ts @@ -4,7 +4,7 @@ import { extractStyleOptions, getIndicatorTypeSpecificOptions, } from './translate-widget-style-options'; -import { AreaStyleOptions, BaseStyleOptions } from '../types'; +import { AreaStyleOptions, BaseAxisStyleOptions, BaseStyleOptions } from '../types'; import { CartesianWidgetStyle, FunnelWidgetStyle, @@ -12,11 +12,14 @@ import { PanelItem, PolarWidgetStyle, ScatterWidgetStyle, + TreemapWidgetStyle, WidgetSubtype, WidgetType, } from './types'; import { jaqlMock } from './__mocks__/jaql-mock'; +type BaseStyleOptionsWithAxes = BaseStyleOptions & BaseAxisStyleOptions; + function generateWidgetAxisOptions(options = {}) { const defaultOptions = { enabled: true, @@ -92,7 +95,7 @@ describe('translate widget style options', () => { '' as WidgetSubtype, widgetStyle, widgetPanels, - ) as BaseStyleOptions; + ) as BaseStyleOptionsWithAxes; expect(styleOptions.xAxis).toEqual({ ...widgetStyle.xAxis, @@ -115,7 +118,7 @@ describe('translate widget style options', () => { '' as WidgetSubtype, widgetStyle, widgetPanels, - ) as BaseStyleOptions; + ) as BaseStyleOptionsWithAxes; expect(styleOptions.xAxis?.title?.text).toEqual(widgetPanels[0].items[1].jaql.title); expect(styleOptions.xAxis?.x2Title?.text).toEqual(widgetPanels[0].items[0].jaql.title); @@ -181,7 +184,7 @@ describe('translate widget style options', () => { '' as WidgetSubtype, widgetStyle, widgetPanels, - ) as BaseStyleOptions; + ) as BaseStyleOptionsWithAxes; expect(styleOptions.xAxis).toEqual(widgetStyle.categories); expect(styleOptions.yAxis).toEqual({ @@ -204,7 +207,7 @@ describe('translate widget style options', () => { '' as WidgetSubtype, widgetStyle, widgetPanels, - ) as BaseStyleOptions; + ) as BaseStyleOptionsWithAxes; expect(styleOptions.xAxis?.title?.text).toEqual(widgetPanels[0].items[0].jaql.title); }); @@ -241,7 +244,7 @@ describe('translate widget style options', () => { '' as WidgetSubtype, widgetStyle, widgetPanels, - ) as BaseStyleOptions; + ) as BaseStyleOptionsWithAxes; expect(styleOptions.xAxis).toEqual(widgetStyle.xAxis); expect(styleOptions.yAxis).toEqual(widgetStyle.yAxis); @@ -258,7 +261,7 @@ describe('translate widget style options', () => { '' as WidgetSubtype, widgetStyle, widgetPanels, - ) as BaseStyleOptions; + ) as BaseStyleOptionsWithAxes; expect(styleOptions.xAxis?.title?.text).toEqual(widgetPanels[0].items[0].jaql.title); expect(styleOptions.yAxis?.title?.text).toEqual(widgetPanels[1].items[0].jaql.title); @@ -440,4 +443,64 @@ describe('translate widget style options', () => { ).toStrictEqual(expectedResult); }); }); + + describe('should prepare correct treemap style options', () => { + it('case 1 - default', () => { + const widgetStyle = { + 'title/1': true, + 'title/2': true, + 'title/3': true, + 'tooltip/value': true, + } as TreemapWidgetStyle; + + const expected = { + labels: { + category: [{ enabled: true }, { enabled: true }, { enabled: true }], + }, + tooltip: { + mode: 'value', + }, + }; + const result = extractStyleOptions(WidgetType.TreemapChart, 'treemap', widgetStyle, []); + + expect(result).toEqual(expected); + }); + + it('case 2 - disabled labels and contribution mode', () => { + const widgetStyle = { + 'title/1': false, + 'title/2': false, + 'title/3': false, + 'tooltip/value': false, + } as TreemapWidgetStyle; + + const expected = { + labels: { + category: [{ enabled: false }, { enabled: false }, { enabled: false }], + }, + tooltip: { + mode: 'contribution', + }, + }; + const result = extractStyleOptions(WidgetType.TreemapChart, 'treemap', widgetStyle, []); + + expect(result).toEqual(expected); + }); + + it('case 3 - empty widget style', () => { + const widgetStyle = {} as TreemapWidgetStyle; + + const expected = { + labels: { + category: [{ enabled: true }, { enabled: true }, { enabled: true }], + }, + tooltip: { + mode: 'value', + }, + }; + const result = extractStyleOptions(WidgetType.TreemapChart, 'treemap', widgetStyle, []); + + expect(result).toEqual(expected); + }); + }); }); diff --git a/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.ts b/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.ts index 9166bff9..970c4eab 100644 --- a/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.ts +++ b/packages/sdk-ui/src/dashboard-widget/translate-widget-style-options.ts @@ -8,7 +8,6 @@ import { AreaStyleOptions, StackableStyleOptions, AxisLabel, - BaseStyleOptions, PolarStyleOptions, ScatterStyleOptions, FunnelStyleOptions, @@ -17,6 +16,8 @@ import { NumericBarIndicatorStyleOptions, NumericSimpleIndicatorStyleOptions, GaugeIndicatorStyleOptions, + TreemapStyleOptions, + BaseAxisStyleOptions, } from '../types'; import { Panel, @@ -29,6 +30,7 @@ import { ScatterWidgetStyle, TableWidgetStyle, IndicatorWidgetStyle, + TreemapWidgetStyle, AxisStyle, } from './types'; import { getEnabledPanelItems, getChartSubtype } from './utils'; @@ -53,7 +55,7 @@ function extractAxisStyleOptions(widgetAxisStyleOptions?: AxisStyle) { }; } -type AxisStyleOptions = Pick; +type AxisStyleOptions = Pick; function prepareCartesianChartAxisOptions( widgetType: WidgetType, @@ -320,6 +322,21 @@ function extractIndicatorChartStyleOptions( }; } +function extractTreemapChartStyleOptions(widgetStyle: TreemapWidgetStyle): TreemapStyleOptions { + return { + labels: { + category: [ + { enabled: widgetStyle['title/1'] ?? true }, + { enabled: widgetStyle['title/2'] ?? true }, + { enabled: widgetStyle['title/3'] ?? true }, + ], + }, + tooltip: { + mode: widgetStyle['tooltip/value'] ?? true ? 'value' : 'contribution', + }, + }; +} + export function extractStyleOptions( widgetType: WidgetType, widgetSubtype: WidgetSubtype, @@ -343,6 +360,8 @@ export function extractStyleOptions( return extractScatterChartDataOptions(widgetSubtype, style as ScatterWidgetStyle, panels); case WidgetType.FunnelChart: return extractFunnelChartDataOptions(widgetSubtype, style as FunnelWidgetStyle); + case WidgetType.TreemapChart: + return extractTreemapChartStyleOptions(style as TreemapWidgetStyle); case WidgetType.PieChart: return extractBaseStyleOptions(widgetSubtype, style); case WidgetType.Table: diff --git a/packages/sdk-ui/src/dashboard-widget/translate-widget.test.ts b/packages/sdk-ui/src/dashboard-widget/translate-widget.test.ts index 7b4f5788..d7dca807 100644 --- a/packages/sdk-ui/src/dashboard-widget/translate-widget.test.ts +++ b/packages/sdk-ui/src/dashboard-widget/translate-widget.test.ts @@ -219,18 +219,18 @@ describe('translate widget', () => { const { category } = dataOptions as CartesianChartDataOptions; verifyColumn(category[0], widget.metadata.panels[0].items[0].parent!.parent!); - verifyColumn(drilldownOptions?.drilldownCategories![1]!, widget.metadata.panels[0].items[0]); + verifyColumn(drilldownOptions?.drilldownDimensions![1]!, widget.metadata.panels[0].items[0]); verifyColumn( - drilldownOptions?.drilldownCategories![0]!, + drilldownOptions?.drilldownDimensions![0]!, widget.metadata.panels[0].items[0].parent!, ); verifyColumn( - drilldownOptions?.drilldownSelections![1].nextCategory!, + drilldownOptions?.drilldownSelections![1].nextDimension!, widget.metadata.panels[0].items[0], ); verifyColumn( - drilldownOptions?.drilldownSelections![0].nextCategory!, + drilldownOptions?.drilldownSelections![0].nextDimension!, widget.metadata.panels[0].items[0].parent!, ); expect(drilldownOptions?.drilldownSelections![1].points).toEqual([ diff --git a/packages/sdk-ui/src/dashboard-widget/types.ts b/packages/sdk-ui/src/dashboard-widget/types.ts index ecc07ffd..cd74bf38 100644 --- a/packages/sdk-ui/src/dashboard-widget/types.ts +++ b/packages/sdk-ui/src/dashboard-widget/types.ts @@ -6,6 +6,7 @@ export const enum WidgetType { LineChart = 'chart/line', AreaChart = 'chart/area', FunnelChart = 'chart/funnel', + TreemapChart = 'treemap', ScatterChart = 'chart/scatter', IndicatorChart = 'indicator', PolarChart = 'chart/polar', @@ -36,7 +37,8 @@ export type WidgetSubtype = | 'line/polar' | 'indicator/numeric' | 'indicator/gauge' - | 'bubble/scatter'; + | 'bubble/scatter' + | 'treemap'; /** * The data transfer object (DTO) containing info of a widget on a dashboard. @@ -184,6 +186,7 @@ export type PanelItem = { through?: PanelItem; singleSeriesType?: SeriesType; categoriesSorting?: SortDirection; + isColored?: boolean; }; export type PanelColorFormat = @@ -396,10 +399,27 @@ export type IndicatorWidgetStyle = { }; }; +export type TreemapWidgetStyle = { + 'title/1': boolean; + 'title/2': boolean; + 'title/3': boolean; + 'tooltip/contribution': boolean; + 'tooltip/value': boolean; +}; + export type WidgetStyle = | CartesianWidgetStyle | PolarWidgetStyle | FunnelWidgetStyle | ScatterWidgetStyle | TableWidgetStyle - | IndicatorWidgetStyle; + | IndicatorWidgetStyle + | TreemapWidgetStyle; + +export enum FiltersMergeStrategyEnum { + WIDGET_FIRST = 'widgetFirst', + CODE_FIRST = 'codeFirst', + CODE_ONLY = 'codeOnly', +} + +export type FiltersMergeStrategy = `${FiltersMergeStrategyEnum}`; diff --git a/packages/sdk-ui/src/dashboard-widget/utils.ts b/packages/sdk-ui/src/dashboard-widget/utils.ts index 47db588e..6e11122a 100644 --- a/packages/sdk-ui/src/dashboard-widget/utils.ts +++ b/packages/sdk-ui/src/dashboard-widget/utils.ts @@ -1,6 +1,10 @@ +import { type Filter } from '@sisense/sdk-data'; +import unionBy from 'lodash/unionBy'; import { ChartSubtype } from '../chart-options-processor/subtype-to-design-options'; import { ChartType, SortDirection } from '../types'; import { + FiltersMergeStrategy, + FiltersMergeStrategyEnum, Panel, PanelItem, SortDirection as JaqlSortDirection, @@ -17,6 +21,7 @@ export function getChartType(widgetType: WidgetType) { [WidgetType.PolarChart]: 'polar', [WidgetType.PieChart]: 'pie', [WidgetType.FunnelChart]: 'funnel', + [WidgetType.TreemapChart]: 'treemap', [WidgetType.ScatterChart]: 'scatter', [WidgetType.IndicatorChart]: 'indicator', }; @@ -48,6 +53,7 @@ export function getChartSubtype(widgetSubtype: WidgetSubtype): ChartSubtype | un 'line/polar': 'polar/line', 'indicator/numeric': 'indicator/numeric', 'indicator/gauge': 'indicator/gauge', + treemap: 'treemap', }; return widgetSubtypeToChartSubtype[widgetSubtype]; } @@ -63,6 +69,7 @@ export function isSupportedWidgetType(widgetType: WidgetTypeOrString): widgetTyp WidgetType.PolarChart, WidgetType.PieChart, WidgetType.FunnelChart, + WidgetType.TreemapChart, WidgetType.ScatterChart, WidgetType.IndicatorChart, WidgetType.Table, @@ -95,3 +102,48 @@ export function getSortType(jaqlSort: JaqlSortDirection | undefined): SortDirect return 'sortNone'; } } + +/** + * Merges two arrays of filter objects, prioritizing 'targetFilters' over 'sourceFilters', + * and removes duplicates based on filter attribute expression (dim) + * + * @param {Filter[]} [sourceFilters=[]] - The source array of filter objects. + * @param {Filter[]} [targetFilters=[]] - The target array of filter objects. + * @returns {Filter[]} - The merged array of filter objects. + */ +export function mergeFilters(sourceFilters: Filter[] = [], targetFilters: Filter[] = []) { + return unionBy( + targetFilters, + sourceFilters, + // TODO: remove fallback on 'filter.jaql()' after removing temporal 'jaql()' workaround from filter translation layer + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (filter) => filter.attribute?.expression ?? filter.jaql().jaql.dim, + ); +} + +/** + * Merge two arrays of filters using the specified merge strategy. + * + * @param {Filter[]} widgetFilters - The filters from the widget. + * @param {Filter[]} codeFilters - The filters from the code. + * @param {FiltersMergeStrategy} [mergeStrategy] - The strategy to use for merging filters. + * + * @returns {Filter[]} The merged filters based on the selected strategy. + */ +export function mergeFiltersByStrategy( + widgetFilters: Filter[] = [], + codeFilters: Filter[] = [], + mergeStrategy?: FiltersMergeStrategy, +) { + switch (mergeStrategy) { + case FiltersMergeStrategyEnum.WIDGET_FIRST: + return mergeFilters(codeFilters, widgetFilters); + case FiltersMergeStrategyEnum.CODE_FIRST: + return mergeFilters(widgetFilters, codeFilters); + case FiltersMergeStrategyEnum.CODE_ONLY: + return codeFilters; + default: + // apply 'widgetFirst' filters merge strategy by default + return mergeFilters(codeFilters, widgetFilters); + } +} diff --git a/packages/sdk-ui/src/index.ts b/packages/sdk-ui/src/index.ts index 7182a6ec..14eee157 100644 --- a/packages/sdk-ui/src/index.ts +++ b/packages/sdk-ui/src/index.ts @@ -11,8 +11,11 @@ export { DashboardWidget } from './dashboard-widget/dashboard-widget'; export * from './components/query-execution'; export { executeQuery } from './query/execute-query'; export { SisenseContextProvider } from './components/sisense-context/sisense-context-provider'; +export { DrilldownWidget } from './widgets/drilldown-widget'; export { ChartWidget } from './widgets/chart-widget'; export { TableWidget } from './widgets/table-widget'; +export { ContextMenu } from './widgets/common/context-menu'; +export { DrilldownBreadcrumbs } from './widgets/common/drilldown-breadcrumbs'; export * from './components/line-chart'; export * from './components/column-chart'; export * from './components/area-chart'; @@ -23,6 +26,8 @@ export * from './components/polar-chart'; export * from './components/scatter-chart'; export * from './components/indicator-chart'; export * from './components/table'; +export * from './components/treemap-chart'; + export * from './props'; export * from './types'; diff --git a/packages/sdk-ui/src/props.tsx b/packages/sdk-ui/src/props.tsx index af8d9331..c8efbc76 100644 --- a/packages/sdk-ui/src/props.tsx +++ b/packages/sdk-ui/src/props.tsx @@ -19,6 +19,10 @@ import { TableStyleOptions, ThemeOid, WidgetStyleOptions, + TreemapStyleOptions, + CustomDrilldownResult, + MenuPosition, + MenuItemSection, } from './types'; import { HighchartsOptions } from './chart-options-processor/chart-options-service'; import { PropsWithChildren, ReactNode } from 'react'; @@ -32,8 +36,8 @@ import { DataPointsEventHandler, } from './chart-options-processor/apply-event-handlers'; import { AppConfig } from './app/client-application'; -import { MenuItemSection } from './widgets/common/context-menu'; import { ExecuteQueryParams } from './components/query-execution'; +import { FiltersMergeStrategy } from './dashboard-widget/types'; export type { DataPointEventHandler, DataPointsEventHandler, MenuItemSection, HighchartsOptions }; @@ -510,6 +514,12 @@ export interface DashboardWidgetProps * @category Data */ highlights?: Filter[]; + /** + * {@inheritDoc ExecuteQueryByWidgetIdProps.filtersMergeStrategy} + * + * @category Data + */ + filtersMergeStrategy?: FiltersMergeStrategy; /** * Title of the widget * @@ -605,7 +615,7 @@ export interface ChartWidgetProps extends ChartEventProps { * * @category Data */ - dataSource: DataSource; + dataSource?: DataSource; /** * Filters that will slice query results @@ -716,7 +726,7 @@ export interface TableWidgetProps { * * @category Data */ - dataSource: DataSource; + dataSource?: DataSource; /** * Filters that will slice query results @@ -785,9 +795,146 @@ export interface ExecuteQueryByWidgetIdProps { /** Identifier of the dashboard that contains the widget */ dashboardOid: string; + /** + * Filters that will slice query results. + * + * The provided filters will be merged with the existing widget filters based on `filtersMergeStrategy` + */ + filters?: Filter[]; + + /** Highlight filters that will highlight results that pass filter criteria */ + highlights?: Filter[]; + + /** + * Strategy for merging the existing widget filters with the filters provided via the `filters` prop: + * + * - `widgetFirst` - prioritizes the widget filters over the provided filters in case of filter conflicts by certain attributes. + * - `codeFirst` - prioritizes the provided filters over the widget filters in case of filter conflicts by certain attributes. + * - `codeOnly` - applies only the provided filters and completely ignores the widget filters. + * + * If not specified, the default strategy is `widgetFirst`. + */ + filtersMergeStrategy?: FiltersMergeStrategy; + /** Function as child component that is called to render the query results */ children?: (queryResult: QueryResultData, queryParams: ExecuteQueryParams) => ReactNode; /** Callback function that is evaluated when query results are ready */ onDataChanged?: (data: QueryResultData, queryParams: ExecuteQueryParams) => void; } + +/** + * Props of the {@link TreemapChart} component. + */ +export interface TreemapChartProps extends BaseChartProps { + /** + * Configurations for how to interpret and present the data passed to the chart + * + * @category Chart + */ + dataOptions: CategoricalChartDataOptions; + /** + * Configuration that define functional style of the various chart elements + * + * @category Chart + */ + styleOptions?: TreemapStyleOptions; +} + +/** + * Props for {@link ContextMenu} component. + */ +export type ContextMenuProps = { + /** + * Position of the context menu + * + * @category Widget + */ + position?: MenuPosition | null; + /** + * Callback function that is evaluated when context menu is closed + * + * @category Widget + */ + closeContextMenu: () => void; + /** + * Sections of menu items + * + * @category Widget + */ + itemSections?: MenuItemSection[]; + /** + * React nodes to be rendered at the bottom of the context menu + * + * @category Widget + */ + children?: React.ReactNode; +}; + +export type DrilldownBreadcrumbsProps = { + /** + * List of drilldown filters formatted to be displayed as breadcrumbs + * + * @category Widget + */ + filtersDisplayValues: string[][]; + /** + * Currently selected drilldown dimension + * + * @category Widget + */ + currentDimension: Attribute; + /** + * Callback function that is evaluated when X button is clicked + * + * @category Widget + */ + clearDrilldownSelections: () => void; + /** + * Callback function that is evaluated when a breadcrumb is clicked + * + * @category Widget + */ + sliceDrilldownSelections: (i: number) => void; +}; + +/** + * Props for the {@link DrilldownWidget} component + */ +export type DrilldownWidgetProps = { + /** + * List of dimensions to allow drilldowns on + * + * @category Widget + */ + drilldownDimensions: Attribute[]; + /** + * Initial dimension to apply first set of filters to + * + * @category Widget + */ + initialDimension: Attribute; + /** + * React component to be rendered as breadcrumbs + * + * {@link DrilldownBreadcrumbs} will be used if not provided + * + * @category Widget + */ + breadcrumbsComponent?: (drilldownBreadcrumbProps: DrilldownBreadcrumbsProps) => JSX.Element; + /** + * React component to be rendered as context menu + * + * {@link ContextMenu} will be used if not provided + * + * @category Widget + */ + contextMenuComponent?: (contextMenuProps: ContextMenuProps) => JSX.Element; + /** + * A function that allows to pass calculated drilldown filters + * and new dimension to a ReactNode to be rendered (custom chart) + * + * @category Widget + */ + children: (customDrilldownResult: CustomDrilldownResult) => ReactNode; +}; 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 928a663a..1e2d2f3b 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 @@ -60,6 +60,7 @@ export const redThemeSettings: ThemeSettings = { textColor: '#FFFFFF', backgroundColor: '#ec4646', secondaryTextColor: '#C5C8CF', + panelBackgroundColor: '#313138', }, typography: { fontFamily: 'Open Sans', diff --git a/packages/sdk-ui/src/themes/legacy-design-settings.ts b/packages/sdk-ui/src/themes/legacy-design-settings.ts index 61c6707f..54092e8c 100644 --- a/packages/sdk-ui/src/themes/legacy-design-settings.ts +++ b/packages/sdk-ui/src/themes/legacy-design-settings.ts @@ -93,6 +93,7 @@ export function convertToThemeSettings( textColor: legacyDesignSettings.dashboards.widgetTextColor, backgroundColor: legacyDesignSettings.dashboards.widgetBackgroundColor, secondaryTextColor: legacyDesignSettings.dashboards.widgetSecondaryTextColor, + panelBackgroundColor: legacyDesignSettings.dashboards.panelBackgroundColor, }, typography: { fontFamily: legacyDesignSettings.typography.fontFamily, diff --git a/packages/sdk-ui/src/types.ts b/packages/sdk-ui/src/types.ts index f6e9cd3a..9215e4e5 100644 --- a/packages/sdk-ui/src/types.ts +++ b/packages/sdk-ui/src/types.ts @@ -1,5 +1,5 @@ /* eslint-disable max-lines */ -import { Attribute } from '@sisense/sdk-data'; +import { Attribute, MembersFilter } from '@sisense/sdk-data'; import { DeepRequired } from 'ts-essentials'; import { AreaSubtype, @@ -22,6 +22,7 @@ import { IndicatorChartType, TableType, } from './chart-options-processor/translations/types'; +import { DataPointsEventHandler } from './props'; export type { AppConfig } from './app/client-application'; export type { DateConfig } from './query/date-formats'; @@ -225,22 +226,12 @@ export interface DataLimits { export interface BaseStyleOptions extends ReservedStyleOptions { /** Configuration for legend - a key that provides information about the data series or colors used in chart */ legend?: Legend; - /** Configuration for markers - symbols or data points that highlight specific values */ - markers?: Markers; - /** Configuration for navigator - zoom/pan tool for large datasets in a chart */ - navigator?: Navigator; /** * Configuration for series labels - titles/names identifying data series in a chart * * @internal */ seriesLabels?: SeriesLabels; - /** Configuration for X axis */ - xAxis?: AxisLabel; - /** Configuration for Y axis */ - yAxis?: AxisLabel; - /** Configuration for second Y axis */ - y2Axis?: AxisLabel; /** Data limit for series or categories that will be plotted */ dataLimits?: DataLimits; /** @@ -262,8 +253,26 @@ export interface BaseStyleOptions extends ReservedStyleOptions { height?: number; } +/** + * Configuration options that define functional style of axes and related elements + * + * @internal + */ +export interface BaseAxisStyleOptions { + /** Configuration for markers - symbols or data points that highlight specific values */ + markers?: Markers; + /** Configuration for navigator - zoom/pan tool for large datasets in a chart */ + navigator?: Navigator; + /** Configuration for X axis */ + xAxis?: AxisLabel; + /** Configuration for Y axis */ + yAxis?: AxisLabel; + /** Configuration for second Y axis */ + y2Axis?: AxisLabel; +} + /** Configuration options that define functional style of the various elements of {@link LineChart} */ -export interface LineStyleOptions extends BaseStyleOptions { +export interface LineStyleOptions extends BaseStyleOptions, BaseAxisStyleOptions { /** Configuration that defines line width */ lineWidth?: LineWidth; /** Subtype of {@link LineChart}*/ @@ -271,7 +280,7 @@ export interface LineStyleOptions extends BaseStyleOptions { } /** Configuration options that define functional style of the various elements of {@link AreaChart} */ -export interface AreaStyleOptions extends BaseStyleOptions { +export interface AreaStyleOptions extends BaseStyleOptions, BaseAxisStyleOptions { /** Configuration that defines line width */ lineWidth?: LineWidth; /** Subtype of {@link AreaChart}*/ @@ -279,8 +288,7 @@ export interface AreaStyleOptions extends BaseStyleOptions { } /** Configuration options that define functional style of the various elements of stackable charts, like Column or Bar */ - -export interface StackableStyleOptions extends BaseStyleOptions { +export interface StackableStyleOptions extends BaseStyleOptions, BaseAxisStyleOptions { /** Subtype of stackable chart */ /* @privateRemarks Subtypes for columns and bars should be separate - currently it is possible to have @@ -317,7 +325,7 @@ export interface FunnelStyleOptions extends BaseStyleOptions { } /** Configuration options that define functional style of the various elements of {@link PolarChart} */ -export interface PolarStyleOptions extends BaseStyleOptions { +export interface PolarStyleOptions extends BaseStyleOptions, BaseAxisStyleOptions { /** Subtype of {@link PolarChart}*/ subtype?: PolarSubtype; } @@ -416,12 +424,29 @@ export interface GaugeIndicatorStyleOptions extends BaseIndicatorStyleOptions { } /** Configuration options that define functional style of the various elements of {@link ScatterChart} */ -export interface ScatterStyleOptions extends BaseStyleOptions { +export interface ScatterStyleOptions extends BaseStyleOptions, BaseAxisStyleOptions { /** Subtype of {@link ScatterChart}*/ subtype?: never; markerSize?: ScatterMarkerSize; } +/** Configuration options that define functional style of the various elements of {@link TreemapChart} */ +export interface TreemapStyleOptions extends BaseStyleOptions { + /** Labels options object */ + labels?: { + /** Array with single label options objects (order of items relative to dataOptions.category) */ + category?: { + /** Define visibility of label */ + enabled?: boolean; + }[]; + }; + /** Tooltip options object */ + tooltip?: { + /** Define mode of data showing */ + mode?: 'value' | 'contribution'; + }; +} + /** * Configuration options that define functional style of the various elements of chart. */ @@ -433,7 +458,8 @@ export type StyleOptions = | FunnelStyleOptions | PolarStyleOptions | IndicatorStyleOptions - | ScatterStyleOptions; + | ScatterStyleOptions + | TreemapStyleOptions; /** Mapping of each of the chart value series to colors. */ export type ValueToColorMap = Record; @@ -532,6 +558,8 @@ export interface ThemeSettings { secondaryTextColor?: string; /** Background color */ backgroundColor?: string; + /** Toolbar Background color, can be used as a secondary background color */ + panelBackgroundColor?: string; }; /** Collection of colors used to color various elements */ palette?: ColorPaletteTheme; @@ -619,14 +647,20 @@ export declare type ColorPaletteTheme = { variantColors: Color[]; }; +/** Configuration for the drilldown */ export type DrilldownOptions = { - drilldownCategories?: Attribute[]; + /** Dimensions that can be used for drilldown */ + drilldownDimensions?: Attribute[]; + /** Current selections for multiple drilldowns */ drilldownSelections?: DrilldownSelection[]; }; +/** Selection for the drilldown */ export type DrilldownSelection = { + /** Points selected for drilldown */ points: DataPoint[]; - nextCategory: Attribute; + /** Dimension to drilldown to */ + nextDimension: Attribute; }; /** Data point in a chart. */ @@ -708,3 +742,51 @@ export type SeriesWithAlerts = { series: T; alerts: string[]; }; + +/** + * Context menu position coordinates + * Used in {@link ContextMenu} component + */ +export type MenuPosition = { + /** Horizontal position */ + left: number; + /** Vertical position */ + top: number; +}; + +/** + * Context menu section + * Used in {@link ContextMenu} component + */ +export type MenuItemSection = { + /** Optional section title */ + sectionTitle?: string; + /** Optional list of menu items */ + items?: { key?: string; onClick?: () => void; caption: string }[]; +}; + +/** + * Result of custom drilldown execution + * + * User provides selected points and desired category to drilldown to + * and receives set of filters to apply and new category to display + * + */ +export type CustomDrilldownResult = { + /** + * The drilldown filters that should be applied to the next drilldown + */ + drilldownFilters: MembersFilter[]; + /** + * New dimension that should replace the current dimension + */ + drilldownDimension: Attribute; + /** + * Callback to provide next points to drilldown to + */ + onDataPointsSelected: DataPointsEventHandler; + /** + * Callback to open context menu + */ + onContextMenu: (menuPosition: MenuPosition) => void; +}; diff --git a/packages/sdk-ui/src/utils/color/color-interpolation.ts b/packages/sdk-ui/src/utils/color/color-interpolation.ts index 1e94b665..70f495f9 100644 --- a/packages/sdk-ui/src/utils/color/color-interpolation.ts +++ b/packages/sdk-ui/src/utils/color/color-interpolation.ts @@ -89,7 +89,7 @@ export const getDarkFactor = (color: Color) => { return 1 - (0.299 * R + 0.587 * G + 0.114 * B) / 255; }; -function isBright(color: Color) { +export function isBright(color: Color) { return getDarkFactor(color) < 0.9; } diff --git a/packages/sdk-ui/src/widgets/chart-widget.tsx b/packages/sdk-ui/src/widgets/chart-widget.tsx index fb8fbd2b..5dee1646 100644 --- a/packages/sdk-ui/src/widgets/chart-widget.tsx +++ b/packages/sdk-ui/src/widgets/chart-widget.tsx @@ -6,9 +6,9 @@ import React, { useCallback, useMemo, useState, type FunctionComponent } from 'react'; import { Chart } from '../components/chart'; -import { DataPoint, CompleteThemeSettings } from '../types'; +import { DataPoint, CompleteThemeSettings, MenuPosition } from '../types'; import { ChartWidgetProps } from '../props'; -import { ContextMenu, MenuPosition } from './common/context-menu'; +import { ContextMenu } from './common/context-menu'; import { useWidgetDrilldown } from './common/use-widget-drilldown'; import { WidgetHeader } from './common/widget-header'; import { ThemeProvider, useThemeContext } from '../components/theme-provider'; @@ -34,7 +34,7 @@ import { DynamicSizeContainer, getWidgetDefaultSize } from '../components/dynami * breakBy: [], * }} * drilldownOptions={{ - * drilldownCategories: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], + * drilldownDimensions: [DM.Commerce.AgeRange, DM.Commerce.Gender, DM.Commerce.Condition], * }} * /> * ``` diff --git a/packages/sdk-ui/src/widgets/common/context-menu.tsx b/packages/sdk-ui/src/widgets/common/context-menu.tsx index a24a66d8..e669bada 100644 --- a/packages/sdk-ui/src/widgets/common/context-menu.tsx +++ b/packages/sdk-ui/src/widgets/common/context-menu.tsx @@ -2,30 +2,14 @@ import Divider from '@mui/material/Divider'; import ListSubheader from '@mui/material/ListSubheader'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; - -export type MenuPosition = { - left: number; - top: number; -}; - -export type MenuItemSection = { - /** Optional section title */ - sectionTitle?: string; - /** Optional list of menu items */ - items?: { key?: string; onClick?: () => void; caption: string }[]; -}; +import { ContextMenuProps } from '../../props'; export const ContextMenu = ({ position, closeContextMenu, itemSections, children, -}: { - position?: MenuPosition | null; - closeContextMenu: () => void; - itemSections?: MenuItemSection[]; - children?: React.ReactNode; -}) => { +}: ContextMenuProps) => { const open = !!position; return ( diff --git a/packages/sdk-ui/src/widgets/common/custom-drilldown.test.ts b/packages/sdk-ui/src/widgets/common/custom-drilldown.test.ts new file mode 100644 index 00000000..7c359784 --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/custom-drilldown.test.ts @@ -0,0 +1,40 @@ +import { Column, createAttribute } from '@sisense/sdk-data'; +import { processDrilldownSelections, useCustomDrilldown } from './custom-drilldown.js'; + +const ageRange = createAttribute({ + name: 'AgeRange', + type: 'text-attribute', + expression: '[Commerce.Age Range]', +}); + +const gender = createAttribute({ + name: 'Gender', + type: 'text-attribute', + expression: '[Commerce.Gender]', +}); + +describe('useCustomDrilldown', () => { + it('should notify initial dimension is required', () => { + expect(() => + useCustomDrilldown({ drilldownDimensions: [], initialDimension: null as unknown as Column }), + ).toThrow('Initial dimension has to be specified to use drilldown with custom components'); + }); + + it('should process drilldown dimensions correctly', () => { + const points = [ + { categoryValue: 'Male', categoryDisplayValue: 'Gentlemen' }, + { categoryValue: 'Female', categoryDisplayValue: 'Ladies' }, + ]; + const nextDimension = ageRange; + + const { drilldownFilters, drilldownFiltersDisplayValues, drilldownDimension } = + processDrilldownSelections([{ points, nextDimension }], gender); + expect(drilldownFilters.length).toBe(1); + expect(drilldownFilters[0].members).toStrictEqual(points.map((point) => point.categoryValue)); + expect(drilldownFiltersDisplayValues.length).toBe(1); + expect(drilldownFiltersDisplayValues[0]).toStrictEqual( + points.map((point) => point.categoryDisplayValue), + ); + expect(drilldownDimension).toBe(nextDimension); + }); +}); diff --git a/packages/sdk-ui/src/widgets/common/custom-drilldown.ts b/packages/sdk-ui/src/widgets/common/custom-drilldown.ts new file mode 100644 index 00000000..ad620e08 --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/custom-drilldown.ts @@ -0,0 +1,91 @@ +/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable max-lines-per-function */ +import { useCallback, useMemo, useState } from 'react'; + +import { DataPoint, StyledColumn, DrilldownSelection } from '../../types.js'; +import { Attribute, Column, MembersFilter, filters as filterFactory } from '@sisense/sdk-data'; + +export const useCustomDrilldown = ({ + drilldownDimensions, + initialDimension, +}: { + drilldownDimensions: Attribute[]; + initialDimension: Column | StyledColumn; +}) => { + if (!initialDimension) { + throw new Error( + 'Initial dimension has to be specified to use drilldown with custom components', + ); + } + + const [drilldownSelections, setDrilldownSelections] = useState([] as DrilldownSelection[]); + + const availableDrilldowns = useMemo( + () => + drilldownDimensions.filter(({ expression }) => + drilldownSelections.every(({ nextDimension }) => nextDimension.expression !== expression), + ), + [drilldownDimensions, drilldownSelections], + ); + + const selectDrilldown = useCallback( + (points: DataPoint[], nextDimension: Attribute) => { + setDrilldownSelections((state) => [...state, { points, nextDimension }]); + }, + [setDrilldownSelections], + ); + + const sliceDrilldownSelections = useCallback( + (i: number) => { + setDrilldownSelections((state) => state.slice(0, i)); + }, + [setDrilldownSelections], + ); + + const clearDrilldownSelections = useCallback(() => { + setDrilldownSelections([]); + }, [setDrilldownSelections]); + + const drilldownProps = useMemo( + () => processDrilldownSelections(drilldownSelections, initialDimension), + [drilldownSelections, initialDimension], + ); + + return { + selectDrilldown, + sliceDrilldownSelections, + clearDrilldownSelections, + drilldownSelections, + availableDrilldowns, + ...drilldownProps, + }; +}; + +export const processDrilldownSelections = ( + drilldownSelections: DrilldownSelection[], + initialDimension: Column | StyledColumn | null, +) => { + let currentDimension = ((initialDimension as StyledColumn).column ?? + initialDimension) as Attribute; + const drilldownFilters: MembersFilter[] = []; + const drilldownFiltersDisplayValues: string[][] = []; + + drilldownSelections.forEach(({ points, nextDimension }) => { + drilldownFilters.push( + filterFactory.members( + currentDimension, + points.map((point) => `${point.categoryValue}`), + ) as MembersFilter, + ); + drilldownFiltersDisplayValues.push( + points.map((point) => `${point.categoryDisplayValue ?? point.categoryValue}`), + ); + currentDimension = nextDimension; + }); + + return { + drilldownFilters, + drilldownFiltersDisplayValues, + drilldownDimension: currentDimension, + }; +}; diff --git a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs.tsx b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs.tsx deleted file mode 100644 index 64b0b820..00000000 --- a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useState } from 'react'; -import { Attribute } from '@sisense/sdk-data'; -import Box from '@mui/material/Box'; -import Breadcrumbs from '@mui/material/Breadcrumbs'; -import Button from '@mui/material/Button'; -import Paper from '@mui/material/Paper'; -import Popper from '@mui/material/Popper'; - -export const DrilldownBreadcrumbs = ({ - filtersDisplayValues, - currentCategory, - clearDrilldownSelections, - sliceDrilldownSelections, -}: { - filtersDisplayValues: string[][]; - currentCategory: Attribute; - - clearDrilldownSelections: () => void; - sliceDrilldownSelections: (i: number) => void; -}) => { - const [popperParams, setPopoverParams] = useState<{ - filterDisplayValues: string[]; - anchorEl: HTMLElement; - } | null>(null); - - const handlePopperOpen = - (filterDisplayValues: string[]) => (event: React.MouseEvent) => { - setPopoverParams({ filterDisplayValues, anchorEl: event.currentTarget }); - }; - - const handlePopperClose = () => { - setPopoverParams(null); - }; - - if (!filtersDisplayValues.length) return null; - - const open = !!popperParams; - - return ( - - - {filtersDisplayValues.map((filterDisplayValues, i) => ( - - ))}{' '} - - - - {popperParams?.filterDisplayValues.join(', ')} - - - - ); -}; diff --git a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/drilldown-breadcrumbs.tsx b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/drilldown-breadcrumbs.tsx new file mode 100644 index 00000000..248b546a --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/drilldown-breadcrumbs.tsx @@ -0,0 +1,199 @@ +/* eslint-disable complexity */ +/* eslint-disable max-lines */ +import { useState } from 'react'; +import Breadcrumbs from '@mui/material/Breadcrumbs'; +import Button from '@mui/material/Button'; +import useButtons from './use-buttons'; +import DrillPopper from './use-popper'; +import { useThemeForBreadcrumbs } from './use-theme-for-breadcrumbs'; +import React from 'react'; +import styled from '@emotion/styled'; + +import { DrilldownBreadcrumbsProps } from '../../../props'; + +interface DrillButtonProps { + isActive: boolean; + isLastActive: boolean; + filterDisplayValue: string[]; + handleMouseEnter: (event: React.MouseEvent) => void; + handleMouseLeave: () => void; + handleClick: () => void; + themeProps: ThemeProps; + popperParams?: { + filterDisplayValues: string[]; + anchorEl: HTMLElement; + } | null; + index: number; +} +interface ThemeProps { + primaryTextColor: string; + secondaryTextColor: string; + fontFamily: string; + backgroundColor: string; + brandColor: string; + primaryButtonTextColor: string; + chartBackgroundColor: string; + activeDrillBackgroundColor: string; + activeDrillHoverBackgroundColor: string; +} + +interface StyledButtonProps { + theme: ThemeProps; + active: string; + index: number; +} + +export const BREADCRUMBS_BORDER_COLOR = '#F2F2F2'; + +const StyledDrillButton = styled(Button)` + && { + font-family: ${({ theme }) => theme.fontFamily}; + position: relative; + border-radius: 0; + border: 1px solid ${BREADCRUMBS_BORDER_COLOR}; + border-right: none; + color: ${({ active, theme }) => + active === 'true' ? theme.primaryTextColor : theme.secondaryTextColor}; + background-color: ${({ active, theme }) => + active === 'true' ? theme.activeDrillBackgroundColor : theme.chartBackgroundColor}; + left: ${({ index }) => (index === 0 ? '-1.875rem' : index === 2 ? '-3.188rem' : '-2.55rem')}; + padding-right: 1.25rem; + padding-left: 1.875rem; + height: 1.85rem; + text-transform: none; + transition: background-color 0.2s, border-color 0.2s, color 0.2s; + cursor: ${({ active }) => (active === 'true' ? 'pointer' : 'auto')}; + + &:hover { + background-color: ${({ active, theme }) => + active === 'true' ? theme.activeDrillHoverBackgroundColor : theme.chartBackgroundColor}; + border: 1px solid ${BREADCRUMBS_BORDER_COLOR}; + border-right: none; + } + } +`; +const DrillButton: React.FC = ({ + isActive, + filterDisplayValue, + handleMouseEnter, + handleMouseLeave, + handleClick, + themeProps, + popperParams, + index, +}) => { + return ( + + + + {filterDisplayValue.slice(0, 2).join(', ')} + {filterDisplayValue.length > 2 && ', ...'} + + {isActive ? ( + + ) : undefined} + + + + ); +}; + +export const DrilldownBreadcrumbs: React.FC = ({ + filtersDisplayValues, + currentDimension, + clearDrilldownSelections, + sliceDrilldownSelections, +}) => { + const [popperParams, setPopoverParams] = useState<{ + filterDisplayValues: string[]; + anchorEl: HTMLElement; + } | null>(null); + const [isHovered, setIsHovered] = useState(false); + const themeProps = useThemeForBreadcrumbs(); + const { CancelButton, CurrentDrillButton } = useButtons({ + clearDrilldownSelections, + currentDimension, + filtersDisplayValues, + isHovered, + setIsHovered, + themeProps, + }); + const handleMouseEnter = + (filterDisplayValue: string[]) => (event: React.MouseEvent) => { + setIsHovered(true); + setPopoverParams({ filterDisplayValues: filterDisplayValue, anchorEl: event.currentTarget }); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + setPopoverParams(null); + }; + + const isActiveDrill = (i: number) => i < filtersDisplayValues.length - 1; + const isLastActiveDrill = (i: number) => i === filtersDisplayValues.length - 2; + + if (!filtersDisplayValues.length) return null; + + return ( + + + {filtersDisplayValues.map((filterDisplayValue, i) => { + const isActive = isActiveDrill(i); + const isLastActive = isLastActiveDrill(i); + return ( +
+ sliceDrilldownSelections(i + 1)} + themeProps={themeProps} + popperParams={popperParams} + index={i} + /> +
+ ); + })} + + +
+ ); +}; diff --git a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/index.ts b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/index.ts new file mode 100644 index 00000000..55c51fb6 --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/index.ts @@ -0,0 +1 @@ +export { DrilldownBreadcrumbs } from './drilldown-breadcrumbs'; diff --git a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-buttons.tsx b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-buttons.tsx new file mode 100644 index 00000000..247f965a --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-buttons.tsx @@ -0,0 +1,137 @@ +import Button from '@mui/material/Button'; +import React from 'react'; +import { Attribute } from '@sisense/sdk-data'; +import { Dispatch, SetStateAction } from 'react'; +import styled from '@emotion/styled'; +import { BREADCRUMBS_BORDER_COLOR } from './drilldown-breadcrumbs'; + +interface ButtonsProps { + clearDrilldownSelections: () => void; + currentDimension: Attribute; + filtersDisplayValues: string[][]; + isHovered: boolean; + setIsHovered: Dispatch>; + themeProps: ThemeProps; +} +interface ThemeProps { + primaryTextColor: string; + secondaryTextColor: string; + fontFamily: string; + backgroundColor: string; + brandColor: string; + primaryButtonTextColor: string; + chartBackgroundColor: string; + activeDrillBackgroundColor: string; + activeDrillHoverBackgroundColor: string; +} +interface StyledButton { + theme: ThemeProps; +} +interface Buttons { + CancelButton: React.FC; + CurrentDrillButton: React.FC; +} + +// eslint-disable-next-line max-lines-per-function +const useButtons = ({ + clearDrilldownSelections, + currentDimension, + filtersDisplayValues, + setIsHovered, + themeProps, +}: ButtonsProps): Buttons => { + const currentColumn = currentDimension.expression.match(/\[(.*?)]/)?.[1]?.split('.')[1] || ''; + + const StyledCancelButton = styled(Button)` + && { + background-color: ${themeProps.activeDrillBackgroundColor}; + color: ${themeProps.primaryButtonTextColor}; + border-radius: 100%; + border: 1px solid ${BREADCRUMBS_BORDER_COLOR}; + min-width: 38px; + z-index: 10; + padding: 7px; + cursor: pointer; + text-transform: none; + + &:hover { + background-color: ${themeProps.activeDrillHoverBackgroundColor}; + color: ${themeProps.primaryTextColor}; + } + } + `; + + const Icon = styled.svg` + width: 24px; + height: 24px; + fill: currentColor; + `; + + const CancelButton: React.FC = () => { + return ( + setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + onClick={clearDrilldownSelections} + > + + + + + ); + }; + + const StyledCurrentDrillButton = styled(Button)` + && { + position: relative; + font-family: ${(props) => props.theme.fontFamily}; + border-radius: 0; + border: 1px solid ${BREADCRUMBS_BORDER_COLOR}; + background-color: ${(props) => props.theme.chartBackgroundColor}; + border-right: none; + border-left: none; + left: ${filtersDisplayValues.length < 2 ? '-3rem' : '-4.5rem'}; + color: ${(props) => props.theme.secondaryTextColor}; + padding-right: 1.25rem; + padding-left: ${filtersDisplayValues.length === 2 ? '3.125rem' : '2.5rem'}; + height: 1.85rem; + transition: background-color 0.2s, border-color 0.2s, color 0.2s; + text-transform: none; + cursor: auto; + pointer-events: none; + + &:hover { + background-color: ${(props) => props.theme.chartBackgroundColor}; + border: 1px solid ${BREADCRUMBS_BORDER_COLOR}; + border-right: none; + border-left: none; + } + } + `; + + const CurrentDrillButton: React.FC = () => { + return ( + + {currentColumn} (All) + + + + + ); + }; + + return { CancelButton, CurrentDrillButton }; +}; + +export default useButtons; diff --git a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-popper.tsx b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-popper.tsx new file mode 100644 index 00000000..ecd8d599 --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-popper.tsx @@ -0,0 +1,104 @@ +import React from 'react'; +import Popper from '@mui/material/Popper'; +import Typography from '@mui/material/Typography'; + +interface DrilldownBreadcrumbsThemeProps { + popperParams?: { + filterDisplayValues: string[]; + anchorEl: HTMLElement; + } | null; + currentDimension: { + expression: string; + }; + themeProps: ThemeProps; +} + +interface ThemeProps { + primaryTextColor: string; + secondaryTextColor: string; + fontFamily: string; + backgroundColor: string; + brandColor: string; + primaryButtonTextColor: string; + chartBackgroundColor: string; + activeDrillBackgroundColor: string; + activeDrillHoverBackgroundColor: string; +} + +const popperOptions = { + modifiers: [ + { + name: 'offset', + options: { + offset: [0, 12], + }, + }, + ], +}; + +const PopperContent: React.FC<{ + themeProps: ThemeProps; + filterDisplayValues: string[]; + currentTable: string; + currentColumn: string; +}> = ({ themeProps, filterDisplayValues, currentTable, currentColumn }) => ( +
+
+ + Members + + + {filterDisplayValues.join(', ')} + +
+
+ + Table + + + {currentTable} + +
+
+ + Column + + + {currentColumn} + +
+
+); + +const DrillPopper: React.FC = ({ + popperParams, + currentDimension, + themeProps, +}) => { + const match = currentDimension.expression.match(/\[(.*?)]/); + const [currentTable, currentColumn] = match ? match[1].split('.') : ['', '']; + const open = !!popperParams; + + return ( + + {popperParams && ( + + )} + + ); +}; + +export default DrillPopper; diff --git a/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-theme-for-breadcrumbs.tsx b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-theme-for-breadcrumbs.tsx new file mode 100644 index 00000000..2164420e --- /dev/null +++ b/packages/sdk-ui/src/widgets/common/drilldown-breadcrumbs/use-theme-for-breadcrumbs.tsx @@ -0,0 +1,28 @@ +import { useThemeContext } from '../../../components/theme-provider'; +import { darken } from '@mui/material'; + +export const useThemeForBreadcrumbs = () => { + const { + themeSettings: { + typography: { primaryTextColor, secondaryTextColor, fontFamily }, + general: { backgroundColor, brandColor, primaryButtonTextColor }, + chart: { backgroundColor: chartBackgroundColor, panelBackgroundColor }, + }, + } = useThemeContext(); + const activeDrillBackgroundColor: string = + panelBackgroundColor != chartBackgroundColor + ? panelBackgroundColor + : darken(panelBackgroundColor, 0.3); + const activeDrillHoverBackgroundColor = darken(activeDrillBackgroundColor, 0.1); + return { + primaryTextColor, + secondaryTextColor, + fontFamily, + backgroundColor, + brandColor, + primaryButtonTextColor, + chartBackgroundColor, + activeDrillBackgroundColor, + activeDrillHoverBackgroundColor, + }; +}; diff --git a/packages/sdk-ui/src/widgets/common/drilldown.ts b/packages/sdk-ui/src/widgets/common/drilldown.ts index 2b8c55b2..564c9e37 100644 --- a/packages/sdk-ui/src/widgets/common/drilldown.ts +++ b/packages/sdk-ui/src/widgets/common/drilldown.ts @@ -9,22 +9,22 @@ export const useDrilldown = ( dataOptions: ChartDataOptions, drilldownOptions?: DrilldownOptions, ) => { - const { drilldownCategories = [], drilldownSelections: initialSelections = [] } = + const { drilldownDimensions = [], drilldownSelections: initialSelections = [] } = drilldownOptions ?? {}; const [drilldownSelections, setDrilldownSelections] = useState(initialSelections); const availableDrilldowns = useMemo( () => - drilldownCategories.filter(({ expression }) => - drilldownSelections.every(({ nextCategory }) => nextCategory.expression !== expression), + drilldownDimensions.filter(({ expression }) => + drilldownSelections.every(({ nextDimension }) => nextDimension.expression !== expression), ), - [drilldownCategories, drilldownSelections], + [drilldownDimensions, drilldownSelections], ); const selectDrilldown = useCallback( - (points: DataPoint[], nextCategory: Attribute) => { - setDrilldownSelections((state) => [...state, { points, nextCategory }]); + (points: DataPoint[], nextDimension: Attribute) => { + setDrilldownSelections((state) => [...state, { points, nextDimension }]); }, [setDrilldownSelections], ); @@ -63,36 +63,36 @@ const processDrilldownSelections = ( return { drilldownFilters: [], drilldownFiltersDisplayValues: [], - drilldownCategory: undefined, + drilldownDimension: undefined, dataOptionsWithDrilldown: dataOptions, }; } const [firstCategory, ...otherCategories] = dataOptions.category; - let currentCategory = firstCategory; + let currentDimension = firstCategory; const drilldownFilters: MembersFilter[] = []; const drilldownFiltersDisplayValues: string[][] = []; - drilldownSelections.forEach(({ points, nextCategory }) => { + drilldownSelections.forEach(({ points, nextDimension }) => { drilldownFilters.push( filterFactory.members( - translateColumnToAttribure(currentCategory), + translateColumnToAttribure(currentDimension), points.map((point) => `${point.categoryValue}`), ) as MembersFilter, ); drilldownFiltersDisplayValues.push( points.map((point) => `${point.categoryDisplayValue ?? point.categoryValue}`), ); - currentCategory = nextCategory; + currentDimension = nextDimension; }); return { drilldownFilters, drilldownFiltersDisplayValues, - drilldownCategory: translateColumnToAttribure(currentCategory), + drilldownDimension: translateColumnToAttribure(currentDimension), dataOptionsWithDrilldown: { ...dataOptions, - category: [currentCategory, ...otherCategories], + category: [currentDimension, ...otherCategories], }, }; }; diff --git a/packages/sdk-ui/src/widgets/common/use-widget-drilldown.tsx b/packages/sdk-ui/src/widgets/common/use-widget-drilldown.tsx index 2e5cac88..1411d0d2 100644 --- a/packages/sdk-ui/src/widgets/common/use-widget-drilldown.tsx +++ b/packages/sdk-ui/src/widgets/common/use-widget-drilldown.tsx @@ -13,7 +13,7 @@ import { import { ChartWidgetProps } from '../../props'; import { useDrilldown } from './drilldown'; import { DrilldownBreadcrumbs } from './drilldown-breadcrumbs'; -import { MenuItemSection } from './context-menu'; +import { MenuItemSection } from '../../types'; const defaultDataOptions = { category: [], value: [], breakBy: [] }; const defaultFilters: Filter[] = []; @@ -38,13 +38,13 @@ export const useWidgetDrilldown = (props: ChartWidgetProps): ChartWidgetProps => availableDrilldowns, drilldownFilters, drilldownFiltersDisplayValues, - drilldownCategory, + drilldownDimension, dataOptionsWithDrilldown, } = useDrilldown(dataOptions, drilldownOptions); const onMenuDrilldownClick = useCallback( - (selectedPoints: DataPoint[], nextCategory: Attribute) => { - selectDrilldown(selectedPoints, nextCategory); + (selectedPoints: DataPoint[], nextDimension: Attribute) => { + selectDrilldown(selectedPoints, nextDimension); }, [selectDrilldown], ); @@ -115,7 +115,7 @@ export const useWidgetDrilldown = (props: ChartWidgetProps): ChartWidgetProps => const contextMenuItems = useMemo(() => { if (drilldownOptions) { const drillDownMenuItems: MenuItemSection[] = [ - ...(drilldownCategory ? [{ sectionTitle: drilldownCategory?.name }] : []), + ...(drilldownDimension ? [{ sectionTitle: drilldownDimension?.name }] : []), ...(selectedDataPoints.length ? [ { @@ -135,7 +135,7 @@ export const useWidgetDrilldown = (props: ChartWidgetProps): ChartWidgetProps => }, [ restProps.contextMenuItems, drilldownOptions, - drilldownCategory, + drilldownDimension, selectedDataPoints, availableDrilldowns, onMenuDrilldownClick, @@ -156,10 +156,10 @@ export const useWidgetDrilldown = (props: ChartWidgetProps): ChartWidgetProps => topSlot: ( <> {restProps.topSlot} - {drilldownCategory && ( + {drilldownDimension && ( diff --git a/packages/sdk-ui/src/widgets/drilldown-widget.tsx b/packages/sdk-ui/src/widgets/drilldown-widget.tsx new file mode 100644 index 00000000..02cc8003 --- /dev/null +++ b/packages/sdk-ui/src/widgets/drilldown-widget.tsx @@ -0,0 +1,144 @@ +/* eslint-disable max-lines-per-function */ + +import { useState, useCallback, useMemo } from 'react'; +import { Attribute } from '@sisense/sdk-data'; +import { DataPoint, MenuPosition, MenuItemSection } from '../types'; +import { ContextMenu } from './common/context-menu'; +import { DrilldownBreadcrumbs } from './common/drilldown-breadcrumbs'; +import { useCustomDrilldown } from './common/custom-drilldown'; +import { DrilldownWidgetProps } from '../props'; + +/** + * React component designed to add drilldown functionality to any type of chart + * + * It acts as a wrapper around a given chart component, enhancing it with drilldown capabilities + * + * The widget offers several features including: + * - A context menu for initiating drilldown actions (can be provided as a custom component) + * - Breadcrumbs that not only allow for drilldown selection slicing but also + * provide an option to clear the selection (can be provided as a custom component) + * - Filters specifically created for drilldown operation + * - An option to navigate to the next drilldown dimension + * + * When an `initialDimension` is specified, the `drilldownDimension` will automatically inherit its value, + * even before any points on the chart are selected. + * This allows for complete control over the chart's dimensions to be handed over to the DrilldownWidget + * + * @example + * Example of using the `DrilldownWidget` component to + * plot a custom React component that uses the `ExecuteQuery` component to + * query the `Sample ECommerce` data source hosted in a Sisense instance. + * ```tsx + * + * {({ drilldownFilters, drilldownDimension, onDataPointsSelected, onContextMenu }) => ( + * + * {(data) => ( + * + * )} + * + * )} + * + * ``` + * + * @param props - DrilldownWidget properties + * @returns DrilldownWidget wrapper component + */ +export const DrilldownWidget = ({ + drilldownDimensions, + initialDimension, + contextMenuComponent, + breadcrumbsComponent, + children, +}: DrilldownWidgetProps) => { + const [selectedDataPoints, setSelectedDataPoints] = useState([]); + const [contextMenuPos, setContextMenuPos] = useState(null); + + const ContextMenuComponent = contextMenuComponent ?? ContextMenu; + const BreadcrumbsComponent = breadcrumbsComponent ?? DrilldownBreadcrumbs; + + const { + selectDrilldown, + sliceDrilldownSelections, + clearDrilldownSelections, + availableDrilldowns, + drilldownFilters, + drilldownFiltersDisplayValues, + drilldownDimension, + } = useCustomDrilldown({ + drilldownDimensions, + initialDimension, + }); + + const openContextMenu = (menuPos: { top: number; left: number }) => { + setContextMenuPos(menuPos); + }; + + const closeContextMenu = useCallback(() => { + setSelectedDataPoints([]); + setContextMenuPos(null); + }, [setSelectedDataPoints]); + + const onMenuDrilldownClick = useCallback( + (nextDimension: Attribute) => { + selectDrilldown(selectedDataPoints, nextDimension); + }, + [selectDrilldown, selectedDataPoints], + ); + + const onDataPointsSelected = useCallback( + (points: DataPoint[]) => { + setSelectedDataPoints(points); + }, + [setSelectedDataPoints], + ); + + const drilldownMenuItems: MenuItemSection[] = useMemo( + () => [ + ...(drilldownDimension ? [{ sectionTitle: drilldownDimension?.name }] : []), + { + sectionTitle: 'Drill', + items: availableDrilldowns.map((nextDimension) => ({ + caption: nextDimension.name, + onClick: () => onMenuDrilldownClick(nextDimension), + })), + }, + ], + [drilldownDimension, availableDrilldowns, onMenuDrilldownClick], + ); + + return ( + <> + + {drilldownDimension && ( + + )} + {children({ + drilldownFilters, + drilldownDimension, + onDataPointsSelected, + onContextMenu: openContextMenu, + })} + + ); +}; diff --git a/packages/sdk-ui/tailwind.config.ts b/packages/sdk-ui/tailwind.config.ts index 4cb87d0a..928f2448 100644 --- a/packages/sdk-ui/tailwind.config.ts +++ b/packages/sdk-ui/tailwind.config.ts @@ -7,6 +7,9 @@ const config: Config = { content: ['./src/**/*.{js,ts,jsx,tsx}'], theme: { extend: { + boxShadow: { + ['ai-shadow-sm']: '0px 1px 2px rgba(9, 9, 10, 0.1), 0px 2px 4px rgba(9, 9, 10, 0.1)', + }, gridTemplateColumns: { // Simple 16 column grid auto: 'repeat(auto-fit, minmax(0, 1fr))', diff --git a/packages/sdk-ui/vitest.config.ts b/packages/sdk-ui/vitest.config.ts index 768af5c8..19e6c2ef 100644 --- a/packages/sdk-ui/vitest.config.ts +++ b/packages/sdk-ui/vitest.config.ts @@ -22,6 +22,7 @@ const config: UserConfig = { 'src/__demo__', 'src/__stories__', 'src/@types', + 'src/widgets/common/drilldown-breadcrumbs', ], }, }, diff --git a/yarn.lock b/yarn.lock index a399638f..18cefa53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2312,6 +2312,17 @@ __metadata: languageName: node linkType: hard +"@choojs/findup@npm:^0.2.0": + version: 0.2.1 + resolution: "@choojs/findup@npm:0.2.1" + dependencies: + commander: ^2.15.1 + bin: + findup: bin/findup.js + checksum: 9496321caa276f2a560ebae0e7607ba009012e8eff16db68fb405561ec482606edecf1c5ce1956805d77721c2db34c4bd9e2e95a2be2eec1c5ae8bb289ed5fd2 + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -3636,6 +3647,78 @@ __metadata: languageName: node linkType: hard +"@mapbox/geojson-rewind@npm:^0.5.0": + version: 0.5.2 + resolution: "@mapbox/geojson-rewind@npm:0.5.2" + dependencies: + get-stream: ^6.0.1 + minimist: ^1.2.6 + bin: + geojson-rewind: geojson-rewind + checksum: 721470ab5e8912d69aef06fa4db891bade8b028d6708a35a982b1dfec0f40eb4ba05a749258867f5844cf4e776e53866813bf9c97e3289054b21cbf7840d3608 + languageName: node + linkType: hard + +"@mapbox/geojson-types@npm:^1.0.2": + version: 1.0.2 + resolution: "@mapbox/geojson-types@npm:1.0.2" + checksum: ab1fa0afcedb384aea39b25218b74dd823fc86929c5df5f15fbebac1d98eb30c16f4dded7199999c99d23a0a5f36c6e3380aad91adc736c302a94adbd3980ace + languageName: node + linkType: hard + +"@mapbox/jsonlint-lines-primitives@npm:^2.0.2": + version: 2.0.2 + resolution: "@mapbox/jsonlint-lines-primitives@npm:2.0.2" + checksum: 4eb31edd3ccff530f7b687ddc6d813d6e24fc66e9a563460882e7861b49f9331c5ded6fd7e927b37affbbd98f83bff1f7b916119044f1931df03c6ffedba2cfb + languageName: node + linkType: hard + +"@mapbox/mapbox-gl-supported@npm:^1.5.0": + version: 1.5.0 + resolution: "@mapbox/mapbox-gl-supported@npm:1.5.0" + peerDependencies: + mapbox-gl: ">=0.32.1 <2.0.0" + checksum: 0861f89e2a1e116a8731242fe049e6ad398ff3ac1481b87df9b042daa8ad76f5f6e1f60acc37d2bd483546817280259bde57e1aa51e46d1bef9efcecd4884efe + languageName: node + linkType: hard + +"@mapbox/point-geometry@npm:0.1.0, @mapbox/point-geometry@npm:^0.1.0, @mapbox/point-geometry@npm:~0.1.0": + version: 0.1.0 + resolution: "@mapbox/point-geometry@npm:0.1.0" + checksum: ed41c1ce0140de81039424415d9a199abba72cdb2287314e1b8c3e295da3224f7e8c1b0ae99a9b097703e7abe63e1978a518e29896989cc8bba3d482360bc22f + languageName: node + linkType: hard + +"@mapbox/tiny-sdf@npm:^1.1.1": + version: 1.2.5 + resolution: "@mapbox/tiny-sdf@npm:1.2.5" + checksum: d4cfd700c8ccd8b9183da78a943e314cada4184966a52758857cc7141391829a2da31b733046ee0a57e169396314533ffbde8445ce3476a193c6aefcc7bc883a + languageName: node + linkType: hard + +"@mapbox/unitbezier@npm:^0.0.0": + version: 0.0.0 + resolution: "@mapbox/unitbezier@npm:0.0.0" + checksum: 22ae6d56f743570fb222a5b0d323398e342007f689ae6445b6238d60a2faaa312b41c1de1fb2553bca4ccdb2d3f7006af04d94457c54b44a6454ce0198eebf9e + languageName: node + linkType: hard + +"@mapbox/vector-tile@npm:^1.3.1": + version: 1.3.1 + resolution: "@mapbox/vector-tile@npm:1.3.1" + dependencies: + "@mapbox/point-geometry": ~0.1.0 + checksum: 7093d4fa7d0382a0eae9d79526c5ad57c32099300b013d3afb4ab7499ac2a096f6f0a487cc81151ef81e0432a4b157513666b1592a4a4c1497341cde835551aa + languageName: node + linkType: hard + +"@mapbox/whoots-js@npm:^3.1.0": + version: 3.1.0 + resolution: "@mapbox/whoots-js@npm:3.1.0" + checksum: c1837c04effd205b207f441356d952eae7e8aad6c58f7c4900de50318c2147cf175936fc9434f20dfa409f9e6a78ec604d61e70c1c20572db0cc7655fbb65f50 + languageName: node + linkType: hard + "@mdx-js/react@npm:^2.1.5": version: 2.3.0 resolution: "@mdx-js/react@npm:2.3.0" @@ -4032,6 +4115,54 @@ __metadata: languageName: node linkType: hard +"@plotly/d3-sankey-circular@npm:0.33.1": + version: 0.33.1 + resolution: "@plotly/d3-sankey-circular@npm:0.33.1" + dependencies: + d3-array: ^1.2.1 + d3-collection: ^1.0.4 + d3-shape: ^1.2.0 + elementary-circuits-directed-graph: ^1.0.4 + checksum: cf1d7b1b703c9f8a39933b453dd2ba66dce2ad03982407bafb2a9571b3f433f2c77b090a98a99548b3fc6c5e7b4eaf8d9ce4da8d146f1331e51cca7604a8dba6 + languageName: node + linkType: hard + +"@plotly/d3-sankey@npm:0.7.2": + version: 0.7.2 + resolution: "@plotly/d3-sankey@npm:0.7.2" + dependencies: + d3-array: 1 + d3-collection: 1 + d3-shape: ^1.2.0 + checksum: fc3f764c62b9e8eec7f915c5118aa912381561289687324a132e1b9ee8829b771ae62ad4dd7cc2a97b21cd9116f5c5828f70656cf672af1a6a6937454d096d3d + languageName: node + linkType: hard + +"@plotly/d3@npm:3.8.1": + version: 3.8.1 + resolution: "@plotly/d3@npm:3.8.1" + checksum: 917e686b7cb02fd8fb16d29b477fb2736352e2fe79a6d37281da2c9cc607e5a62298cb43d41adc175209a29d6b375dbdcb02c5bee3a404ec8e343519c25268de + languageName: node + linkType: hard + +"@plotly/point-cluster@npm:^3.1.9": + version: 3.1.9 + resolution: "@plotly/point-cluster@npm:3.1.9" + dependencies: + array-bounds: ^1.0.1 + binary-search-bounds: ^2.0.4 + clamp: ^1.0.1 + defined: ^1.0.0 + dtype: ^2.0.0 + flatten-vertex-data: ^1.0.2 + is-obj: ^1.0.1 + math-log2: ^1.0.1 + parse-rect: ^1.2.0 + pick-by-alias: ^1.2.0 + checksum: 14056dbf1c5a81f7e386d33cb0e77fe1de255a91f6220e8e6739c36a68a67f4774272e303f74cad5295f2975aeb82b7ceaaadae80f4b9f480005672affd4cea8 + languageName: node + linkType: hard + "@popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.2": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" @@ -4319,11 +4450,11 @@ __metadata: resolution: "@sisense/sdk-cli@workspace:packages/sdk-cli" dependencies: "@babel/preset-env": ^7.20.2 - "@sisense/sdk-common": ^0.10.0 - "@sisense/sdk-data": ^0.10.0 - "@sisense/sdk-modeling": ^0.10.0 - "@sisense/sdk-query-client": ^0.10.0 - "@sisense/sdk-rest-client": ^0.10.0 + "@sisense/sdk-common": ^0.11.0 + "@sisense/sdk-data": ^0.11.0 + "@sisense/sdk-modeling": ^0.11.0 + "@sisense/sdk-query-client": ^0.11.0 + "@sisense/sdk-rest-client": ^0.11.0 "@types/inquirer": 8.2.6 "@types/yargs": ^17.0.22 cross-fetch: ^4.0.0 @@ -4338,7 +4469,7 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-common@^0.10.0, @sisense/sdk-common@workspace:^, @sisense/sdk-common@workspace:packages/sdk-common": +"@sisense/sdk-common@^0.11.0, @sisense/sdk-common@workspace:^, @sisense/sdk-common@workspace:packages/sdk-common": version: 0.0.0-use.local resolution: "@sisense/sdk-common@workspace:packages/sdk-common" dependencies: @@ -4349,12 +4480,12 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-data@^0.10.0, @sisense/sdk-data@workspace:^, @sisense/sdk-data@workspace:packages/sdk-data": +"@sisense/sdk-data@^0.11.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-rest-client": ^0.10.0 + "@sisense/sdk-rest-client": ^0.11.0 "@types/numeral": 2.0.2 eslint: ^8.40.0 guid-typescript: ^1.0.9 @@ -4364,24 +4495,24 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-modeling@^0.10.0, @sisense/sdk-modeling@workspace:packages/sdk-modeling": +"@sisense/sdk-modeling@^0.11.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": ^0.10.0 + "@sisense/sdk-data": ^0.11.0 eslint: ^8.40.0 prettier: 2.8.4 typescript: 4.8.4 languageName: unknown linkType: soft -"@sisense/sdk-query-client@^0.10.0, @sisense/sdk-query-client@workspace:packages/sdk-query-client": +"@sisense/sdk-query-client@^0.11.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-data": ^0.10.0 - "@sisense/sdk-rest-client": ^0.10.0 + "@sisense/sdk-data": ^0.11.0 + "@sisense/sdk-rest-client": ^0.11.0 "@sisense/task-manager": ^0.1.0 "@types/tar": ^6.1.4 "@types/uuid": ^9.0.0 @@ -4397,7 +4528,7 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-rest-client@^0.10.0, @sisense/sdk-rest-client@workspace:^, @sisense/sdk-rest-client@workspace:packages/sdk-rest-client": +"@sisense/sdk-rest-client@^0.11.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: @@ -4436,7 +4567,7 @@ __metadata: dependencies: "@preact/preset-vite": 2.5.0 "@sisense/sdk-data": "workspace:^" - "@sisense/sdk-ui": ^0.10.0 + "@sisense/sdk-ui": ^0.11.0 "@types/node": ^18.16.0 eslint: ^8.40.0 preact: ^10.13.2 @@ -4469,7 +4600,7 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sdk-ui@^0.10.0, @sisense/sdk-ui@workspace:^, @sisense/sdk-ui@workspace:packages/sdk-ui": +"@sisense/sdk-ui@^0.11.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: @@ -4478,10 +4609,10 @@ __metadata: "@emotion/styled": ^11.10.5 "@mui/material": ^5.11.6 "@sisense/sdk-common": "workspace:^" - "@sisense/sdk-data": ^0.10.0 - "@sisense/sdk-query-client": ^0.10.0 - "@sisense/sdk-rest-client": ^0.10.0 - "@sisense/sisense-charts": 5.1.0-alpha-812d1e70.0 + "@sisense/sdk-data": ^0.11.0 + "@sisense/sdk-query-client": ^0.11.0 + "@sisense/sdk-rest-client": ^0.11.0 + "@sisense/sisense-charts": 5.1.0-alpha-04052758.0 "@storybook/addon-actions": 7.0.24 "@storybook/addon-docs": 7.0.24 "@storybook/addon-essentials": 7.0.24 @@ -4499,6 +4630,7 @@ __metadata: "@types/react": 18.2.0 "@types/react-datepicker": ^4.11.2 "@types/react-dom": 18.2.0 + "@types/react-plotly.js": ^2.6.0 "@vitejs/plugin-react-swc": ^3.3.0 autoprefixer: ^10.4.14 classnames: ^2.3.2 @@ -4513,12 +4645,14 @@ __metadata: jsdom: ^22.1.0 lodash: ^4.17.21 merge-deep: ^3.0.3 + plotly.js: ^2.25.2 postcss: ^8.4.22 prettier: 2.8.4 react: 18.2.0 react-datepicker: ^4.16.0 react-dom: ^18.2.0 react-number-format: ^5.1.0 + react-plotly.js: ^2.6.0 sass: 1.58.3 storybook: 7.0.24 tailwindcss: ^3.3.1 @@ -4538,14 +4672,14 @@ __metadata: languageName: unknown linkType: soft -"@sisense/sisense-charts@npm:5.1.0-alpha-812d1e70.0": - version: 5.1.0-alpha-812d1e70.0 - resolution: "@sisense/sisense-charts@npm:5.1.0-alpha-812d1e70.0::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40sisense%2Fsisense-charts%2F5.1.0-alpha-812d1e70.0%2F7d465d57b7d7a9927a98562841f918c71d4f5aca" +"@sisense/sisense-charts@npm:5.1.0-alpha-04052758.0": + version: 5.1.0-alpha-04052758.0 + resolution: "@sisense/sisense-charts@npm:5.1.0-alpha-04052758.0::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40sisense%2Fsisense-charts%2F5.1.0-alpha-04052758.0%2F3163216e90d59c5c1d9e7aee0a49d12bbfafabfd" dependencies: "@emotion/css": ^11.9.0 highcharts: 10.3.3 lodash-es: ^4.17.21 - checksum: 23ca8b0bdcaef006b5e1b1f49dbbfe22232d732b476804144d46275ec6aa551ce0c916a8c92fa5ddb2a8ee14ba7d920de1ff08f8b1399205190b81f86f9b16fa + checksum: cc2e71e91078cb91c1cd8a8b3aefa4d63d63958e31f716dc874438c0757fbbebba14df10380004fffc681532cd49fd252b3ce34f9bbd3e5def8997e5607ed189 languageName: node linkType: hard @@ -5803,6 +5937,52 @@ __metadata: languageName: node linkType: hard +"@turf/area@npm:^6.4.0": + version: 6.5.0 + resolution: "@turf/area@npm:6.5.0" + dependencies: + "@turf/helpers": ^6.5.0 + "@turf/meta": ^6.5.0 + checksum: 4b62c6874f65bd477483ef259fa0fd34dc745a672a7544f5fbaba4a2b06a6b542edef8de786f907348594d847b38f82f22998534747d2810d2d0ed4587bf6e92 + languageName: node + linkType: hard + +"@turf/bbox@npm:^6.4.0": + version: 6.5.0 + resolution: "@turf/bbox@npm:6.5.0" + dependencies: + "@turf/helpers": ^6.5.0 + "@turf/meta": ^6.5.0 + checksum: 537be56ae0c5ad44e71a691717b35745e947e19a6bd9f20fdac2ab4318caf98cd88472d7dbf576e8b32ead5da034d273ffb3f4559d6d386820ddcb88a1f7fedd + languageName: node + linkType: hard + +"@turf/centroid@npm:^6.0.2": + version: 6.5.0 + resolution: "@turf/centroid@npm:6.5.0" + dependencies: + "@turf/helpers": ^6.5.0 + "@turf/meta": ^6.5.0 + checksum: 1a37c26232f9aabde9174c6408c42863fd9718a541ad664abf063ffd4c59764c1e7e974b607cadb3a1dae62e8fa4632d6b431a6bfdc9d42e8c21911e43d07b21 + languageName: node + linkType: hard + +"@turf/helpers@npm:^6.5.0": + version: 6.5.0 + resolution: "@turf/helpers@npm:6.5.0" + checksum: d57f746351357838c654e0a9b98be3285a14b447504fd6d59753d90c6d437410bb24805d61c65b612827f07f6c2ade823bb7e56e41a1a946217abccfbd64c117 + languageName: node + linkType: hard + +"@turf/meta@npm:^6.5.0": + version: 6.5.0 + resolution: "@turf/meta@npm:6.5.0" + dependencies: + "@turf/helpers": ^6.5.0 + checksum: c6bb936aa92bf3365e87a50dc65f248e070c5767a36fac390754c00c89bf2d1583418686ab19a10332bfa9340b8cac6aaf2c55dad7f5fcf77f1a2dda75ccf363 + languageName: node + linkType: hard + "@types/argparse@npm:1.0.38": version: 1.0.38 resolution: "@types/argparse@npm:1.0.38" @@ -6242,6 +6422,13 @@ __metadata: languageName: node linkType: hard +"@types/plotly.js@npm:*": + version: 2.12.26 + resolution: "@types/plotly.js@npm:2.12.26" + checksum: 3d623adcfc72e45f5398cacc5c0f877b3938ff421b28c60b6e58c06882d733fcda40001aaef0a8341ae46da4839199895477a895b40f45046b32784f74bf2b3f + languageName: node + linkType: hard + "@types/pretty-hrtime@npm:^1.0.0": version: 1.0.1 resolution: "@types/pretty-hrtime@npm:1.0.1" @@ -6309,6 +6496,16 @@ __metadata: languageName: node linkType: hard +"@types/react-plotly.js@npm:^2.6.0": + version: 2.6.0 + resolution: "@types/react-plotly.js@npm:2.6.0" + dependencies: + "@types/plotly.js": "*" + "@types/react": "*" + checksum: 91ab4eb8f1ab68add2884f01419884ce9746121681e6c9e883c8ce26e9a549108bf61cdeb2008b64bd1886934d4ac106af4c3c61d1d159e13236b4a1858e6ea8 + languageName: node + linkType: hard + "@types/react-transition-group@npm:^4.4.6": version: 4.4.6 resolution: "@types/react-transition-group@npm:4.4.6" @@ -7225,6 +7422,13 @@ __metadata: languageName: node linkType: hard +"abs-svg-path@npm:^0.1.1, abs-svg-path@npm:~0.1.1": + version: 0.1.1 + resolution: "abs-svg-path@npm:0.1.1" + checksum: af1a167c09e8bdb76c80adca7333f3d828e5b50e37b9702aa03675e271919e7b1eeaa35cce939970ecba14769953b7465ea34c2129ab683ddff9d973a07f164f + languageName: node + linkType: hard + "accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" @@ -7267,7 +7471,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^7.4.1": +"acorn@npm:^7.1.1, acorn@npm:^7.4.1": version: 7.4.1 resolution: "acorn@npm:7.4.1" bin: @@ -7395,6 +7599,13 @@ __metadata: languageName: node linkType: hard +"almost-equal@npm:^1.1.0": + version: 1.1.0 + resolution: "almost-equal@npm:1.1.0" + checksum: 6022fbd07dc46fdbcaac24472ab31ed1e9942fc3ae59b24a2df86ab3458a75d5e3e5df5af256f5e0068840308761d760dcd44d5787585df44d5bdb0756526caa + languageName: node + linkType: hard + "ansi-colors@npm:4.1.3, ansi-colors@npm:^4.1.3": version: 4.1.3 resolution: "ansi-colors@npm:4.1.3" @@ -7604,6 +7815,13 @@ __metadata: languageName: node linkType: hard +"array-bounds@npm:^1.0.0, array-bounds@npm:^1.0.1": + version: 1.0.1 + resolution: "array-bounds@npm:1.0.1" + checksum: 67367cfcaac3f83403ae9e4f9ff750d6f51202d971bf023c50cd913ba7ff58d0b1fbea2ebf3079a3996bcda0adf2f22b4e0ba6dde5cb6c1bc344533db938678d + languageName: node + linkType: hard + "array-buffer-byte-length@npm:^1.0.0": version: 1.0.0 resolution: "array-buffer-byte-length@npm:1.0.0" @@ -7614,6 +7832,13 @@ __metadata: languageName: node linkType: hard +"array-find-index@npm:^1.0.2": + version: 1.0.2 + resolution: "array-find-index@npm:1.0.2" + checksum: aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081 + languageName: node + linkType: hard + "array-flatten@npm:1.1.1": version: 1.1.1 resolution: "array-flatten@npm:1.1.1" @@ -7648,6 +7873,29 @@ __metadata: languageName: node linkType: hard +"array-normalize@npm:^1.1.4": + version: 1.1.4 + resolution: "array-normalize@npm:1.1.4" + dependencies: + array-bounds: ^1.0.0 + checksum: 821eda0e8a633e537340ec08bda4af13b99cf94660cb639009d75b94d919e6e3582b6aed8a622ec2fb80d50620c37ea0f6844d2a54ccad760ee341fcd92356ff + languageName: node + linkType: hard + +"array-range@npm:^1.0.1": + version: 1.0.1 + resolution: "array-range@npm:1.0.1" + checksum: ca00a9773bdb91294b9e7f74ad836b852146fb528cf3531f1493eec3f004affff6221676c718857318a5e4d1191e18262ad21c9b0ce53ab820334c254685333c + languageName: node + linkType: hard + +"array-rearrange@npm:^2.2.2": + version: 2.2.2 + resolution: "array-rearrange@npm:2.2.2" + checksum: bcf44e81b29f24a53211406b12ec964dba8f8d4e4a78a3d250dff70fe83c6858b54cbd89ebc70f5f59613e700a5a61cd98ab75693bc87bb1b6aa8639ae530f88 + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -8057,6 +8305,37 @@ __metadata: languageName: node linkType: hard +"binary-search-bounds@npm:^2.0.4": + version: 2.0.5 + resolution: "binary-search-bounds@npm:2.0.5" + checksum: e073e265570ad09fe7520835c620f1e95036c7e9696c4f2135c9b20f4b4a44e0306b38977e057b049dab60fea4ab53ed4ad2ee19d9bf44cb6b652aa081788b89 + languageName: node + linkType: hard + +"bit-twiddle@npm:^1.0.0, bit-twiddle@npm:^1.0.2": + version: 1.0.2 + resolution: "bit-twiddle@npm:1.0.2" + checksum: 2f97b47d755efac7bae5f49c2eb0929867dad2921a853a4507466b4fa5c5b97803fdf8b729ca56da35934888f50730888b8137614e9974b783f1023da908a1ea + languageName: node + linkType: hard + +"bitmap-sdf@npm:^1.0.0": + version: 1.0.4 + resolution: "bitmap-sdf@npm:1.0.4" + checksum: 3165504a2a3e97de14c110c80bf0e7fea662ad81702d02a5d9aeaf9482d8702be139f5c3b9b2c893d8472eb799ae0e5c49b3062edbceaddde5fe10039e4a8be5 + languageName: node + linkType: hard + +"bl@npm:^2.2.1": + version: 2.2.1 + resolution: "bl@npm:2.2.1" + dependencies: + readable-stream: ^2.3.5 + safe-buffer: ^5.1.1 + checksum: 4f5d9b258919646a8d02f1731379e53b6f6309e34596ae02afbc3aeb183910bd2d0b70681f889b7c620ca48f65dc1cd0992ee1266c90d6d7c3be60688d141233 + languageName: node + linkType: hard + "bl@npm:^4.0.3, bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -8382,6 +8661,15 @@ __metadata: languageName: node linkType: hard +"canvas-fit@npm:^1.5.0": + version: 1.5.0 + resolution: "canvas-fit@npm:1.5.0" + dependencies: + element-size: ^1.1.1 + checksum: 5ac1eca0b4c06318856cd746c677e5bee2ab8bdc0e5e977ee3f619c3ff3aef16b535a74202af6a18d5a286a07aec3d07f343615ddc2e02c97ea763d0571e647f + languageName: node + linkType: hard + "chai@npm:^4.3.7": version: 4.3.8 resolution: "chai@npm:4.3.8" @@ -8517,6 +8805,13 @@ __metadata: languageName: node linkType: hard +"clamp@npm:^1.0.1": + version: 1.0.1 + resolution: "clamp@npm:1.0.1" + checksum: 799bd7083736eb975cd4a9a7e8f1a1e38cc3cb6be0384f9732c1da263accb3205385e5c2880e661a0d5a74e0066bfbf8fcd17dd2f509595ce52dd04c84522833 + languageName: node + linkType: hard + "classnames@npm:^2.2.6, classnames@npm:^2.3.2": version: 2.3.2 resolution: "classnames@npm:2.3.2" @@ -8664,6 +8959,24 @@ __metadata: languageName: node linkType: hard +"color-alpha@npm:1.0.4": + version: 1.0.4 + resolution: "color-alpha@npm:1.0.4" + dependencies: + color-parse: ^1.3.8 + checksum: e0e5dd4c7b746113156abf10284efa69e9400e8ff0f2c1b54839e3fe87884c0e561dc09eefc335731b3315f64d42cf7a66671d96aeb5393fc551bd41e09f949f + languageName: node + linkType: hard + +"color-alpha@npm:^1.0.4": + version: 1.1.3 + resolution: "color-alpha@npm:1.1.3" + dependencies: + color-parse: ^1.4.1 + checksum: 7c47fa16e1ceffd567731439e4c84f7c971767eb522fa3ba74be1f5a4f22b204962b02a969ce32c40b0f2358b63ec44ddf1115f29264d07369c6103c0fed97e7 + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -8682,6 +8995,15 @@ __metadata: languageName: node linkType: hard +"color-id@npm:^1.1.0": + version: 1.1.0 + resolution: "color-id@npm:1.1.0" + dependencies: + clamp: ^1.0.1 + checksum: 11590fcaa3413b81a300e665f3995dd0f3e00bff14ce72eb90d387582f7f974e49ccca3576b3392fcdc5c55a7f138184825196113fd57ccee4d16f5136fd9bdb + languageName: node + linkType: hard + "color-name@npm:1.1.3": version: 1.1.3 resolution: "color-name@npm:1.1.3" @@ -8689,13 +9011,92 @@ __metadata: languageName: node linkType: hard -"color-name@npm:^1.1.4, color-name@npm:~1.1.4": +"color-name@npm:^1.0.0, color-name@npm:^1.1.4, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 languageName: node linkType: hard +"color-normalize@npm:1.5.0": + version: 1.5.0 + resolution: "color-normalize@npm:1.5.0" + dependencies: + clamp: ^1.0.1 + color-rgba: ^2.1.1 + dtype: ^2.0.0 + checksum: 4217dada6ec6302e2067fb4c113ec3d0976557466d7888f9499ebc96e33e67630f73718c3d9cbb9707e782f3561f279ec312a4b42d0ec6fff221ba4107c2b1f5 + languageName: node + linkType: hard + +"color-normalize@npm:^1.5.0": + version: 1.5.2 + resolution: "color-normalize@npm:1.5.2" + dependencies: + color-rgba: ^2.2.0 + dtype: ^2.0.0 + checksum: 162686b78da1d5276e3c9d7da6906a1823d2e939ce38fc38f7a45133c02838eb1c5d479bf3fbf3f1a5badc884c835730608cfec9b1f5eda34638b8b2d8aec28e + languageName: node + linkType: hard + +"color-parse@npm:1.3.8": + version: 1.3.8 + resolution: "color-parse@npm:1.3.8" + dependencies: + color-name: ^1.0.0 + defined: ^1.0.0 + is-plain-obj: ^1.1.0 + checksum: 181ede6955bcc4b7cdc2d53844ffffcd67532070a77089fa4d070b5ff2b0a9252beca5a3a4ddae3588e3623353f43ab5aa3f9ef8598113f2e62c72de5bd47017 + languageName: node + linkType: hard + +"color-parse@npm:^1.3.8, color-parse@npm:^1.4.1, color-parse@npm:^1.4.2": + version: 1.4.3 + resolution: "color-parse@npm:1.4.3" + dependencies: + color-name: ^1.0.0 + checksum: 3fb417857664c3f16250e60cf97a2b48b36b414c2ea6b163719fb4632879d98505ce4fe1c2a4afd870a399abcf1a794f9a0366556cb3f8eaebd41fddeebddc38 + languageName: node + linkType: hard + +"color-rgba@npm:2.1.1": + version: 2.1.1 + resolution: "color-rgba@npm:2.1.1" + dependencies: + clamp: ^1.0.1 + color-parse: ^1.3.8 + color-space: ^1.14.6 + checksum: 0bdceaffa2ced014f51bc6f070181554c578ace7e1a1bea567e5ead3a95c875b27daad33ebacd979d4f5590cd689b260ef4a89d19de2e8045665cbd92595a61d + languageName: node + linkType: hard + +"color-rgba@npm:^2.1.1, color-rgba@npm:^2.2.0": + version: 2.4.0 + resolution: "color-rgba@npm:2.4.0" + dependencies: + color-parse: ^1.4.2 + color-space: ^2.0.0 + checksum: a72b1001af4bed60d4677f6e368e3ea44fd228f6f3098182dd8d8d612165cb847f0792252539b36aa238840f45f1c644b8d7ed867e3d735d67d4e4b107384279 + languageName: node + linkType: hard + +"color-space@npm:^1.14.6": + version: 1.16.0 + resolution: "color-space@npm:1.16.0" + dependencies: + hsluv: ^0.0.3 + mumath: ^3.3.4 + checksum: 655ae748f81ef96f2a031e0aaa1e6a6dacf23731c4d7845d7d996dbf6a0a7971d533b378a82031b04e7397c55efd34a2fef784a4af1b89d81ff920e8af03fadf + languageName: node + linkType: hard + +"color-space@npm:^2.0.0": + version: 2.0.1 + resolution: "color-space@npm:2.0.1" + checksum: 98f8f6acc716d2332705ef6a98876b47e8e39094256b83eec1df17246a5b5c37d107ae682e87d96488b06da12df3595ed5ad4f0e354a45571e23fb2196e4c6e7 + languageName: node + linkType: hard + "color-support@npm:^1.1.2, color-support@npm:^1.1.3": version: 1.1.3 resolution: "color-support@npm:1.1.3" @@ -8749,6 +9150,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:2, commander@npm:^2.15.1, commander@npm:^2.19.0, commander@npm:^2.20.0": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e + languageName: node + linkType: hard + "commander@npm:^10.0.0": version: 10.0.1 resolution: "commander@npm:10.0.1" @@ -8756,13 +9164,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.19.0, commander@npm:^2.20.0": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e - languageName: node - linkType: hard - "commander@npm:^4.0.0": version: 4.1.1 resolution: "commander@npm:4.1.1" @@ -8846,7 +9247,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.6.2": +"concat-stream@npm:^1.5.2, concat-stream@npm:^1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -9040,6 +9441,13 @@ __metadata: languageName: node linkType: hard +"country-regex@npm:^1.1.0": + version: 1.1.0 + resolution: "country-regex@npm:1.1.0" + checksum: e9be62b811166632799abaee80cd1926febe04993641241965be4fc619ff15bbfb913cb63fb1b457627925531de3247647d4c53eda8b456a253d9ab1db7259d8 + languageName: node + linkType: hard + "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -9110,6 +9518,58 @@ __metadata: languageName: node linkType: hard +"css-font-size-keywords@npm:^1.0.0": + version: 1.0.0 + resolution: "css-font-size-keywords@npm:1.0.0" + checksum: 1b7479e85058ae88df597027557d3305adee34f04d29273840891f431e08275e016d10ebdfd8b23c35901f1e048d0dc5279f9cf3805490cb35213a4592c148a3 + languageName: node + linkType: hard + +"css-font-stretch-keywords@npm:^1.0.1": + version: 1.0.1 + resolution: "css-font-stretch-keywords@npm:1.0.1" + checksum: 4c3bf449e8331ba1fdb81e4f556df02081e999469b67b907c755b5d7449d87959a2754f77d1db5bd9f83af2ec0383b30f5e3a5ccab2393bf8d7008095fb69e23 + languageName: node + linkType: hard + +"css-font-style-keywords@npm:^1.0.1": + version: 1.0.1 + resolution: "css-font-style-keywords@npm:1.0.1" + checksum: 136720ebf56354cac4675b1a9daf1731289c0d89c2af7ebb425ac86bd786f440132f885fb79d8da9d4a785035b24c3b745383c27513b33349d2b5650f0a4a576 + languageName: node + linkType: hard + +"css-font-weight-keywords@npm:^1.0.0": + version: 1.0.0 + resolution: "css-font-weight-keywords@npm:1.0.0" + checksum: 6a36eff4c81c82f05d30e84f1b0c0c118b530960fef9307eeee8aaebf4147289971019acb1d1b2de88b65e8b46df2101133fa45bedc82084c445764733bcdf92 + languageName: node + linkType: hard + +"css-font@npm:^1.0.0, css-font@npm:^1.2.0": + version: 1.2.0 + resolution: "css-font@npm:1.2.0" + dependencies: + css-font-size-keywords: ^1.0.0 + css-font-stretch-keywords: ^1.0.1 + css-font-style-keywords: ^1.0.1 + css-font-weight-keywords: ^1.0.0 + css-global-keywords: ^1.0.1 + css-system-font-keywords: ^1.0.0 + pick-by-alias: ^1.2.0 + string-split-by: ^1.0.0 + unquote: ^1.1.0 + checksum: e1b327c846eedcd4d7a36c42f76093c82bd994b1c1d2b9bcca9675032c449370282083bbe43a89339e557f60c0474126da9ab8beb9d90e146ea29b14de1adcf5 + languageName: node + linkType: hard + +"css-global-keywords@npm:^1.0.1": + version: 1.0.1 + resolution: "css-global-keywords@npm:1.0.1" + checksum: 390c46d9a02595a11f3eec2ff9851a97870801f1428fc6090c6e7a4f58f65fc80142da6fac928f9e800dda24b16eb6894e123b7a7fa0761e0958ccaf652c27f7 + languageName: node + linkType: hard + "css-loader@npm:6.7.3": version: 6.7.3 resolution: "css-loader@npm:6.7.3" @@ -9141,6 +9601,13 @@ __metadata: languageName: node linkType: hard +"css-system-font-keywords@npm:^1.0.0": + version: 1.0.0 + resolution: "css-system-font-keywords@npm:1.0.0" + checksum: 2a2ce26d6faf3e1f35385a141eed2929adbe072af6e1c03b17b7312af1b5dbfd31cdde1dc0697b97baa223bb2f9a2c24751ecf6f5c5f80712317d9ce315703e3 + languageName: node + linkType: hard + "css-what@npm:^6.0.1": version: 6.1.0 resolution: "css-what@npm:6.1.0" @@ -9155,6 +9622,13 @@ __metadata: languageName: node linkType: hard +"csscolorparser@npm:~1.0.3": + version: 1.0.3 + resolution: "csscolorparser@npm:1.0.3" + checksum: e40f3045ea15c7e7eaa78e110412fe8b820d47b698c1eb1d1e7ecb42703bf447406a24304b891ae9df61e85d947f33fc67bd0120c7f9e3a5183e6e0b9afff92c + languageName: node + linkType: hard + "cssesc@npm:^3.0.0": version: 3.0.0 resolution: "cssesc@npm:3.0.0" @@ -9194,17 +9668,163 @@ __metadata: languageName: node linkType: hard -"damerau-levenshtein@npm:^1.0.8": - version: 1.0.8 - resolution: "damerau-levenshtein@npm:1.0.8" - checksum: d240b7757544460ae0586a341a53110ab0a61126570ef2d8c731e3eab3f0cb6e488e2609e6a69b46727635de49be20b071688698744417ff1b6c1d7ccd03e0de +"d3-array@npm:1, d3-array@npm:^1.2.1": + version: 1.2.4 + resolution: "d3-array@npm:1.2.4" + checksum: d0be1fa7d72dbfac8a3bcffbb669d42bcb9128d8818d84d2b1df0c60bbe4c8e54a798be0457c55a219b399e2c2fabcbd581cbb130eb638b5436b0618d7e56000 languageName: node linkType: hard -"dargs@npm:^7.0.0": - version: 7.0.0 - resolution: "dargs@npm:7.0.0" - checksum: b8f1e3cba59c42e1f13a114ad4848c3fc1cf7470f633ee9e9f1043762429bc97d91ae31b826fb135eefde203a3fdb20deb0c0a0222ac29d937b8046085d668d1 +"d3-collection@npm:1, d3-collection@npm:^1.0.4": + version: 1.0.7 + resolution: "d3-collection@npm:1.0.7" + checksum: 9c6b910a9da0efb021e294509f98263ca4f62d10b997bb30ccfb6edd582b703da36e176b968b5bac815fbb0f328e49643c38cf93b5edf8572a179ba55cf4a09d + languageName: node + linkType: hard + +"d3-color@npm:1 - 3": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b + languageName: node + linkType: hard + +"d3-dispatch@npm:1": + version: 1.0.6 + resolution: "d3-dispatch@npm:1.0.6" + checksum: b4ecb016b6dda8b99aa4263b2d0a0c7b12e7dea93e4b0ce3013c94dca4d360d9ba00f5bdc15dc944cc4543af8e341067bd628f061f7b8deb642257e2ac90d06c + languageName: node + linkType: hard + +"d3-force@npm:^1.2.1": + version: 1.2.1 + resolution: "d3-force@npm:1.2.1" + dependencies: + d3-collection: 1 + d3-dispatch: 1 + d3-quadtree: 1 + d3-timer: 1 + checksum: b73fe29d6c9a9c432ae65166d71238d14578a3a9537df095bebff87b7814161cd2822aff54a38d2400edb98b7f6d9221a810dcad7a53c6e8ddff0973f44ab3fa + languageName: node + linkType: hard + +"d3-format@npm:^1.4.5": + version: 1.4.5 + resolution: "d3-format@npm:1.4.5" + checksum: 1b8b2c0bca182173bccd290a43e8b635a83fc8cfe52ec878c7bdabb997d47daac11f2b175cebbe73f807f782ad655f542bdfe18180ca5eb3498a3a82da1e06ab + languageName: node + linkType: hard + +"d3-geo-projection@npm:^2.9.0": + version: 2.9.0 + resolution: "d3-geo-projection@npm:2.9.0" + dependencies: + commander: 2 + d3-array: 1 + d3-geo: ^1.12.0 + resolve: ^1.1.10 + bin: + geo2svg: bin/geo2svg + geograticule: bin/geograticule + geoproject: bin/geoproject + geoquantize: bin/geoquantize + geostitch: bin/geostitch + checksum: 05ff12195fa521a675b6e43672b0bdd9cc13b37f8ead8124b4d5292c81b765a3c9454ff44bd4bfabd0f072e7618869247574e3f6ace559478d6039bf7465e1e2 + languageName: node + linkType: hard + +"d3-geo@npm:^1.12.0, d3-geo@npm:^1.12.1": + version: 1.12.1 + resolution: "d3-geo@npm:1.12.1" + dependencies: + d3-array: 1 + checksum: 8ede498e5fce65c127403646f5cc6181a858a1e401e23e2856ce50ad27e6fdf8b49aeb88d2fad02696879d5825a45420ca1b5db9fa9c935ee413fe15b5bc37c4 + languageName: node + linkType: hard + +"d3-hierarchy@npm:^1.1.9": + version: 1.1.9 + resolution: "d3-hierarchy@npm:1.1.9" + checksum: 5fd8761c302252cb9abe9ce2a0934fc97104dd0df8d1b5de6472532903416f40e13b4b58d03ce215a0b816d7129c4ed4503bd4fdbc00a130fdcf46a63d734a52 + languageName: node + linkType: hard + +"d3-interpolate@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: 1 - 3 + checksum: a42ba314e295e95e5365eff0f604834e67e4a3b3c7102458781c477bd67e9b24b6bb9d8e41ff5521050a3f2c7c0c4bbbb6e187fd586daa3980943095b267e78b + languageName: node + linkType: hard + +"d3-path@npm:1": + version: 1.0.9 + resolution: "d3-path@npm:1.0.9" + checksum: d4382573baf9509a143f40944baeff9fead136926aed6872f7ead5b3555d68925f8a37935841dd51f1d70b65a294fe35c065b0906fb6e42109295f6598fc16d0 + languageName: node + linkType: hard + +"d3-quadtree@npm:1": + version: 1.0.7 + resolution: "d3-quadtree@npm:1.0.7" + checksum: 32181f578cbd69eed6b240073fed7f977f8039a121a3b9fc58ea1eea0c3c14d1237ef48cb4f80abb833063f8b0e7b885ef6de734e7bcc4e5b37e53ec444830f8 + languageName: node + linkType: hard + +"d3-shape@npm:^1.2.0": + version: 1.3.7 + resolution: "d3-shape@npm:1.3.7" + dependencies: + d3-path: 1 + checksum: 46566a3ab64a25023653bf59d64e81e9e6c987e95be985d81c5cedabae5838bd55f4a201a6b69069ca862eb63594cd263cac9034afc2b0e5664dfe286c866129 + languageName: node + linkType: hard + +"d3-time-format@npm:^2.2.3": + version: 2.3.0 + resolution: "d3-time-format@npm:2.3.0" + dependencies: + d3-time: 1 + checksum: 5445eaaf2b3b2095cdc1fa75dfd2f361a61c39b677dcc1c2ba4cb6bc0442953de0fbaaa397d7d7a9325ad99c63d869f162a713e150e826ff8af482615664cb3f + languageName: node + linkType: hard + +"d3-time@npm:1, d3-time@npm:^1.1.0": + version: 1.1.0 + resolution: "d3-time@npm:1.1.0" + checksum: 33fcfff94ff093dde2048c190ecca8b39fe0ec8b3c61e9fc39c5f6072ce5b86dd2b91823f086366995422bbbac7f74fd9abdb7efe4f292a73b1c6197c699cc78 + languageName: node + linkType: hard + +"d3-timer@npm:1": + version: 1.0.10 + resolution: "d3-timer@npm:1.0.10" + checksum: f7040953672deb2dfa03830ace80dbbcb212f80890218eba15dcca6f33f74102d943023ccc2a563295195cd8c63639bb2410ef1691c8fecff4a114fdf5c666f4 + languageName: node + linkType: hard + +"d@npm:1, d@npm:^1.0.1": + version: 1.0.1 + resolution: "d@npm:1.0.1" + dependencies: + es5-ext: ^0.10.50 + type: ^1.0.1 + checksum: 49ca0639c7b822db670de93d4fbce44b4aa072cd848c76292c9978a8cd0fff1028763020ff4b0f147bd77bfe29b4c7f82e0f71ade76b2a06100543cdfd948d19 + languageName: node + linkType: hard + +"damerau-levenshtein@npm:^1.0.8": + version: 1.0.8 + resolution: "damerau-levenshtein@npm:1.0.8" + checksum: d240b7757544460ae0586a341a53110ab0a61126570ef2d8c731e3eab3f0cb6e488e2609e6a69b46727635de49be20b071688698744417ff1b6c1d7ccd03e0de + languageName: node + linkType: hard + +"dargs@npm:^7.0.0": + version: 7.0.0 + resolution: "dargs@npm:7.0.0" + checksum: b8f1e3cba59c42e1f13a114ad4848c3fc1cf7470f633ee9e9f1043762429bc97d91ae31b826fb135eefde203a3fdb20deb0c0a0222ac29d937b8046085d668d1 languageName: node linkType: hard @@ -9251,7 +9871,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:2.6.9, debug@npm:^2.6.9": +"debug@npm:2, debug@npm:2.6.9, debug@npm:^2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" dependencies: @@ -9340,7 +9960,7 @@ __metadata: languageName: node linkType: hard -"deep-is@npm:^0.1.3": +"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 @@ -9408,6 +10028,13 @@ __metadata: languageName: node linkType: hard +"defined@npm:^1.0.0": + version: 1.0.1 + resolution: "defined@npm:1.0.1" + checksum: b1a852300bdb57f297289b55eafdd0c517afaa3ec8190e78fce91b9d8d0c0369d4505ecbdacfd3d98372e664f4a267d9bd793938d4a8c76209c9d9516fbe2101 + languageName: node + linkType: hard + "defu@npm:^6.1.2": version: 6.1.2 resolution: "defu@npm:6.1.2" @@ -9487,6 +10114,13 @@ __metadata: languageName: node linkType: hard +"detect-kerning@npm:^2.1.2": + version: 2.1.2 + resolution: "detect-kerning@npm:2.1.2" + checksum: bffd569e6b9b900cfa09205d5f423f7e70cfb06e0c182afac8225920c584c67692c970e060cf25271680e16377761b2419586616488f3522876ccd5ec7662809 + languageName: node + linkType: hard + "detect-node@npm:^2.0.4": version: 2.1.0 resolution: "detect-node@npm:2.1.0" @@ -9674,7 +10308,31 @@ __metadata: languageName: node linkType: hard -"duplexify@npm:^3.5.0, duplexify@npm:^3.6.0": +"draw-svg-path@npm:^1.0.0": + version: 1.0.0 + resolution: "draw-svg-path@npm:1.0.0" + dependencies: + abs-svg-path: ~0.1.1 + normalize-svg-path: ~0.1.0 + checksum: d1f6b7979193d3989bccc330ee9bf96219df7a1c5925066b4b14a98177c9def1ef5cdaf50b453c13fc7f73c3d06ebd850c3b662143982f33c6061d127f599015 + languageName: node + linkType: hard + +"dtype@npm:^2.0.0": + version: 2.0.0 + resolution: "dtype@npm:2.0.0" + checksum: a8fcdf549eda9237d453a6d9a163a93e7ac5dff10fe50e33e6cca04fe303a63bc63490fc0b4c7a53f058bedb1bf28588bf0b80a6f68d35a99cfa37c90fe2ee59 + languageName: node + linkType: hard + +"dup@npm:^1.0.0": + version: 1.0.0 + resolution: "dup@npm:1.0.0" + checksum: 1abda5b5b0b85f7ed1fef0fbe68e426c0951b0b9c0daea264d0e2fd844d6cc644e838faefc4e7db5385896a244e1284bfe3d3f6b4e673f37aac5f58f61970e36 + languageName: node + linkType: hard + +"duplexify@npm:^3.4.5, duplexify@npm:^3.5.0, duplexify@npm:^3.6.0": version: 3.7.1 resolution: "duplexify@npm:3.7.1" dependencies: @@ -9697,6 +10355,13 @@ __metadata: languageName: unknown linkType: soft +"earcut@npm:^2.1.5, earcut@npm:^2.2.2": + version: 2.2.4 + resolution: "earcut@npm:2.2.4" + checksum: aea0466cb2f24e0c3c57148d8d28ac9846f53c4f43ee66780826474303ac851b305ef988152d0bdeb31e8f7ca939dc0df737e7505cfb1c1bdf2ff9d7f9ea2faa + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -9729,6 +10394,22 @@ __metadata: languageName: node linkType: hard +"element-size@npm:^1.1.1": + version: 1.1.1 + resolution: "element-size@npm:1.1.1" + checksum: 0592332e840e0aa7dbc9fb83c63bd871671ccacb7fac5a0b4d2b9df1dfc57a74613d7bb125f2e9a83f059e3f181d98ac3b32436eda626c44bde90272f0119ea6 + languageName: node + linkType: hard + +"elementary-circuits-directed-graph@npm:^1.0.4": + version: 1.3.1 + resolution: "elementary-circuits-directed-graph@npm:1.3.1" + dependencies: + strongly-connected-components: ^1.0.1 + checksum: e88536739ab587e92dcae0046bf17b6182902fd75cbaf53027e148bb01810cf52c7afa17ff53b7c28f1016e1b54e42c1d5ec583c6a44bb578f8aa4053384d19a + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -9966,6 +10647,17 @@ __metadata: languageName: node linkType: hard +"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.46, es5-ext@npm:^0.10.50": + version: 0.10.62 + resolution: "es5-ext@npm:0.10.62" + dependencies: + es6-iterator: ^2.0.3 + es6-symbol: ^3.1.3 + next-tick: ^1.1.0 + checksum: 25f42f6068cfc6e393cf670bc5bba249132c5f5ec2dd0ed6e200e6274aca2fed8e9aec8a31c76031744c78ca283c57f0b41c7e737804c6328c7b8d3fbcba7983 + languageName: node + linkType: hard + "es6-error@npm:^4.0.1": version: 4.1.1 resolution: "es6-error@npm:4.1.1" @@ -9973,6 +10665,17 @@ __metadata: languageName: node linkType: hard +"es6-iterator@npm:^2.0.3": + version: 2.0.3 + resolution: "es6-iterator@npm:2.0.3" + dependencies: + d: 1 + es5-ext: ^0.10.35 + es6-symbol: ^3.1.1 + checksum: 6e48b1c2d962c21dee604b3d9f0bc3889f11ed5a8b33689155a2065d20e3107e2a69cc63a71bd125aeee3a589182f8bbcb5c8a05b6a8f38fa4205671b6d09697 + languageName: node + linkType: hard + "es6-object-assign@npm:^1.1.0": version: 1.1.0 resolution: "es6-object-assign@npm:1.1.0" @@ -9980,6 +10683,28 @@ __metadata: languageName: node linkType: hard +"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3": + version: 3.1.3 + resolution: "es6-symbol@npm:3.1.3" + dependencies: + d: ^1.0.1 + ext: ^1.1.2 + checksum: cd49722c2a70f011eb02143ef1c8c70658d2660dead6641e160b94619f408b9cf66425515787ffe338affdf0285ad54f4eae30ea5bd510e33f8659ec53bcaa70 + languageName: node + linkType: hard + +"es6-weak-map@npm:^2.0.3": + version: 2.0.3 + resolution: "es6-weak-map@npm:2.0.3" + dependencies: + d: 1 + es5-ext: ^0.10.46 + es6-iterator: ^2.0.3 + es6-symbol: ^3.1.1 + checksum: 19ca15f46d50948ce78c2da5f21fb5b1ef45addd4fe17b5df952ff1f2a3d6ce4781249bc73b90995257264be2a98b2ec749bb2aba0c14b5776a1154178f9c927 + languageName: node + linkType: hard + "esbuild-plugin-alias@npm:^0.2.1": version: 0.2.1 resolution: "esbuild-plugin-alias@npm:0.2.1" @@ -10359,6 +11084,25 @@ __metadata: languageName: node linkType: hard +"escodegen@npm:^1.11.1": + version: 1.14.3 + resolution: "escodegen@npm:1.14.3" + dependencies: + esprima: ^4.0.1 + estraverse: ^4.2.0 + esutils: ^2.0.2 + optionator: ^0.8.1 + source-map: ~0.6.1 + dependenciesMeta: + source-map: + optional: true + bin: + escodegen: bin/escodegen.js + esgenerate: bin/esgenerate.js + checksum: 381cdc4767ecdb221206bbbab021b467bbc2a6f5c9a99c9e6353040080bdd3dfe73d7604ad89a47aca6ea7d58bc635f6bd3fbc8da9a1998e9ddfa8372362ccd0 + languageName: node + linkType: hard + "escodegen@npm:^2.0.0": version: 2.1.0 resolution: "escodegen@npm:2.1.0" @@ -10860,7 +11604,7 @@ __metadata: languageName: node linkType: hard -"estraverse@npm:^4.1.1": +"estraverse@npm:^4.1.1, estraverse@npm:^4.2.0": version: 4.3.0 resolution: "estraverse@npm:4.3.0" checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 @@ -11027,6 +11771,15 @@ __metadata: languageName: node linkType: hard +"ext@npm:^1.1.2": + version: 1.7.0 + resolution: "ext@npm:1.7.0" + dependencies: + type: ^2.7.2 + checksum: ef481f9ef45434d8c867cfd09d0393b60945b7c8a1798bedc4514cb35aac342ccb8d8ecb66a513e6a2b4ec1e294a338e3124c49b29736f8e7c735721af352c31 + languageName: node + linkType: hard + "extend@npm:^3.0.0": version: 3.0.2 resolution: "extend@npm:3.0.2" @@ -11059,6 +11812,16 @@ __metadata: languageName: node linkType: hard +"falafel@npm:^2.1.0": + version: 2.2.5 + resolution: "falafel@npm:2.2.5" + dependencies: + acorn: ^7.1.1 + isarray: ^2.0.1 + checksum: bfd46e92bca87670fd2ef31c6123088431271f98f3b2a300a58e9c3e5f4f9944f0058f7daaaaa8cefd68d461a334bd528c952bcec17061522b68b61f7925b382 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -11086,6 +11849,15 @@ __metadata: languageName: node linkType: hard +"fast-isnumeric@npm:^1.1.4": + version: 1.1.4 + resolution: "fast-isnumeric@npm:1.1.4" + dependencies: + is-string-blank: ^1.0.1 + checksum: 7485fd8d9bcd3be03a6b38fb0fbb289669e4f3eedf59a6a007bd2f536bc04c8a8af318fd5d102b7898d7a2e8966deb8934983aeae282e7b6642e23e647425327 + languageName: node + linkType: hard + "fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" @@ -11093,7 +11865,7 @@ __metadata: languageName: node linkType: hard -"fast-levenshtein@npm:^2.0.6": +"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c @@ -11312,6 +12084,15 @@ __metadata: languageName: node linkType: hard +"flatten-vertex-data@npm:^1.0.2": + version: 1.0.2 + resolution: "flatten-vertex-data@npm:1.0.2" + dependencies: + dtype: ^2.0.0 + checksum: 45757b5f023b4ab76a7b44105b3ce6e3303b6f937deaabc67d4800fb31eccbaf489b115d11cd16b7456fe9b99f79b350ed6d5a2a285f96c0cbaadc1b105d461c + languageName: node + linkType: hard + "flow-parser@npm:0.*": version: 0.215.1 resolution: "flow-parser@npm:0.215.1" @@ -11329,6 +12110,24 @@ __metadata: languageName: node linkType: hard +"font-atlas@npm:^2.1.0": + version: 2.1.0 + resolution: "font-atlas@npm:2.1.0" + dependencies: + css-font: ^1.0.0 + checksum: 2a1309cf480ced5fe2ca4b897b3ddee48777edafd76786b48344e8a321a8e4b103596338bb7c8df9116a09249607d9892688ab7ae072a82b89d133ba2323f6b7 + languageName: node + linkType: hard + +"font-measure@npm:^1.2.2": + version: 1.2.2 + resolution: "font-measure@npm:1.2.2" + dependencies: + css-font: ^1.2.0 + checksum: 2cc2ad1772adcafec651e9ccc13981708de178005b0cbed8f2724f242b20a7deb2c93cc9fd0f775b27513da4e62fd2fac068d1c650d79998ac97d2f452d5010e + languageName: node + linkType: hard + "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -11431,6 +12230,16 @@ __metadata: languageName: node linkType: hard +"from2@npm:^2.3.0": + version: 2.3.0 + resolution: "from2@npm:2.3.0" + dependencies: + inherits: ^2.0.1 + readable-stream: ^2.0.0 + checksum: 6080eba0793dce32f475141fb3d54cc15f84ee52e420ee22ac3ab0ad639dc95a1875bc6eb9c0e1140e94972a36a89dc5542491b85f1ab8df0c126241e0f1a61b + languageName: node + linkType: hard + "fromentries@npm:^1.2.0": version: 1.3.2 resolution: "fromentries@npm:1.3.2" @@ -11614,6 +12423,13 @@ __metadata: languageName: node linkType: hard +"geojson-vt@npm:^3.2.1": + version: 3.2.1 + resolution: "geojson-vt@npm:3.2.1" + checksum: 7c7973cfaf9e3bb1c1dc9578ec00e602efb6f8d57f4dd7f6b28baeb7825bcaeb1684018b850211e333ab4b90a4a89a02ff7793732c505d67101ccbc38e307e02 + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -11621,6 +12437,13 @@ __metadata: languageName: node linkType: hard +"get-canvas-context@npm:^1.0.1": + version: 1.0.2 + resolution: "get-canvas-context@npm:1.0.2" + checksum: 7068d497311071f80244de4f6a5a9ce7405539f9a0eca8f8f88295c1c09b991f4265f9db3494433a19bba1e86496d2741f53f7869fb102b90528edc5daead9e1 + languageName: node + linkType: hard + "get-func-name@npm:^2.0.0": version: 2.0.0 resolution: "get-func-name@npm:2.0.0" @@ -11717,6 +12540,60 @@ __metadata: languageName: node linkType: hard +"gl-mat4@npm:^1.2.0": + version: 1.2.0 + resolution: "gl-mat4@npm:1.2.0" + checksum: 04fb6b7a34ad1f0c97f6825d047fecaae26a4ee3e431f635e2fa9dd98a25a394b7c9e6202b885b354e13ebb3b04d144f482a1e87631152c0a9870ce4133ea511 + languageName: node + linkType: hard + +"gl-matrix@npm:^3.2.1": + version: 3.4.3 + resolution: "gl-matrix@npm:3.4.3" + checksum: c47830ba727f3d0fab635c48135af96aef66274079a3e0afd6f68b68c98eae9fc1bcfdc7312fe2301e4fd22dd24c5e0f1b5d025960a208e50d07101ed8d940f9 + languageName: node + linkType: hard + +"gl-text@npm:^1.3.1": + version: 1.3.1 + resolution: "gl-text@npm:1.3.1" + dependencies: + bit-twiddle: ^1.0.2 + color-normalize: ^1.5.0 + css-font: ^1.2.0 + detect-kerning: ^2.1.2 + es6-weak-map: ^2.0.3 + flatten-vertex-data: ^1.0.2 + font-atlas: ^2.1.0 + font-measure: ^1.2.2 + gl-util: ^3.1.2 + is-plain-obj: ^1.1.0 + object-assign: ^4.1.1 + parse-rect: ^1.2.0 + parse-unit: ^1.0.1 + pick-by-alias: ^1.2.0 + regl: ^2.0.0 + to-px: ^1.0.1 + typedarray-pool: ^1.1.0 + checksum: fb78872ba09eee6bfc5a2b96074a037428b739cc91d6bb6db933bfe5a75e2fc52244fa7d779f9b25c42231b0765ba24eaf75dd7f63122f4a981fed448bc556be + languageName: node + linkType: hard + +"gl-util@npm:^3.1.2": + version: 3.1.3 + resolution: "gl-util@npm:3.1.3" + dependencies: + is-browser: ^2.0.1 + is-firefox: ^1.0.3 + is-plain-obj: ^1.1.0 + number-is-integer: ^1.0.1 + object-assign: ^4.1.0 + pick-by-alias: ^1.2.0 + weak-map: ^1.0.5 + checksum: f1625858545923539c74bad032f85f056002039807bf27080d42287ffbb76139edfd3205ad4867c25da565fd4b18192aa5e64f2c008244827fa19ca7e9172ee2 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -11881,6 +12758,165 @@ __metadata: languageName: node linkType: hard +"glsl-inject-defines@npm:^1.0.1": + version: 1.0.3 + resolution: "glsl-inject-defines@npm:1.0.3" + dependencies: + glsl-token-inject-block: ^1.0.0 + glsl-token-string: ^1.0.1 + glsl-tokenizer: ^2.0.2 + checksum: 91d707cc4cdc924ec1ea13bcc332357c41754542e3c3d8d95f2331569c339a9cfab37c343e253fea10e56d5a70f930b9027b62431c5c786e34e7d8f785456836 + languageName: node + linkType: hard + +"glsl-resolve@npm:0.0.1": + version: 0.0.1 + resolution: "glsl-resolve@npm:0.0.1" + dependencies: + resolve: ^0.6.1 + xtend: ^2.1.2 + checksum: 8bc83f4c56c06d771761c32042fff8fed60f4bcc320d5fc3ec86cf115eb3c0bb5bacf3ca5f80cb88133399734d02c65788845bca9eb90244e08c41e98ddb0275 + languageName: node + linkType: hard + +"glsl-token-assignments@npm:^2.0.0": + version: 2.0.2 + resolution: "glsl-token-assignments@npm:2.0.2" + checksum: efd6051cfd0e5dc4749cc05530e79c42b2396685345695d1232ab3904011e65f117110a2ef7e92a06bc687abf6182f4e90b6b51cc4ab20147aafcc57f724ecb5 + languageName: node + linkType: hard + +"glsl-token-defines@npm:^1.0.0": + version: 1.0.0 + resolution: "glsl-token-defines@npm:1.0.0" + dependencies: + glsl-tokenizer: ^2.0.0 + checksum: 79c3738e4c858c1eb400a7d288a372cf275b6aacee4eed2a89f1c4269a9849d3210bbc770123af408bf0a9d8bf909e558154a27f4c976cee287ea9a4bf9b0047 + languageName: node + linkType: hard + +"glsl-token-depth@npm:^1.1.0, glsl-token-depth@npm:^1.1.1": + version: 1.1.2 + resolution: "glsl-token-depth@npm:1.1.2" + checksum: 97fff701eef20c2ef4552885f060dbf05b307f59b9f1637ddd73c3d5e7d3cc5b4851123706be9f2590042566132f5175ae86a82576bdcfa1edd4625c58d6843c + languageName: node + linkType: hard + +"glsl-token-descope@npm:^1.0.2": + version: 1.0.2 + resolution: "glsl-token-descope@npm:1.0.2" + dependencies: + glsl-token-assignments: ^2.0.0 + glsl-token-depth: ^1.1.0 + glsl-token-properties: ^1.0.0 + glsl-token-scope: ^1.1.0 + checksum: a0d578d5e71178cd5679504a94a60e0811980f46fe6b3cb018bb165530faa75ffcb61b62a1984052223cf2455e36c08f9aa72cf3fdce419aac5d8844ec84cf5a + languageName: node + linkType: hard + +"glsl-token-inject-block@npm:^1.0.0": + version: 1.1.0 + resolution: "glsl-token-inject-block@npm:1.1.0" + checksum: a08aca0f0684ee00eb9beb44993ab59d6d6330947d282204fe114c09a34fe9b9719f035eda0ed317a5409e5d4118674955c225034bb28c5d8334bcc3f905d7dc + languageName: node + linkType: hard + +"glsl-token-properties@npm:^1.0.0": + version: 1.0.1 + resolution: "glsl-token-properties@npm:1.0.1" + checksum: 9b4d1caf02d52f6407479bcd3e780133d6952ba6ae0d85ccd4f3de9ead061a173da0820b0238a0e721ae75370b645152d468bc24eb6f1fd37b5000c500d97cd4 + languageName: node + linkType: hard + +"glsl-token-scope@npm:^1.1.0, glsl-token-scope@npm:^1.1.1": + version: 1.1.2 + resolution: "glsl-token-scope@npm:1.1.2" + checksum: d62812c81a399d7bdd001ce4414293e508dbd78d480b1984190c8d3243c14817c34109893a71503a50ef09de28e4b0c0124be1979292aba5df3f0207eace1b70 + languageName: node + linkType: hard + +"glsl-token-string@npm:^1.0.1": + version: 1.0.1 + resolution: "glsl-token-string@npm:1.0.1" + checksum: 3260c1486b620277396ecb92b13434764eddcd59330ffb7a25d0e5fc2750fbd4330899e2acb5ab36408ea7451f3e103418ca0430b4c6a225a7e5f318b5028fda + languageName: node + linkType: hard + +"glsl-token-whitespace-trim@npm:^1.0.0": + version: 1.0.0 + resolution: "glsl-token-whitespace-trim@npm:1.0.0" + checksum: ffb0d09118a18fa807a249414762e93835d303f476feae8bbb80320ec850a5aa24fa2760245b374312310ebb0ef099da9a9190ff5b587be45566d2aee1503777 + languageName: node + linkType: hard + +"glsl-tokenizer@npm:^2.0.0, glsl-tokenizer@npm:^2.0.2": + version: 2.1.5 + resolution: "glsl-tokenizer@npm:2.1.5" + dependencies: + through2: ^0.6.3 + checksum: daf70e91c66a3143fe0b22be18a0f8cc965d7b81f73a58b14d55d08593bdcc3f996996549bda78b4cc822d7fe8c216aaeaab71f2695d802fb79fc9e89fb507d3 + languageName: node + linkType: hard + +"glslify-bundle@npm:^5.0.0": + version: 5.1.1 + resolution: "glslify-bundle@npm:5.1.1" + dependencies: + glsl-inject-defines: ^1.0.1 + glsl-token-defines: ^1.0.0 + glsl-token-depth: ^1.1.1 + glsl-token-descope: ^1.0.2 + glsl-token-scope: ^1.1.1 + glsl-token-string: ^1.0.1 + glsl-token-whitespace-trim: ^1.0.0 + glsl-tokenizer: ^2.0.2 + murmurhash-js: ^1.0.0 + shallow-copy: 0.0.1 + checksum: e3a5e438dd0ffbdaa72adad23b4eae80258f3f903b3fde3d7022d2f662df1bbb76ce479c2c030ed4aebeb899965e7e3bb7db83748963e0643bbbded3bacdebff + languageName: node + linkType: hard + +"glslify-deps@npm:^1.2.5": + version: 1.3.2 + resolution: "glslify-deps@npm:1.3.2" + dependencies: + "@choojs/findup": ^0.2.0 + events: ^3.2.0 + glsl-resolve: 0.0.1 + glsl-tokenizer: ^2.0.0 + graceful-fs: ^4.1.2 + inherits: ^2.0.1 + map-limit: 0.0.1 + resolve: ^1.0.0 + checksum: 3eb50a26171f66d02582cfa90a9ac7c964ff970d44cd48025af2015fe465be1632cfc7fcec05f5aa4210571ec936c4a26de0e100d9c4d0c2ab655362290a616c + languageName: node + linkType: hard + +"glslify@npm:^7.0.0, glslify@npm:^7.1.1": + version: 7.1.1 + resolution: "glslify@npm:7.1.1" + dependencies: + bl: ^2.2.1 + concat-stream: ^1.5.2 + duplexify: ^3.4.5 + falafel: ^2.1.0 + from2: ^2.3.0 + glsl-resolve: 0.0.1 + glsl-token-whitespace-trim: ^1.0.0 + glslify-bundle: ^5.0.0 + glslify-deps: ^1.2.5 + minimist: ^1.2.5 + resolve: ^1.1.5 + stack-trace: 0.0.9 + static-eval: ^2.0.5 + through2: ^2.0.1 + xtend: ^4.0.0 + bin: + glslify: bin.js + checksum: 2bb59c0480041ca73dcb6e0c6f56d3f063e546c87901f82582a914864ebf836145289316bddb507874bf9405113a3efb3efbeacc0e888337d7d268ef1823ca7b + languageName: node + linkType: hard + "gopd@npm:^1.0.1": version: 1.0.1 resolution: "gopd@npm:1.0.1" @@ -11904,6 +12940,13 @@ __metadata: languageName: node linkType: hard +"grid-index@npm:^1.1.0": + version: 1.1.0 + resolution: "grid-index@npm:1.1.0" + checksum: 0e9d427b606ac644a723719116bb067639c01dccc881f161525e8eddb13b2de3b8a274641ef6d926d7629877ad8ed06b45290d52dd2d8af45532c50ccbbefe43 + languageName: node + linkType: hard + "guid-typescript@npm:^1.0.9": version: 1.0.9 resolution: "guid-typescript@npm:1.0.9" @@ -11980,6 +13023,24 @@ __metadata: languageName: node linkType: hard +"has-hover@npm:^1.0.1": + version: 1.0.1 + resolution: "has-hover@npm:1.0.1" + dependencies: + is-browser: ^2.0.1 + checksum: ba5b89fa611eb4c71fea87249174b44330ff5b4dacc99a40cafa4035bf8269174f906a900318d2dca183c7625750c7f2b5370172cf8b7b0e66bb6bc5efe8f129 + languageName: node + linkType: hard + +"has-passive-events@npm:^1.0.0": + version: 1.0.0 + resolution: "has-passive-events@npm:1.0.0" + dependencies: + is-browser: ^2.0.1 + checksum: 604b447817d210186080e0b2e6d349c9fc7527f77b77abab4db9883b8dc519e5b799178df8bba176cf39c17d8ec05b3ce4e0813315be7b05abf882eb3bca4827 + languageName: node + linkType: hard + "has-property-descriptors@npm:^1.0.0": version: 1.0.0 resolution: "has-property-descriptors@npm:1.0.0" @@ -12145,6 +13206,13 @@ __metadata: languageName: node linkType: hard +"hsluv@npm:^0.0.3": + version: 0.0.3 + resolution: "hsluv@npm:0.0.3" + checksum: 2cd6dbe3423de7b8dade6429530388c4473dd3f7ded52d2c395dc99b4a0712c2ab215c8186a38a3617e51f344f555a562ac785db433e7364d75011657d1f17da + languageName: node + linkType: hard + "html-encoding-sniffer@npm:^3.0.0": version: 3.0.0 resolution: "html-encoding-sniffer@npm:3.0.0" @@ -12313,7 +13381,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": +"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24, iconv-lite@npm:^0.4.4": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" dependencies: @@ -12340,7 +13408,7 @@ __metadata: languageName: node linkType: hard -"ieee754@npm:^1.1.13": +"ieee754@npm:^1.1.12, ieee754@npm:^1.1.13": version: 1.2.1 resolution: "ieee754@npm:1.2.1" checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e @@ -12427,7 +13495,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 @@ -12638,6 +13706,13 @@ __metadata: languageName: node linkType: hard +"is-browser@npm:^2.0.1": + version: 2.1.0 + resolution: "is-browser@npm:2.1.0" + checksum: fe8d9a68d028a8b16111b70ff662efc163b4708dc3a26024ff83a3416b6221321289de95b41abcb72cd41884e01a815d587e2086c98df5662137c6fe38bb3d73 + languageName: node + linkType: hard + "is-buffer@npm:^1.0.2, is-buffer@npm:^1.1.5": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" @@ -12725,6 +13800,20 @@ __metadata: languageName: node linkType: hard +"is-finite@npm:^1.0.1": + version: 1.1.0 + resolution: "is-finite@npm:1.1.0" + checksum: 532b97ed3d03e04c6bd203984d9e4ba3c0c390efee492bad5d1d1cd1802a68ab27adbd3ef6382f6312bed6c8bb1bd3e325ea79a8dc8fe080ed7a06f5f97b93e7 + languageName: node + linkType: hard + +"is-firefox@npm:^1.0.3": + version: 1.0.3 + resolution: "is-firefox@npm:1.0.3" + checksum: 8d4800d6804373ac83bf636a0cfe5b0a5d60ab9a129f0c9eeb4ec604a46f91703c965ad9123c9c1858f56ed71369988a51c1f40afb579e205e50c856abd9b59b + languageName: node + linkType: hard + "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -12771,6 +13860,13 @@ __metadata: languageName: node linkType: hard +"is-iexplorer@npm:^1.0.0": + version: 1.0.0 + resolution: "is-iexplorer@npm:1.0.0" + checksum: cc6c14c46080a7e2c4a914487d4b82d866f09f70aa7272b939a14166badbeaa6bd97523a84a9b817eac3cb09417d0e60e462ac0e1c544a52cfcbba46ea183339 + languageName: node + linkType: hard + "is-interactive@npm:^1.0.0": version: 1.0.0 resolution: "is-interactive@npm:1.0.0" @@ -12792,6 +13888,13 @@ __metadata: languageName: node linkType: hard +"is-mobile@npm:^4.0.0": + version: 4.0.0 + resolution: "is-mobile@npm:4.0.0" + checksum: 1c4f32ab030ac6c203d63b547ef23933eacfebe81fd9d800c86739d5a73afad7983aea4c5e832c3d9c0a63d1e68cd318637490e6406bdda1cbadc8f701d5d557 + languageName: node + linkType: hard + "is-module@npm:^1.0.0": version: 1.0.0 resolution: "is-module@npm:1.0.0" @@ -12832,6 +13935,13 @@ __metadata: languageName: node linkType: hard +"is-obj@npm:^1.0.1": + version: 1.0.1 + resolution: "is-obj@npm:1.0.1" + checksum: 3ccf0efdea12951e0b9c784e2b00e77e87b2f8bd30b42a498548a8afcc11b3287342a2030c308e473e93a7a19c9ea7854c99a8832a476591c727df2a9c79796c + languageName: node + linkType: hard + "is-obj@npm:^2.0.0": version: 2.0.0 resolution: "is-obj@npm:2.0.0" @@ -12930,6 +14040,13 @@ __metadata: languageName: node linkType: hard +"is-string-blank@npm:^1.0.1": + version: 1.0.1 + resolution: "is-string-blank@npm:1.0.1" + checksum: 00a0955c2bac08cc84f9f878d2a3fdba86997ac23c0b661e50f39efba635444d9cec84237337200be9a4e07234069318498592817614525cd959ae0d43df2151 + languageName: node + linkType: hard + "is-string@npm:^1.0.5, is-string@npm:^1.0.7": version: 1.0.7 resolution: "is-string@npm:1.0.7" @@ -12939,6 +14056,13 @@ __metadata: languageName: node linkType: hard +"is-svg-path@npm:^1.0.1": + version: 1.0.2 + resolution: "is-svg-path@npm:1.0.2" + checksum: ed35f610d117f3bd2b6a1a637e9c03136f408976221c2396acfa811636ac71853b7509338245853154e2da69f9b5223a65ecf8d1d6192bd8b337a32b46b589e3 + languageName: node + linkType: hard + "is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3": version: 1.0.4 resolution: "is-symbol@npm:1.0.4" @@ -13029,7 +14153,14 @@ __metadata: languageName: node linkType: hard -"isarray@npm:^2.0.5": +"isarray@npm:0.0.1": + version: 0.0.1 + resolution: "isarray@npm:0.0.1" + checksum: 49191f1425681df4a18c2f0f93db3adb85573bcdd6a4482539d98eac9e705d8961317b01175627e860516a2fc45f8f9302db26e5a380a97a520e272e2a40a8d4 + languageName: node + linkType: hard + +"isarray@npm:^2.0.1, isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a @@ -13608,6 +14739,13 @@ __metadata: languageName: node linkType: hard +"kdbush@npm:^3.0.0": + version: 3.0.0 + resolution: "kdbush@npm:3.0.0" + checksum: bc5fa433958e42664a8a92457e4f0d1db55b3b8e36956aac0102964adb2eab043bdbff156570dc8d867144ceff588fb7a1c6e099ba9be068cd1767a73e1ace92 + languageName: node + linkType: hard + "keyv@npm:^4.5.3": version: 4.5.3 resolution: "keyv@npm:4.5.3" @@ -13803,6 +14941,16 @@ __metadata: languageName: node linkType: hard +"levn@npm:~0.3.0": + version: 0.3.0 + resolution: "levn@npm:0.3.0" + dependencies: + prelude-ls: ~1.1.2 + type-check: ~0.3.2 + checksum: 0d084a524231a8246bb10fec48cdbb35282099f6954838604f3c7fc66f2e16fa66fd9cc2f3f20a541a113c4dafdf181e822c887c8a319c9195444e6c64ac395e + languageName: node + linkType: hard + "license-webpack-plugin@npm:4.0.2": version: 4.0.2 resolution: "license-webpack-plugin@npm:4.0.2" @@ -14256,6 +15404,15 @@ __metadata: languageName: node linkType: hard +"map-limit@npm:0.0.1": + version: 0.0.1 + resolution: "map-limit@npm:0.0.1" + dependencies: + once: ~1.3.0 + checksum: e7ad9a66037d4168f2e3dbd20654cb0503126911e0e43c8fe95ae1a3ea54b72e84f94f8577a13598708a29a096cc6ecf136622ea6a5d393c227f84f6f1445b83 + languageName: node + linkType: hard + "map-obj@npm:^1.0.0": version: 1.0.1 resolution: "map-obj@npm:1.0.1" @@ -14277,6 +15434,37 @@ __metadata: languageName: node linkType: hard +"mapbox-gl@npm:1.10.1": + version: 1.10.1 + resolution: "mapbox-gl@npm:1.10.1" + dependencies: + "@mapbox/geojson-rewind": ^0.5.0 + "@mapbox/geojson-types": ^1.0.2 + "@mapbox/jsonlint-lines-primitives": ^2.0.2 + "@mapbox/mapbox-gl-supported": ^1.5.0 + "@mapbox/point-geometry": ^0.1.0 + "@mapbox/tiny-sdf": ^1.1.1 + "@mapbox/unitbezier": ^0.0.0 + "@mapbox/vector-tile": ^1.3.1 + "@mapbox/whoots-js": ^3.1.0 + csscolorparser: ~1.0.3 + earcut: ^2.2.2 + geojson-vt: ^3.2.1 + gl-matrix: ^3.2.1 + grid-index: ^1.1.0 + minimist: ^1.2.5 + murmurhash-js: ^1.0.0 + pbf: ^3.2.1 + potpack: ^1.0.1 + quickselect: ^2.0.0 + rw: ^1.3.3 + supercluster: ^7.0.0 + tinyqueue: ^2.0.3 + vt-pbf: ^3.1.1 + checksum: 94e285367f631c29d794b19017d25d635895b74d2b2c2934613c8e7c95cf18aff3760d6061d93865d5b67d1a738c843005785cf50c8e3a9173ccd6ac332d938b + languageName: node + linkType: hard + "markdown-to-jsx@npm:^7.1.8": version: 7.3.2 resolution: "markdown-to-jsx@npm:7.3.2" @@ -14295,6 +15483,13 @@ __metadata: languageName: node linkType: hard +"math-log2@npm:^1.0.1": + version: 1.0.1 + resolution: "math-log2@npm:1.0.1" + checksum: b9a9c746ec0b28157865b5b9e9bdba25d04b77112f45ec65eb129b07ae42b0f017d59919d21e409fb6bb6587da28e5c40b4e49e80b917fa00a74f7ea5446932e + languageName: node + linkType: hard + "mdast-util-definitions@npm:^4.0.0": version: 4.0.0 resolution: "mdast-util-definitions@npm:4.0.0" @@ -14724,6 +15919,40 @@ __metadata: languageName: node linkType: hard +"mouse-change@npm:^1.4.0": + version: 1.4.0 + resolution: "mouse-change@npm:1.4.0" + dependencies: + mouse-event: ^1.0.0 + checksum: 67f7e5c7e24a61b3eca8e547a3ba56a5b3bc861bdd42e7a3d02a0c2ff0a19ebe7a024dc744bb30ad30a056cfd59ea40aa7df3b8e9ceb51da084c6bff24abe576 + languageName: node + linkType: hard + +"mouse-event-offset@npm:^3.0.2": + version: 3.0.2 + resolution: "mouse-event-offset@npm:3.0.2" + checksum: f8cf9885bcb37b23a27c010105c736ec696384da95010ff7a5fcb7c44aa79661eb008c8e4861ee5f054cd145825b9f88c25cdabc62f4b91940ed67d7c84562b6 + languageName: node + linkType: hard + +"mouse-event@npm:^1.0.0": + version: 1.0.5 + resolution: "mouse-event@npm:1.0.5" + checksum: 1e7fa5deb6360b9a9e4de0da701b03f0c3467c55bd6f3c18f1dd22fc156aafbeb390fb8c75dffc69cbdd1c7c5511d4fe92967ccc400a1cb77083c70eb330d5f9 + languageName: node + linkType: hard + +"mouse-wheel@npm:^1.2.0": + version: 1.2.0 + resolution: "mouse-wheel@npm:1.2.0" + dependencies: + right-now: ^1.0.0 + signum: ^1.0.0 + to-px: ^1.0.1 + checksum: 28e41ccac43fb4e284cfbbe348c0c5e391417bb997a3f8ad2e280152883721ad55aec1596200060ad4d99b256f5b167dbdf35d4dd83c84c80401a95fa0e5725c + languageName: node + linkType: hard + "mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" @@ -14778,6 +16007,22 @@ __metadata: languageName: node linkType: hard +"mumath@npm:^3.3.4": + version: 3.3.4 + resolution: "mumath@npm:3.3.4" + dependencies: + almost-equal: ^1.1.0 + checksum: 1c4e9fbfa65541399290db370fa6334b09585600f701b99b947ceca6ab080bcd67dc13c8a48c6a99032f2ce46e4522a5c845bd98f9e59c68424a2aee3cbd0d2f + languageName: node + linkType: hard + +"murmurhash-js@npm:^1.0.0": + version: 1.0.0 + resolution: "murmurhash-js@npm:1.0.0" + checksum: 083cea92a11bc9eb25be1446fc92eded3f49731bc1ad34fa8023afd68c234d1dd59458d70eb20e667b1383bedeeb8dfb1a16c89913b6ffe3584fd22fb598739d + languageName: node + linkType: hard + "mute-stream@npm:0.0.8": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -14805,6 +16050,13 @@ __metadata: languageName: node linkType: hard +"native-promise-only@npm:^0.8.1": + version: 0.8.1 + resolution: "native-promise-only@npm:0.8.1" + checksum: bb4d8416c47d1b2cef0d4eb2c7f3442a9ed04d3734287f4037dfb7ff25948612976928e5baed105081927d5337d3f657e3a42ad2e8cca38a6428a81b32cd6dc4 + languageName: node + linkType: hard + "natural-compare-lite@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare-lite@npm:1.4.0" @@ -14819,6 +16071,19 @@ __metadata: languageName: node linkType: hard +"needle@npm:^2.5.2": + version: 2.9.1 + resolution: "needle@npm:2.9.1" + dependencies: + debug: ^3.2.6 + iconv-lite: ^0.4.4 + sax: ^1.2.4 + bin: + needle: ./bin/needle + checksum: 746ae3a3782f0a057ff304a98843cc6f2009f978a0fad0c3e641a9d46d0b5702bb3e197ba08aecd48678067874a991c4f5fc320c7e51a4c041d9dd3441146cf0 + languageName: node + linkType: hard + "needle@npm:^3.1.0": version: 3.2.0 resolution: "needle@npm:3.2.0" @@ -14846,6 +16111,13 @@ __metadata: languageName: node linkType: hard +"next-tick@npm:^1.1.0": + version: 1.1.0 + resolution: "next-tick@npm:1.1.0" + checksum: 83b5cf36027a53ee6d8b7f9c0782f2ba87f4858d977342bfc3c20c21629290a2111f8374d13a81221179603ffc4364f38374b5655d17b6a8f8a8c77bdea4fe8b + languageName: node + linkType: hard + "ng-packagr@npm:^15.2.2": version: 15.2.2 resolution: "ng-packagr@npm:15.2.2" @@ -15072,6 +16344,22 @@ __metadata: languageName: node linkType: hard +"normalize-svg-path@npm:^1.0.0": + version: 1.1.0 + resolution: "normalize-svg-path@npm:1.1.0" + dependencies: + svg-arc-to-cubic-bezier: ^3.0.0 + checksum: 106e108b2f99e9e222a1c6edfc859523c6c3c2b0a6ba64743ed08af120b23b9bc2c16682bc2ae043a24c011c34c8252376c68525cf11735c6f110b571740eb2e + languageName: node + linkType: hard + +"normalize-svg-path@npm:~0.1.0": + version: 0.1.0 + resolution: "normalize-svg-path@npm:0.1.0" + checksum: acf31e84e7ad3bf72fe7e3e329bc14be16a03c68d1586b3b592b8331f1bdbe0f97abe517e5a805dd01b9905b0c4d541c4d6fa0a81f994523531c43dd73e9d796 + languageName: node + linkType: hard + "npm-bundled@npm:^3.0.0": version: 3.0.0 resolution: "npm-bundled@npm:3.0.0" @@ -15229,6 +16517,15 @@ __metadata: languageName: node linkType: hard +"number-is-integer@npm:^1.0.1": + version: 1.0.1 + resolution: "number-is-integer@npm:1.0.1" + dependencies: + is-finite: ^1.0.1 + checksum: 6cbe30d839d254e5577c8f27f3038339b2d75b3731c6f4a6b4b0168eb00ae716a8035763c9e72ff1b603df805408fab4fa48235570eec1e7b90368bc26edecae + languageName: node + linkType: hard + "numeral@npm:^2.0.6": version: 2.0.6 resolution: "numeral@npm:2.0.6" @@ -15280,7 +16577,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": +"object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f @@ -15417,6 +16714,15 @@ __metadata: languageName: node linkType: hard +"once@npm:~1.3.0": + version: 1.3.3 + resolution: "once@npm:1.3.3" + dependencies: + wrappy: 1 + checksum: 8e832de08b1d73b470e01690c211cb4fcefccab1fd1bd19e706d572d74d3e9b7e38a8bfcdabdd364f9f868757d9e8e5812a59817dc473eaf698ff3bfae2219f2 + languageName: node + linkType: hard + "onetime@npm:^5.1.0, onetime@npm:^5.1.2": version: 5.1.2 resolution: "onetime@npm:5.1.2" @@ -15467,6 +16773,20 @@ __metadata: languageName: node linkType: hard +"optionator@npm:^0.8.1": + version: 0.8.3 + resolution: "optionator@npm:0.8.3" + dependencies: + deep-is: ~0.1.3 + fast-levenshtein: ~2.0.6 + levn: ~0.3.0 + prelude-ls: ~1.1.2 + type-check: ~0.3.2 + word-wrap: ~1.2.3 + checksum: b8695ddf3d593203e25ab0900e265d860038486c943ff8b774f596a310f8ceebdb30c6832407a8198ba3ec9debe1abe1f51d4aad94843612db3b76d690c61d34 + languageName: node + linkType: hard + "optionator@npm:^0.9.3": version: 0.9.3 resolution: "optionator@npm:0.9.3" @@ -15657,6 +16977,13 @@ __metadata: languageName: node linkType: hard +"parenthesis@npm:^3.1.5": + version: 3.1.8 + resolution: "parenthesis@npm:3.1.8" + checksum: 47d86bb7d9d7d50cfa89c1766a8d4a1223c054ac6d3d2e5baad64cb5c680a2d5d51c26008f2e192300f6111e378f7ca78f6d6ef9732788db059b14815ce05706 + languageName: node + linkType: hard + "parse-entities@npm:^2.0.0": version: 2.0.0 resolution: "parse-entities@npm:2.0.0" @@ -15693,10 +17020,33 @@ __metadata: languageName: node linkType: hard -"parse-node-version@npm:^1.0.1": +"parse-node-version@npm:^1.0.1": + version: 1.0.1 + resolution: "parse-node-version@npm:1.0.1" + checksum: c192393b6a978092c1ef8df2c42c0a02e4534b96543e23d335f1b9b5b913ac75473d18fe6050b58d6995c57fb383ee71a5cb8397e363caaf38a6df8215cc52fd + languageName: node + linkType: hard + +"parse-rect@npm:^1.2.0": + version: 1.2.0 + resolution: "parse-rect@npm:1.2.0" + dependencies: + pick-by-alias: ^1.2.0 + checksum: 5abf383475cef7a0bc636b80c56e0202a1f428f219c3fa7f2a3f57d60ccaecacc6fefa37fa28275989c6d330e0157dcadc54d03761c46f961188b1ffde00afe3 + languageName: node + linkType: hard + +"parse-svg-path@npm:^0.1.2": + version: 0.1.2 + resolution: "parse-svg-path@npm:0.1.2" + checksum: bba7d4b4207fcc9eaf553b0d34db96ea8a1173635bc94528b5b66e1581902d4792d8d6229103764f01af4d839274234e97a4fa1c6f0fe7dcce195383848cec56 + languageName: node + linkType: hard + +"parse-unit@npm:^1.0.1": version: 1.0.1 - resolution: "parse-node-version@npm:1.0.1" - checksum: c192393b6a978092c1ef8df2c42c0a02e4534b96543e23d335f1b9b5b913ac75473d18fe6050b58d6995c57fb383ee71a5cb8397e363caaf38a6df8215cc52fd + resolution: "parse-unit@npm:1.0.1" + checksum: fdd7d2b91a3e536d7835e408caec21345eac6d4ae442d0cfecd5ebb8750c89cfc3ed4cd5da389826313134aedca04e30e52188005b564ec13c212720821731c8 languageName: node linkType: hard @@ -15855,6 +17205,18 @@ __metadata: languageName: node linkType: hard +"pbf@npm:^3.2.1": + version: 3.2.1 + resolution: "pbf@npm:3.2.1" + dependencies: + ieee754: ^1.1.12 + resolve-protobuf-schema: ^2.1.0 + bin: + pbf: bin/pbf + checksum: 8033f5e21fffdc485e85d50bbff07ab3313c6841c3630a4ba9bc9e82d2e9005ab92000a1a90cb911223caa44316293e367bab607dd8110d5c771e6c8aaad63e1 + languageName: node + linkType: hard + "peek-stream@npm:^1.1.0": version: 1.1.3 resolution: "peek-stream@npm:1.1.3" @@ -15873,6 +17235,20 @@ __metadata: languageName: node linkType: hard +"performance-now@npm:^2.1.0": + version: 2.1.0 + resolution: "performance-now@npm:2.1.0" + checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550 + languageName: node + linkType: hard + +"pick-by-alias@npm:^1.2.0": + version: 1.2.0 + resolution: "pick-by-alias@npm:1.2.0" + checksum: 720c85f13a75f7ca865fdc44f924419b47ec0e21555c523b3c6ed3dd7304e1447255a092fb49a2d55f30252d5856be9aa044ef00822eb08dad4368db230d1b19 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -15995,6 +17371,70 @@ __metadata: languageName: node linkType: hard +"plotly.js@npm:^2.25.2": + version: 2.25.2 + resolution: "plotly.js@npm:2.25.2" + dependencies: + "@plotly/d3": 3.8.1 + "@plotly/d3-sankey": 0.7.2 + "@plotly/d3-sankey-circular": 0.33.1 + "@turf/area": ^6.4.0 + "@turf/bbox": ^6.4.0 + "@turf/centroid": ^6.0.2 + canvas-fit: ^1.5.0 + color-alpha: 1.0.4 + color-normalize: 1.5.0 + color-parse: 1.3.8 + color-rgba: 2.1.1 + country-regex: ^1.1.0 + d3-force: ^1.2.1 + d3-format: ^1.4.5 + d3-geo: ^1.12.1 + d3-geo-projection: ^2.9.0 + d3-hierarchy: ^1.1.9 + d3-interpolate: ^3.0.1 + d3-time: ^1.1.0 + d3-time-format: ^2.2.3 + fast-isnumeric: ^1.1.4 + gl-mat4: ^1.2.0 + gl-text: ^1.3.1 + glslify: ^7.1.1 + has-hover: ^1.0.1 + has-passive-events: ^1.0.0 + is-mobile: ^4.0.0 + mapbox-gl: 1.10.1 + mouse-change: ^1.4.0 + mouse-event-offset: ^3.0.2 + mouse-wheel: ^1.2.0 + native-promise-only: ^0.8.1 + parse-svg-path: ^0.1.2 + point-in-polygon: ^1.1.0 + polybooljs: ^1.2.0 + probe-image-size: ^7.2.3 + regl: "npm:@plotly/regl@^2.1.2" + regl-error2d: ^2.0.12 + regl-line2d: ^3.1.2 + regl-scatter2d: ^3.2.9 + regl-splom: ^1.0.14 + strongly-connected-components: ^1.0.1 + superscript-text: ^1.0.0 + svg-path-sdf: ^1.1.3 + tinycolor2: ^1.4.2 + to-px: 1.0.1 + topojson-client: ^3.1.0 + webgl-context: ^2.2.0 + world-calendars: ^1.0.3 + checksum: fa28179677ef799e20d9a6864de8a76d0910d57f0480fae7db474c233b0650276d3ff47d3dc675055abe5e1b73e1a9319ab0daf11b182ad6d166b7dd7ddaacc8 + languageName: node + linkType: hard + +"point-in-polygon@npm:^1.1.0": + version: 1.1.0 + resolution: "point-in-polygon@npm:1.1.0" + checksum: 67a6374f0b79bc872bde8e375d7d5ea011a1419c5f4320dfb7705801cd3a8fcaee8bff385465e075b2ce863bbc86ccd74c63345d9f326981cd0807642bc5199c + languageName: node + linkType: hard + "polished@npm:^4.2.2": version: 4.2.2 resolution: "polished@npm:4.2.2" @@ -16004,6 +17444,13 @@ __metadata: languageName: node linkType: hard +"polybooljs@npm:^1.2.0": + version: 1.2.0 + resolution: "polybooljs@npm:1.2.0" + checksum: a5faaa71c3dca26ae0cf02748b8f6fc4a5b97ca4afe7044e249da4167cfc43a983471e38c02732c3debfd338a673e0e9e6215bf9114294b5db65b6ae8150195a + languageName: node + linkType: hard + "postcss-import@npm:^15.1.0": version: 15.1.0 resolution: "postcss-import@npm:15.1.0" @@ -16168,6 +17615,13 @@ __metadata: languageName: node linkType: hard +"potpack@npm:^1.0.1": + version: 1.0.2 + resolution: "potpack@npm:1.0.2" + checksum: 9dfdbbce012ce80842249abcdd89e20222eb8ae96beba8d578b7e41e78feefc7e33b5c72d46fb8dd3a1e382cb4da9c34574764d88aa8849ab36f542fd2088b42 + languageName: node + linkType: hard + "preact@npm:^10.13.2": version: 10.17.1 resolution: "preact@npm:10.17.1" @@ -16182,6 +17636,13 @@ __metadata: languageName: node linkType: hard +"prelude-ls@npm:~1.1.2": + version: 1.1.2 + resolution: "prelude-ls@npm:1.1.2" + checksum: c4867c87488e4a0c233e158e4d0d5565b609b105d75e4c05dc760840475f06b731332eb93cc8c9cecb840aa8ec323ca3c9a56ad7820ad2e63f0261dadcb154e4 + languageName: node + linkType: hard + "prettier-linter-helpers@npm:^1.0.0": version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" @@ -16259,6 +17720,17 @@ __metadata: languageName: node linkType: hard +"probe-image-size@npm:^7.2.3": + version: 7.2.3 + resolution: "probe-image-size@npm:7.2.3" + dependencies: + lodash.merge: ^4.6.2 + needle: ^2.5.2 + stream-parser: ~0.3.1 + checksum: 1a5eeb8f5cb979172144a5d7a017c70fcd664ccc8af9ad3a803903ee81864abea4036adae4fc6e66e9ae21bd3ce0febefaf1f32e65a77ff226b2eb61e9e4978c + languageName: node + linkType: hard + "proc-log@npm:^3.0.0": version: 3.0.0 resolution: "proc-log@npm:3.0.0" @@ -16343,6 +17815,13 @@ __metadata: languageName: node linkType: hard +"protocol-buffers-schema@npm:^3.3.1": + version: 3.6.0 + resolution: "protocol-buffers-schema@npm:3.6.0" + checksum: 8713b5770f6745ddbcdf3bbd03ee020624d506233bb567927a6615a6f69a5bd620a5f49597f34f4115792b853a4c9cb9e2d5d6b930a1c04bf198023e45c1c349 + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -16476,6 +17955,22 @@ __metadata: languageName: node linkType: hard +"quickselect@npm:^2.0.0": + version: 2.0.0 + resolution: "quickselect@npm:2.0.0" + checksum: ed2e78431050d223fb75da20ee98011aef1a03f7cb04e1a32ee893402e640be3cfb76d72e9dbe01edf3bb457ff6a62e5c2d85748424d1aa531f6ba50daef098c + languageName: node + linkType: hard + +"raf@npm:^3.4.1": + version: 3.4.1 + resolution: "raf@npm:3.4.1" + dependencies: + performance-now: ^2.1.0 + checksum: 50ba284e481c8185dbcf45fc4618ba3aec580bb50c9121385d5698cb6012fe516d2015b1df6dd407a7b7c58d44be8086108236affbce1861edd6b44637c8cd52 + languageName: node + linkType: hard + "ramda@npm:0.29.0": version: 0.29.0 resolution: "ramda@npm:0.29.0" @@ -16673,6 +18168,18 @@ __metadata: languageName: node linkType: hard +"react-plotly.js@npm:^2.6.0": + version: 2.6.0 + resolution: "react-plotly.js@npm:2.6.0" + dependencies: + prop-types: ^15.8.1 + peerDependencies: + plotly.js: ">1.34.0" + react: ">0.13.0" + checksum: e826a3c94ec831c9d8fd92fa73aeece35d8ac04e0828d8362b28139d5b2923b83530356fb39c690debce20c47ba5d0a809f458a8c741d94edf88211e4ea4439f + languageName: node + linkType: hard + "react-popper@npm:^2.2.5, react-popper@npm:^2.3.0": version: 2.3.0 resolution: "react-popper@npm:2.3.0" @@ -16809,7 +18316,19 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.2.2, readable-stream@npm:~2.3.6": +"readable-stream@npm:>=1.0.33-1 <1.1.0-0": + version: 1.0.34 + resolution: "readable-stream@npm:1.0.34" + dependencies: + core-util-is: ~1.0.0 + inherits: ~2.0.1 + isarray: 0.0.1 + string_decoder: ~0.10.x + checksum: 85042c537e4f067daa1448a7e257a201070bfec3dd2706abdbd8ebc7f3418eb4d3ed4b8e5af63e2544d69f88ab09c28d5da3c0b77dc76185fddd189a59863b60 + languageName: node + linkType: hard + +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -17016,6 +18535,94 @@ __metadata: languageName: node linkType: hard +"regl-error2d@npm:^2.0.12": + version: 2.0.12 + resolution: "regl-error2d@npm:2.0.12" + dependencies: + array-bounds: ^1.0.1 + color-normalize: ^1.5.0 + flatten-vertex-data: ^1.0.2 + object-assign: ^4.1.1 + pick-by-alias: ^1.2.0 + to-float32: ^1.1.0 + update-diff: ^1.1.0 + checksum: a7a2f22c05f0cb2c72f40dfed601e4a1ad66986469227eaf1093fbbc2b1dcbbe68cb5131498900472ee578de318b28f9293c1cb3e1683bf4360ee60bdf3be7be + languageName: node + linkType: hard + +"regl-line2d@npm:^3.1.2": + version: 3.1.2 + resolution: "regl-line2d@npm:3.1.2" + dependencies: + array-bounds: ^1.0.1 + array-find-index: ^1.0.2 + array-normalize: ^1.1.4 + color-normalize: ^1.5.0 + earcut: ^2.1.5 + es6-weak-map: ^2.0.3 + flatten-vertex-data: ^1.0.2 + glslify: ^7.0.0 + object-assign: ^4.1.1 + parse-rect: ^1.2.0 + pick-by-alias: ^1.2.0 + to-float32: ^1.1.0 + checksum: aa15125c922b3186993e4fd33df5f98e0e8daff14d59ebadc7e8f41d4f3453243a85481a306856f4bf72882db78b04bfe511a875b5b55eeecd5d1ad05b43f2fd + languageName: node + linkType: hard + +"regl-scatter2d@npm:^3.2.3, regl-scatter2d@npm:^3.2.9": + version: 3.2.9 + resolution: "regl-scatter2d@npm:3.2.9" + dependencies: + "@plotly/point-cluster": ^3.1.9 + array-range: ^1.0.1 + array-rearrange: ^2.2.2 + clamp: ^1.0.1 + color-id: ^1.1.0 + color-normalize: ^1.5.0 + color-rgba: ^2.1.1 + flatten-vertex-data: ^1.0.2 + glslify: ^7.0.0 + is-iexplorer: ^1.0.0 + object-assign: ^4.1.1 + parse-rect: ^1.2.0 + pick-by-alias: ^1.2.0 + to-float32: ^1.1.0 + update-diff: ^1.1.0 + checksum: 9429360fd33a5e5b0d9d27381b484cf3bc87da569e2cc2aa6f1518f6ad02245578905f9e694b251b5b96ddc5ce6ceafa7e8e5146ca595adb9354d90e0247c6b6 + languageName: node + linkType: hard + +"regl-splom@npm:^1.0.14": + version: 1.0.14 + resolution: "regl-splom@npm:1.0.14" + dependencies: + array-bounds: ^1.0.1 + array-range: ^1.0.1 + color-alpha: ^1.0.4 + flatten-vertex-data: ^1.0.2 + parse-rect: ^1.2.0 + pick-by-alias: ^1.2.0 + raf: ^3.4.1 + regl-scatter2d: ^3.2.3 + checksum: 6ba15b38710b38625955e018a313b0829aa571ebd39df5822fda6a50b730aca2378e3f02eb69101e6dbe00a06c6b9dff534b46956fcb16837672b5a04478c4f4 + languageName: node + linkType: hard + +"regl@npm:@plotly/regl@^2.1.2": + version: 2.1.2 + resolution: "@plotly/regl@npm:2.1.2" + checksum: ea3364f799b68712fb3389ec1f1bd5ddc8b68ee02de46f12d945905e8f9408e4cb31315cb948c002f87cd354cc709fe197a133596e959164e43bf652be4d02a5 + languageName: node + linkType: hard + +"regl@npm:^2.0.0": + version: 2.1.0 + resolution: "regl@npm:2.1.0" + checksum: dd890b7f50f0cc803f53212870343f910c135343d99b1e3de8cf6167bfde8beaa968aab59a41ea88c6dd58a192be07cbb9ae64989efea329457467f5c491cfbe + languageName: node + linkType: hard + "release-zalgo@npm:^1.0.0": version: 1.0.0 resolution: "release-zalgo@npm:1.0.0" @@ -17107,6 +18714,15 @@ __metadata: languageName: node linkType: hard +"resolve-protobuf-schema@npm:^2.1.0": + version: 2.1.0 + resolution: "resolve-protobuf-schema@npm:2.1.0" + dependencies: + protocol-buffers-schema: ^3.3.1 + checksum: 88fffab2a3757888884a36f9aa4e24be5186b01820a8c26297dc1ce406b9daf776594926bdf524c2c8e8e5b0aba8ac48362b6584cdecc9a7083215ebca01c599 + languageName: node + linkType: hard + "resolve-url-loader@npm:5.0.0": version: 5.0.0 resolution: "resolve-url-loader@npm:5.0.0" @@ -17133,7 +18749,14 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:~1.22.1": +"resolve@npm:^0.6.1": + version: 0.6.3 + resolution: "resolve@npm:0.6.3" + checksum: c3b5d34ba79635ffe380eb0e428e0b49259734ad2c86945c6b3238155b0753d8bcf858c6b99966b3fdb536062f6e204675e4542269f065e34210bb3a6f602f9d + languageName: node + linkType: hard + +"resolve@npm:^1.0.0, resolve@npm:^1.1.10, resolve@npm:^1.1.5, resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:~1.22.1": version: 1.22.4 resolution: "resolve@npm:1.22.4" dependencies: @@ -17182,7 +18805,14 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.10.1#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@~1.22.1#~builtin": +"resolve@patch:resolve@^0.6.1#~builtin": + version: 0.6.3 + resolution: "resolve@patch:resolve@npm%3A0.6.3#~builtin::version=0.6.3&hash=07638b" + checksum: fbdc248b89f655da8ff1509c000027702455d36e99943307d6e939bbef8b6f2bf67f82aa82ceb968f121febea128dd9b3e544fc6497c105204b1633bee1efad9 + languageName: node + linkType: hard + +"resolve@patch:resolve@^1.0.0#~builtin, resolve@patch:resolve@^1.1.10#~builtin, resolve@patch:resolve@^1.1.5#~builtin, resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.10.1#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@~1.22.1#~builtin": version: 1.22.4 resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=07638b" dependencies: @@ -17266,6 +18896,13 @@ __metadata: languageName: node linkType: hard +"right-now@npm:^1.0.0": + version: 1.0.0 + resolution: "right-now@npm:1.0.0" + checksum: 3969ddeceff4f7ca04dd368328fd04929a88161fe425219da54038a9a60be515961419afcdc2c910341cb28c0cfda3df689102cb6f68559694cb15a962819e46 + languageName: node + linkType: hard + "rimraf@npm:^2.6.1": version: 2.7.1 resolution: "rimraf@npm:2.7.1" @@ -17360,6 +18997,13 @@ __metadata: languageName: node linkType: hard +"rw@npm:^1.3.3": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: c20d82421f5a71c86a13f76121b751553a99cd4a70ea27db86f9b23f33db941f3f06019c30f60d50c356d0bd674c8e74764ac146ea55e217c091bde6fba82aa3 + languageName: node + linkType: hard + "rxjs@npm:6.6.7": version: 6.6.7 resolution: "rxjs@npm:6.6.7" @@ -17404,7 +19048,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 @@ -17727,6 +19371,13 @@ __metadata: languageName: node linkType: hard +"shallow-copy@npm:0.0.1": + version: 0.0.1 + resolution: "shallow-copy@npm:0.0.1" + checksum: 2d249a5a57a160b439d84fbf9ed7c0a107a3d656d1bda0b73edf9476c6e6ea9d2afa79829bf33fce6677fae35b15c14e5c28f9902dc4d07a302637a225d00634 + languageName: node + linkType: hard + "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" @@ -17823,6 +19474,13 @@ __metadata: languageName: node linkType: hard +"signum@npm:^1.0.0": + version: 1.0.0 + resolution: "signum@npm:1.0.0" + checksum: f045c95499c199889b5255bd0446c10d51ef91fdef404b993826b31fe33e2947baa4b69eb4fab7200c34b984c8158593dbf548ea34e23003d52944be92182569 + languageName: node + linkType: hard + "sigstore@npm:^1.0.0": version: 1.9.0 resolution: "sigstore@npm:1.9.0" @@ -18075,6 +19733,13 @@ __metadata: languageName: node linkType: hard +"stack-trace@npm:0.0.9": + version: 0.0.9 + resolution: "stack-trace@npm:0.0.9" + checksum: 5b1ff9708eaeae2518f70ea10027aa608892faedfd95d3c92b0e3b14cf49b013da22421a32b5bbe29ae711436e53fdf966793cf58a4bd0ad20a71859d27a894f + languageName: node + linkType: hard + "stack-utils@npm:^2.0.3": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -18091,6 +19756,15 @@ __metadata: languageName: node linkType: hard +"static-eval@npm:^2.0.5": + version: 2.1.0 + resolution: "static-eval@npm:2.1.0" + dependencies: + escodegen: ^1.11.1 + checksum: 21297ee9af37cd23ef92b3a4b1fd535073539b870d2bb83a4b92f6b668183f7fb552d3c791bbdcd460c62583a2c33d46e5d56e86a7f5851b65b29e19e5d28b41 + languageName: node + linkType: hard + "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -18140,6 +19814,15 @@ __metadata: languageName: node linkType: hard +"stream-parser@npm:~0.3.1": + version: 0.3.1 + resolution: "stream-parser@npm:0.3.1" + dependencies: + debug: 2 + checksum: 4d86ff8cffe7c7587dc91433fff9dce38a93ea7e9f47560055addc81eae6b6befab22b75643ce539faf325fe2b17d371778242566bed086e75f6cffb1e76c06c + languageName: node + linkType: hard + "stream-shift@npm:^1.0.0": version: 1.0.1 resolution: "stream-shift@npm:1.0.1" @@ -18154,6 +19837,15 @@ __metadata: languageName: node linkType: hard +"string-split-by@npm:^1.0.0": + version: 1.0.0 + resolution: "string-split-by@npm:1.0.0" + dependencies: + parenthesis: ^3.1.5 + checksum: bd38cf3b3d365ec3c418eefedd8130e3b2ebaf8ea381fd49a3fa903a927e8858db05563d9b14bd0d11f1b2eb27677fc17c3f91637b11f9dab40fa6c8fcf2e8c8 + languageName: node + linkType: hard + "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -18245,6 +19937,13 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:~0.10.x": + version: 0.10.31 + resolution: "string_decoder@npm:0.10.31" + checksum: fe00f8e303647e5db919948ccb5ce0da7dea209ab54702894dd0c664edd98e5d4df4b80d6fabf7b9e92b237359d21136c95bf068b2f7760b772ca974ba970202 + languageName: node + linkType: hard + "string_decoder@npm:~1.1.1": version: 1.1.1 resolution: "string_decoder@npm:1.1.1" @@ -18325,6 +20024,13 @@ __metadata: languageName: node linkType: hard +"strongly-connected-components@npm:^1.0.1": + version: 1.0.1 + resolution: "strongly-connected-components@npm:1.0.1" + checksum: f731c4a1e9b02b9d19a419e6bf1f901b1a7369cb4e0edca3b7ecb6c5076d2afe151ba12103669156594b2c2186ec9cffbd84f9d45c7e7928373d705e7ff7c3b2 + languageName: node + linkType: hard + "stylis@npm:4.2.0": version: 4.2.0 resolution: "stylis@npm:4.2.0" @@ -18350,6 +20056,22 @@ __metadata: languageName: node linkType: hard +"supercluster@npm:^7.0.0": + version: 7.1.5 + resolution: "supercluster@npm:7.1.5" + dependencies: + kdbush: ^3.0.0 + checksum: 69863238870093b96617135884721b6343746e14f396b2d67d6b55c52c362ec0516c5e386aa21815e75a9cef2054e831ac34023d0d8b600091d28cea0794f027 + languageName: node + linkType: hard + +"superscript-text@npm:^1.0.0": + version: 1.0.0 + resolution: "superscript-text@npm:1.0.0" + checksum: 4c437554359b4a7f78d17caa9b870e0a62cef59039608470ccf48bcdae7922d8c893712906b3f0371a3e45a6c57e8476a6364b0202f188d3604403cc7b6e262c + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -18384,6 +20106,38 @@ __metadata: languageName: node linkType: hard +"svg-arc-to-cubic-bezier@npm:^3.0.0": + version: 3.2.0 + resolution: "svg-arc-to-cubic-bezier@npm:3.2.0" + checksum: 55bf17756d558b9c0daddf636a6c9f2fe01fd5ac412229dfa2d4b29740226a82c980bcd3b5eb09ce311cbea282106c7549d97f8c8dba3a5a7b75f786bcb5e155 + languageName: node + linkType: hard + +"svg-path-bounds@npm:^1.0.1": + version: 1.0.2 + resolution: "svg-path-bounds@npm:1.0.2" + dependencies: + abs-svg-path: ^0.1.1 + is-svg-path: ^1.0.1 + normalize-svg-path: ^1.0.0 + parse-svg-path: ^0.1.2 + checksum: 8590a4e14942a34f595df64d804a3533cb83a29498b34f61723cf3172958a5a3c3b211805c6c4b2f93fb90ff4eab74b08a2dc1daa489d6ba429534aca5f5184d + languageName: node + linkType: hard + +"svg-path-sdf@npm:^1.1.3": + version: 1.1.3 + resolution: "svg-path-sdf@npm:1.1.3" + dependencies: + bitmap-sdf: ^1.0.0 + draw-svg-path: ^1.0.0 + is-svg-path: ^1.0.1 + parse-svg-path: ^0.1.2 + svg-path-bounds: ^1.0.1 + checksum: 34cb031e125682aa6c4a20bb89caef8631dfb3c1de57b33aeb2e77368f0a341412a5ec5d46bf738e890f192af8094079475050c11fe12695733ea4eb70ae096e + languageName: node + linkType: hard + "symbol-observable@npm:4.0.0": version: 4.0.0 resolution: "symbol-observable@npm:4.0.0" @@ -18615,7 +20369,17 @@ __metadata: languageName: node linkType: hard -"through2@npm:^2.0.3": +"through2@npm:^0.6.3": + version: 0.6.5 + resolution: "through2@npm:0.6.5" + dependencies: + readable-stream: ">=1.0.33-1 <1.1.0-0" + xtend: ">=4.0.0 <4.1.0-0" + checksum: dfea228e3134a33219a588448847250897a9994a687807dab52f850fac8b4eb1dc18e3b2c1d3d60dd0d78eb492d2032fdf814ac6576ba5b8d5ba0dade29a3544 + languageName: node + linkType: hard + +"through2@npm:^2.0.1, through2@npm:^2.0.3": version: 2.0.5 resolution: "through2@npm:2.0.5" dependencies: @@ -18662,6 +20426,13 @@ __metadata: languageName: node linkType: hard +"tinycolor2@npm:^1.4.2": + version: 1.6.0 + resolution: "tinycolor2@npm:1.6.0" + checksum: 6df4d07fceeedc0a878d7bac47e2cd47c1ceeb1078340a9eb8a295bc0651e17c750f73d47b3028d829f30b85c15e0572c0fd4142083e4c21a30a597e47f47230 + languageName: node + linkType: hard + "tinypool@npm:^0.7.0": version: 0.7.0 resolution: "tinypool@npm:0.7.0" @@ -18669,6 +20440,13 @@ __metadata: languageName: node linkType: hard +"tinyqueue@npm:^2.0.3": + version: 2.0.3 + resolution: "tinyqueue@npm:2.0.3" + checksum: 0b6bda46b680dca072f84aef1acd22a7085a2ff2aa8e222bb41045c61a056943805056d77d7f976587ed6a0597872beb5c416043f65f0314304432d6c178dd20 + languageName: node + linkType: hard + "tinyspy@npm:^2.1.1": version: 2.1.1 resolution: "tinyspy@npm:2.1.1" @@ -18699,6 +20477,31 @@ __metadata: languageName: node linkType: hard +"to-float32@npm:^1.1.0": + version: 1.1.0 + resolution: "to-float32@npm:1.1.0" + checksum: aff308bbc7b36df8804def8811e1f4a6ec3c476776e48a9dc9fd4039c50608c6afd08edd5902aa3445a18b89510b9cf4d9737da6d35c043ebbde073ecef30950 + languageName: node + linkType: hard + +"to-px@npm:1.0.1": + version: 1.0.1 + resolution: "to-px@npm:1.0.1" + dependencies: + parse-unit: ^1.0.1 + checksum: 4cf87de44413d7c6391e2e03ddc25efb80a7ca912e8da1fac70dcedc17acd512aecdbc01252a0a914981b99276b9f139a98df62c951792ffe98e77ade2c7da62 + languageName: node + linkType: hard + +"to-px@npm:^1.0.1": + version: 1.1.0 + resolution: "to-px@npm:1.1.0" + dependencies: + parse-unit: ^1.0.1 + checksum: bb434716a751a8918c8c711a79f9a95786b84572fac0253f64cff8d5cf9843ecdbb8e47a6d81152042aa2ccab9db5091f8dca2473f4fb3d3554bf36cfb41b7d9 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -18715,6 +20518,19 @@ __metadata: languageName: node linkType: hard +"topojson-client@npm:^3.1.0": + version: 3.1.0 + resolution: "topojson-client@npm:3.1.0" + dependencies: + commander: 2 + bin: + topo2geo: bin/topo2geo + topomerge: bin/topomerge + topoquantize: bin/topoquantize + checksum: 8c029a4f18324ace0b8b55dd90edbd40c9e3c6de18bafbb5da37ca20ebf20e26fbd4420891acb3c2c264e214185f7557871f5651a9eee517028663be98d836de + languageName: node + linkType: hard + "tough-cookie@npm:^4.1.2": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3" @@ -18913,6 +20729,15 @@ __metadata: languageName: node linkType: hard +"type-check@npm:~0.3.2": + version: 0.3.2 + resolution: "type-check@npm:0.3.2" + dependencies: + prelude-ls: ~1.1.2 + checksum: dd3b1495642731bc0e1fc40abe5e977e0263005551ac83342ecb6f4f89551d106b368ec32ad3fb2da19b3bd7b2d1f64330da2ea9176d8ddbfe389fb286eb5124 + languageName: node + linkType: hard + "type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": version: 4.0.8 resolution: "type-detect@npm:4.0.8" @@ -18986,6 +20811,20 @@ __metadata: languageName: node linkType: hard +"type@npm:^1.0.1": + version: 1.2.0 + resolution: "type@npm:1.2.0" + checksum: dae8c64f82c648b985caf321e9dd6e8b7f4f2e2d4f846fc6fd2c8e9dc7769382d8a52369ddbaccd59aeeceb0df7f52fb339c465be5f2e543e81e810e413451ee + languageName: node + linkType: hard + +"type@npm:^2.7.2": + version: 2.7.2 + resolution: "type@npm:2.7.2" + checksum: 0f42379a8adb67fe529add238a3e3d16699d95b42d01adfe7b9a7c5da297f5c1ba93de39265ba30ffeb37dfd0afb3fb66ae09f58d6515da442219c086219f6f4 + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.0": version: 1.0.0 resolution: "typed-array-buffer@npm:1.0.0" @@ -19040,6 +20879,16 @@ __metadata: languageName: node linkType: hard +"typedarray-pool@npm:^1.1.0": + version: 1.2.0 + resolution: "typedarray-pool@npm:1.2.0" + dependencies: + bit-twiddle: ^1.0.0 + dup: ^1.0.0 + checksum: dbba84b83f51052212fc61bb9ca802793c225b1c37eba3c9ddcadba486ba95c5346b37c176a7e6508fafdb27fef8059c4d8365e7e4630e374bcd824974ad192a + languageName: node + linkType: hard + "typedarray-to-buffer@npm:^3.1.5": version: 3.1.5 resolution: "typedarray-to-buffer@npm:3.1.5" @@ -19334,6 +21183,13 @@ __metadata: languageName: node linkType: hard +"unquote@npm:^1.1.0": + version: 1.1.1 + resolution: "unquote@npm:1.1.1" + checksum: 71745867d09cba44ba2d26cb71d6dda7045a98b14f7405df4faaf2b0c90d24703ad027a9d90ba9a6e0d096de2c8d56f864fd03f1c0498c0b7a3990f73b4c8f5f + languageName: node + linkType: hard + "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" @@ -19355,6 +21211,13 @@ __metadata: languageName: node linkType: hard +"update-diff@npm:^1.1.0": + version: 1.1.0 + resolution: "update-diff@npm:1.1.0" + checksum: 546400522d9ad1d91e10ac4fb0c97ebb94471096ae56d9af2a528458fbf2a332099c304c9a8d7223c9dc0c08647a8608e2941bdbdd651bbb727164296c599697 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -19840,6 +21703,17 @@ __metadata: languageName: node linkType: hard +"vt-pbf@npm:^3.1.1": + version: 3.1.3 + resolution: "vt-pbf@npm:3.1.3" + dependencies: + "@mapbox/point-geometry": 0.1.0 + "@mapbox/vector-tile": ^1.3.1 + pbf: ^3.2.1 + checksum: 83375b7ffe2e92ab2a4c9924cf2cd80e311b38e9e616c244656140a76090c037c55a1b1379b234cb6567444f32e9cb40fd2c5b6e555ffff4330feba56250f90c + languageName: node + linkType: hard + "vue-eslint-parser@npm:^9.1.1, vue-eslint-parser@npm:^9.3.1": version: 9.3.1 resolution: "vue-eslint-parser@npm:9.3.1" @@ -19950,6 +21824,22 @@ __metadata: languageName: node linkType: hard +"weak-map@npm:^1.0.5": + version: 1.0.8 + resolution: "weak-map@npm:1.0.8" + checksum: ce030b3c6b1a461bda6eac88b3b3be57245ce26330c6ddb98d821d85c0636117ca94693ef8292407066fd367740ec6a1ef6cd9027111453d7ced43f4f78b327a + languageName: node + linkType: hard + +"webgl-context@npm:^2.2.0": + version: 2.2.0 + resolution: "webgl-context@npm:2.2.0" + dependencies: + get-canvas-context: ^1.0.1 + checksum: b9ee376f86256ed6a7cf7277199ab7ea187cee7afd26e7b822d2e5c1d27f1f9230ac34281bac66365c8fdb97aa850fd41cc342f56089de1c368a09cfe331845f + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -20301,6 +22191,13 @@ __metadata: languageName: node linkType: hard +"word-wrap@npm:~1.2.3": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: f93ba3586fc181f94afdaff3a6fef27920b4b6d9eaefed0f428f8e07adea2a7f54a5f2830ce59406c8416f033f86902b91eb824072354645eea687dff3691ccb + languageName: node + linkType: hard + "wordwrap@npm:^1.0.0": version: 1.0.0 resolution: "wordwrap@npm:1.0.0" @@ -20308,6 +22205,15 @@ __metadata: languageName: node linkType: hard +"world-calendars@npm:^1.0.3": + version: 1.0.3 + resolution: "world-calendars@npm:1.0.3" + dependencies: + object-assign: ^4.1.0 + checksum: bf3470042a498ccd5a003fbdddb0cb711d42515fe4c3cb71c9cb708c11fa8162f7b2aa7138364f2ac9d8d3d779e78112acbe68c93f0770723398494149ed50ce + languageName: node + linkType: hard + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -20419,13 +22325,20 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.0, xtend@npm:~4.0.1": +"xtend@npm:>=4.0.0 <4.1.0-0, xtend@npm:^4.0.0, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a languageName: node linkType: hard +"xtend@npm:^2.1.2": + version: 2.2.0 + resolution: "xtend@npm:2.2.0" + checksum: 9fcd1ddabefdb3c68a698b08177525ad14a6df3423b13bad9a53900d19374e476a43c219b0756d39675776b2326a35fe477c547cfb8a05ae9fea4ba2235bebe2 + languageName: node + linkType: hard + "xxhashjs@npm:~0.2.2": version: 0.2.2 resolution: "xxhashjs@npm:0.2.2"