mirror of https://github.com/buster-so/buster.git
dashboard updates
This commit is contained in:
parent
da76a0e19b
commit
f6ad1e24f0
|
@ -67,7 +67,7 @@ const _DashboardMetricItem: React.FC<{
|
||||||
const cardClassNamesMemoized = useMemo(() => {
|
const cardClassNamesMemoized = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
body: `h-full w-full overflow-hidden ${isTable ? '!p-0' : '!px-2 !pt-2 !pb-0.5'} relative`,
|
body: `h-full w-full overflow-hidden ${isTable ? '!p-0' : '!px-2 !pt-2 !pb-0.5'} relative`,
|
||||||
header: cx(`!p-0 !min-h-[52px]`, styles.cardTitle)
|
header: cx(`!p-0 !min-h-[52px] !mb-0`, styles.cardTitle)
|
||||||
};
|
};
|
||||||
}, [isTable]);
|
}, [isTable]);
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ export const MetricTitle: React.FC<{
|
||||||
<Title
|
<Title
|
||||||
{...titleConfig}
|
{...titleConfig}
|
||||||
level={4}
|
level={4}
|
||||||
className="max-w-[calc(100%_-_24px)] !text-md"
|
className="max-w-[calc(100%_-_22px)] !text-md"
|
||||||
style={{ fontSize: '14px' }}>
|
style={{ fontSize: '14px' }}>
|
||||||
{`${title}`}
|
{`${title}`}
|
||||||
</Title>
|
</Title>
|
||||||
|
|
|
@ -31,6 +31,7 @@ export const BusterChartJSTooltip: React.FC<{
|
||||||
const isScatter = selectedChartType === ChartType.Scatter;
|
const isScatter = selectedChartType === ChartType.Scatter;
|
||||||
const isLine = selectedChartType === ChartType.Line;
|
const isLine = selectedChartType === ChartType.Line;
|
||||||
const isBar = selectedChartType === ChartType.Bar;
|
const isBar = selectedChartType === ChartType.Bar;
|
||||||
|
const isPie = selectedChartType === ChartType.Pie;
|
||||||
const isComboChart = selectedChartType === ChartType.Combo;
|
const isComboChart = selectedChartType === ChartType.Combo;
|
||||||
const datasets = chart.data.datasets;
|
const datasets = chart.data.datasets;
|
||||||
const dataPoints = dataPointsProp.filter((item) => !item.dataset.isTrendline);
|
const dataPoints = dataPointsProp.filter((item) => !item.dataset.isTrendline);
|
||||||
|
@ -38,7 +39,6 @@ export const BusterChartJSTooltip: React.FC<{
|
||||||
const title = useMemo(() => {
|
const title = useMemo(() => {
|
||||||
if (isScatter) return undefined;
|
if (isScatter) return undefined;
|
||||||
|
|
||||||
const isTimeAxis = chart.scales.x.type === 'time';
|
|
||||||
const dataIndex = dataPoints[0].dataIndex;
|
const dataIndex = dataPoints[0].dataIndex;
|
||||||
const value = chart.data.labels?.[dataIndex!];
|
const value = chart.data.labels?.[dataIndex!];
|
||||||
if (typeof value === 'string') return String(value);
|
if (typeof value === 'string') return String(value);
|
||||||
|
@ -50,16 +50,8 @@ export const BusterChartJSTooltip: React.FC<{
|
||||||
const key = xAxisKeys.at(0)!;
|
const key = xAxisKeys.at(0)!;
|
||||||
const columnLabelFormat = columnLabelFormats[key!];
|
const columnLabelFormat = columnLabelFormats[key!];
|
||||||
|
|
||||||
// if (columnLabelFormat.dateFormat === 'auto') {
|
|
||||||
// const parsedXValue = dataPoints[0]?.parsed?.x;
|
|
||||||
// const assosciatedTick = chart.scales.x.ticks.find((tick) => tick.value === parsedXValue);
|
|
||||||
// if (assosciatedTick) {
|
|
||||||
// return assosciatedTick.label as string;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return formatLabel(value as number | Date, columnLabelFormat);
|
return formatLabel(value as number | Date, columnLabelFormat);
|
||||||
}, [dataPoints, chart]);
|
}, [dataPoints, isPie, isScatter, chart]);
|
||||||
|
|
||||||
const tooltipItems: ITooltipItem[] = useMemo(() => {
|
const tooltipItems: ITooltipItem[] = useMemo(() => {
|
||||||
if (isBar || isLine || isComboChart) {
|
if (isBar || isLine || isComboChart) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Text } from '@/components/text';
|
import { ShimmerText, Text } from '@/components/text';
|
||||||
import { busterChartsTwMerge } from '@/styles/busterChartsTwMerge';
|
import { busterChartsTwMerge } from '@/styles/busterChartsTwMerge';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
@ -8,17 +8,22 @@ export const PreparingYourRequestLoader: React.FC<{
|
||||||
className?: string;
|
className?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
error?: string | null;
|
error?: string | null;
|
||||||
}> = ({ className = '', text = 'Processing your request...', error }) => {
|
useShimmer?: boolean;
|
||||||
|
}> = ({ className = '', text = 'Processing your request...', error, useShimmer = true }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={busterChartsTwMerge(
|
className={busterChartsTwMerge(
|
||||||
'flex h-full w-full items-center justify-center space-x-1.5',
|
'flex h-full w-full items-center justify-center space-x-1.5',
|
||||||
className
|
className
|
||||||
)}>
|
)}>
|
||||||
<Text type="tertiary" className="flex items-center text-center">
|
{error || useShimmer === false ? (
|
||||||
{/* {!!error && <AppMaterialIcons icon="error" className="mr-1" />} */}
|
<Text type="tertiary" className="flex items-center text-center">
|
||||||
{error || text}
|
{/* {!!error && <AppMaterialIcons icon="error" className="mr-1" />} */}
|
||||||
</Text>
|
{error || text}
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<ShimmerText text={text} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { useMemoizedFn, useMount } from 'ahooks';
|
||||||
import { useBusterWebSocket } from '../BusterWebSocket';
|
import { useBusterWebSocket } from '../BusterWebSocket';
|
||||||
import type { BusterMetricData } from '../Metrics';
|
import type { BusterMetricData } from '../Metrics';
|
||||||
import { MetricEvent_fetchingData } from '@/api/buster_socket/metrics/eventsInterfaces';
|
import { MetricEvent_fetchingData } from '@/api/buster_socket/metrics/eventsInterfaces';
|
||||||
import { MOCK_DATA } from './MOCK_DATA';
|
|
||||||
import { DEFAULT_MESSAGE_DATA } from './config';
|
import { DEFAULT_MESSAGE_DATA } from './config';
|
||||||
|
import { createMockData } from './MOCK_DATA';
|
||||||
|
|
||||||
const useMetricData = () => {
|
const useMetricData = () => {
|
||||||
const busterSocket = useBusterWebSocket();
|
const busterSocket = useBusterWebSocket();
|
||||||
|
@ -103,10 +103,7 @@ const useMetricData = () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
//TODO: remove mock data
|
//TODO: remove mock data
|
||||||
// _setMetricData(metricId, { ...MOCK_DATA, fetched: true });
|
// _setMetricData(metricId, { ...MOCK_DATA, fetched: true });
|
||||||
onSetDataForMetric({
|
onSetDataForMetric(createMockData(metricId));
|
||||||
...MOCK_DATA,
|
|
||||||
metricId
|
|
||||||
});
|
|
||||||
}, Math.random() * 5000);
|
}, Math.random() * 5000);
|
||||||
|
|
||||||
return await busterSocket.emitAndOnce({
|
return await busterSocket.emitAndOnce({
|
||||||
|
|
|
@ -3,15 +3,13 @@ import type { BusterMetricData } from '../Metrics';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
|
|
||||||
const mockData = (): Record<string, string | number | null>[] => {
|
const mockData = (): Record<string, string | number | null>[] => {
|
||||||
return Array.from({ length: faker.number.int({ min: 20, max: 150 }) }, (x, index) => ({
|
return Array.from({ length: faker.number.int({ min: 5, max: 150 }) }, (x, index) => ({
|
||||||
sales: index + 1,
|
sales: index + 1,
|
||||||
date: faker.date.past({ years: index + 1 }).toISOString(),
|
date: faker.date.past({ years: index + 1 }).toISOString(),
|
||||||
product: faker.commerce.productName()
|
product: faker.commerce.productName()
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = mockData();
|
|
||||||
|
|
||||||
const dataMetadata: DataMetadata = {
|
const dataMetadata: DataMetadata = {
|
||||||
column_count: 3,
|
column_count: 3,
|
||||||
column_metadata: [
|
column_metadata: [
|
||||||
|
@ -40,15 +38,15 @@ const dataMetadata: DataMetadata = {
|
||||||
type: 'text'
|
type: 'text'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
row_count: data.length
|
row_count: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MOCK_DATA: Required<BusterMetricData> = {
|
const MOCK_DATA: Required<BusterMetricData> = {
|
||||||
fetched: true,
|
fetched: true,
|
||||||
fetching: false,
|
fetching: false,
|
||||||
error: null,
|
error: null,
|
||||||
fetchedAt: Date.now(),
|
fetchedAt: Date.now(),
|
||||||
data: data,
|
data: mockData(),
|
||||||
metricId: faker.string.uuid(),
|
metricId: faker.string.uuid(),
|
||||||
data_metadata: dataMetadata,
|
data_metadata: dataMetadata,
|
||||||
dataFromRerun: null,
|
dataFromRerun: null,
|
||||||
|
@ -62,9 +60,14 @@ ORDER BY date ASC`
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createMockData = (metricId: string): Required<BusterMetricData> => {
|
export const createMockData = (metricId: string): Required<BusterMetricData> => {
|
||||||
|
const data = mockData();
|
||||||
return {
|
return {
|
||||||
...MOCK_DATA,
|
...MOCK_DATA,
|
||||||
metricId,
|
metricId,
|
||||||
data: mockData()
|
data: data,
|
||||||
|
data_metadata: {
|
||||||
|
...dataMetadata,
|
||||||
|
row_count: data.length
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,22 +9,38 @@ import { IBusterMetric } from './interfaces';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
import { ChartType } from '@/components/charts';
|
import { ChartType } from '@/components/charts';
|
||||||
|
|
||||||
const MOCK_CHART_CONFIG: IBusterMetricChartConfig = {
|
const createMockChartConfig = (): IBusterMetricChartConfig => {
|
||||||
...DEFAULT_CHART_CONFIG,
|
const chartType = faker.helpers.arrayElement([
|
||||||
selectedChartType: ChartType.Bar,
|
ChartType.Bar,
|
||||||
barAndLineAxis: {
|
ChartType.Table,
|
||||||
x: ['date'],
|
ChartType.Line,
|
||||||
y: ['sales'],
|
ChartType.Pie,
|
||||||
category: []
|
ChartType.Scatter,
|
||||||
},
|
ChartType.Metric
|
||||||
pieChartAxis: {
|
]);
|
||||||
x: ['product'],
|
|
||||||
y: ['sales']
|
return {
|
||||||
},
|
...DEFAULT_CHART_CONFIG,
|
||||||
scatterAxis: {
|
selectedChartType: chartType,
|
||||||
x: ['date'],
|
barAndLineAxis: {
|
||||||
y: ['sales']
|
x: ['date'],
|
||||||
}
|
y: ['sales'],
|
||||||
|
category: []
|
||||||
|
},
|
||||||
|
pieChartAxis: {
|
||||||
|
x: ['product'],
|
||||||
|
y: ['sales']
|
||||||
|
},
|
||||||
|
scatterAxis: {
|
||||||
|
x: ['date'],
|
||||||
|
y: ['sales']
|
||||||
|
},
|
||||||
|
metricColumnId: 'sales',
|
||||||
|
metricHeader: {
|
||||||
|
columnId: 'sales',
|
||||||
|
useValue: false
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const dataMetadata: DataMetadata = {
|
const dataMetadata: DataMetadata = {
|
||||||
|
@ -58,105 +74,100 @@ const dataMetadata: DataMetadata = {
|
||||||
row_count: 10
|
row_count: 10
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MOCK_METRIC = (id = ''): IBusterMetric => ({
|
|
||||||
id: id || '123',
|
|
||||||
title: id + ' - ' + faker.lorem.words({ min: 2, max: 6 }),
|
|
||||||
version_number: 1,
|
|
||||||
file_name: `${faker.lorem.words({ min: 1, max: 3 })}.yml`,
|
|
||||||
description: faker.commerce.productName(),
|
|
||||||
data_source_id: '6840fa04-c0d7-4e0e-8d3d-ea9190d93874',
|
|
||||||
time_frame: '1d',
|
|
||||||
type: 'metric',
|
|
||||||
chart_config: MOCK_CHART_CONFIG,
|
|
||||||
fetched: true,
|
|
||||||
fetching: false,
|
|
||||||
fetchedAt: 0,
|
|
||||||
dataset_id: '21c91803-c324-4341-98d1-960ef6a3e003',
|
|
||||||
dataset_name: 'Mock Dataset',
|
|
||||||
error: null,
|
|
||||||
data_metadata: dataMetadata,
|
|
||||||
status: VerificationStatus.notRequested,
|
|
||||||
evaluation_score: 'Moderate',
|
|
||||||
evaluation_summary: faker.lorem.sentence(33),
|
|
||||||
file: `
|
|
||||||
metric:
|
|
||||||
name: sales_performance
|
|
||||||
description: Monthly sales performance by product
|
|
||||||
source: sales_database
|
|
||||||
refresh_interval: daily
|
|
||||||
|
|
||||||
dimensions:
|
|
||||||
- name: date
|
|
||||||
type: date
|
|
||||||
format: YYYY-MM-DD
|
|
||||||
- name: product
|
|
||||||
type: string
|
|
||||||
- name: region
|
|
||||||
type: string
|
|
||||||
|
|
||||||
measures:
|
|
||||||
- name: sales_amount
|
|
||||||
type: decimal
|
|
||||||
aggregation: sum
|
|
||||||
- name: units_sold
|
|
||||||
type: integer
|
|
||||||
aggregation: sum
|
|
||||||
|
|
||||||
filters:
|
|
||||||
- field: date
|
|
||||||
operator: between
|
|
||||||
value: [2024-01-01, 2024-12-31]
|
|
||||||
- field: region
|
|
||||||
operator: in
|
|
||||||
value: [North, South, East, West]
|
|
||||||
|
|
||||||
joins:
|
|
||||||
- name: product_details
|
|
||||||
type: left
|
|
||||||
on: product_id
|
|
||||||
|
|
||||||
sorting:
|
|
||||||
- field: sales_amount
|
|
||||||
direction: desc
|
|
||||||
|
|
||||||
limit: 1000`,
|
|
||||||
created_at: '',
|
|
||||||
updated_at: '',
|
|
||||||
sent_by_id: '',
|
|
||||||
sent_by_name: '',
|
|
||||||
sent_by_avatar_url: '',
|
|
||||||
code: `WITH records AS (
|
|
||||||
SELECT
|
|
||||||
response_time_id,
|
|
||||||
interaction_id,
|
|
||||||
agent_id,
|
|
||||||
customer_id,
|
|
||||||
channel,
|
|
||||||
date
|
|
||||||
FROM demo.response_times
|
|
||||||
ORDER BY date ASC
|
|
||||||
LIMIT 100
|
|
||||||
)
|
|
||||||
SELECT * FROM records;`,
|
|
||||||
feedback: null,
|
|
||||||
draft_session_id: null,
|
|
||||||
collections: [],
|
|
||||||
dashboards: [],
|
|
||||||
sharingKey: '',
|
|
||||||
individual_permissions: [],
|
|
||||||
team_permissions: [],
|
|
||||||
organization_permissions: [],
|
|
||||||
password_secret_id: '',
|
|
||||||
public_expiry_date: '',
|
|
||||||
public_enabled_by: '',
|
|
||||||
publicly_accessible: false,
|
|
||||||
public_password: '',
|
|
||||||
permission: ShareRole.OWNER
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createMockMetric = (id: string): IBusterMetric => {
|
export const createMockMetric = (id: string): IBusterMetric => {
|
||||||
return {
|
return {
|
||||||
...MOCK_METRIC(id),
|
title: id + ' - ' + faker.lorem.words({ min: 2, max: 6 }),
|
||||||
|
version_number: 1,
|
||||||
|
file_name: `${faker.lorem.words({ min: 1, max: 3 })}.yml`,
|
||||||
|
description: faker.commerce.productName(),
|
||||||
|
data_source_id: '6840fa04-c0d7-4e0e-8d3d-ea9190d93874',
|
||||||
|
time_frame: '1d',
|
||||||
|
type: 'metric',
|
||||||
|
chart_config: createMockChartConfig(),
|
||||||
|
fetched: true,
|
||||||
|
fetching: false,
|
||||||
|
fetchedAt: 0,
|
||||||
|
dataset_id: '21c91803-c324-4341-98d1-960ef6a3e003',
|
||||||
|
dataset_name: 'Mock Dataset',
|
||||||
|
error: null,
|
||||||
|
data_metadata: dataMetadata,
|
||||||
|
status: VerificationStatus.notRequested,
|
||||||
|
evaluation_score: 'Moderate',
|
||||||
|
evaluation_summary: faker.lorem.sentence(33),
|
||||||
|
file: `
|
||||||
|
metric:
|
||||||
|
name: sales_performance
|
||||||
|
description: Monthly sales performance by product
|
||||||
|
source: sales_database
|
||||||
|
refresh_interval: daily
|
||||||
|
|
||||||
|
dimensions:
|
||||||
|
- name: date
|
||||||
|
type: date
|
||||||
|
format: YYYY-MM-DD
|
||||||
|
- name: product
|
||||||
|
type: string
|
||||||
|
- name: region
|
||||||
|
type: string
|
||||||
|
|
||||||
|
measures:
|
||||||
|
- name: sales_amount
|
||||||
|
type: decimal
|
||||||
|
aggregation: sum
|
||||||
|
- name: units_sold
|
||||||
|
type: integer
|
||||||
|
aggregation: sum
|
||||||
|
|
||||||
|
filters:
|
||||||
|
- field: date
|
||||||
|
operator: between
|
||||||
|
value: [2024-01-01, 2024-12-31]
|
||||||
|
- field: region
|
||||||
|
operator: in
|
||||||
|
value: [North, South, East, West]
|
||||||
|
|
||||||
|
joins:
|
||||||
|
- name: product_details
|
||||||
|
type: left
|
||||||
|
on: product_id
|
||||||
|
|
||||||
|
sorting:
|
||||||
|
- field: sales_amount
|
||||||
|
direction: desc
|
||||||
|
|
||||||
|
limit: 1000`,
|
||||||
|
created_at: '',
|
||||||
|
updated_at: '',
|
||||||
|
sent_by_id: '',
|
||||||
|
sent_by_name: '',
|
||||||
|
sent_by_avatar_url: '',
|
||||||
|
code: `WITH records AS (
|
||||||
|
SELECT
|
||||||
|
response_time_id,
|
||||||
|
interaction_id,
|
||||||
|
agent_id,
|
||||||
|
customer_id,
|
||||||
|
channel,
|
||||||
|
date
|
||||||
|
FROM demo.response_times
|
||||||
|
ORDER BY date ASC
|
||||||
|
LIMIT 100
|
||||||
|
)
|
||||||
|
SELECT * FROM records;`,
|
||||||
|
feedback: null,
|
||||||
|
draft_session_id: null,
|
||||||
|
collections: [],
|
||||||
|
dashboards: [],
|
||||||
|
sharingKey: '',
|
||||||
|
individual_permissions: [],
|
||||||
|
team_permissions: [],
|
||||||
|
organization_permissions: [],
|
||||||
|
password_secret_id: '',
|
||||||
|
public_expiry_date: '',
|
||||||
|
public_enabled_by: '',
|
||||||
|
publicly_accessible: false,
|
||||||
|
public_password: '',
|
||||||
|
permission: ShareRole.OWNER,
|
||||||
id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue