diff --git a/packages/cubejs-playground/src/PlaygroundQueryBuilder.tsx b/packages/cubejs-playground/src/PlaygroundQueryBuilder.tsx
index 778ed6df56bd3..8817f99bad5aa 100644
--- a/packages/cubejs-playground/src/PlaygroundQueryBuilder.tsx
+++ b/packages/cubejs-playground/src/PlaygroundQueryBuilder.tsx
@@ -1,6 +1,6 @@
import { useState, useRef, useEffect, RefObject } from 'react';
-import { Col, Row, Divider, Typography, Space } from 'antd';
-import Icon, { LockOutlined, CloudOutlined } from '@ant-design/icons';
+import { Col, Row, Divider } from 'antd';
+import { LockOutlined, CloudOutlined } from '@ant-design/icons';
import {
QueryBuilder,
SchemaChangeProps,
@@ -24,7 +24,7 @@ import LivePreviewBar from './components/LivePreviewContext/LivePreviewBar';
import ChartRenderer from './components/ChartRenderer/ChartRenderer';
import { SectionHeader, SectionRow } from './components';
import ChartContainer from './ChartContainer';
-import { dispatchPlaygroundEvent, formatNumber } from './utils';
+import { dispatchPlaygroundEvent } from './utils';
import {
useDeepCompareMemoize,
useSecurityContext,
@@ -33,7 +33,7 @@ import {
import { Button, Card, FatalError } from './atoms';
import { UIFramework } from './types';
import DashboardSource from './DashboardSource';
-import { LightningIcon } from './shared/icons/LightningIcon';
+import { PreAggregationStatus } from './components/PlaygroundQueryBuilder/components';
const Section = styled.div`
display: flex;
@@ -125,62 +125,30 @@ function PivotChangeEmitter({
return null;
}
+type QueryChangeEmitterProps = {
+ query1: Query | null;
+ query2: Query | null;
+ onChange: () => void;
+};
+
+function QueryChangeEmitter({
+ query1,
+ query2,
+ onChange,
+}: QueryChangeEmitterProps) {
+ useEffect(() => {
+ onChange();
+ }, [areQueriesEqual(query1, query2)]);
+
+ return null;
+}
+
type THandleRunButtonClickProps = {
query: Query;
pivotConfig?: PivotConfig;
chartType: ChartType;
};
-type PreAggregationStatusProps = {
- time: number;
- isAggregated: boolean;
-};
-
-const Label = styled.div`
- display: flex;
- align-items: center;
- padding: 2px 4px;
- border-radius: 4px;
- background: rgba(251, 188, 5, 0.1);
-`;
-
-function PreAggregationStatus({
- time,
- isAggregated,
-}: PreAggregationStatusProps) {
- const renderTime = () => (
-
- {formatNumber(time)} ms
-
- );
-
- return (
-
- {isAggregated ? (
-
- ) : (
- renderTime()
- )}
-
-
- Query was not accelerated with pre-aggregation {'->'}
-
-
-
- Query was accelerated with pre-aggregation
-
-
- );
-}
-
export type TPlaygroundQueryBuilderProps = {
apiUrl: string;
cubejsToken: string;
@@ -192,6 +160,11 @@ export type TPlaygroundQueryBuilderProps = {
onSchemaChange?: (props: SchemaChangeProps) => void;
};
+export type QueryStatus = {
+ timeElapsed: number;
+ isAggregated: boolean;
+};
+
export default function PlaygroundQueryBuilder({
apiUrl,
cubejsToken,
@@ -205,6 +178,7 @@ export default function PlaygroundQueryBuilder({
const ref = useRef(null);
const queryRef = useRef(null);
+ const [queryStatus, setQueryStatus] = useState(null);
const [framework, setFramework] = useState('react');
const [chartingLibrary, setChartingLibrary] = useState('bizcharts');
const [isChartRendererReady, setChartRendererReady] = useState(false);
@@ -482,7 +456,12 @@ export default function PlaygroundQueryBuilder({
onUpdate={updatePivotConfig.update}
/>
-
+ {queryStatus ? (
+
+ ) : null}
@@ -569,12 +548,22 @@ export default function PlaygroundQueryBuilder({
isLoading,
resultSet,
error,
+ isAggregated,
+ timeElapsed,
}) => {
if (resultSet) {
setQueryError(null);
+
+ if (isAggregated != null && timeElapsed != null) {
+ setQueryStatus({
+ isAggregated,
+ timeElapsed,
+ });
+ }
}
if (error) {
setQueryError(error);
+ setQueryStatus(null);
}
setQueryLoading(isLoading);
@@ -608,6 +597,12 @@ export default function PlaygroundQueryBuilder({
+
+ setQueryStatus(null)}
+ />
>
);
}}
diff --git a/packages/cubejs-playground/src/components/ChartRenderer/ChartRenderer.tsx b/packages/cubejs-playground/src/components/ChartRenderer/ChartRenderer.tsx
index 0d7845a71642a..3a1d83cd124ab 100644
--- a/packages/cubejs-playground/src/components/ChartRenderer/ChartRenderer.tsx
+++ b/packages/cubejs-playground/src/components/ChartRenderer/ChartRenderer.tsx
@@ -9,6 +9,7 @@ import type { PivotConfig, Query, ChartType } from '@cubejs-client/core';
import { Button, CubeLoader } from '../../atoms';
import { UIFramework } from '../../types';
import { event } from '../../events';
+import { QueryStatus } from '../../PlaygroundQueryBuilder';
const { Text } = Typography;
@@ -69,7 +70,7 @@ export type TQueryLoadResult = {
isLoading: boolean;
resultSet?: ResultSet;
error?: Error | null;
-};
+} & Partial;
type TChartRendererProps = {
query: Query;
@@ -99,7 +100,7 @@ export default function ChartRenderer({
onChartRendererReadyChange,
onQueryStatusChange,
onRunButtonClick,
- onQueryChange
+ onQueryChange,
}: TChartRendererProps) {
const runButtonRef = useRef(null);
const [slowQuery, setSlowQuery] = useState(false);
@@ -121,19 +122,23 @@ export default function ChartRenderer({
useEffect(() => {
onQueryChange();
- }, [areQueriesEqual])
+ }, [areQueriesEqual]);
useEffect(() => {
setResultSet(false);
}, [framework]);
useLayoutEffect(() => {
+ let queryStartTime: number;
window['__cubejsPlayground'] = {
...window['__cubejsPlayground'],
onQueryStart: () => {
+ queryStartTime = Date.now();
onQueryStatusChange({ isLoading: true });
},
onQueryLoad: ({ resultSet, error }: TQueryLoadResult) => {
+ let isAggregated;
+ const timeElapsed = Date.now() - queryStartTime;
if (resultSet) {
const { loadResponse } = resultSet.serialize();
@@ -141,13 +146,25 @@ export default function ChartRenderer({
Boolean(loadResponse.slowQuery) && setSlowQuery(false);
setResultSet(true);
- const servedByPreAggregation = Object.keys(loadResponse.results[0]?.usedPreAggregations || {}).length > 0;
+ isAggregated =
+ Object.keys(loadResponse.results[0]?.usedPreAggregations || {})
+ .length > 0;
- event(servedByPreAggregation ? 'load_request_success_aggregated:frontend' : 'load_request_success:frontend');
+ event(
+ isAggregated
+ ? 'load_request_success_aggregated:frontend'
+ : 'load_request_success:frontend'
+ );
}
if (resultSet || error) {
- onQueryStatusChange({ resultSet, error, isLoading: false });
+ onQueryStatusChange({
+ resultSet,
+ error,
+ isLoading: false,
+ timeElapsed,
+ isAggregated
+ });
}
},
onQueryProgress: (progress) => {
diff --git a/packages/cubejs-playground/src/components/PlaygroundQueryBuilder/components/PreAggregationStatus.tsx b/packages/cubejs-playground/src/components/PlaygroundQueryBuilder/components/PreAggregationStatus.tsx
new file mode 100644
index 0000000000000..63f6e10955484
--- /dev/null
+++ b/packages/cubejs-playground/src/components/PlaygroundQueryBuilder/components/PreAggregationStatus.tsx
@@ -0,0 +1,61 @@
+import styled from 'styled-components';
+import { Space, Typography } from 'antd';
+import Icon from '@ant-design/icons';
+
+import { formatNumber } from '../../../utils';
+import { LightningIcon } from '../../../shared/icons/LightningIcon';
+
+type PreAggregationStatusProps = {
+ timeElapsed: number;
+ isAggregated: boolean;
+};
+
+const Badge = styled.div`
+ display: flex;
+ align-items: center;
+ padding: 2px 4px;
+ border-radius: 4px;
+ background: var(--warning-bg-color);
+`;
+
+export function PreAggregationStatus({
+ timeElapsed,
+ isAggregated,
+}: PreAggregationStatusProps) {
+ const renderTime = () => (
+
+ {formatNumber(timeElapsed)} ms
+
+ );
+
+ return (
+
+ {isAggregated ? (
+
+
+ }
+ />
+ {renderTime()}
+
+
+ ) : (
+ renderTime()
+ )}
+
+ {isAggregated ? (
+
+ Query was accelerated with pre-aggregation
+
+ ) : (
+
+ Query was not accelerated with pre-aggregation {'->'}
+
+ )}
+
+ );
+}
diff --git a/packages/cubejs-playground/src/components/PlaygroundQueryBuilder/components/index.ts b/packages/cubejs-playground/src/components/PlaygroundQueryBuilder/components/index.ts
new file mode 100644
index 0000000000000..8bcdec50e3396
--- /dev/null
+++ b/packages/cubejs-playground/src/components/PlaygroundQueryBuilder/components/index.ts
@@ -0,0 +1 @@
+export * from './PreAggregationStatus'
diff --git a/packages/cubejs-playground/src/variables-esm.js b/packages/cubejs-playground/src/variables-esm.js
index 8213bf0fed6ba..c00dd79b16744 100644
--- a/packages/cubejs-playground/src/variables-esm.js
+++ b/packages/cubejs-playground/src/variables-esm.js
@@ -9,7 +9,9 @@ const colors = {
'dark-03': '114, 114, 144',
'dark-04': '161, 161, 181',
'dark-05': '213, 213, 226',
- light: '1, 2, 251',
+ light: '243, 243, 251',
+ green: '65, 181, 111',
+ yellow: '251, 188, 5',
};
function color(name, opacity = 1) {
@@ -34,6 +36,11 @@ const VARIABLES = {
'remove-btn-hover-bg': color('purple', 0.2),
'primary-color': color('purple'),
+ 'success-bg-color': color('green', 0.1),
+ 'success-color': color('green', 0.9),
+ 'warning-bg-color': color('yellow', 0.1),
+ 'warning-color': color('yellow', 0.9),
+
'pink-8': color('pink', 0.2),
'pink-9': color('pink', 0.1),
diff --git a/packages/cubejs-playground/src/variables.js b/packages/cubejs-playground/src/variables.js
index f09a63ac4b53f..10b0b4511ac16 100644
--- a/packages/cubejs-playground/src/variables.js
+++ b/packages/cubejs-playground/src/variables.js
@@ -10,6 +10,8 @@ const colors = {
'dark-04': '161, 161, 181',
'dark-05': '213, 213, 226',
light: '243, 243, 251',
+ green: '65, 181, 111',
+ yellow: '251, 188, 5',
};
function color(name, opacity = 1) {
@@ -34,6 +36,11 @@ const VARIABLES = {
'remove-btn-hover-bg': color('purple', 0.2),
'primary-color': color('purple'),
+ 'success-bg-color': color('green', 0.1),
+ 'success-color': color('green', 0.9),
+ 'warning-bg-color': color('yellow', 0.1),
+ 'warning-color': color('yellow', 0.9),
+
'pink-8': color('pink', 0.2),
'pink-9': color('pink', 0.1),