- console.log('Failed to send tracking error event: ', trackingSendingError),
- );
+ });
+ } catch (trackingSendingError) {
+ console.log('Failed to send tracking error event: ', trackingSendingError);
+ }
}
render(): ReactNode {
if (this.httpClient && this.postponedErrors.length > 0) {
- this.postponedErrors.forEach((error) => this.sendErrorTracking(error, this.httpClient!));
+ this.postponedErrors.forEach((error) => this.sendErrorTracking(error));
}
this.postponedErrors = [];
return this.props.children;
diff --git a/packages/sdk-ui/src/decorators/component-decorators/with-tracking/use-track-component-init.tsx b/packages/sdk-ui/src/decorators/component-decorators/with-tracking/use-track-component-init.tsx
index c4cbc3c0..ce48f86e 100644
--- a/packages/sdk-ui/src/decorators/component-decorators/with-tracking/use-track-component-init.tsx
+++ b/packages/sdk-ui/src/decorators/component-decorators/with-tracking/use-track-component-init.tsx
@@ -1,9 +1,10 @@
-import { TrackingDetails, trackProductEvent } from '@sisense/sdk-tracking';
+import { TrackingEventDetails } from '@sisense/sdk-tracking';
import { useSisenseContext } from '../../../sisense-context/sisense-context';
import { createContext, ReactNode, useContext, useEffect, useRef } from 'react';
+import { useTracking } from '@/common/hooks/use-tracking';
const action = 'sdkComponentInit';
-interface ComponentInitEventDetails extends TrackingDetails {
+interface ComponentInitEventDetails extends TrackingEventDetails {
packageName: string;
packageVersion: string;
componentName: string;
@@ -20,17 +21,15 @@ export const TrackingContextProvider = ({
}) => {children};
export const useTrackComponentInit = (componentName: string, props: P) => {
- const { app, tracking } = useSisenseContext();
+ const { tracking } = useSisenseContext();
+ const { trackEvent } = useTracking();
const inTrackingContext = useContext(TrackingContext);
const hasTrackedRef = useRef(false);
useEffect(() => {
- if (!app?.httpClient) {
- return;
- }
-
+ if (!tracking) return;
const hasBeenTracked = hasTrackedRef.current;
if (!hasBeenTracked && !inTrackingContext) {
const payload: ComponentInitEventDetails = {
@@ -43,9 +42,9 @@ export const useTrackComponentInit = (componentName: string, props
.join(', '),
};
- void trackProductEvent(action, payload, app.httpClient, !tracking.enabled).finally(
+ void trackEvent(action, payload, !tracking.enabled).finally(
() => (hasTrackedRef.current = true),
);
}
- }, [componentName, props, app, tracking, inTrackingContext]);
+ }, [componentName, props, tracking, inTrackingContext, trackEvent]);
};
diff --git a/packages/sdk-ui/src/decorators/component-decorators/with-tracking/with-tracking.tsx b/packages/sdk-ui/src/decorators/component-decorators/with-tracking/with-tracking.tsx
index 0571164c..aa7f2d27 100644
--- a/packages/sdk-ui/src/decorators/component-decorators/with-tracking/with-tracking.tsx
+++ b/packages/sdk-ui/src/decorators/component-decorators/with-tracking/with-tracking.tsx
@@ -3,6 +3,7 @@ import { ComponentDecorator } from '../as-sisense-component';
import isBoolean from 'lodash/isBoolean';
import isFunction from 'lodash/isFunction';
import { ErrorTracker } from './error-tracker';
+import { useTracking } from '@/common/hooks/use-tracking';
type TrackingDecoratorConfig = {
componentName: string;
@@ -22,6 +23,8 @@ export const withTracking: ComponentDecorator = ({
const { skip, transparent } = config || {};
return (Component) => {
return function Tracking(props) {
+ const { trackError } = useTracking();
+
if ((isBoolean(skip) && skip) || (isFunction(skip) && skip(props))) {
return ;
}
@@ -30,7 +33,7 @@ export const withTracking: ComponentDecorator = ({
return (
// If component is transperent for tracking, nested components will be tracked
-
+
diff --git a/packages/sdk-ui/src/decorators/hook-decorators/with-tracking.ts b/packages/sdk-ui/src/decorators/hook-decorators/with-tracking.ts
index f9194f12..6c8d6ad8 100644
--- a/packages/sdk-ui/src/decorators/hook-decorators/with-tracking.ts
+++ b/packages/sdk-ui/src/decorators/hook-decorators/with-tracking.ts
@@ -1,7 +1,8 @@
-import { TrackingDetails, trackProductEvent } from '@sisense/sdk-tracking';
+import { TrackingEventDetails, trackProductEvent } from '@sisense/sdk-tracking';
import { useEffect, useRef } from 'react';
import { useSisenseContext } from '../../sisense-context/sisense-context';
import { ClientApplication } from '../../app/client-application';
+import { useTracking } from '@/common/hooks/use-tracking';
export type HookDecorator = (
decoratorConfig: DecoratorConfig,
@@ -9,7 +10,7 @@ export type HookDecorator = (
hook: (...args: HookArgs) => HookResult,
) => (...args: HookArgs) => HookResult;
-interface HookEventDetails extends TrackingDetails {
+interface HookEventDetails extends TrackingEventDetails {
hookName: string;
}
@@ -40,22 +41,24 @@ export const trackHook = (
};
function useTrackHook(hookName: string) {
- const { app, tracking } = useSisenseContext();
+ const { tracking } = useSisenseContext();
+ const { trackEvent } = useTracking();
const hasTrackedRef = useRef(false);
useEffect(() => {
- if (app?.httpClient && !hasTrackedRef.current) {
+ if (!tracking) return;
+ if (!hasTrackedRef.current) {
const payload: HookEventDetails = {
- packageName: tracking.packageName,
+ packageName: tracking.packageName || 'sdk-ui',
packageVersion: __PACKAGE_VERSION__,
hookName,
};
- void trackProductEvent(action, payload, app.httpClient, !tracking.enabled).finally(
+ void trackEvent(action, payload, !tracking.enabled).finally(
() => (hasTrackedRef.current = true),
);
}
- }, [app, tracking, hookName]);
+ }, [tracking, hookName, trackEvent]);
}
export const withTracking: HookDecorator =
diff --git a/packages/sdk-ui/src/error-boundary/error-boundary.tsx b/packages/sdk-ui/src/error-boundary/error-boundary.tsx
index d3b622c4..91598efa 100644
--- a/packages/sdk-ui/src/error-boundary/error-boundary.tsx
+++ b/packages/sdk-ui/src/error-boundary/error-boundary.tsx
@@ -50,8 +50,8 @@ export class ErrorBoundary extends Component : ;
+ if (error && this.showErrorBox) {
+ return ;
}
return this.props.children;
diff --git a/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.test.tsx b/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.test.tsx
index d8556c06..e2c687d7 100644
--- a/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.test.tsx
+++ b/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.test.tsx
@@ -12,9 +12,11 @@ import { setTimeout } from 'timers/promises';
const contextProviderProps: SisenseContextProviderProps = {
url: mockUrl,
token: mockToken,
- enableTracking: false,
defaultDataSource: 'Sample ECommerce',
- appConfig: { queryCacheConfig: { enabled: false } },
+ appConfig: {
+ queryCacheConfig: { enabled: false },
+ trackingConfig: { enabled: false },
+ },
};
describe('CascadingFilterTile', () => {
diff --git a/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.tsx b/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.tsx
index c7f33f30..f52741a1 100644
--- a/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.tsx
+++ b/packages/sdk-ui/src/filters/components/cascading-filter-tile/cascading-filter-tile.tsx
@@ -3,8 +3,8 @@ import { CascadingFilter, DataSource, Filter } from '@sisense/sdk-data';
import { asSisenseComponent } from '../../../decorators/component-decorators/as-sisense-component.js';
import { FilterVariant } from '../common/filter-utils.js';
import { CascadingLevelFilterTile } from './cascading-level-filter.js';
-import { cloneFilterAndToggleDisabled } from '@/filters/utils.js';
import { useSynchronizedFilter } from '@/filters/hooks/use-synchronized-filter.js';
+import { clearMembersFilter, cloneFilterAndToggleDisabled } from '@/utils/filters.js';
/**
* Props for {@link CascadingFilterTile}
@@ -50,9 +50,24 @@ export const CascadingFilterTile = asSisenseComponent({ componentName: 'Cascadin
const levelFilters = filter.filters;
- const handleLevelFilterChange = (levelFilter: Filter, index: number) => {
- levelFilters[`${index}`] = levelFilter;
- updateFilter(filter);
+ const handleLevelFilterChange = (
+ changedLevelFilter: Filter,
+ changedLevelFilterIndex: number,
+ ) => {
+ const newLevelFilters = filter.filters.map((levelFilter, index) => {
+ if (index === changedLevelFilterIndex) {
+ return changedLevelFilter;
+ }
+ if (index > changedLevelFilterIndex) {
+ return clearMembersFilter(levelFilter);
+ }
+ return levelFilter;
+ });
+
+ const newCascadingFilter = new CascadingFilter(newLevelFilters, filter.guid);
+ newCascadingFilter.disabled = filter.disabled;
+
+ updateFilter(newCascadingFilter);
};
return (
diff --git a/packages/sdk-ui/src/filters/components/date-filter/date-range-filter-tile/date-range-filter-tile.test.tsx b/packages/sdk-ui/src/filters/components/date-filter/date-range-filter-tile/date-range-filter-tile.test.tsx
index e04a0d61..318eb839 100644
--- a/packages/sdk-ui/src/filters/components/date-filter/date-range-filter-tile/date-range-filter-tile.test.tsx
+++ b/packages/sdk-ui/src/filters/components/date-filter/date-range-filter-tile/date-range-filter-tile.test.tsx
@@ -21,7 +21,11 @@ describe('DateRangeFilterTile', () => {
const dateRangeFilter = filterFactory.dateRange(DM.Commerce.Date.Years);
const { container } = render(
-
+
{
const dateRangeFilter = filterFactory.dateRange(DM.Commerce.Date.Years);
const { findByLabelText, findByText } = render(
-
+
{
const dateRangeFilter = filterFactory.dateRange(DM.Commerce.Date.Years, '2009-01-01');
render(
-
+
`
background-color: ${({ theme }) => theme.chart.backgroundColor};
@@ -53,11 +54,9 @@ export type FiltersPanelProps = {
*
* @internal
*/
-export const FiltersPanel = ({
- filters,
- onFiltersChange,
- defaultDataSource,
-}: FiltersPanelProps) => {
+export const FiltersPanel = asSisenseComponent({
+ componentName: 'FiltersPanel',
+})(({ filters, onFiltersChange, defaultDataSource }: FiltersPanelProps) => {
const { themeSettings } = useThemeContext();
const filterList = [...filters] as (Filter | null)[];
const handleFilterChange = (filter: Filter | null, index: number) => {
@@ -85,4 +84,4 @@ export const FiltersPanel = ({
);
-};
+});
diff --git a/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.test.tsx b/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.test.tsx
index aab2a892..8fa8e6ba 100644
--- a/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.test.tsx
+++ b/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.test.tsx
@@ -12,8 +12,10 @@ import { MemberFilterTile } from './member-filter-tile';
const contextProviderProps: SisenseContextProviderProps = {
url: mockUrl,
token: mockToken,
- enableTracking: false,
- appConfig: { queryCacheConfig: { enabled: false } },
+ appConfig: {
+ queryCacheConfig: { enabled: false },
+ trackingConfig: { enabled: false },
+ },
};
describe('MemberFilterTile', () => {
diff --git a/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.tsx b/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.tsx
index 07af8440..58a9eab5 100644
--- a/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.tsx
+++ b/packages/sdk-ui/src/filters/components/member-filter-tile/member-filter-tile.tsx
@@ -7,8 +7,8 @@ import { FilterTile, FilterTileDesignOptions } from '../filter-tile';
import { useSynchronizedFilter } from '@/filters/hooks/use-synchronized-filter';
import { PillSection } from './pill-section';
import { MemberList } from './member-list';
-import { cloneFilterAndToggleDisabled } from '@/filters/utils';
import merge from 'lodash/merge';
+import { cloneFilterAndToggleDisabled } from '@/utils/filters';
/**
* Props for {@link MemberFilterTile}
diff --git a/packages/sdk-ui/src/filters/utils.ts b/packages/sdk-ui/src/filters/utils.ts
deleted file mode 100644
index 155dbd56..00000000
--- a/packages/sdk-ui/src/filters/utils.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { type Filter } from '@sisense/sdk-data';
-import cloneDeep from 'lodash/cloneDeep';
-
-/**
- * Clones a filter with a toggled 'disabled' state.
- *
- * @param filter - Filter to clone
- */
-export const cloneFilterAndToggleDisabled = (filter: TFilter): TFilter => {
- const newFilter = cloneFilter(filter);
- newFilter.disabled = !filter.disabled;
- return newFilter;
-};
-
-export const cloneFilter = (filter: TFilter): TFilter => {
- const newFilter = cloneDeep(filter);
- Object.setPrototypeOf(newFilter, filter);
- return newFilter;
-};
diff --git a/packages/sdk-ui/src/formulas/use-get-shared-formula.test.ts b/packages/sdk-ui/src/formulas/use-get-shared-formula.test.ts
index a2fac088..62a4212f 100644
--- a/packages/sdk-ui/src/formulas/use-get-shared-formula.test.ts
+++ b/packages/sdk-ui/src/formulas/use-get-shared-formula.test.ts
@@ -63,6 +63,7 @@ describe('useGetSharedFormula', () => {
});
fetchFormulaMock.mockImplementation(() => Promise.resolve(calculatedMeasureMock));
fetchFormulaByOidMock.mockImplementation(() => Promise.resolve(calculatedMeasureMock));
+ trackProductEventMock.mockClear();
});
it('should trow an error if no identifier provided', () => {
try {
diff --git a/packages/sdk-ui/src/index.ts b/packages/sdk-ui/src/index.ts
index c16649ba..595085d8 100644
--- a/packages/sdk-ui/src/index.ts
+++ b/packages/sdk-ui/src/index.ts
@@ -5,12 +5,7 @@ export { ClientApplication, createClientApplication } from './app/client-applica
export * from './chart-data-options/types';
export { Chart } from './chart';
export { ThemeProvider } from './theme-provider';
-export {
- DashboardById,
- Dashboard,
- type DashboardByIdProps,
- type DashboardProps,
-} from './dashboard';
+export * from './dashboard';
export { DashboardWidget } from './dashboard-widget/dashboard-widget';
export { getSortType } from './dashboard-widget/utils';
export {
@@ -23,7 +18,7 @@ export * from './query-execution';
export { executeQuery } from './query/execute-query';
export { SisenseContextProvider } from './sisense-context/sisense-context-provider';
export { DrilldownWidget } from './widgets/drilldown-widget';
-export { processDrilldownSelections } from './widgets/common/custom-drilldown';
+export { processDrilldownSelections } from './widgets/common/use-drilldown';
export { ChartWidget } from './widgets/chart-widget';
export { TableWidget } from './widgets/table-widget';
export { ContextMenu } from './widgets/common/context-menu';
@@ -80,6 +75,9 @@ export {
type GetDashboardModelsOptions,
type Layout,
type WidgetFilterOptions,
+ type CommonFiltersOptions,
+ type CommonFiltersApplyMode,
+ type FiltersIgnoringRules,
} from './models';
export { boxWhiskerProcessResult } from './boxplot-utils';
export { queryStateReducer } from './query-execution/query-state-reducer';
diff --git a/packages/sdk-ui/src/models/dashboard/get-dashboard-model.ts b/packages/sdk-ui/src/models/dashboard/get-dashboard-model.ts
index 978e46b0..760fea5b 100644
--- a/packages/sdk-ui/src/models/dashboard/get-dashboard-model.ts
+++ b/packages/sdk-ui/src/models/dashboard/get-dashboard-model.ts
@@ -24,13 +24,13 @@ export interface GetDashboardModelOptions {
/**
* Retrieves a dashboard model by its OID.
+ *
* @param http - The HTTP client
* @param dashboardOid - The OID of the dashboard
* @param options - The options to include widgets and filters in the dashboard model
* @param themeSettings - Optional theme settings
* @param appSettings - Optional application settings
* @returns The dashboard model
- *
* @internal
*/
export async function getDashboardModel(
diff --git a/packages/sdk-ui/src/models/dashboard/types.ts b/packages/sdk-ui/src/models/dashboard/types.ts
index 1e8e7a8a..b4c6bfb5 100644
--- a/packages/sdk-ui/src/models/dashboard/types.ts
+++ b/packages/sdk-ui/src/models/dashboard/types.ts
@@ -1,7 +1,15 @@
import { CommonFiltersOptions } from '@/common-filters/types';
import { ColorPaletteTheme } from '@/types';
-/** @internal */
+export type {
+ CommonFiltersOptions,
+ CommonFiltersApplyMode,
+ FiltersIgnoringRules,
+} from '@/common-filters/types';
+
+/**
+ * Layout of a dashboard.
+ */
export interface Layout {
columns: {
widthPercentage: number;
@@ -15,10 +23,21 @@ export interface Layout {
}[];
}
-/** @internal */
+/**
+ * Options for how common filters defined at the dashboard level should be applied to widgets.
+ */
export type WidgetFilterOptions = Record;
-/** @internal */
+/**
+ * Style options for the dashboard.
+ */
export type DashboardStyleOptions = {
+ /** Collection of colors used to color various elements */
palette?: ColorPaletteTheme;
+ /** Background color */
+ backgroundColor?: string;
+ /** Width of the divider line between widgets */
+ dividerLineWidth?: number;
+ /** Divider line color */
+ dividerLineColor?: string;
};
diff --git a/packages/sdk-ui/src/models/dashboard/use-get-dashboard-model.test.ts b/packages/sdk-ui/src/models/dashboard/use-get-dashboard-model.test.ts
index ec80ed52..d44c2e33 100644
--- a/packages/sdk-ui/src/models/dashboard/use-get-dashboard-model.test.ts
+++ b/packages/sdk-ui/src/models/dashboard/use-get-dashboard-model.test.ts
@@ -62,6 +62,7 @@ const trackProductEventMock = trackProductEvent as Mock<
describe('useGetDashboardModel', () => {
beforeEach(() => {
getDashboardModelMock.mockClear();
+ trackProductEventMock.mockClear();
useSisenseContextMock.mockReturnValue({
app: {} as ClientApplication,
isInitialized: true,
diff --git a/packages/sdk-ui/src/models/dashboard/use-get-dashboard-models.test.ts b/packages/sdk-ui/src/models/dashboard/use-get-dashboard-models.test.ts
index 921ab644..1d131511 100644
--- a/packages/sdk-ui/src/models/dashboard/use-get-dashboard-models.test.ts
+++ b/packages/sdk-ui/src/models/dashboard/use-get-dashboard-models.test.ts
@@ -59,6 +59,7 @@ const trackProductEventMock = trackProductEvent as Mock<
describe('useGetDashboardModels', () => {
beforeEach(() => {
getDashboarsdModelsMock.mockClear();
+ trackProductEventMock.mockClear();
useSisenseContextMock.mockReturnValue({
app: {} as ClientApplication,
isInitialized: true,
diff --git a/packages/sdk-ui/src/models/widget/get-widget-model.ts b/packages/sdk-ui/src/models/widget/get-widget-model.ts
index 7b888428..a6bd750e 100644
--- a/packages/sdk-ui/src/models/widget/get-widget-model.ts
+++ b/packages/sdk-ui/src/models/widget/get-widget-model.ts
@@ -7,13 +7,13 @@ import { AppSettings } from '@/app/settings/settings';
/**
* Retrieves a widget model by its OID.
+ *
* @param httpClient - The HTTP client
* @param dashboardOid - The OID of the dashboard
* @param widgetOid - The OID of the widget
* @param themeSettings - Optional theme settings
* @param appSettings - Optional application settings
* @returns The widget model
- *
* @internal
*/
export async function getWidgetModel(
diff --git a/packages/sdk-ui/src/models/widget/translate-widget.ts b/packages/sdk-ui/src/models/widget/translate-widget.ts
index 8f8cdb11..199f5a0d 100644
--- a/packages/sdk-ui/src/models/widget/translate-widget.ts
+++ b/packages/sdk-ui/src/models/widget/translate-widget.ts
@@ -7,6 +7,7 @@ import { AppSettings } from '@/app/settings/settings';
/**
* Translates a widget DTO to a widget model.
+ *
* @param widget - The widget DTO to be converted to a widget model
* @param themeSettings - Optional theme settings
* @param appSettings - Optional application settings
diff --git a/packages/sdk-ui/src/models/widget/widget-model.ts b/packages/sdk-ui/src/models/widget/widget-model.ts
index b56c2019..ee6d054f 100644
--- a/packages/sdk-ui/src/models/widget/widget-model.ts
+++ b/packages/sdk-ui/src/models/widget/widget-model.ts
@@ -1,4 +1,4 @@
-import { getPivotQueryOptions } from '@/pivot-table/use-get-pivot-table-query';
+import { getPivotQueryOptions } from '@/pivot-table/hooks/use-get-pivot-table-query';
import { Attribute, Filter, Measure } from '@sisense/sdk-data';
import { over } from 'lodash';
import { getTranslatedDataOptions } from '../../chart-data-options/get-translated-data-options';
diff --git a/packages/sdk-ui/src/pivot-table/__snapshots__/pivot-table.test.tsx.snap b/packages/sdk-ui/src/pivot-table/__snapshots__/pivot-table.test.tsx.snap
index 18b87fd5..8b0d05fb 100644
--- a/packages/sdk-ui/src/pivot-table/__snapshots__/pivot-table.test.tsx.snap
+++ b/packages/sdk-ui/src/pivot-table/__snapshots__/pivot-table.test.tsx.snap
@@ -17,7 +17,936 @@ exports[`PivotTable > should render empty pivot table 1`] = `
>
+ >
+
+