update server shared to include new types

This commit is contained in:
Nate Kelley 2025-07-03 15:54:31 -06:00
parent 7364f328d4
commit 4cdde9203f
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
149 changed files with 621 additions and 1759 deletions

View File

@ -1,77 +0,0 @@
import { z } from 'zod/v4';
import { GoalLineSchema, TrendlineSchema } from './annotationInterfaces';
import { ColumnSettingsSchema } from './columnInterfaces';
import { IColumnLabelFormatSchema } from './columnLabelInterfaces';
import { ChartTypeSchema } from './enum';
import { ShowLegendHeadlineSchema } from './etcInterfaces';
import {
CategoryAxisStyleConfigSchema,
XAxisConfigSchema,
Y2AxisConfigSchema,
YAxisConfigSchema
} from './tickInterfaces';
import { DEFAULT_CHART_THEME } from './configColors';
import { BarChartPropsSchema } from './barChartProps';
import { LineChartPropsSchema } from './lineChartProps';
import { ScatterChartPropsSchema } from './scatterChartProps';
import { PieChartPropsSchema } from './pieChartProps';
import { TableChartPropsSchema } from './tableChartProps';
import { ComboChartPropsSchema } from './comboChartProps';
import { MetricChartPropsSchema, DerivedMetricTitleSchema } from './metricChartProps';
export const BusterChartConfigPropsSchema = z.object({
selectedChartType: ChartTypeSchema,
// COLUMN SETTINGS
// OPTIONAL because the defaults will be determined by the UI
columnSettings: z.record(z.string(), z.optional(ColumnSettingsSchema)).default({}),
columnLabelFormats: z.record(z.string(), z.optional(IColumnLabelFormatSchema)).default({}),
// OPTIONAL: default is the buster color palette
colors: z.array(z.string()).default(DEFAULT_CHART_THEME),
// OPTIONAL: default is null and will be true if there are multiple Y axes or if a category axis is used
showLegend: z.nullable(z.boolean()).default(null),
// OPTIONAL: default: true
gridLines: z.boolean().default(true),
// OPTIONAL
showLegendHeadline: ShowLegendHeadlineSchema,
// OPTIONAL: default is no goal lines
goalLines: z.array(GoalLineSchema).default([]),
// OPTIONAL: default is no trendlines
trendlines: z.array(TrendlineSchema).default([]),
// OPTIONAL: default is false
disableTooltip: z.boolean().default(false),
// Spread the shape properties from all schemas
...YAxisConfigSchema.shape,
...XAxisConfigSchema.shape,
...CategoryAxisStyleConfigSchema.shape,
...Y2AxisConfigSchema.shape,
...BarChartPropsSchema.shape,
...LineChartPropsSchema.shape,
...ScatterChartPropsSchema.shape,
...PieChartPropsSchema.shape,
...TableChartPropsSchema.shape,
...ComboChartPropsSchema.shape,
...MetricChartPropsSchema.shape
});
// Re-export schemas for backward compatibility
export {
BarChartPropsSchema,
LineChartPropsSchema,
ScatterChartPropsSchema,
PieChartPropsSchema,
TableChartPropsSchema,
ComboChartPropsSchema,
MetricChartPropsSchema,
DerivedMetricTitleSchema
};
// Export original types for backward compatibility
export type BusterChartConfigProps = z.infer<typeof BusterChartConfigPropsSchema>;
export type DerivedMetricTitle = z.infer<typeof DerivedMetricTitleSchema>;
export type MetricChartProps = z.infer<typeof MetricChartPropsSchema>;
export type BarChartProps = z.infer<typeof BarChartPropsSchema>;
export type LineChartProps = z.infer<typeof LineChartPropsSchema>;
export type ScatterChartProps = z.infer<typeof ScatterChartPropsSchema>;
export type PieChartProps = z.infer<typeof PieChartPropsSchema>;
export type TableChartProps = z.infer<typeof TableChartPropsSchema>;
export type ComboChartProps = z.infer<typeof ComboChartPropsSchema>;

View File

@ -1,125 +0,0 @@
import { DEFAULT_CHART_THEME } from './configColors';
import { BusterChartConfigPropsSchema, type BusterChartConfigProps } from './chartConfigProps';
import { z } from 'zod/v4';
/**
* Extracts all default values from a Zod schema.
* This function creates a partial version of the schema where all fields are optional,
* then parses an empty object to get all the default values.
*/
function getDefaults<T extends z.ZodObject<z.ZodRawShape>>(schema: T): z.infer<T> {
// Create a partial version of the schema where all fields are optional
const partialSchema = schema.partial();
// Parse an empty object through the partial schema
// This will apply all default values without throwing on missing required fields
const defaults = partialSchema.parse({});
// Now try to parse the defaults through the original schema
// This ensures we get the correct type and validates the defaults
try {
return schema.parse(defaults);
} catch {
// If the original schema fails (missing required fields without defaults),
// return what we have as a partial
return defaults as z.infer<T>;
}
}
/**
* Alternative implementation that only returns fields with explicit defaults.
* This is useful when you want to know which fields have defaults vs which are undefined.
*/
function getDefaultsPartial<T extends z.ZodObject<z.ZodRawShape>>(schema: T): Partial<z.infer<T>> {
// Make all fields optional and parse an empty object
const partialSchema = schema.partial();
return partialSchema.parse({}) as Partial<z.infer<T>>;
}
export const DEFAULT_CHART_CONFIG: BusterChartConfigProps = getDefaults(
BusterChartConfigPropsSchema
);
// export const DEFAULT_CHART_CONFIG: BusterChartConfigProps = {
// colors: DEFAULT_CHART_THEME,
// selectedChartType: 'table',
// yAxisShowAxisLabel: true,
// yAxisShowAxisTitle: true,
// yAxisAxisTitle: null,
// yAxisStartAxisAtZero: null,
// yAxisScaleType: 'linear',
// y2AxisShowAxisLabel: true,
// y2AxisAxisTitle: null,
// y2AxisShowAxisTitle: true,
// y2AxisStartAxisAtZero: true,
// y2AxisScaleType: 'linear',
// xAxisTimeInterval: null,
// xAxisShowAxisLabel: true,
// xAxisShowAxisTitle: true,
// xAxisAxisTitle: null,
// xAxisLabelRotation: 'auto',
// xAxisDataZoom: false,
// categoryAxisTitle: null,
// showLegend: null,
// gridLines: true,
// goalLines: [],
// trendlines: [],
// showLegendHeadline: false,
// disableTooltip: false,
// barAndLineAxis: {
// x: [],
// y: [],
// category: [],
// tooltip: null
// },
// scatterAxis: {
// x: [],
// y: [],
// size: [],
// tooltip: null
// },
// comboChartAxis: {
// x: [],
// y: [],
// y2: [],
// tooltip: null
// },
// pieChartAxis: {
// x: [],
// y: [],
// tooltip: null
// },
// //LINE
// lineGroupType: null,
// //SCATTER
// scatterDotSize: [3, 15],
// //BAR
// barSortBy: [],
// barLayout: 'vertical',
// barGroupType: 'group',
// barShowTotalAtTop: false,
// //PIE
// pieShowInnerLabel: true,
// pieInnerLabelAggregate: 'sum',
// pieInnerLabelTitle: 'Total',
// pieLabelPosition: null,
// pieDonutWidth: 40,
// pieMinimumSlicePercentage: 0,
// pieDisplayLabelAs: 'number',
// pieSortBy: 'value',
// //METRIC
// metricColumnId: '',
// metricValueAggregate: 'sum',
// metricHeader: null,
// metricSubHeader: null,
// metricValueLabel: null,
// //TABLE
// tableColumnOrder: null,
// tableColumnWidths: null,
// tableHeaderBackgroundColor: null,
// tableHeaderFontColor: null,
// tableColumnFontColor: null,
// //MUST LOOP THROUGH ALL COLUMNS
// columnSettings: {},
// columnLabelFormats: {}
// };

View File

@ -1,69 +0,0 @@
import { z } from 'zod/v4';
export const IColumnLabelFormatSchema = z.object({
columnType: z.enum(['number', 'text', 'date'] as const),
style: z.enum(['currency', 'percent', 'number', 'date', 'string']),
// All other properties from ColumnLabelFormat
// OPTIONAL: if this is not specifically requested by the user, then you should ignore this and the columnId will be used and formatted
displayName: z.optional(z.string()),
// OPTIONAL: default is ','. You should add this style if the column type requires a unique separator style. This will only apply if the format is set to 'number'.
numberSeparatorStyle: z.optional(z.nullable(z.literal(','))),
// OPTIONAL: default is 0. This is essentially used to set a minimum number of decimal places. This will only apply if the format is set to 'number'.
minimumFractionDigits: z.optional(
z
.number()
.check(
z.gte(0, 'Minimum fraction digits must be at least 0'),
z.lte(20, 'Minimum fraction digits must be at most 20')
)
),
// OPTIONAL: default is 2. This is essentially used to set a maximum number of decimal places. This will only apply if the format is set to 'number'.
maximumFractionDigits: z.optional(
z
.number()
.check(
z.gte(0, 'Maximum fraction digits must be at least 0'),
z.lte(20, 'Maximum fraction digits must be at most 20')
)
),
// OPTIONAL: default is 1. This will only apply if the format is set to 'number', 'currency', or 'percent'.
multiplier: z.optional(
z
.number()
.check(
z.gte(0.001, 'Multiplier must be at least 0.001'),
z.lte(1000000, 'Multiplier must be at most 1,000,000')
)
),
// OPTIONAL: default is ''. This sets a prefix to go in front of each value found within the column. This will only apply if the format is set to 'number' or 'percent'.
prefix: z.optional(z.string()),
// OPTIONAL: default is ''. This sets a suffix to go after each value found within the column. This will only apply if the format is set to 'number' or 'percent'.
suffix: z.optional(z.string()),
// OPTIONAL: default is 0. This will only apply if the format is set to 'number'. This will replace missing data with the specified value.
replaceMissingDataWith: z.optional(z.union([z.literal(0), z.null(), z.string()])),
useRelativeTime: z.optional(z.boolean()),
isUTC: z.optional(z.boolean()),
makeLabelHumanReadable: z.optional(z.boolean()),
// DO NOT SHARE WITH LLM
compactNumbers: z.optional(z.boolean()),
// Currency-specific properties
// OPTIONAL: default is 'USD'. This will only apply if the format is set to 'currency'. It should be the ISO 4217 currency code.
currency: z.optional(z.string()),
// Date-specific properties
// OPTIONAL: default is 'LL'. This will only apply if the format is set to 'date'. This will convert the date to the specified format. This MUST BE IN dayjs format. If you determine that a column type is a date column, you should specify it's date format here.
dateFormat: z.optional(z.union([z.literal('auto'), z.string()])),
// OPTIONAL: default is null. This will only apply if the format is set to 'number'. This will convert the number to a specified date unit. For example, if month_of_year is selected, then the number 0 will be converted to January.
convertNumberTo: z.optional(
z.nullable(z.enum(['day_of_week', 'month_of_year', 'quarter', 'number']))
)
});
// Create ColumnLabelFormatSchema by extending IColumnLabelFormatSchema with optional columnType and style
export const ColumnLabelFormatSchema = IColumnLabelFormatSchema.extend({
columnType: z.optional(z.enum(['number', 'text', 'date'] as const)),
style: z.optional(z.enum(['currency', 'percent', 'number', 'date', 'string']))
});
// Export inferred types
export type ColumnLabelFormat = z.infer<typeof ColumnLabelFormatSchema>;
export type IColumnLabelFormat = z.infer<typeof IColumnLabelFormatSchema>;

View File

@ -1,10 +1 @@
export * from './annotationInterfaces';
export * from './axisInterfaces';
export * from './chartBaseInterfaces';
export * from './chartConfigProps';
export * from './columnInterfaces';
export * from './columnLabelInterfaces';
export * from './enum';
export * from './etcInterfaces';
export * from './interfaces'; export * from './interfaces';
export * from './tickInterfaces';

View File

@ -1,6 +1,5 @@
import type { Chart, ChartType, DefaultDataPoint } from 'chart.js'; import type { Chart, ChartType, DefaultDataPoint } from 'chart.js';
import type { ColumnMetaData } from '../interfaces'; import type { ColumnMetaData, ChartConfigProps } from '@buster/server-shared/metrics';
import type { BusterChartConfigProps } from './chartConfigProps';
export type BusterChartProps = { export type BusterChartProps = {
data: Record<string, string | number | null | Date>[] | null; data: Record<string, string | number | null | Date>[] | null;
@ -15,7 +14,7 @@ export type BusterChartProps = {
readOnly?: boolean; readOnly?: boolean;
onInitialAnimationEnd?: () => void; onInitialAnimationEnd?: () => void;
onChartMounted?: (chart?: ChartJSOrUndefined) => void; onChartMounted?: (chart?: ChartJSOrUndefined) => void;
} & BusterChartConfigProps; } & ChartConfigProps;
type ChartJSOrUndefined< type ChartJSOrUndefined<
TType extends ChartType = ChartType, TType extends ChartType = ChartType,

View File

@ -1,36 +0,0 @@
import { z } from 'zod/v4';
import { PieChartAxisSchema } from './axisInterfaces';
import { PieSortBySchema } from './etcInterfaces';
export const PieChartPropsSchema = z.object({
// OPTIONAL: default: value
pieSortBy: PieSortBySchema,
// Required for Pie
pieChartAxis: PieChartAxisSchema,
// OPTIONAL: default: number
pieDisplayLabelAs: z.enum(['percent', 'number']).default('number'),
// OPTIONAL: default true if donut width is set. If the data contains a percentage, set this as false.
pieShowInnerLabel: z.boolean().default(true),
// OPTIONAL: default: sum
pieInnerLabelAggregate: z
.enum(['sum', 'average', 'median', 'max', 'min', 'count'])
.default('sum'),
// OPTIONAL: default is null and will be the name of the pieInnerLabelAggregate
pieInnerLabelTitle: z.string().optional(),
// OPTIONAL: default: outside
pieLabelPosition: z.nullable(z.enum(['inside', 'outside', 'none'])).default(null),
// OPTIONAL: default: 55 | range 0-65 | range represents percent size of the donut hole. If user asks for a pie this should be 0
pieDonutWidth: z
.number()
.min(0, 'Donut width must be at least 0')
.max(65, 'Donut width must be at most 65')
.default(40),
// OPTIONAL: default: 2.5 | range 0-100 | If there are items that are less than this percentage of the pie, they combine to form a single slice.
pieMinimumSlicePercentage: z
.number()
.min(0, 'Minimum slice percentage must be at least 0')
.max(100, 'Minimum slice percentage must be at most 100')
.default(0)
});
export type PieChartProps = z.infer<typeof PieChartPropsSchema>;

View File

@ -1,70 +0,0 @@
import { z } from 'zod/v4';
/**
* Configuration options for the Y-axis of a chart.
*/
export const YAxisConfigSchema = z.object({
// Whether to show the axis label. Defaults to true.
yAxisShowAxisLabel: z.boolean().default(true),
// Whether to show the axis title. Defaults to true.
yAxisShowAxisTitle: z.boolean().default(true),
// The title of the Y-axis. @default null - Uses the name of the first column plotted on the Y-axis
yAxisAxisTitle: z.nullable(z.string()).default(null),
// Whether to start the axis at zero. Defaults to null.
yAxisStartAxisAtZero: z.nullable(z.boolean()).default(null),
// The scale type for the Y-axis. @default "linear"
yAxisScaleType: z.enum(['log', 'linear']).default('linear')
});
//The y2 (or right axis) Y-axis is used for secondary Y-axes in a combo chart.
/**
* Configuration options for the secondary Y-axis (Y2) in a combo chart.
*/
export const Y2AxisConfigSchema = z.object({
// Whether to show the axis label. Defaults to true.
y2AxisShowAxisLabel: z.boolean().default(true),
// Whether to show the axis title. Defaults to true.
y2AxisShowAxisTitle: z.boolean().default(true),
// The title of the secondary Y-axis. @default null - Uses the name of the first column plotted on the Y2-axis
y2AxisAxisTitle: z.nullable(z.string()).default(null),
// Whether to start the axis at zero. Defaults to true.
y2AxisStartAxisAtZero: z.boolean().default(true),
// The scale type for the secondary Y-axis. @default "linear"
y2AxisScaleType: z.enum(['log', 'linear']).default('linear')
});
/**
* Configuration options for the X-axis of a chart.
*/
export const XAxisConfigSchema = z.object({
// The time interval for the X-axis. Only applies to combo and line charts. @default null
xAxisTimeInterval: z.nullable(z.enum(['day', 'week', 'month', 'quarter', 'year'])).default(null),
// Whether to show the axis label. Defaults to true.
xAxisShowAxisLabel: z.boolean().default(true),
// Whether to show the axis title. Defaults to true.
xAxisShowAxisTitle: z.boolean().default(true),
// The title of the X-axis. @default null - Uses a concatenation of all X columns applied to the axis
xAxisAxisTitle: z.nullable(z.string()).default(null),
// The rotation angle for the X-axis labels. @default "auto"
xAxisLabelRotation: z
.union([z.literal(0), z.literal(45), z.literal(90), z.literal('auto')])
.default('auto'),
// Whether to enable data zooming on the X-axis. Should only be set to true by the user. @default false
xAxisDataZoom: z.boolean().default(false)
});
//The category axis works differently than the other axes. It is used to color and group the data.
/**
* Configuration options for styling the category axis.
* The category axis is used to color and group the data.
*/
export const CategoryAxisStyleConfigSchema = z.object({
// The title of the category axis. @default null
categoryAxisTitle: z.nullable(z.string()).default(null)
});
// Export inferred types
export type YAxisConfig = z.infer<typeof YAxisConfigSchema>;
export type Y2AxisConfig = z.infer<typeof Y2AxisConfigSchema>;
export type XAxisConfig = z.infer<typeof XAxisConfigSchema>;
export type CategoryAxisStyleConfig = z.infer<typeof CategoryAxisStyleConfigSchema>;

View File

@ -1,187 +0,0 @@
import { ShareRole } from '../share/shareInterfaces';
import { VerificationStatus } from '../share/verificationInterfaces';
import { type ColumnLabelFormat, type ColumnSettings } from './charts';
import { DEFAULT_CHART_THEME } from './charts/configColors';
import type { ColumnMetaData } from './interfaces';
import type { IBusterMetric, IBusterMetricChartConfig } from './requireInterfaces';
export const DEFAULT_CHART_CONFIG: IBusterMetricChartConfig = {
colors: DEFAULT_CHART_THEME,
selectedChartType: 'table',
yAxisShowAxisLabel: true,
yAxisShowAxisTitle: true,
yAxisAxisTitle: null,
yAxisStartAxisAtZero: null,
yAxisScaleType: 'linear',
y2AxisShowAxisLabel: true,
y2AxisAxisTitle: null,
y2AxisShowAxisTitle: true,
y2AxisStartAxisAtZero: true,
y2AxisScaleType: 'linear',
xAxisTimeInterval: null,
xAxisShowAxisLabel: true,
xAxisShowAxisTitle: true,
xAxisAxisTitle: null,
xAxisLabelRotation: 'auto',
xAxisDataZoom: false,
categoryAxisTitle: null,
showLegend: null,
gridLines: true,
goalLines: [],
trendlines: [],
showLegendHeadline: false,
disableTooltip: false,
barAndLineAxis: {
x: [],
y: [],
category: [],
tooltip: null
},
scatterAxis: {
x: [],
y: [],
category: [],
size: [],
tooltip: null
},
comboChartAxis: {
x: [],
y: [],
y2: [],
category: [],
tooltip: null
},
pieChartAxis: {
x: [],
y: [],
tooltip: null
},
//LINE
lineGroupType: null,
//SCATTER
scatterDotSize: [3, 15],
//BAR
barSortBy: [],
barLayout: 'vertical',
barGroupType: 'group',
barShowTotalAtTop: false,
//PIE
pieShowInnerLabel: true,
pieInnerLabelAggregate: 'sum',
pieInnerLabelTitle: 'Total',
pieLabelPosition: null,
pieDonutWidth: 40,
pieMinimumSlicePercentage: 0,
pieDisplayLabelAs: 'number',
pieSortBy: 'value',
//METRIC
metricColumnId: '',
metricValueAggregate: 'sum',
metricHeader: null,
metricSubHeader: null,
metricValueLabel: null,
//TABLE
tableColumnOrder: null,
tableColumnWidths: null,
tableHeaderBackgroundColor: null,
tableHeaderFontColor: null,
tableColumnFontColor: null,
//MUST LOOP THROUGH ALL COLUMNS
columnSettings: {},
columnLabelFormats: {}
};
export const DEFAULT_COLUMN_SETTINGS: Required<ColumnSettings> = {
showDataLabels: false,
columnVisualization: 'bar',
lineWidth: 2,
lineStyle: 'line',
lineType: 'normal',
lineSymbolSize: 0,
barRoundness: 8,
showDataLabelsAsPercentage: false
};
export const DEFAULT_COLUMN_LABEL_FORMAT: Required<ColumnLabelFormat> = {
style: 'string',
compactNumbers: false,
columnType: 'text',
displayName: '',
numberSeparatorStyle: ',',
minimumFractionDigits: 0,
maximumFractionDigits: 2,
currency: 'USD',
convertNumberTo: null,
dateFormat: 'auto',
useRelativeTime: false,
isUTC: false,
multiplier: 1,
prefix: '',
suffix: '',
replaceMissingDataWith: 0,
makeLabelHumanReadable: true
};
export const ENABLED_DOTS_ON_LINE = 3.5;
export const DEFAULT_CHART_CONFIG_ENTRIES = Object.entries(DEFAULT_CHART_CONFIG);
export const DEFAULT_BAR_ROUNDNESS = DEFAULT_COLUMN_SETTINGS.barRoundness;
export const MIN_DONUT_WIDTH = 15;
export const DEFAULT_DAY_OF_WEEK_FORMAT = 'ddd';
export const DEFAULT_DATE_FORMAT_DAY_OF_WEEK = 'dddd';
export const DEFAULT_DATE_FORMAT_MONTH_OF_YEAR = 'MMMM';
export const DEFAULT_DATE_FORMAT_QUARTER = 'YYYY [Q]Q';
export const ENABLED_DOTS_ON_LINE_SIZE = 4;
export const DEFAULT_COLUMN_METADATA: ColumnMetaData[] = [];
export const DEFAULT_IBUSTER_METRIC: Required<IBusterMetric> = {
id: 'DEFAULT_ID',
type: 'metric',
name: '',
version_number: 1,
description: '',
time_frame: '',
sql: null,
dataset_id: '',
dataset_name: null,
error: null,
data_metadata: null,
status: VerificationStatus.NOT_REQUESTED,
evaluation_score: 'Moderate',
evaluation_summary: '',
file_name: '',
file: '',
data_source_id: '',
created_at: '',
updated_at: '',
sent_by_id: '',
sent_by_name: '',
permission: ShareRole.CAN_VIEW,
sent_by_avatar_url: null,
dashboards: [],
collections: [],
chart_config: DEFAULT_CHART_CONFIG,
individual_permissions: null,
public_expiry_date: null,
public_enabled_by: null,
publicly_accessible: false,
public_password: null,
versions: []
};
export const DEFAULT_TRENDLINE_CONFIG: Required<IBusterMetricChartConfig['trendlines'][number]> = {
id: 'DEFAULT_ID',
columnId: '',
show: true,
showTrendlineLabel: false,
trendlineLabel: null,
type: 'linear_regression',
trendLineColor: '#FF0000',
trendlineLabelPositionOffset: 85,
projection: true,
lineStyle: 'solid',
polynomialOrder: 2,
aggregateAllCategories: true,
offset: 0
};

View File

@ -1,6 +1,4 @@
export * from './charts'; export * from './charts';
export * from './defaults';
export * from './interfaces'; export * from './interfaces';
export * from './listInterfaces'; export * from './listInterfaces';
export * from './metricDataInterfaces'; export * from './metricDataInterfaces';
export * from './requireInterfaces';

View File

@ -1,88 +1,3 @@
import type { BusterShare, VerificationStatus } from '../share'; import type { Metric } from '@buster/server-shared/metrics';
import type { BusterChartConfigProps } from './charts';
export type BusterMetric = { export type BusterMetric = Metric;
id: string;
type: 'metric';
name: string;
version_number: number;
description: string | null;
file_name: string;
time_frame: string;
dataset_id: string;
data_source_id: string;
dataset_name: string | null;
error: string | null;
chart_config?: BusterChartConfigProps;
data_metadata: DataMetadata;
status: VerificationStatus;
evaluation_score: 'Moderate' | 'High' | 'Low';
evaluation_summary: string;
file: string; //yaml file
created_at: string;
updated_at: string;
sent_by_id: string;
sent_by_name: string;
sent_by_avatar_url: string | null;
sql: string | null;
dashboards: {
id: string;
name: string;
}[];
collections: {
id: string;
name: string;
}[];
versions: {
version_number: number;
updated_at: string;
}[];
} & BusterShare;
export type DataMetadata = {
column_count: number;
column_metadata: ColumnMetaData[];
row_count: number;
} | null;
export type ColumnMetaData = {
name: string;
min_value: number | string;
max_value: number | string;
unique_values: number;
simple_type: 'text' | 'number' | 'date';
type:
| 'text'
| 'float'
| 'integer'
| 'date'
| 'float8'
| 'timestamp'
| 'timestamptz'
| 'bool'
| 'date'
| 'time'
| 'boolean'
| 'json'
| 'jsonb'
| 'int8'
| 'int4'
| 'int2'
| 'decimal'
| 'char'
| 'character varying'
| 'character'
| 'varchar'
| 'text'
| 'number'
| 'numeric'
| 'tinytext'
| 'mediumtext'
| 'longtext'
| 'nchar'
| 'nvarchat'
| 'ntext'
| 'float4';
};
export type IDataResult = Record<string, null | string | number>[] | null;

View File

@ -1,15 +1,3 @@
import type { VerificationStatus } from '../share'; import type { MetricListItem } from '@buster/server-shared/metrics';
export type BusterMetricListItem = { export type BusterMetricListItem = MetricListItem;
id: string;
name: string;
last_edited: string;
dataset_name: string;
dataset_uuid: string;
created_by_id: string;
created_by_name: string;
created_by_email: string;
created_by_avatar: string;
status: VerificationStatus;
is_shared: boolean;
};

View File

@ -1,14 +1,14 @@
import type { DataMetadata, IDataResult } from './interfaces'; import type { DataMetadata, DataResult } from '@buster/server-shared/metrics';
export type BusterMetricData = { export type BusterMetricData = {
data: IDataResult | null; data: DataResult | null;
data_metadata: DataMetadata; data_metadata: DataMetadata;
metricId: string; metricId: string;
}; };
export type IBusterMetricData = { export type BusterMetricDataExtended = {
data: IDataResult | null; data: DataResult | null;
dataFromRerun?: IDataResult; //this is actually only used in the UI. maybe move this to ? dataFromRerun?: DataResult; //this is actually only used in the UI. maybe move this to ?
data_metadata: DataMetadata; data_metadata: DataMetadata;
runRunDataMetadata?: DataMetadata; runRunDataMetadata?: DataMetadata;
metricId: string; metricId: string;

View File

@ -1,13 +0,0 @@
import type { BusterChartConfigProps, ColumnSettings, IColumnLabelFormat } from './charts';
import type { BusterMetric } from './interfaces';
export type IBusterMetricChartConfig = Required<
Omit<BusterChartConfigProps, 'columnLabelFormats'>
> & {
columnLabelFormats: Record<string, Required<IColumnLabelFormat>>;
columnSettings: Required<Record<string, Required<ColumnSettings>>>;
};
export interface IBusterMetric extends Required<BusterMetric> {
chart_config: IBusterMetricChartConfig;
}

View File

@ -6,9 +6,9 @@ import {
} from '@tanstack/react-query'; } from '@tanstack/react-query';
import last from 'lodash/last'; import last from 'lodash/last';
import type { import type {
BusterMetric,
BusterMetricData, BusterMetricData,
IBusterMetric, BusterMetricDataExtended
IBusterMetricData
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import { metricsQueryKeys } from '@/api/query_keys/metric'; import { metricsQueryKeys } from '@/api/query_keys/metric';
import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider'; import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider';
@ -19,7 +19,7 @@ import type { RustApiError } from '../errors';
import { useGetMetricVersionNumber, useMetricQueryStore } from './metricQueryStore'; import { useGetMetricVersionNumber, useMetricQueryStore } from './metricQueryStore';
import { getMetric, getMetricData } from './requests'; import { getMetric, getMetricData } from './requests';
export const useGetMetric = <TData = IBusterMetric>( export const useGetMetric = <TData = BusterMetric>(
{ {
id, id,
versionNumber: versionNumberProp versionNumber: versionNumberProp
@ -27,7 +27,7 @@ export const useGetMetric = <TData = IBusterMetric>(
id: string | undefined; id: string | undefined;
versionNumber?: number | null; //if null it will not use a params from the query params versionNumber?: number | null; //if null it will not use a params from the query params
}, },
params?: Omit<UseQueryOptions<IBusterMetric, RustApiError, TData>, 'queryKey' | 'queryFn'> params?: Omit<UseQueryOptions<BusterMetric, RustApiError, TData>, 'queryKey' | 'queryFn'>
) => { ) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const setOriginalMetric = useOriginalMetricStore((x) => x.setOriginalMetric); const setOriginalMetric = useOriginalMetricStore((x) => x.setOriginalMetric);
@ -108,7 +108,7 @@ export const usePrefetchGetMetricClient = () => {
); );
}; };
export const useGetMetricData = <TData = IBusterMetricData>( export const useGetMetricData = <TData = BusterMetricDataExtended>(
{ {
id, id,
versionNumber: versionNumberProp versionNumber: versionNumberProp

View File

@ -1,9 +1,9 @@
import type { import type {
BusterChartConfigProps,
BusterMetric, BusterMetric,
BusterMetricData, BusterMetricData,
BusterMetricListItem BusterMetricListItem
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import type { ChartConfigProps } from '@buster/server-shared/metrics';
import type { VerificationStatus } from '@/api/asset_interfaces/share'; import type { VerificationStatus } from '@/api/asset_interfaces/share';
import type { import type {
ShareDeleteRequest, ShareDeleteRequest,
@ -72,7 +72,7 @@ export const updateMetric = async (params: {
/** SQL query associated with the metric */ /** SQL query associated with the metric */
sql?: string; sql?: string;
/** chart_config to update */ /** chart_config to update */
chart_config?: BusterChartConfigProps; chart_config?: ChartConfigProps;
/** file in yaml format to update */ /** file in yaml format to update */
file?: string; file?: string;
/** update the version number of the metric - default is true */ /** update the version number of the metric - default is true */

View File

@ -1,6 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { create } from 'mutative'; import { create } from 'mutative';
import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetric } from '@/api/asset_interfaces/metric';
import { collectionQueryKeys } from '@/api/query_keys/collection'; import { collectionQueryKeys } from '@/api/query_keys/collection';
import { metricsQueryKeys } from '@/api/query_keys/metric'; import { metricsQueryKeys } from '@/api/query_keys/metric';
import { useOriginalMetricStore } from '@/context/Metrics/useOriginalMetricStore'; import { useOriginalMetricStore } from '@/context/Metrics/useOriginalMetricStore';
@ -225,9 +225,9 @@ export const useShareMetric = () => {
variables.id, variables.id,
selectedVersionNumber selectedVersionNumber
).queryKey; ).queryKey;
queryClient.setQueryData(queryKey, (previousData: IBusterMetric | undefined) => { queryClient.setQueryData(queryKey, (previousData: BusterMetric | undefined) => {
if (!previousData) return previousData; if (!previousData) return previousData;
return create(previousData, (draft: IBusterMetric) => { return create(previousData, (draft: BusterMetric) => {
draft.individual_permissions = [ draft.individual_permissions = [
...variables.params, ...variables.params,
...(draft.individual_permissions || []) ...(draft.individual_permissions || [])
@ -260,9 +260,9 @@ export const useUnshareMetric = () => {
variables.id, variables.id,
selectedVersionNumber selectedVersionNumber
).queryKey; ).queryKey;
queryClient.setQueryData(queryKey, (previousData: IBusterMetric | undefined) => { queryClient.setQueryData(queryKey, (previousData: BusterMetric | undefined) => {
if (!previousData) return previousData; if (!previousData) return previousData;
return create(previousData, (draft: IBusterMetric) => { return create(previousData, (draft: BusterMetric) => {
draft.individual_permissions = draft.individual_permissions =
draft.individual_permissions?.filter((t) => !variables.data.includes(t.email)) || []; draft.individual_permissions?.filter((t) => !variables.data.includes(t.email)) || [];
}); });
@ -293,9 +293,9 @@ export const useUpdateMetricShare = () => {
variables.id, variables.id,
selectedVersionNumber selectedVersionNumber
).queryKey; ).queryKey;
queryClient.setQueryData(queryKey, (previousData: IBusterMetric | undefined) => { queryClient.setQueryData(queryKey, (previousData: BusterMetric | undefined) => {
if (!previousData) return previousData; if (!previousData) return previousData;
return create(previousData, (draft: IBusterMetric) => { return create(previousData, (draft: BusterMetric) => {
draft.individual_permissions = draft.individual_permissions =
draft.individual_permissions?.map((t) => { draft.individual_permissions?.map((t) => {
const found = variables.params.users?.find((v) => v.email === t.email); const found = variables.params.users?.find((v) => v.email === t.email);
@ -330,7 +330,7 @@ export const useUpdateMetric = (params: {
const { selectedVersionNumber } = useGetMetricVersionNumber(); const { selectedVersionNumber } = useGetMetricVersionNumber();
const saveMetricToServer = useMemoizedFn( const saveMetricToServer = useMemoizedFn(
async (newMetric: IBusterMetric, prevMetric: IBusterMetric) => { async (newMetric: BusterMetric, prevMetric: BusterMetric) => {
const changedValues = prepareMetricUpdateMetric(newMetric, prevMetric); const changedValues = prepareMetricUpdateMetric(newMetric, prevMetric);
if (changedValues) { if (changedValues) {
await saveMetric({ ...changedValues, update_version: updateVersion }); await saveMetric({ ...changedValues, update_version: updateVersion });
@ -342,7 +342,7 @@ export const useUpdateMetric = (params: {
({ ({
id: metricId, id: metricId,
...newMetricPartial ...newMetricPartial
}: Omit<Partial<IBusterMetric>, 'status'> & { id: string }) => { }: Omit<Partial<BusterMetric>, 'status'> & { id: string }) => {
const options = metricsQueryKeys.metricsGetMetric(metricId, selectedVersionNumber); const options = metricsQueryKeys.metricsGetMetric(metricId, selectedVersionNumber);
const prevMetric = getOriginalMetric(metricId); const prevMetric = getOriginalMetric(metricId);
const newMetric = create(prevMetric, (draft) => { const newMetric = create(prevMetric, (draft) => {
@ -358,7 +358,7 @@ export const useUpdateMetric = (params: {
); );
const mutationFn = useMemoizedFn( const mutationFn = useMemoizedFn(
async (newMetricPartial: Omit<Partial<IBusterMetric>, 'status'> & { id: string }) => { async (newMetricPartial: Omit<Partial<BusterMetric>, 'status'> & { id: string }) => {
const { newMetric, prevMetric } = combineAndSaveMetric(newMetricPartial); const { newMetric, prevMetric } = combineAndSaveMetric(newMetricPartial);
if (newMetric && prevMetric && saveToServer) { if (newMetric && prevMetric && saveToServer) {
@ -389,13 +389,13 @@ export const useBulkUpdateMetricVerificationStatus = () => {
onMutate: (variables) => { onMutate: (variables) => {
for (const metric of variables) { for (const metric of variables) {
const latestVersionNumber = getLatestMetricVersion(metric.id); const latestVersionNumber = getLatestMetricVersion(metric.id);
const foundMetric = queryClient.getQueryData<IBusterMetric>( const foundMetric = queryClient.getQueryData<BusterMetric>(
metricsQueryKeys.metricsGetMetric(metric.id, latestVersionNumber).queryKey metricsQueryKeys.metricsGetMetric(metric.id, latestVersionNumber).queryKey
); );
if (foundMetric) { if (foundMetric) {
queryClient.setQueryData( queryClient.setQueryData(
metricsQueryKeys.metricsGetMetric(metric.id, latestVersionNumber).queryKey, metricsQueryKeys.metricsGetMetric(metric.id, latestVersionNumber).queryKey,
create(foundMetric, (draft: IBusterMetric) => { create(foundMetric, (draft: BusterMetric) => {
draft.status = metric.status; draft.status = metric.status;
}) })
); );

View File

@ -1,13 +1,13 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import type { import type {
BusterMetricListItem, BusterMetricListItem,
IBusterMetric, BusterMetric,
IBusterMetricData BusterMetricDataExtended
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import type { listMetrics } from '../buster_rest/metrics'; import type { listMetrics } from '../buster_rest/metrics';
export const metricsGetMetric = (metricId: string, version_number: number | null) => { export const metricsGetMetric = (metricId: string, version_number: number | null) => {
return queryOptions<IBusterMetric>({ return queryOptions<BusterMetric>({
queryKey: ['metrics', 'get', metricId, version_number || 'INITIAL'] as const, queryKey: ['metrics', 'get', metricId, version_number || 'INITIAL'] as const,
staleTime: 60 * 1000 staleTime: 60 * 1000
}); });
@ -27,7 +27,7 @@ export const metricsGetList = (
}); });
export const metricsGetData = (id: string, version_number: number) => export const metricsGetData = (id: string, version_number: number) =>
queryOptions<IBusterMetricData>({ queryOptions<BusterMetricDataExtended>({
queryKey: ['metrics', 'data', id, version_number || 'INITIAL'] as const, queryKey: ['metrics', 'data', id, version_number || 'INITIAL'] as const,
staleTime: 3 * 60 * 60 * 1000 // 3 hours, staleTime: 3 * 60 * 60 * 1000 // 3 hours,
}); });

View File

@ -2,11 +2,11 @@ import type {
BusterCollection, BusterCollection,
BusterDashboardResponse, BusterDashboardResponse,
BusterShare, BusterShare,
IBusterMetric BusterMetric
} from '@/api/asset_interfaces'; } from '@/api/asset_interfaces';
export const getShareAssetConfig = ( export const getShareAssetConfig = (
message: IBusterMetric | BusterDashboardResponse | BusterCollection | null message: BusterMetric | BusterDashboardResponse | BusterCollection | null
): BusterShare | null => { ): BusterShare | null => {
if (!message) return null; if (!message) return null;

View File

@ -2,7 +2,7 @@
import type React from 'react'; import type React from 'react';
import { useEffect, useMemo, useState, useTransition } from 'react'; import { useEffect, useMemo, useState, useTransition } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces/metric'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces/metric';
import type { import type {
BusterChartProps, BusterChartProps,
ChartEncodes, ChartEncodes,
@ -28,7 +28,7 @@ interface UseBusterChartJSLegendProps {
selectedChartType: ChartType; selectedChartType: ChartType;
chartMounted: boolean; chartMounted: boolean;
selectedAxis: ChartEncodes | undefined; selectedAxis: ChartEncodes | undefined;
showLegendHeadline: IBusterMetricChartConfig['showLegendHeadline'] | undefined; showLegendHeadline: BusterMetricChartConfig['showLegendHeadline'] | undefined;
columnLabelFormats: NonNullable<BusterChartProps['columnLabelFormats']>; columnLabelFormats: NonNullable<BusterChartProps['columnLabelFormats']>;
loading: boolean; loading: boolean;
lineGroupType: BusterChartProps['lineGroupType']; lineGroupType: BusterChartProps['lineGroupType'];

View File

@ -1,5 +1,5 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric/charts'; import type { ChartConfigProps } from '@buster/server-shared/metrics';
import { formatLabel } from '@/lib/columnFormatter'; import { formatLabel } from '@/lib/columnFormatter';
import { AXIS_TITLE_SEPARATOR } from '../../../../commonHelpers/axisHelper'; import { AXIS_TITLE_SEPARATOR } from '../../../../commonHelpers/axisHelper';
import { truncateWithEllipsis } from '../../../../commonHelpers/titleHelpers'; import { truncateWithEllipsis } from '../../../../commonHelpers/titleHelpers';
@ -12,10 +12,10 @@ export const useY2AxisTitle = ({
y2AxisShowAxisTitle y2AxisShowAxisTitle
}: { }: {
y2Axis: string[]; y2Axis: string[];
columnLabelFormats: NonNullable<BusterChartConfigProps['columnLabelFormats']>; columnLabelFormats: NonNullable<ChartConfigProps['columnLabelFormats']>;
isSupportedChartForAxisTitles: boolean; isSupportedChartForAxisTitles: boolean;
y2AxisAxisTitle: BusterChartConfigProps['y2AxisAxisTitle']; y2AxisAxisTitle: ChartConfigProps['y2AxisAxisTitle'];
y2AxisShowAxisTitle: BusterChartConfigProps['y2AxisShowAxisTitle']; y2AxisShowAxisTitle: ChartConfigProps['y2AxisShowAxisTitle'];
}) => { }) => {
const y2AxisColumnLabelFormats = useMemo(() => { const y2AxisColumnLabelFormats = useMemo(() => {
return y2Axis.map((y) => columnLabelFormats[y]); return y2Axis.map((y) => columnLabelFormats[y]);

View File

@ -1,11 +1,11 @@
import type { CoreInteractionOptions } from 'chart.js'; import type { CoreInteractionOptions } from 'chart.js';
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { DeepPartial } from 'utility-types'; // Add this import import type { DeepPartial } from 'utility-types'; // Add this import
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric/charts'; import type { ChartConfigProps } from '@buster/server-shared/metrics';
interface UseInteractionsProps { interface UseInteractionsProps {
selectedChartType: BusterChartConfigProps['selectedChartType']; selectedChartType: ChartConfigProps['selectedChartType'];
barLayout: BusterChartConfigProps['barLayout']; barLayout: ChartConfigProps['barLayout'];
} }
export const useInteractions = ({ selectedChartType, barLayout }: UseInteractionsProps) => { export const useInteractions = ({ selectedChartType, barLayout }: UseInteractionsProps) => {

View File

@ -1,5 +1,5 @@
import type { Chart, ChartTypeRegistry, TooltipItem } from 'chart.js'; import type { Chart, ChartTypeRegistry, TooltipItem } from 'chart.js';
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric/charts'; import type { ChartConfigProps } from '@buster/server-shared/metrics';
import { formatLabel } from '@/lib'; import { formatLabel } from '@/lib';
import type { ITooltipItem } from '../../../../BusterChartTooltip/interfaces'; import type { ITooltipItem } from '../../../../BusterChartTooltip/interfaces';
import { getPercentage } from './helpers'; import { getPercentage } from './helpers';
@ -7,7 +7,7 @@ import { getPercentage } from './helpers';
export const barAndLineTooltipHelper = ( export const barAndLineTooltipHelper = (
dataPoints: TooltipItem<keyof ChartTypeRegistry>[], dataPoints: TooltipItem<keyof ChartTypeRegistry>[],
chart: Chart, chart: Chart,
columnLabelFormats: NonNullable<BusterChartConfigProps['columnLabelFormats']>, columnLabelFormats: NonNullable<ChartConfigProps['columnLabelFormats']>,
keyToUsePercentage: string[], keyToUsePercentage: string[],
hasMultipleShownDatasets: boolean, hasMultipleShownDatasets: boolean,
percentageMode: undefined | 'stacked' percentageMode: undefined | 'stacked'

View File

@ -1,11 +1,11 @@
import type { ChartTypeRegistry, TooltipItem } from 'chart.js'; import type { ChartTypeRegistry, TooltipItem } from 'chart.js';
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric/charts'; import type { ChartConfigProps } from '@buster/server-shared/metrics';
import { formatLabel } from '@/lib/columnFormatter'; import { formatLabel } from '@/lib/columnFormatter';
import type { ITooltipItem } from '../../../../BusterChartTooltip/interfaces'; import type { ITooltipItem } from '../../../../BusterChartTooltip/interfaces';
export const scatterTooltipHelper = ( export const scatterTooltipHelper = (
dataPoints: TooltipItem<keyof ChartTypeRegistry>[], dataPoints: TooltipItem<keyof ChartTypeRegistry>[],
columnLabelFormats: NonNullable<BusterChartConfigProps['columnLabelFormats']> columnLabelFormats: NonNullable<ChartConfigProps['columnLabelFormats']>
): ITooltipItem[] => { ): ITooltipItem[] => {
return dataPoints.slice(0, 1).flatMap<ITooltipItem>((dataPoint) => { return dataPoints.slice(0, 1).flatMap<ITooltipItem>((dataPoint) => {
const dataPointDataset = dataPoint.dataset; const dataPointDataset = dataPoint.dataset;

View File

@ -1,18 +1,19 @@
import type { Scale, ScaleChartOptions } from 'chart.js'; import type { Scale, ScaleChartOptions } from 'chart.js';
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { DeepPartial } from 'utility-types'; import type { DeepPartial } from 'utility-types';
import { DEFAULT_CHART_CONFIG, DEFAULT_COLUMN_LABEL_FORMAT } from '@/api/asset_interfaces/metric';
import {
type BusterChartConfigProps,
type BusterChartProps,
type ChartEncodes,
ChartType,
type ComboChartAxis,
type IColumnLabelFormat
} from '@/api/asset_interfaces/metric/charts';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { formatYAxisLabel, yAxisSimilar } from '../../../commonHelpers'; import { formatYAxisLabel, yAxisSimilar } from '../../../commonHelpers';
import { useY2AxisTitle } from './axisHooks/useY2AxisTitle'; import { useY2AxisTitle } from './axisHooks/useY2AxisTitle';
import {
DEFAULT_CHART_CONFIG,
DEFAULT_COLUMN_LABEL_FORMAT,
type ChartConfigProps,
type ChartEncodes,
type ChartType,
type ColumnLabelFormat,
type ComboChartAxis
} from '@buster/server-shared/metrics';
import type { BusterChartProps } from '@/api/asset_interfaces';
export const useY2Axis = ({ export const useY2Axis = ({
columnLabelFormats, columnLabelFormats,
@ -24,7 +25,7 @@ export const useY2Axis = ({
y2AxisStartAxisAtZero, y2AxisStartAxisAtZero,
y2AxisScaleType y2AxisScaleType
}: { }: {
columnLabelFormats: NonNullable<BusterChartConfigProps['columnLabelFormats']>; columnLabelFormats: NonNullable<ChartConfigProps['columnLabelFormats']>;
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
selectedChartType: ChartType; selectedChartType: ChartType;
y2AxisAxisTitle: BusterChartProps['y2AxisAxisTitle']; y2AxisAxisTitle: BusterChartProps['y2AxisAxisTitle'];
@ -64,10 +65,10 @@ export const useY2Axis = ({
return y2AxisScaleType === 'log' ? 'logarithmic' : 'linear'; return y2AxisScaleType === 'log' ? 'logarithmic' : 'linear';
}, [y2AxisScaleType, isSupportedType]); }, [y2AxisScaleType, isSupportedType]);
const y2AxisColumnFormats: Record<string, IColumnLabelFormat> = useMemo(() => { const y2AxisColumnFormats: Record<string, ColumnLabelFormat> = useMemo(() => {
if (!isSupportedType) return {}; if (!isSupportedType) return {};
return y2AxisKeys.reduce<Record<string, IColumnLabelFormat>>((acc, y) => { return y2AxisKeys.reduce<Record<string, ColumnLabelFormat>>((acc, y) => {
acc[y] = columnLabelFormats[y] || DEFAULT_COLUMN_LABEL_FORMAT; acc[y] = columnLabelFormats[y] || DEFAULT_COLUMN_LABEL_FORMAT;
return acc; return acc;
}, {}); }, {});

View File

@ -1,4 +1,4 @@
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces/metric'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces/metric';
import type { BusterChartProps, ShowLegendHeadline } from '@/api/asset_interfaces/metric/charts'; import type { BusterChartProps, ShowLegendHeadline } from '@/api/asset_interfaces/metric/charts';
import { formatLabel } from '@/lib/columnFormatter'; import { formatLabel } from '@/lib/columnFormatter';
import { ArrayOperations } from '@/lib/math'; import { ArrayOperations } from '@/lib/math';
@ -11,7 +11,7 @@ export const addLegendHeadlines = (
showLegendHeadline: ShowLegendHeadline, showLegendHeadline: ShowLegendHeadline,
columnMetadata: NonNullable<BusterChartProps['columnMetadata']>, columnMetadata: NonNullable<BusterChartProps['columnMetadata']>,
columnLabelFormats: NonNullable<BusterChartProps['columnLabelFormats']>, columnLabelFormats: NonNullable<BusterChartProps['columnLabelFormats']>,
selectedChartType: IBusterMetricChartConfig['selectedChartType'], selectedChartType: BusterMetricChartConfig['selectedChartType'],
xAxisKeys: string[] xAxisKeys: string[]
) => { ) => {
const isScatterChart = selectedChartType === 'scatter'; const isScatterChart = selectedChartType === 'scatter';

View File

@ -3,7 +3,7 @@ import React, { useCallback } from 'react';
import { import {
type BusterChartPropsBase, type BusterChartPropsBase,
DEFAULT_CHART_CONFIG, DEFAULT_CHART_CONFIG,
type IBusterMetricChartConfig type BusterMetricChartConfig
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import { AppDataGrid } from '@/components/ui/table/AppDataGrid'; import { AppDataGrid } from '@/components/ui/table/AppDataGrid';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
@ -30,7 +30,7 @@ const BusterTableChartBase: React.FC<BusterTableChartProps> = ({
}) => { }) => {
const { onUpdateMetricChartConfig, onInitializeTableColumnWidths } = useUpdateMetricChart(); const { onUpdateMetricChartConfig, onInitializeTableColumnWidths } = useUpdateMetricChart();
const onChangeConfig = useMemoizedFn((config: Partial<IBusterMetricChartConfig>) => { const onChangeConfig = useMemoizedFn((config: Partial<BusterMetricChartConfig>) => {
if (readOnly) return; if (readOnly) return;
onUpdateMetricChartConfig({ chartConfig: config }); onUpdateMetricChartConfig({ chartConfig: config });
if ( if (
@ -42,7 +42,7 @@ const BusterTableChartBase: React.FC<BusterTableChartProps> = ({
}); });
const onUpdateTableColumnOrder = useMemoizedFn((columns: string[]) => { const onUpdateTableColumnOrder = useMemoizedFn((columns: string[]) => {
const config: Partial<IBusterMetricChartConfig> = { const config: Partial<BusterMetricChartConfig> = {
tableColumnOrder: columns tableColumnOrder: columns
}; };
@ -51,7 +51,7 @@ const BusterTableChartBase: React.FC<BusterTableChartProps> = ({
const onUpdateTableColumnSize = useMemoizedFn((columns: { key: string; size: number }[]) => { const onUpdateTableColumnSize = useMemoizedFn((columns: { key: string; size: number }[]) => {
if (readOnly) return; if (readOnly) return;
const config: Partial<IBusterMetricChartConfig> = { const config: Partial<BusterMetricChartConfig> = {
tableColumnWidths: columns.reduce<Record<string, number>>((acc, { key, size }) => { tableColumnWidths: columns.reduce<Record<string, number>>((acc, { key, size }) => {
acc[key] = Number(size.toFixed(1)); acc[key] = Number(size.toFixed(1));
return acc; return acc;

View File

@ -1,7 +1,7 @@
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric/charts'; import type { ChartConfigProps } from '@buster/server-shared/metrics';
export const InnerLabelTitleRecord: Record< export const InnerLabelTitleRecord: Record<
NonNullable<BusterChartConfigProps['pieInnerLabelAggregate']>, NonNullable<ChartConfigProps['pieInnerLabelAggregate']>,
string string
> = { > = {
sum: 'Total', sum: 'Total',
@ -13,8 +13,8 @@ export const InnerLabelTitleRecord: Record<
}; };
export const getPieInnerLabelTitle = ( export const getPieInnerLabelTitle = (
pieInnerLabelTitle: BusterChartConfigProps['pieInnerLabelTitle'], pieInnerLabelTitle: ChartConfigProps['pieInnerLabelTitle'],
pieInnerLabelAggregate: BusterChartConfigProps['pieInnerLabelAggregate'] = 'sum' pieInnerLabelAggregate: ChartConfigProps['pieInnerLabelAggregate'] = 'sum'
) => { ) => {
return pieInnerLabelTitle ?? InnerLabelTitleRecord[pieInnerLabelAggregate]; return pieInnerLabelTitle ?? InnerLabelTitleRecord[pieInnerLabelAggregate];
}; };

View File

@ -1,13 +1,13 @@
'use client'; 'use client';
import type { BusterDashboardResponse } from '@/api/asset_interfaces/dashboard'; import type { BusterDashboardResponse } from '@/api/asset_interfaces/dashboard';
import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetric } from '@/api/asset_interfaces/metric';
import { HydrationBoundaryDashboardStore } from '../Dashboards/useOriginalDashboardStore'; import { HydrationBoundaryDashboardStore } from '../Dashboards/useOriginalDashboardStore';
import { HydrationBoundaryMetricStore } from '../Metrics/useOriginalMetricStore'; import { HydrationBoundaryMetricStore } from '../Metrics/useOriginalMetricStore';
export const HydrationBoundaryAssetStore: React.FC<{ export const HydrationBoundaryAssetStore: React.FC<{
children: React.ReactNode; children: React.ReactNode;
asset: IBusterMetric | BusterDashboardResponse | undefined; asset: BusterMetric | BusterDashboardResponse | undefined;
}> = ({ children, asset }) => { }> = ({ children, asset }) => {
if (!asset) return <>{children}</>; if (!asset) return <>{children}</>;

View File

@ -1,5 +1,5 @@
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import type { IBusterMetric, IBusterMetricData } from '@/api/asset_interfaces/metric'; import type { BusterMetric, BusterMetricDataExtended } from '@/api/asset_interfaces/metric';
import { useGetMetricVersionNumber } from '@/api/buster_rest/metrics'; import { useGetMetricVersionNumber } from '@/api/buster_rest/metrics';
import { queryKeys } from '@/api/query_keys'; import { queryKeys } from '@/api/query_keys';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
@ -9,7 +9,7 @@ export const useGetMetricMemoized = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { selectedVersionNumber } = useGetMetricVersionNumber(); const { selectedVersionNumber } = useGetMetricVersionNumber();
const getMetricMemoized = useMemoizedFn( const getMetricMemoized = useMemoizedFn(
(metricId: string, versionNumberProp?: number): IBusterMetric => { (metricId: string, versionNumberProp?: number): BusterMetric => {
const options = queryKeys.metricsGetMetric( const options = queryKeys.metricsGetMetric(
metricId, metricId,
versionNumberProp || selectedVersionNumber versionNumberProp || selectedVersionNumber
@ -25,7 +25,7 @@ export const useGetMetricDataMemoized = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { selectedVersionNumber, latestVersionNumber } = useGetMetricVersionNumber(); const { selectedVersionNumber, latestVersionNumber } = useGetMetricVersionNumber();
const getMetricDataMemoized = useMemoizedFn( const getMetricDataMemoized = useMemoizedFn(
(metricId: string, versionNumberProp?: number): IBusterMetricData | undefined => { (metricId: string, versionNumberProp?: number): BusterMetricDataExtended | undefined => {
const versionNumber = versionNumberProp ?? selectedVersionNumber ?? latestVersionNumber; const versionNumber = versionNumberProp ?? selectedVersionNumber ?? latestVersionNumber;
if (versionNumber == null) return undefined; if (versionNumber == null) return undefined;
const options = queryKeys.metricsGetData(metricId, versionNumber); const options = queryKeys.metricsGetData(metricId, versionNumber);

View File

@ -1,6 +1,6 @@
import { act, renderHook } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it } from 'vitest'; import { beforeEach, describe, expect, it } from 'vitest';
import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetric } from '@/api/asset_interfaces/metric';
import { DEFAULT_CHART_CONFIG } from '@/api/asset_interfaces/metric/defaults'; import { DEFAULT_CHART_CONFIG } from '@/api/asset_interfaces/metric/defaults';
import { VerificationStatus } from '@/api/asset_interfaces/share'; import { VerificationStatus } from '@/api/asset_interfaces/share';
import { ShareRole } from '@/api/asset_interfaces/share/shareInterfaces'; import { ShareRole } from '@/api/asset_interfaces/share/shareInterfaces';
@ -13,7 +13,7 @@ describe('useOriginalMetricStore', () => {
}); });
it('should correctly set and get a metric', () => { it('should correctly set and get a metric', () => {
const mockMetric: IBusterMetric = { const mockMetric: BusterMetric = {
id: 'test-metric-1', id: 'test-metric-1',
type: 'metric' as const, type: 'metric' as const,
name: 'Test Metric', name: 'Test Metric',

View File

@ -1,27 +1,27 @@
'use client'; 'use client';
import { create } from 'zustand'; import { create } from 'zustand';
import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetric } from '@/api/asset_interfaces/metric';
import { useMount } from '@/hooks'; import { useMount } from '@/hooks';
type OriginalMetricStore = { type OriginalMetricStore = {
originalMetrics: Record<string, IBusterMetric>; originalMetrics: Record<string, BusterMetric>;
bulkAddOriginalMetrics: (metrics: Record<string, IBusterMetric>) => void; bulkAddOriginalMetrics: (metrics: Record<string, BusterMetric>) => void;
setOriginalMetric: (metric: IBusterMetric) => void; setOriginalMetric: (metric: BusterMetric) => void;
getOriginalMetric: (metricId: string | undefined) => IBusterMetric | undefined; getOriginalMetric: (metricId: string | undefined) => BusterMetric | undefined;
removeOriginalMetric: (metricId: string) => void; removeOriginalMetric: (metricId: string) => void;
}; };
export const useOriginalMetricStore = create<OriginalMetricStore>((set, get) => ({ export const useOriginalMetricStore = create<OriginalMetricStore>((set, get) => ({
originalMetrics: {}, originalMetrics: {},
bulkAddOriginalMetrics: (metrics: Record<string, IBusterMetric>) => bulkAddOriginalMetrics: (metrics: Record<string, BusterMetric>) =>
set((prev) => ({ set((prev) => ({
originalMetrics: { originalMetrics: {
...prev.originalMetrics, ...prev.originalMetrics,
...metrics ...metrics
} }
})), })),
setOriginalMetric: (metric: IBusterMetric) => setOriginalMetric: (metric: BusterMetric) =>
set((state) => ({ set((state) => ({
originalMetrics: { originalMetrics: {
...state.originalMetrics, ...state.originalMetrics,

View File

@ -5,7 +5,7 @@ import { useState } from 'react';
import { import {
type ColumnSettings, type ColumnSettings,
DEFAULT_CHART_CONFIG, DEFAULT_CHART_CONFIG,
type IBusterMetricChartConfig, type BusterMetricChartConfig,
type IColumnLabelFormat type IColumnLabelFormat
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import { useUpdateMetric } from '@/api/buster_rest/metrics'; import { useUpdateMetric } from '@/api/buster_rest/metrics';
@ -39,7 +39,7 @@ export const useUpdateMetricChart = (props?: { metricId?: string; chatId?: strin
chartConfig, chartConfig,
ignoreUndoRedo ignoreUndoRedo
}: { }: {
chartConfig: Partial<IBusterMetricChartConfig>; chartConfig: Partial<BusterMetricChartConfig>;
ignoreUndoRedo?: boolean; ignoreUndoRedo?: boolean;
}) => { }) => {
const currentMetric = getMetricMemoized(metricId); const currentMetric = getMetricMemoized(metricId);
@ -52,7 +52,7 @@ export const useUpdateMetricChart = (props?: { metricId?: string; chatId?: strin
// }); // });
} }
const newChartConfig: IBusterMetricChartConfig = { const newChartConfig: BusterMetricChartConfig = {
...DEFAULT_CHART_CONFIG, ...DEFAULT_CHART_CONFIG,
...currentMetric.chart_config, ...currentMetric.chart_config,
...chartConfig ...chartConfig
@ -129,10 +129,10 @@ export const useUpdateMetricChart = (props?: { metricId?: string; chatId?: strin
}); });
const onInitializeTableColumnWidths = useMemoizedFn( const onInitializeTableColumnWidths = useMemoizedFn(
(tableColumnWidths: IBusterMetricChartConfig['tableColumnWidths']) => { (tableColumnWidths: BusterMetricChartConfig['tableColumnWidths']) => {
const originalMetric = getOriginalMetric(metricId); const originalMetric = getOriginalMetric(metricId);
if (originalMetric) { if (originalMetric) {
const newChartConfig: IBusterMetricChartConfig = { const newChartConfig: BusterMetricChartConfig = {
...DEFAULT_CHART_CONFIG, ...DEFAULT_CHART_CONFIG,
...originalMetric.chart_config, ...originalMetric.chart_config,
tableColumnWidths tableColumnWidths

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetric } from '@/api/asset_interfaces/metric';
import { Button, type ButtonProps } from '@/components/ui/buttons'; import { Button, type ButtonProps } from '@/components/ui/buttons';
import { import {
CircleCheck, CircleCheck,
@ -9,7 +9,7 @@ import {
import { Popover } from '@/components/ui/popover/Popover'; import { Popover } from '@/components/ui/popover/Popover';
export const MetricChartEvaluation: React.FC<{ export const MetricChartEvaluation: React.FC<{
evaluationScore: IBusterMetric['evaluation_score'] | undefined; evaluationScore: BusterMetric['evaluation_score'] | undefined;
evaluationSummary: string | undefined; evaluationSummary: string | undefined;
}> = React.memo(({ evaluationScore, evaluationSummary }) => { }> = React.memo(({ evaluationScore, evaluationSummary }) => {
const text = useMemo(() => { const text = useMemo(() => {

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
@ -8,7 +8,7 @@ import { MetricStylingAppSegments } from './config';
export const MetricStylingAppSegment: React.FC<{ export const MetricStylingAppSegment: React.FC<{
segment: MetricStylingAppSegments; segment: MetricStylingAppSegments;
setSegment: (segment: MetricStylingAppSegments) => void; setSegment: (segment: MetricStylingAppSegments) => void;
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
className?: string; className?: string;
}> = React.memo(({ segment, setSegment, selectedChartType, className = '' }) => { }> = React.memo(({ segment, setSegment, selectedChartType, className = '' }) => {
const isTable = selectedChartType === 'table'; const isTable = selectedChartType === 'table';

View File

@ -1,6 +1,6 @@
import isEqual from 'lodash/isEqual'; import isEqual from 'lodash/isEqual';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import type { IColorTheme } from '../Common'; import type { IColorTheme } from '../Common';
import { ThemeList } from '../Common/ThemeList'; import { ThemeList } from '../Common/ThemeList';
@ -8,8 +8,8 @@ import { ColorStyleSegments } from './ColorStyleSegments';
import { COLORFUL_THEMES, ColorAppSegments, MONOCHROME_THEMES } from './config'; import { COLORFUL_THEMES, ColorAppSegments, MONOCHROME_THEMES } from './config';
export const ColorsApp: React.FC<{ export const ColorsApp: React.FC<{
colors: IBusterMetricChartConfig['colors']; colors: BusterMetricChartConfig['colors'];
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = ({ colors, onUpdateChartConfig }) => { }> = ({ colors, onUpdateChartConfig }) => {
const initialSelectedSegment = useMemo(() => { const initialSelectedSegment = useMemo(() => {
const isFromColorfulThemes = COLORFUL_THEMES.some((theme) => isEqual(theme.colors, colors)); const isFromColorfulThemes = COLORFUL_THEMES.some((theme) => isEqual(theme.colors, colors));
@ -44,7 +44,7 @@ export const ColorsApp: React.FC<{
const ColorPicker: React.FC<{ const ColorPicker: React.FC<{
selectedSegmentColors: IColorTheme[]; selectedSegmentColors: IColorTheme[];
colors: IBusterMetricChartConfig['colors']; colors: BusterMetricChartConfig['colors'];
onChangeColorTheme: (theme: IColorTheme) => void; onChangeColorTheme: (theme: IColorTheme) => void;
}> = React.memo(({ selectedSegmentColors, colors, onChangeColorTheme }) => { }> = React.memo(({ selectedSegmentColors, colors, onChangeColorTheme }) => {
const themes = useMemo(() => { const themes = useMemo(() => {

View File

@ -1,4 +1,3 @@
import { DEFAULT_CHART_THEME } from '@/api/asset_interfaces/metric/charts/configColors';
import { import {
BLUE_THEME, BLUE_THEME,
BLUE_TO_ORANGE_GRADIENT, BLUE_TO_ORANGE_GRADIENT,

View File

@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Text } from '@/components/ui/typography'; import { Text } from '@/components/ui/typography';
export const PaletteApp: React.FC<{ export const PaletteApp: React.FC<{
colors: IBusterMetricChartConfig['colors']; colors: BusterMetricChartConfig['colors'];
}> = React.memo(({ colors }) => { }> = React.memo(({ colors }) => {
return ( return (
<div className="flex h-full min-h-[200px] items-center justify-center"> <div className="flex h-full min-h-[200px] items-center justify-center">

View File

@ -1,6 +1,6 @@
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import React, { useState } from 'react'; import React, { useState } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
@ -11,13 +11,13 @@ import { PaletteApp } from './PaletteApp';
export const StylingAppColors: React.FC<{ export const StylingAppColors: React.FC<{
className: string; className: string;
colors: IBusterMetricChartConfig['colors']; colors: BusterMetricChartConfig['colors'];
}> = React.memo(({ className, colors }) => { }> = React.memo(({ className, colors }) => {
const [selectedTab, setSelectedTab] = useState<StylingAppColorsTab>(StylingAppColorsTab.Colors); const [selectedTab, setSelectedTab] = useState<StylingAppColorsTab>(StylingAppColorsTab.Colors);
const { onUpdateMetricChartConfig } = useUpdateMetricChart(); const { onUpdateMetricChartConfig } = useUpdateMetricChart();
const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<IBusterMetricChartConfig>) => { const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<BusterMetricChartConfig>) => {
onUpdateMetricChartConfig({ chartConfig }); onUpdateMetricChartConfig({ chartConfig });
}); });

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { BarSortBy } from '@/api/asset_interfaces/metric/charts'; import type { BarSortBy } from '@/api/asset_interfaces/metric/charts';
import { BarChartSortNoneIcon } from '@/components/ui/icons/customIcons/BarChart_NoSort'; import { BarChartSortNoneIcon } from '@/components/ui/icons/customIcons/BarChart_NoSort';
import { BarChartSortAscIcon } from '@/components/ui/icons/customIcons/BarChartSortAscIcon'; import { BarChartSortAscIcon } from '@/components/ui/icons/customIcons/BarChartSortAscIcon';
@ -27,8 +27,8 @@ const options: SegmentedItem<BarSortBy[0]>[] = [
]; ];
export const EditBarSorting: React.FC<{ export const EditBarSorting: React.FC<{
barSortBy: IBusterMetricChartConfig['barSortBy']; barSortBy: BusterMetricChartConfig['barSortBy'];
onUpdateChartConfig: (v: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (v: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ barSortBy, onUpdateChartConfig }) => { }> = React.memo(({ barSortBy, onUpdateChartConfig }) => {
const selectedOption = useMemo(() => { const selectedOption = useMemo(() => {
return ( return (

View File

@ -1,12 +1,12 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ColumnSettings } from '@/api/asset_interfaces/metric/charts'; import type { ColumnSettings } from '@/api/asset_interfaces/metric/charts';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { EditBarRoundness } from '../StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditBarRoundness'; import { EditBarRoundness } from '../StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditBarRoundness';
export const EditBarRoundnessGlobal: React.FC<{ export const EditBarRoundnessGlobal: React.FC<{
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ columnSettings, onUpdateChartConfig }) => { }> = React.memo(({ columnSettings, onUpdateChartConfig }) => {
const mostPermissiveBarRoundness = useMemo(() => { const mostPermissiveBarRoundness = useMemo(() => {
return Object.values(columnSettings).reduce((acc, curr) => { return Object.values(columnSettings).reduce((acc, curr) => {
@ -15,9 +15,9 @@ export const EditBarRoundnessGlobal: React.FC<{
}, []); }, []);
const onUpdateBarRoundness = useMemoizedFn((v: Partial<ColumnSettings>) => { const onUpdateBarRoundness = useMemoizedFn((v: Partial<ColumnSettings>) => {
const newColumnSettings: IBusterMetricChartConfig['columnSettings'] = Object.keys( const newColumnSettings: BusterMetricChartConfig['columnSettings'] = Object.keys(
columnSettings columnSettings
).reduce<IBusterMetricChartConfig['columnSettings']>((acc, curr) => { ).reduce<BusterMetricChartConfig['columnSettings']>((acc, curr) => {
acc[curr] = { ...columnSettings[curr], ...v }; acc[curr] = { ...columnSettings[curr], ...v };
return acc; return acc;
}, {}); }, {});

View File

@ -1,13 +1,13 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { ENABLED_DOTS_ON_LINE } from '@/api/asset_interfaces'; import { ENABLED_DOTS_ON_LINE } from '@/api/asset_interfaces';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
export const EditDotsOnLineGlobal: React.FC<{ export const EditDotsOnLineGlobal: React.FC<{
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ columnSettings, onUpdateChartConfig }) => { }> = React.memo(({ columnSettings, onUpdateChartConfig }) => {
const allDotsOnLine = useMemo(() => { const allDotsOnLine = useMemo(() => {
return Object.values(columnSettings).some((column) => column.lineSymbolSize > 0); return Object.values(columnSettings).some((column) => column.lineSymbolSize > 0);
@ -15,12 +15,13 @@ export const EditDotsOnLineGlobal: React.FC<{
const onChangeAllSmooth = useMemoizedFn((value: boolean) => { const onChangeAllSmooth = useMemoizedFn((value: boolean) => {
onUpdateChartConfig({ onUpdateChartConfig({
columnSettings: Object.keys(columnSettings).reduce< columnSettings: Object.keys(columnSettings).reduce<BusterMetricChartConfig['columnSettings']>(
IBusterMetricChartConfig['columnSettings'] (acc, curr) => {
>((acc, curr) => { acc[curr] = { ...columnSettings[curr], lineSymbolSize: value ? ENABLED_DOTS_ON_LINE : 0 };
acc[curr] = { ...columnSettings[curr], lineSymbolSize: value ? ENABLED_DOTS_ON_LINE : 0 }; return acc;
return acc; },
}, {}) {}
)
}); });
}); });

View File

@ -1,11 +1,11 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
export const EditGridLines: React.FC<{ export const EditGridLines: React.FC<{
gridLines: IBusterMetricChartConfig['gridLines']; gridLines: BusterMetricChartConfig['gridLines'];
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ gridLines, onUpdateChartConfig }) => { }> = React.memo(({ gridLines, onUpdateChartConfig }) => {
return ( return (
<LabelAndInput label={'Grid lines'}> <LabelAndInput label={'Grid lines'}>

View File

@ -1,7 +1,7 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { import {
DEFAULT_CHART_CONFIG, DEFAULT_CHART_CONFIG,
type IBusterMetricChartConfig, type BusterMetricChartConfig,
MIN_DONUT_WIDTH MIN_DONUT_WIDTH
} from '@/api/asset_interfaces'; } from '@/api/asset_interfaces';
import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented';
@ -23,9 +23,9 @@ export const EditPieAppearance = React.memo(
onUpdateChartConfig, onUpdateChartConfig,
pieChartAxis pieChartAxis
}: { }: {
pieDonutWidth: IBusterMetricChartConfig['pieDonutWidth']; pieDonutWidth: BusterMetricChartConfig['pieDonutWidth'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
pieChartAxis: IBusterMetricChartConfig['pieChartAxis']; pieChartAxis: BusterMetricChartConfig['pieChartAxis'];
}) => { }) => {
const [showDonutWidthSelector, setShowDonutWidthSelector] = useState(pieDonutWidth > 0); const [showDonutWidthSelector, setShowDonutWidthSelector] = useState(pieDonutWidth > 0);
const [value, setValue] = useState(pieDonutWidth); const [value, setValue] = useState(pieDonutWidth);

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Input } from '@/components/ui/inputs'; import { Input } from '@/components/ui/inputs';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
@ -10,9 +10,9 @@ export const EditPieInnerLabel = React.memo(
pieInnerLabelTitle, pieInnerLabelTitle,
onUpdateChartConfig onUpdateChartConfig
}: { }: {
pieInnerLabelAggregate: IBusterMetricChartConfig['pieInnerLabelAggregate']; pieInnerLabelAggregate: BusterMetricChartConfig['pieInnerLabelAggregate'];
pieInnerLabelTitle: IBusterMetricChartConfig['pieInnerLabelTitle']; pieInnerLabelTitle: BusterMetricChartConfig['pieInnerLabelTitle'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}) => { }) => {
return ( return (
<> <>
@ -31,7 +31,7 @@ export const EditPieInnerLabel = React.memo(
); );
EditPieInnerLabel.displayName = 'EditPieInnerLabel'; EditPieInnerLabel.displayName = 'EditPieInnerLabel';
const options: SelectItem<IBusterMetricChartConfig['pieInnerLabelAggregate']>[] = [ const options: SelectItem<BusterMetricChartConfig['pieInnerLabelAggregate']>[] = [
{ label: 'Sum', value: 'sum' }, { label: 'Sum', value: 'sum' },
{ label: 'Average', value: 'average' }, { label: 'Average', value: 'average' },
{ label: 'Median', value: 'median' }, { label: 'Median', value: 'median' },
@ -41,8 +41,8 @@ const options: SelectItem<IBusterMetricChartConfig['pieInnerLabelAggregate']>[]
]; ];
const EditPieInnerLabelAggregate: React.FC<{ const EditPieInnerLabelAggregate: React.FC<{
pieInnerLabelAggregate: IBusterMetricChartConfig['pieInnerLabelAggregate']; pieInnerLabelAggregate: BusterMetricChartConfig['pieInnerLabelAggregate'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = ({ pieInnerLabelAggregate, onUpdateChartConfig }) => { }> = ({ pieInnerLabelAggregate, onUpdateChartConfig }) => {
const selectedOption = useMemo(() => { const selectedOption = useMemo(() => {
return options.find((option) => option.value === pieInnerLabelAggregate) || options[0]; return options.find((option) => option.value === pieInnerLabelAggregate) || options[0];
@ -56,7 +56,7 @@ const EditPieInnerLabelAggregate: React.FC<{
onChange={(value) => { onChange={(value) => {
const label = options.find((option) => option.value === value)?.label; const label = options.find((option) => option.value === value)?.label;
onUpdateChartConfig({ onUpdateChartConfig({
pieInnerLabelAggregate: value as IBusterMetricChartConfig['pieInnerLabelAggregate'], pieInnerLabelAggregate: value as BusterMetricChartConfig['pieInnerLabelAggregate'],
pieInnerLabelTitle: label as string pieInnerLabelTitle: label as string
}); });
}} }}
@ -66,8 +66,8 @@ const EditPieInnerLabelAggregate: React.FC<{
}; };
const EditPieInnerLabelTitle: React.FC<{ const EditPieInnerLabelTitle: React.FC<{
pieInnerLabelTitle: IBusterMetricChartConfig['pieInnerLabelTitle']; pieInnerLabelTitle: BusterMetricChartConfig['pieInnerLabelTitle'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = ({ pieInnerLabelTitle, onUpdateChartConfig }) => { }> = ({ pieInnerLabelTitle, onUpdateChartConfig }) => {
return ( return (
<LabelAndInput label="Title"> <LabelAndInput label="Title">

View File

@ -1,11 +1,11 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
const options: SelectItem<NonNullable<IBusterMetricChartConfig['pieLabelPosition']>>[] = [ const options: SelectItem<NonNullable<BusterMetricChartConfig['pieLabelPosition']>>[] = [
{ label: 'Outside', value: 'outside' }, { label: 'Outside', value: 'outside' },
{ label: 'Inside', value: 'inside' } { label: 'Inside', value: 'inside' }
]; ];
@ -15,15 +15,15 @@ export const EditPieLabelLocation = React.memo(
pieLabelPosition, pieLabelPosition,
onUpdateChartConfig onUpdateChartConfig
}: { }: {
pieLabelPosition: IBusterMetricChartConfig['pieLabelPosition']; pieLabelPosition: BusterMetricChartConfig['pieLabelPosition'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}) => { }) => {
const selectedLabelPosition = useMemo(() => { const selectedLabelPosition = useMemo(() => {
return options.find((option) => option.value === pieLabelPosition)?.value || 'outside'; return options.find((option) => option.value === pieLabelPosition)?.value || 'outside';
}, [pieLabelPosition]); }, [pieLabelPosition]);
const hideLabel = pieLabelPosition === 'none' || !pieLabelPosition; const hideLabel = pieLabelPosition === 'none' || !pieLabelPosition;
const onChangeSelect = useMemoizedFn((value: IBusterMetricChartConfig['pieLabelPosition']) => { const onChangeSelect = useMemoizedFn((value: BusterMetricChartConfig['pieLabelPosition']) => {
onUpdateChartConfig({ pieLabelPosition: value }); onUpdateChartConfig({ pieLabelPosition: value });
}); });

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { SliderWithInputNumber } from '@/components/ui/slider'; import { SliderWithInputNumber } from '@/components/ui/slider';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
@ -9,8 +9,8 @@ export const EditPieMinimumSlicePercentage = React.memo(
pieMinimumSlicePercentage: initialValue, pieMinimumSlicePercentage: initialValue,
onUpdateChartConfig onUpdateChartConfig
}: { }: {
pieMinimumSlicePercentage: IBusterMetricChartConfig['pieMinimumSlicePercentage']; pieMinimumSlicePercentage: BusterMetricChartConfig['pieMinimumSlicePercentage'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}) => { }) => {
const [pieMinimumSlicePercentage, setIntermediateValue] = useState(initialValue); const [pieMinimumSlicePercentage, setIntermediateValue] = useState(initialValue);

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
@ -8,8 +8,8 @@ export const EditPieShowInnerLabel = React.memo(
pieShowInnerLabel, pieShowInnerLabel,
onUpdateChartConfig onUpdateChartConfig
}: { }: {
pieShowInnerLabel: IBusterMetricChartConfig['pieShowInnerLabel']; pieShowInnerLabel: BusterMetricChartConfig['pieShowInnerLabel'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}) => { }) => {
return ( return (
<LabelAndInput label="Show inner label"> <LabelAndInput label="Show inner label">

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { PieSortBy } from '@/api/asset_interfaces/metric/charts'; import type { PieSortBy } from '@/api/asset_interfaces/metric/charts';
import { Empty, SortAlphaAscending, SortNumAscending } from '@/components/ui/icons'; import { Empty, SortAlphaAscending, SortNumAscending } from '@/components/ui/icons';
import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented';
@ -25,8 +25,8 @@ const options: SegmentedItem<NonNullable<PieSortBy> | 'none'>[] = [
]; ];
export const EditPieSorting: React.FC<{ export const EditPieSorting: React.FC<{
pieSortBy: IBusterMetricChartConfig['pieSortBy']; pieSortBy: BusterMetricChartConfig['pieSortBy'];
onUpdateChartConfig: (v: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (v: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ pieSortBy, onUpdateChartConfig }) => { }> = React.memo(({ pieSortBy, onUpdateChartConfig }) => {
const selectedOption = useMemo(() => { const selectedOption = useMemo(() => {
return ( return (

View File

@ -1,12 +1,12 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts'; import type { IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { EditReplaceMissingData } from '../StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditReplaceMissingData'; import { EditReplaceMissingData } from '../StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditReplaceMissingData';
export const EditReplaceMissingValuesWithGlobal: React.FC<{ export const EditReplaceMissingValuesWithGlobal: React.FC<{
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ columnLabelFormats, onUpdateChartConfig }) => { }> = React.memo(({ columnLabelFormats, onUpdateChartConfig }) => {
const mostPermissiveMissingWith = useMemo(() => { const mostPermissiveMissingWith = useMemo(() => {
return Object.values(columnLabelFormats).some( return Object.values(columnLabelFormats).some(
@ -17,9 +17,9 @@ export const EditReplaceMissingValuesWithGlobal: React.FC<{
}, [columnLabelFormats]); }, [columnLabelFormats]);
const onUpdateColumnLabel = useMemoizedFn((config: Partial<IColumnLabelFormat>) => { const onUpdateColumnLabel = useMemoizedFn((config: Partial<IColumnLabelFormat>) => {
const newColumnLabelFormats: IBusterMetricChartConfig['columnLabelFormats'] = Object.entries( const newColumnLabelFormats: BusterMetricChartConfig['columnLabelFormats'] = Object.entries(
columnLabelFormats columnLabelFormats
).reduce<IBusterMetricChartConfig['columnLabelFormats']>((acc, [key, value]) => { ).reduce<BusterMetricChartConfig['columnLabelFormats']>((acc, [key, value]) => {
acc[key] = { ...value, ...config }; acc[key] = { ...value, ...config };
return acc; return acc;
}, {}); }, {});

View File

@ -1,15 +1,15 @@
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartEncodes, ScatterAxis } from '@/api/asset_interfaces/metric/charts'; import type { ChartEncodes, ScatterAxis } from '@/api/asset_interfaces/metric/charts';
import { Slider } from '@/components/ui/slider'; import { Slider } from '@/components/ui/slider';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
export const EditScatterDotSize: React.FC<{ export const EditScatterDotSize: React.FC<{
scatterDotSize: IBusterMetricChartConfig['scatterDotSize']; scatterDotSize: BusterMetricChartConfig['scatterDotSize'];
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ scatterDotSize, selectedAxis, onUpdateChartConfig }) => { }> = React.memo(({ scatterDotSize, selectedAxis, onUpdateChartConfig }) => {
const hasSize = !isEmpty((selectedAxis as ScatterAxis).size); const hasSize = !isEmpty((selectedAxis as ScatterAxis).size);
const defaultValue = hasSize ? scatterDotSize : scatterDotSize[0]; const defaultValue = hasSize ? scatterDotSize : scatterDotSize[0];

View File

@ -1,7 +1,7 @@
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import type { ColumnMetaData, IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { ColumnMetaData, BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartEncodes, GoalLine } from '@/api/asset_interfaces/metric/charts'; import type { ChartEncodes, GoalLine } from '@/api/asset_interfaces/metric/charts';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { ColorPicker } from '@/components/ui/color-picker'; import { ColorPicker } from '@/components/ui/color-picker';
@ -18,8 +18,8 @@ interface LoopGoalLine extends GoalLine {
} }
export const EditGoalLine: React.FC<{ export const EditGoalLine: React.FC<{
goalLines: IBusterMetricChartConfig['goalLines']; goalLines: BusterMetricChartConfig['goalLines'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
columnMetadata: ColumnMetaData[] | undefined; columnMetadata: ColumnMetaData[] | undefined;
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
}> = React.memo(({ goalLines, onUpdateChartConfig, columnMetadata, selectedAxis }) => { }> = React.memo(({ goalLines, onUpdateChartConfig, columnMetadata, selectedAxis }) => {

View File

@ -1,11 +1,11 @@
import first from 'lodash/first'; import first from 'lodash/first';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
const options: SelectItem<IBusterMetricChartConfig['showLegendHeadline'] | 'false'>[] = [ const options: SelectItem<BusterMetricChartConfig['showLegendHeadline'] | 'false'>[] = [
{ label: 'None', value: 'false' }, { label: 'None', value: 'false' },
{ label: 'Total', value: 'total' }, { label: 'Total', value: 'total' },
{ label: 'Average', value: 'average' }, { label: 'Average', value: 'average' },
@ -21,11 +21,11 @@ const pieOptions: SelectItem<'false' | 'current'>[] = [
]; ];
export const EditShowHeadline: React.FC<{ export const EditShowHeadline: React.FC<{
showLegendHeadline: IBusterMetricChartConfig['showLegendHeadline']; showLegendHeadline: BusterMetricChartConfig['showLegendHeadline'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
}> = React.memo( }> = React.memo(
({ showLegendHeadline, onUpdateChartConfig, lineGroupType, barGroupType, selectedChartType }) => { ({ showLegendHeadline, onUpdateChartConfig, lineGroupType, barGroupType, selectedChartType }) => {
const isStackPercentage = const isStackPercentage =
@ -56,7 +56,7 @@ export const EditShowHeadline: React.FC<{
onUpdateChartConfig({ onUpdateChartConfig({
showLegend: true, showLegend: true,
showLegendHeadline: transformedValue as IBusterMetricChartConfig['showLegendHeadline'] showLegendHeadline: transformedValue as BusterMetricChartConfig['showLegendHeadline']
}); });
}); });

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
@ -14,8 +14,8 @@ export const EditShowLabelPieAsPercentage = React.memo(
pieDisplayLabelAs, pieDisplayLabelAs,
onUpdateChartConfig onUpdateChartConfig
}: { }: {
pieDisplayLabelAs: IBusterMetricChartConfig['pieDisplayLabelAs']; pieDisplayLabelAs: BusterMetricChartConfig['pieDisplayLabelAs'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}) => { }) => {
const selectedValue = useMemo(() => { const selectedValue = useMemo(() => {
return options.find((option) => option.value === pieDisplayLabelAs)?.value || 'number'; return options.find((option) => option.value === pieDisplayLabelAs)?.value || 'number';

View File

@ -1,15 +1,15 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartEncodes, ScatterAxis } from '@/api/asset_interfaces/metric/charts'; import type { ChartEncodes, ScatterAxis } from '@/api/asset_interfaces/metric/charts';
import { useLegendAutoShow } from '@/components/ui/charts/BusterChartLegend'; import { useLegendAutoShow } from '@/components/ui/charts/BusterChartLegend';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
export const EditShowLegend: React.FC<{ export const EditShowLegend: React.FC<{
showLegend: IBusterMetricChartConfig['showLegend']; showLegend: BusterMetricChartConfig['showLegend'];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = React.memo( }> = React.memo(
({ showLegend: showLegendProp, selectedAxis, selectedChartType, onUpdateChartConfig }) => { ({ showLegend: showLegendProp, selectedAxis, selectedChartType, onUpdateChartConfig }) => {
const categoryAxisColumnNames = (selectedAxis as ScatterAxis)?.category; const categoryAxisColumnNames = (selectedAxis as ScatterAxis)?.category;

View File

@ -1,12 +1,12 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../Common'; import { LabelAndInput } from '../Common';
export const EditSmoothLinesGlobal: React.FC<{ export const EditSmoothLinesGlobal: React.FC<{
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ columnSettings, onUpdateChartConfig }) => { }> = React.memo(({ columnSettings, onUpdateChartConfig }) => {
const allSmooth = useMemo(() => { const allSmooth = useMemo(() => {
return Object.values(columnSettings).every((column) => column.lineType === 'smooth'); return Object.values(columnSettings).every((column) => column.lineType === 'smooth');
@ -14,12 +14,13 @@ export const EditSmoothLinesGlobal: React.FC<{
const onChangeAllSmooth = useMemoizedFn((value: boolean) => { const onChangeAllSmooth = useMemoizedFn((value: boolean) => {
onUpdateChartConfig({ onUpdateChartConfig({
columnSettings: Object.keys(columnSettings).reduce< columnSettings: Object.keys(columnSettings).reduce<BusterMetricChartConfig['columnSettings']>(
IBusterMetricChartConfig['columnSettings'] (acc, curr) => {
>((acc, curr) => { acc[curr] = { ...columnSettings[curr], lineType: value ? 'smooth' : 'normal' };
acc[curr] = { ...columnSettings[curr], lineType: value ? 'smooth' : 'normal' }; return acc;
return acc; },
}, {}) {}
)
}); });
}); });

View File

@ -3,7 +3,7 @@ import isEqual from 'lodash/isEqual';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import type { ColumnMetaData } from '@/api/asset_interfaces'; import type { ColumnMetaData } from '@/api/asset_interfaces';
import { DEFAULT_TRENDLINE_CONFIG, type IBusterMetricChartConfig } from '@/api/asset_interfaces'; import { DEFAULT_TRENDLINE_CONFIG, type BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartEncodes, ScatterAxis, Trendline } from '@/api/asset_interfaces/metric/charts'; import type { ChartEncodes, ScatterAxis, Trendline } from '@/api/asset_interfaces/metric/charts';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { JOIN_CHARACTER } from '@/components/ui/charts/commonHelpers'; import { JOIN_CHARACTER } from '@/components/ui/charts/commonHelpers';
@ -30,13 +30,13 @@ export interface LoopTrendline extends Trendline {
} }
export const EditTrendline: React.FC<{ export const EditTrendline: React.FC<{
trendlines: IBusterMetricChartConfig['trendlines']; trendlines: BusterMetricChartConfig['trendlines'];
colors: string[]; colors: string[];
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
columnMetadata: ColumnMetaData[]; columnMetadata: ColumnMetaData[];
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
}> = React.memo( }> = React.memo(
({ ({
trendlines, trendlines,
@ -189,12 +189,12 @@ const EditTrendlineItem: React.FC<{
trend: LoopTrendline; trend: LoopTrendline;
isNewTrend: boolean; isNewTrend: boolean;
columnMetadata: ColumnMetaData[]; columnMetadata: ColumnMetaData[];
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
yAxisEncodes: string[]; yAxisEncodes: string[];
xAxisEncodes: string[]; xAxisEncodes: string[];
categoryEncodes: string[] | null | undefined; categoryEncodes: string[] | null | undefined;
colors: string[]; colors: string[];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
onUpdateExistingTrendline: (trend: LoopTrendline) => void; onUpdateExistingTrendline: (trend: LoopTrendline) => void;
onDeleteTrendline: (id: string) => void; onDeleteTrendline: (id: string) => void;
}> = React.memo( }> = React.memo(
@ -254,8 +254,8 @@ const TrendlineItemContent: React.FC<{
xAxisEncodes: string[]; xAxisEncodes: string[];
colors: string[]; colors: string[];
categoryEncodes: string[] | null | undefined; categoryEncodes: string[] | null | undefined;
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
onUpdateExistingTrendline: (trend: LoopTrendline) => void; onUpdateExistingTrendline: (trend: LoopTrendline) => void;
}> = React.memo( }> = React.memo(
({ ({

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { ColumnMetaData, IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { ColumnMetaData, BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
import { formatLabel } from '@/lib'; import { formatLabel } from '@/lib';
import { LabelAndInput } from '../../Common'; import { LabelAndInput } from '../../Common';
@ -15,7 +15,7 @@ export const TrendlineColumnId = React.memo(
}: { }: {
trend: LoopTrendline; trend: LoopTrendline;
columnMetadata: ColumnMetaData[]; columnMetadata: ColumnMetaData[];
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
onUpdateExistingTrendline: (trend: LoopTrendline) => void; onUpdateExistingTrendline: (trend: LoopTrendline) => void;
yAxisEncodes: string[]; yAxisEncodes: string[];
}) => { }) => {

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartType, Trendline } from '@/api/asset_interfaces/metric/charts'; import type { ChartType, Trendline } from '@/api/asset_interfaces/metric/charts';
import { TriangleWarning } from '@/components/ui/icons'; import { TriangleWarning } from '@/components/ui/icons';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
@ -22,7 +22,7 @@ export const EditTrendlineOption = React.memo(
onUpdateExistingTrendline: (trend: LoopTrendline) => void; onUpdateExistingTrendline: (trend: LoopTrendline) => void;
yAxisEncodes: string[]; yAxisEncodes: string[];
xAxisEncodes: string[]; xAxisEncodes: string[];
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
selectedChartType: ChartType; selectedChartType: ChartType;
}) => { }) => {
const { type } = trend; const { type } = trend;

View File

@ -1,18 +1,18 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { EditAxisScale } from '../StylingAppVisualize/SelectAxis/SelectAxisSettingsContent/EditAxisScale'; import { EditAxisScale } from '../StylingAppVisualize/SelectAxis/SelectAxisSettingsContent/EditAxisScale';
export const EditYAxisScaleGlobal: React.FC<{ export const EditYAxisScaleGlobal: React.FC<{
yAxisScaleType: IBusterMetricChartConfig['yAxisScaleType']; yAxisScaleType: BusterMetricChartConfig['yAxisScaleType'];
y2AxisScaleType: IBusterMetricChartConfig['y2AxisScaleType']; y2AxisScaleType: BusterMetricChartConfig['y2AxisScaleType'];
onUpdateChartConfig: (config: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (config: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ yAxisScaleType, y2AxisScaleType, onUpdateChartConfig }) => { }> = React.memo(({ yAxisScaleType, y2AxisScaleType, onUpdateChartConfig }) => {
const mostPermissiveScale = useMemo(() => { const mostPermissiveScale = useMemo(() => {
return yAxisScaleType === y2AxisScaleType ? yAxisScaleType : 'linear'; return yAxisScaleType === y2AxisScaleType ? yAxisScaleType : 'linear';
}, [yAxisScaleType, y2AxisScaleType]); }, [yAxisScaleType, y2AxisScaleType]);
const onChangeAxisScale = useMemoizedFn((value: IBusterMetricChartConfig['yAxisScaleType']) => { const onChangeAxisScale = useMemoizedFn((value: BusterMetricChartConfig['yAxisScaleType']) => {
onUpdateChartConfig({ onUpdateChartConfig({
yAxisScaleType: value, yAxisScaleType: value,
y2AxisScaleType: value y2AxisScaleType: value

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces/metric'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces/metric';
import { type BarAndLineAxis, ChartType } from '@/api/asset_interfaces/metric/charts'; import { type BarAndLineAxis, ChartType } from '@/api/asset_interfaces/metric/charts';
import { Separator } from '@/components/ui/seperator'; import { Separator } from '@/components/ui/seperator';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
@ -78,16 +78,16 @@ export const StylingAppStyling: React.FC<
const { onUpdateMetricChartConfig } = useUpdateMetricChart(); const { onUpdateMetricChartConfig } = useUpdateMetricChart();
const onUpdateDataLabel = useMemoizedFn((v: boolean) => { const onUpdateDataLabel = useMemoizedFn((v: boolean) => {
const newColumnSettings: IBusterMetricChartConfig['columnSettings'] = Object.keys( const newColumnSettings: BusterMetricChartConfig['columnSettings'] = Object.keys(
columnSettings columnSettings
).reduce<IBusterMetricChartConfig['columnSettings']>((acc, curr) => { ).reduce<BusterMetricChartConfig['columnSettings']>((acc, curr) => {
acc[curr] = { ...columnSettings[curr], showDataLabels: v }; acc[curr] = { ...columnSettings[curr], showDataLabels: v };
return acc; return acc;
}, {}); }, {});
onUpdateChartConfig({ columnSettings: newColumnSettings }); onUpdateChartConfig({ columnSettings: newColumnSettings });
}); });
const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<IBusterMetricChartConfig>) => { const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<BusterMetricChartConfig>) => {
onUpdateMetricChartConfig({ chartConfig }); onUpdateMetricChartConfig({ chartConfig });
}); });
@ -185,9 +185,9 @@ export const StylingAppStyling: React.FC<
const GlobalSettings: React.FC< const GlobalSettings: React.FC<
{ {
className: string; className: string;
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
yAxisShowAxisTitle: IBusterMetricChartConfig['yAxisShowAxisTitle']; yAxisShowAxisTitle: BusterMetricChartConfig['yAxisShowAxisTitle'];
yAxisShowAxisLabel: IBusterMetricChartConfig['yAxisShowAxisLabel']; yAxisShowAxisLabel: BusterMetricChartConfig['yAxisShowAxisLabel'];
} & Parameters<typeof EditShowLegend>[0] & } & Parameters<typeof EditShowLegend>[0] &
Parameters<typeof EditGridLines>[0] & Parameters<typeof EditGridLines>[0] &
Omit<Parameters<typeof EditHideYAxis>[0], 'hideYAxis'> & Omit<Parameters<typeof EditHideYAxis>[0], 'hideYAxis'> &
@ -294,9 +294,9 @@ const GlobalSettings: React.FC<
const ChartSpecificSettings: React.FC< const ChartSpecificSettings: React.FC<
{ {
className: string; className: string;
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
} & Parameters<typeof EditBarRoundnessGlobal>[0] & } & Parameters<typeof EditBarRoundnessGlobal>[0] &
Parameters<typeof EditBarSorting>[0] & Parameters<typeof EditBarSorting>[0] &
Parameters<typeof EditPieSorting>[0] & Parameters<typeof EditPieSorting>[0] &
@ -567,7 +567,7 @@ const EtcSettings: React.FC<
const PieSettings: React.FC< const PieSettings: React.FC<
{ {
className: string; className: string;
pieDonutWidth: IBusterMetricChartConfig['pieDonutWidth']; pieDonutWidth: BusterMetricChartConfig['pieDonutWidth'];
} & Parameters<typeof EditPieShowInnerLabel>[0] & } & Parameters<typeof EditPieShowInnerLabel>[0] &
Parameters<typeof EditPieInnerLabel>[0] Parameters<typeof EditPieInnerLabel>[0]
> = React.memo( > = React.memo(

View File

@ -1,10 +1,10 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { ChartType } from '@/api/asset_interfaces/metric/charts'; import { ChartType } from '@/api/asset_interfaces/metric/charts';
import { Text } from '@/components/ui/typography'; import { Text } from '@/components/ui/typography';
export const StylingAppStylingNotSupported = React.memo( export const StylingAppStylingNotSupported = React.memo(
({ selectedChartType }: { selectedChartType: IBusterMetricChartConfig['selectedChartType'] }) => { ({ selectedChartType }: { selectedChartType: BusterMetricChartConfig['selectedChartType'] }) => {
const title = useMemo(() => { const title = useMemo(() => {
if (selectedChartType === 'table') { if (selectedChartType === 'table') {
return 'Styling for tables charts is coming soon'; return 'Styling for tables charts is coming soon';

View File

@ -1,6 +1,6 @@
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { import type {
CategoryAxisStyleConfig, CategoryAxisStyleConfig,
ChartEncodes, ChartEncodes,
@ -46,7 +46,7 @@ export const SelectAxis: React.FC<
return Object.assign(acc, { [axis]: zone.items }); return Object.assign(acc, { [axis]: zone.items });
}, {} as ChartEncodes); }, {} as ChartEncodes);
const newChartConfig: Partial<IBusterMetricChartConfig> = { const newChartConfig: Partial<BusterMetricChartConfig> = {
[selectedAxisToEdit]: newChartEncodes [selectedAxisToEdit]: newChartEncodes
}; };

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { ChartType, type ColumnSettings } from '@/api/asset_interfaces/metric/charts'; import { ChartType, type ColumnSettings } from '@/api/asset_interfaces/metric/charts';
import { ChartBarAxisX, ChartLine, ChartScatter } from '@/components/ui/icons'; import { ChartBarAxisX, ChartLine, ChartScatter } from '@/components/ui/icons';
import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented';
@ -40,7 +40,7 @@ const options = [
export const EditDisplayAs: React.FC<{ export const EditDisplayAs: React.FC<{
columnVisualization: Required<ColumnSettings>['columnVisualization']; columnVisualization: Required<ColumnSettings>['columnVisualization'];
onUpdateColumnSettingConfig: (columnSettings: Partial<ColumnSettings>) => void; onUpdateColumnSettingConfig: (columnSettings: Partial<ColumnSettings>) => void;
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
}> = React.memo(({ columnVisualization, onUpdateColumnSettingConfig, selectedChartType }) => { }> = React.memo(({ columnVisualization, onUpdateColumnSettingConfig, selectedChartType }) => {
const selectedOption = useMemo(() => { const selectedOption = useMemo(() => {
if (selectedChartType === 'bar') return 'bar'; if (selectedChartType === 'bar') return 'bar';

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { type ChartEncodes, type ColumnSettings } from '@/api/asset_interfaces/metric/charts'; import { type ChartEncodes, type ColumnSettings } from '@/api/asset_interfaces/metric/charts';
import type { IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts/columnLabelInterfaces'; import type { IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts/columnLabelInterfaces';
import { useGetCurrencies } from '@/api/buster_rest/currency'; import { useGetCurrencies } from '@/api/buster_rest/currency';
@ -28,14 +28,14 @@ import { EditSuffix } from './EditSuffix';
import { EditTitle } from './EditTitle'; import { EditTitle } from './EditTitle';
export const SelectAxisDropdownContent: React.FC<{ export const SelectAxisDropdownContent: React.FC<{
columnSetting: IBusterMetricChartConfig['columnSettings'][string]; columnSetting: BusterMetricChartConfig['columnSettings'][string];
columnLabelFormat: IColumnLabelFormat; columnLabelFormat: IColumnLabelFormat;
selectedAxis: ChartEncodes | null; selectedAxis: ChartEncodes | null;
id: string; id: string;
className?: string; className?: string;
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
zoneId: SelectAxisContainerId; zoneId: SelectAxisContainerId;
hideTitle?: boolean; hideTitle?: boolean;
classNames?: { classNames?: {
@ -115,13 +115,13 @@ const ColumnSettingComponent: React.FC<{
formattedTitle: string; formattedTitle: string;
onUpdateColumnConfig: (columnLabelFormat: Partial<IColumnLabelFormat>) => void; onUpdateColumnConfig: (columnLabelFormat: Partial<IColumnLabelFormat>) => void;
onUpdateColumnSettingConfig: (columnSetting: Partial<ColumnSettings>) => void; onUpdateColumnSettingConfig: (columnSetting: Partial<ColumnSettings>) => void;
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
selectedAxis: ChartEncodes | null; selectedAxis: ChartEncodes | null;
columnSetting: IBusterMetricChartConfig['columnSettings'][string]; columnSetting: BusterMetricChartConfig['columnSettings'][string];
columnLabelFormat: IColumnLabelFormat; columnLabelFormat: IColumnLabelFormat;
zoneId: SelectAxisContainerId; zoneId: SelectAxisContainerId;
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
rowCount: number; rowCount: number;
}> = ({ }> = ({
formattedTitle, formattedTitle,
@ -274,7 +274,7 @@ const LabelSettings: React.FC<{
onUpdateColumnConfig: (columnLabelFormat: Partial<IColumnLabelFormat>) => void; onUpdateColumnConfig: (columnLabelFormat: Partial<IColumnLabelFormat>) => void;
id: string; id: string;
zoneId: SelectAxisContainerId; zoneId: SelectAxisContainerId;
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
}> = ({ }> = ({
columnLabelFormat, columnLabelFormat,
onUpdateColumnConfig, onUpdateColumnConfig,

View File

@ -1,13 +1,13 @@
import type { Meta, StoryObj } from '@storybook/react'; import type { Meta, StoryObj } from '@storybook/react';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { type IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { Button } from '@/components/ui/buttons/Button'; import { Button } from '@/components/ui/buttons/Button';
import { SelectAxisContainerId } from './config'; import { SelectAxisContainerId } from './config';
import { import {
SelectAxisColumnPopover, SelectAxisColumnPopover,
type SelectAxisColumnPopoverProps type SelectAxisColumnPopoverProps
} from './SelectAxisColumnPopover'; } from './SelectAxisColumnPopover';
import type { ColumnLabelFormat } from '@buster/server-shared/metrics';
const meta: Meta<typeof SelectAxisColumnPopover> = { const meta: Meta<typeof SelectAxisColumnPopover> = {
title: 'Controllers/EditMetricController/SelectAxisColumnPopover', title: 'Controllers/EditMetricController/SelectAxisColumnPopover',
@ -60,7 +60,7 @@ const mockProps: SelectAxisColumnPopoverProps = {
replaceMissingDataWith: null, replaceMissingDataWith: null,
makeLabelHumanReadable: true, makeLabelHumanReadable: true,
compactNumbers: false compactNumbers: false
} satisfies IColumnLabelFormat, } satisfies ColumnLabelFormat,
columnSetting: { columnSetting: {
showDataLabels: false, showDataLabels: false,
showDataLabelsAsPercentage: false, showDataLabelsAsPercentage: false,
@ -70,7 +70,7 @@ const mockProps: SelectAxisColumnPopoverProps = {
lineType: 'normal' as const, lineType: 'normal' as const,
lineSymbolSize: 0, lineSymbolSize: 0,
barRoundness: 8 barRoundness: 8
} satisfies IBusterMetricChartConfig['columnSettings'][string], } satisfies BusterMetricChartConfig['columnSettings'][string],
id: 'test-id', id: 'test-id',
selectedChartType: 'bar', selectedChartType: 'bar',
barGroupType: 'group', barGroupType: 'group',

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartEncodes, IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts'; import type { ChartEncodes, IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { Popover } from '@/components/ui/popover/Popover'; import { Popover } from '@/components/ui/popover/Popover';
import type { SelectAxisContainerId } from './config'; import type { SelectAxisContainerId } from './config';
@ -7,12 +7,12 @@ import { SelectAxisDropdownContent } from './SelectAxisColumnContent';
export interface SelectAxisColumnPopoverProps { export interface SelectAxisColumnPopoverProps {
columnLabelFormat: IColumnLabelFormat; columnLabelFormat: IColumnLabelFormat;
columnSetting: IBusterMetricChartConfig['columnSettings'][string]; columnSetting: BusterMetricChartConfig['columnSettings'][string];
children: React.ReactNode; children: React.ReactNode;
id: string; id: string;
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
zoneId: SelectAxisContainerId; zoneId: SelectAxisContainerId;
selectedAxis: ChartEncodes | null; selectedAxis: ChartEncodes | null;
rowCount: number; rowCount: number;

View File

@ -1,7 +1,7 @@
import type { DraggableAttributes } from '@dnd-kit/core'; import type { DraggableAttributes } from '@dnd-kit/core';
import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities'; import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ChartEncodes, IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts'; import type { ChartEncodes, IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { DotsVertical } from '@/components/ui/icons'; import { DotsVertical } from '@/components/ui/icons';
@ -59,10 +59,10 @@ export const SelectAxisItemAvailableContainer = React.memo(
const ThreeDotMenu: React.FC<{ const ThreeDotMenu: React.FC<{
isDragging?: boolean; isDragging?: boolean;
columnLabelFormat: IColumnLabelFormat; columnLabelFormat: IColumnLabelFormat;
columnSetting: IBusterMetricChartConfig['columnSettings'][string]; columnSetting: BusterMetricChartConfig['columnSettings'][string];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
zoneId: SelectAxisContainerId; zoneId: SelectAxisContainerId;
selectedAxis: ChartEncodes | null; selectedAxis: ChartEncodes | null;
id: string; id: string;

View File

@ -1,7 +1,6 @@
import type { DraggableAttributes } from '@dnd-kit/core'; import type { DraggableAttributes } from '@dnd-kit/core';
import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities'; import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { ChartEncodes, IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { ErrorBoundary } from '@/components/ui/error'; import { ErrorBoundary } from '@/components/ui/error';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
@ -10,6 +9,7 @@ import { chartTypeToAxis, type SelectAxisContainerId, zoneIdToAxis } from './con
import { SelectAxisDropdownContent } from './SelectAxisColumnContent'; import { SelectAxisDropdownContent } from './SelectAxisColumnContent';
import { SelectAxisItemLabel } from './SelectAxisItemLabel'; import { SelectAxisItemLabel } from './SelectAxisItemLabel';
import { useSelectAxisContextSelector } from './useSelectAxisContext'; import { useSelectAxisContextSelector } from './useSelectAxisContext';
import type { ChartEncodes, ColumnLabelFormat } from '@buster/server-shared/metrics';
interface SelectAxisItemContainerProps { interface SelectAxisItemContainerProps {
id: string; id: string;
@ -25,7 +25,7 @@ interface SelectAxisItemContainerProps {
export const SelectAxisItemContainer = React.memo( export const SelectAxisItemContainer = React.memo(
React.forwardRef<HTMLDivElement, SelectAxisItemContainerProps>( React.forwardRef<HTMLDivElement, SelectAxisItemContainerProps>(
({ id, zoneId, isPlaceholder, ...draggingProps }, ref) => { ({ id, zoneId, isPlaceholder, ...draggingProps }, ref) => {
const columnLabelFormat: undefined | IColumnLabelFormat = useSelectAxisContextSelector( const columnLabelFormat: undefined | ColumnLabelFormat = useSelectAxisContextSelector(
(x) => x.columnLabelFormats[id] (x) => x.columnLabelFormats[id]
); );
const selectedAxis = useSelectAxisContextSelector((x) => x.selectedAxis); const selectedAxis = useSelectAxisContextSelector((x) => x.selectedAxis);

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { useSelectAxisContextSelector } from '../useSelectAxisContext'; import { useSelectAxisContextSelector } from '../useSelectAxisContext';
@ -18,7 +18,7 @@ export const CategoryAxisSettingContent: React.FC = React.memo(() => {
contextOnUpdateMetricChartConfig({ chartConfig: { categoryAxisTitle: value } }); contextOnUpdateMetricChartConfig({ chartConfig: { categoryAxisTitle: value } });
}); });
const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<IBusterMetricChartConfig>) => { const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<BusterMetricChartConfig>) => {
contextOnUpdateMetricChartConfig({ chartConfig }); contextOnUpdateMetricChartConfig({ chartConfig });
}); });

View File

@ -1,10 +1,10 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented, type SegmentedItem } from '@/components/ui/segmented';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../../../Common/LabelAndInput'; import { LabelAndInput } from '../../../Common/LabelAndInput';
const options: SegmentedItem<IBusterMetricChartConfig['xAxisLabelRotation']>[] = [ const options: SegmentedItem<BusterMetricChartConfig['xAxisLabelRotation']>[] = [
{ label: 'Auto', value: 'auto' }, { label: 'Auto', value: 'auto' },
{ label: '0°', value: 0 }, { label: '0°', value: 0 },
{ label: '45°', value: 45 }, { label: '45°', value: 45 },
@ -12,17 +12,17 @@ const options: SegmentedItem<IBusterMetricChartConfig['xAxisLabelRotation']>[] =
]; ];
export const EditAxisLabelRotation: React.FC<{ export const EditAxisLabelRotation: React.FC<{
xAxisLabelRotation: IBusterMetricChartConfig['xAxisLabelRotation']; xAxisLabelRotation: BusterMetricChartConfig['xAxisLabelRotation'];
onChangeLabelRotation: (value: IBusterMetricChartConfig['xAxisLabelRotation']) => void; onChangeLabelRotation: (value: BusterMetricChartConfig['xAxisLabelRotation']) => void;
}> = React.memo(({ xAxisLabelRotation, onChangeLabelRotation }) => { }> = React.memo(({ xAxisLabelRotation, onChangeLabelRotation }) => {
const selectedOption: IBusterMetricChartConfig['xAxisLabelRotation'] = useMemo(() => { const selectedOption: BusterMetricChartConfig['xAxisLabelRotation'] = useMemo(() => {
return ( return (
options.find((option) => option.value === xAxisLabelRotation)?.value ?? options[0]?.value options.find((option) => option.value === xAxisLabelRotation)?.value ?? options[0]?.value
); );
}, [xAxisLabelRotation]); }, [xAxisLabelRotation]);
const onChange = useMemoizedFn((value: SegmentedItem<string>) => { const onChange = useMemoizedFn((value: SegmentedItem<string>) => {
onChangeLabelRotation(value.value as IBusterMetricChartConfig['xAxisLabelRotation']); onChangeLabelRotation(value.value as BusterMetricChartConfig['xAxisLabelRotation']);
}); });
return ( return (

View File

@ -1,18 +1,16 @@
import React from 'react'; import React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Select } from '@/components/ui/select'; import { Select } from '@/components/ui/select';
import { LabelAndInput } from '../../../Common/LabelAndInput'; import { LabelAndInput } from '../../../Common/LabelAndInput';
const options: { label: string; value: IBusterMetricChartConfig['yAxisScaleType'] }[] = [ const options: { label: string; value: BusterMetricChartConfig['yAxisScaleType'] }[] = [
{ label: 'Linear', value: 'linear' }, { label: 'Linear', value: 'linear' },
{ label: 'Logarithmic', value: 'log' } { label: 'Logarithmic', value: 'log' }
]; ];
export const EditAxisScale: React.FC<{ export const EditAxisScale: React.FC<{
scaleType: scaleType: BusterMetricChartConfig['yAxisScaleType'] | BusterMetricChartConfig['y2AxisScaleType'];
| IBusterMetricChartConfig['yAxisScaleType'] onChangeAxisScale: (value: BusterMetricChartConfig['yAxisScaleType']) => void;
| IBusterMetricChartConfig['y2AxisScaleType'];
onChangeAxisScale: (value: IBusterMetricChartConfig['yAxisScaleType']) => void;
}> = React.memo(({ scaleType, onChangeAxisScale }) => { }> = React.memo(({ scaleType, onChangeAxisScale }) => {
return ( return (
<LabelAndInput label="Scale"> <LabelAndInput label="Scale">

View File

@ -1,28 +1,28 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../../../Common/LabelAndInput'; import { LabelAndInput } from '../../../Common/LabelAndInput';
const barGroupingOptions: SelectItem<NonNullable<IBusterMetricChartConfig['barGroupType']>>[] = [ const barGroupingOptions: SelectItem<NonNullable<BusterMetricChartConfig['barGroupType']>>[] = [
{ label: 'Grouped', value: 'group' }, { label: 'Grouped', value: 'group' },
{ label: 'Stacked', value: 'stack' } { label: 'Stacked', value: 'stack' }
]; ];
const lineGroupingOptions: SelectItem< const lineGroupingOptions: SelectItem<
NonNullable<IBusterMetricChartConfig['lineGroupType']> | 'default' NonNullable<BusterMetricChartConfig['lineGroupType']> | 'default'
>[] = [ >[] = [
{ label: 'Default', value: 'default' }, { label: 'Default', value: 'default' },
{ label: 'Stacked', value: 'stack' } { label: 'Stacked', value: 'stack' }
]; ];
export const EditGrouping: React.FC<{ export const EditGrouping: React.FC<{
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
onUpdateChartConfig: (value: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (value: Partial<BusterMetricChartConfig>) => void;
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
barShowTotalAtTop: IBusterMetricChartConfig['barShowTotalAtTop']; barShowTotalAtTop: BusterMetricChartConfig['barShowTotalAtTop'];
}> = React.memo( }> = React.memo(
({ selectedChartType, onUpdateChartConfig, lineGroupType, barGroupType, barShowTotalAtTop }) => { ({ selectedChartType, onUpdateChartConfig, lineGroupType, barGroupType, barShowTotalAtTop }) => {
const isBarChart = selectedChartType === 'bar'; const isBarChart = selectedChartType === 'bar';
@ -30,9 +30,7 @@ export const EditGrouping: React.FC<{
isBarChart ? barGroupType === 'stack' : lineGroupType === 'stack' isBarChart ? barGroupType === 'stack' : lineGroupType === 'stack'
); );
const [value, setValue] = useState< const [value, setValue] = useState<
| IBusterMetricChartConfig['lineGroupType'] BusterMetricChartConfig['lineGroupType'] | 'default' | BusterMetricChartConfig['barGroupType']
| 'default'
| IBusterMetricChartConfig['barGroupType']
>(isBarChart ? barGroupType : lineGroupType); >(isBarChart ? barGroupType : lineGroupType);
const showTotal = useMemo(() => { const showTotal = useMemo(() => {
@ -62,21 +60,21 @@ export const EditGrouping: React.FC<{
const onChangeGroupType = useMemoizedFn( const onChangeGroupType = useMemoizedFn(
( (
value: IBusterMetricChartConfig['lineGroupType'] | IBusterMetricChartConfig['barGroupType'] value: BusterMetricChartConfig['lineGroupType'] | BusterMetricChartConfig['barGroupType']
) => { ) => {
if (selectedChartType === 'bar') { if (selectedChartType === 'bar') {
const barGroupType = value as IBusterMetricChartConfig['barGroupType']; const barGroupType = value as BusterMetricChartConfig['barGroupType'];
onUpdateChartConfig({ barGroupType }); onUpdateChartConfig({ barGroupType });
} else { } else {
const lineGroupType = value as IBusterMetricChartConfig['lineGroupType']; const lineGroupType = value as BusterMetricChartConfig['lineGroupType'];
onUpdateChartConfig({ lineGroupType }); onUpdateChartConfig({ lineGroupType });
} }
} }
); );
const onChangeGrouping = (value: string) => { const onChangeGrouping = (value: string) => {
setValue(value as IBusterMetricChartConfig['barGroupType']); setValue(value as BusterMetricChartConfig['barGroupType']);
onChangeGroupType(value as IBusterMetricChartConfig['barGroupType']); onChangeGroupType(value as BusterMetricChartConfig['barGroupType']);
}; };
return ( return (

View File

@ -1,14 +1,12 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Input } from '@/components/ui/inputs'; import { Input } from '@/components/ui/inputs';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../../../Common/LabelAndInput'; import { LabelAndInput } from '../../../Common/LabelAndInput';
export const EditShowAxisTitle: React.FC<{ export const EditShowAxisTitle: React.FC<{
axisTitle: axisTitle: BusterMetricChartConfig['xAxisAxisTitle'] | BusterMetricChartConfig['yAxisAxisTitle'];
| IBusterMetricChartConfig['xAxisAxisTitle']
| IBusterMetricChartConfig['yAxisAxisTitle'];
showAxisTitle: boolean; showAxisTitle: boolean;
formattedColumnTitle: string; formattedColumnTitle: string;
onChangeAxisTitle: (value: string | null) => void; onChangeAxisTitle: (value: string | null) => void;
@ -64,9 +62,9 @@ const EditToggleAxisTitle: React.FC<{
export const EditAxisTitle: React.FC<{ export const EditAxisTitle: React.FC<{
label?: string; label?: string;
axisTitle: axisTitle:
| IBusterMetricChartConfig['xAxisAxisTitle'] | BusterMetricChartConfig['xAxisAxisTitle']
| IBusterMetricChartConfig['yAxisAxisTitle'] | BusterMetricChartConfig['yAxisAxisTitle']
| IBusterMetricChartConfig['categoryAxisTitle']; | BusterMetricChartConfig['categoryAxisTitle'];
onChangeTitle: (v: string | null) => void; onChangeTitle: (v: string | null) => void;
formattedColumnTitle: string; formattedColumnTitle: string;
}> = ({ axisTitle, onChangeTitle, formattedColumnTitle, label = 'Axis title' }) => { }> = ({ axisTitle, onChangeTitle, formattedColumnTitle, label = 'Axis title' }) => {

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ColumnLabelFormat } from '@/api/asset_interfaces/metric/charts'; import type { ColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { AXIS_TITLE_SEPARATOR } from '@/components/ui/charts/commonHelpers/axisHelper'; import { AXIS_TITLE_SEPARATOR } from '@/components/ui/charts/commonHelpers/axisHelper';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
@ -60,7 +60,7 @@ export const XAxisSettingContent: React.FC = React.memo(() => {
}); });
const onChangeLabelRotation = useMemoizedFn( const onChangeLabelRotation = useMemoizedFn(
(xAxisLabelRotation: IBusterMetricChartConfig['xAxisLabelRotation']) => { (xAxisLabelRotation: BusterMetricChartConfig['xAxisLabelRotation']) => {
onUpdateMetricChartConfig({ onUpdateMetricChartConfig({
chartConfig: { chartConfig: {
xAxisLabelRotation xAxisLabelRotation

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ColumnLabelFormat, ComboChartAxis } from '@/api/asset_interfaces/metric/charts'; import type { ColumnLabelFormat, ComboChartAxis } from '@/api/asset_interfaces/metric/charts';
import { AXIS_TITLE_SEPARATOR } from '@/components/ui/charts/commonHelpers/axisHelper'; import { AXIS_TITLE_SEPARATOR } from '@/components/ui/charts/commonHelpers/axisHelper';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
@ -52,7 +52,7 @@ export const Y2AxisSettingContent: React.FC = React.memo(() => {
}); });
const onChangeAxisScale = useMemoizedFn( const onChangeAxisScale = useMemoizedFn(
(y2AxisScaleType: IBusterMetricChartConfig['y2AxisScaleType']) => { (y2AxisScaleType: BusterMetricChartConfig['y2AxisScaleType']) => {
onUpdateMetricChartConfig({ onUpdateMetricChartConfig({
chartConfig: { chartConfig: {
y2AxisScaleType y2AxisScaleType

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ColumnLabelFormat } from '@/api/asset_interfaces/metric/charts'; import type { ColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import { AXIS_TITLE_SEPARATOR } from '@/components/ui/charts/commonHelpers/axisHelper'; import { AXIS_TITLE_SEPARATOR } from '@/components/ui/charts/commonHelpers/axisHelper';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
@ -52,7 +52,7 @@ export const YAxisSettingContent: React.FC = React.memo(() => {
}); });
const onChangeAxisScale = useMemoizedFn( const onChangeAxisScale = useMemoizedFn(
(yAxisScaleType: IBusterMetricChartConfig['yAxisScaleType']) => { (yAxisScaleType: BusterMetricChartConfig['yAxisScaleType']) => {
onUpdateMetricChartConfig({ onUpdateMetricChartConfig({
chartConfig: { chartConfig: {
yAxisScaleType yAxisScaleType

View File

@ -1,5 +1,5 @@
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { ChartType } from '@/api/asset_interfaces/metric/charts'; import { ChartType } from '@/api/asset_interfaces/metric/charts';
import { SelectAxisContainerId } from './config'; import { SelectAxisContainerId } from './config';
import type { DropZone } from './SelectAxisDragContainer/interfaces'; import type { DropZone } from './SelectAxisDragContainer/interfaces';
@ -60,11 +60,11 @@ const makeY2AxisDropZone = (y2Items: string[] | null | undefined): DropZone =>
makeDropZone(SelectAxisContainerId.Y2Axis, y2Items ?? EMPTY_ARRAY); makeDropZone(SelectAxisContainerId.Y2Axis, y2Items ?? EMPTY_ARRAY);
export const chartTypeToDropZones: Record< export const chartTypeToDropZones: Record<
IBusterMetricChartConfig['selectedChartType'], BusterMetricChartConfig['selectedChartType'],
(selectedAxis: Parameters<typeof getChartTypeDropZones>[0]['selectedAxis']) => DropZone[] (selectedAxis: Parameters<typeof getChartTypeDropZones>[0]['selectedAxis']) => DropZone[]
> = { > = {
['bar']: (selectedAxis) => { ['bar']: (selectedAxis) => {
const _selectedAxis = selectedAxis as IBusterMetricChartConfig['barAndLineAxis']; const _selectedAxis = selectedAxis as BusterMetricChartConfig['barAndLineAxis'];
return [ return [
makeXAxisDropZone(_selectedAxis.x), makeXAxisDropZone(_selectedAxis.x),
makeYAxisDropZone(_selectedAxis.y), makeYAxisDropZone(_selectedAxis.y),
@ -73,7 +73,7 @@ export const chartTypeToDropZones: Record<
]; ];
}, },
['line']: (selectedAxis) => { ['line']: (selectedAxis) => {
const _selectedAxis = selectedAxis as IBusterMetricChartConfig['barAndLineAxis']; const _selectedAxis = selectedAxis as BusterMetricChartConfig['barAndLineAxis'];
return [ return [
makeXAxisDropZone(_selectedAxis.x), makeXAxisDropZone(_selectedAxis.x),
makeYAxisDropZone(_selectedAxis.y), makeYAxisDropZone(_selectedAxis.y),
@ -82,7 +82,7 @@ export const chartTypeToDropZones: Record<
]; ];
}, },
['scatter']: (selectedAxis) => { ['scatter']: (selectedAxis) => {
const _selectedAxis = selectedAxis as IBusterMetricChartConfig['scatterAxis']; const _selectedAxis = selectedAxis as BusterMetricChartConfig['scatterAxis'];
return [ return [
makeXAxisDropZone(_selectedAxis.x), makeXAxisDropZone(_selectedAxis.x),
makeYAxisDropZone(_selectedAxis.y), makeYAxisDropZone(_selectedAxis.y),
@ -92,7 +92,7 @@ export const chartTypeToDropZones: Record<
]; ];
}, },
['pie']: (selectedAxis) => { ['pie']: (selectedAxis) => {
const _selectedAxis = selectedAxis as IBusterMetricChartConfig['pieChartAxis']; const _selectedAxis = selectedAxis as BusterMetricChartConfig['pieChartAxis'];
return [ return [
makeXAxisDropZone(_selectedAxis.x), makeXAxisDropZone(_selectedAxis.x),
makeYAxisDropZone(_selectedAxis.y), makeYAxisDropZone(_selectedAxis.y),
@ -100,7 +100,7 @@ export const chartTypeToDropZones: Record<
]; ];
}, },
['combo']: (selectedAxis) => { ['combo']: (selectedAxis) => {
const _selectedAxis = selectedAxis as IBusterMetricChartConfig['comboChartAxis']; const _selectedAxis = selectedAxis as BusterMetricChartConfig['comboChartAxis'];
return [ return [
makeXAxisDropZone(_selectedAxis.x), makeXAxisDropZone(_selectedAxis.x),
makeYComboAxisDropZone(_selectedAxis.y), makeYComboAxisDropZone(_selectedAxis.y),
@ -122,12 +122,12 @@ export const getChartTypeDropZones = ({
chartType, chartType,
selectedAxis selectedAxis
}: { }: {
chartType: IBusterMetricChartConfig['selectedChartType']; chartType: BusterMetricChartConfig['selectedChartType'];
selectedAxis: selectedAxis:
| IBusterMetricChartConfig['comboChartAxis'] | BusterMetricChartConfig['comboChartAxis']
| IBusterMetricChartConfig['pieChartAxis'] | BusterMetricChartConfig['pieChartAxis']
| IBusterMetricChartConfig['scatterAxis'] | BusterMetricChartConfig['scatterAxis']
| IBusterMetricChartConfig['barAndLineAxis']; | BusterMetricChartConfig['barAndLineAxis'];
}): DropZone[] => { }): DropZone[] => {
return chartTypeToDropZones[chartType](selectedAxis); return chartTypeToDropZones[chartType](selectedAxis);
}; };

View File

@ -1,7 +1,7 @@
import type React from 'react'; import type React from 'react';
import type { PropsWithChildren } from 'react'; import type { PropsWithChildren } from 'react';
import { createContext, useContextSelector } from 'use-context-selector'; import { createContext, useContextSelector } from 'use-context-selector';
import type { ColumnMetaData, IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { ColumnMetaData, BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { import type {
CategoryAxisStyleConfig, CategoryAxisStyleConfig,
ChartEncodes, ChartEncodes,
@ -16,19 +16,19 @@ export interface ISelectAxisContext
Required<Omit<XAxisConfig, 'xAxisTimeInterval'>>, Required<Omit<XAxisConfig, 'xAxisTimeInterval'>>,
Required<CategoryAxisStyleConfig> { Required<CategoryAxisStyleConfig> {
selectedAxis: ChartEncodes | null; selectedAxis: ChartEncodes | null;
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
columnMetadata: ColumnMetaData[]; columnMetadata: ColumnMetaData[];
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
selectedChartType: IBusterMetricChartConfig['selectedChartType']; selectedChartType: BusterMetricChartConfig['selectedChartType'];
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
showLegend: IBusterMetricChartConfig['showLegend']; showLegend: BusterMetricChartConfig['showLegend'];
showLegendHeadline: IBusterMetricChartConfig['showLegendHeadline']; showLegendHeadline: BusterMetricChartConfig['showLegendHeadline'];
gridLines: IBusterMetricChartConfig['gridLines']; gridLines: BusterMetricChartConfig['gridLines'];
goalLines: IBusterMetricChartConfig['goalLines']; goalLines: BusterMetricChartConfig['goalLines'];
trendlines: IBusterMetricChartConfig['trendlines']; trendlines: BusterMetricChartConfig['trendlines'];
barShowTotalAtTop: IBusterMetricChartConfig['barShowTotalAtTop']; barShowTotalAtTop: BusterMetricChartConfig['barShowTotalAtTop'];
disableTooltip: IBusterMetricChartConfig['disableTooltip']; disableTooltip: BusterMetricChartConfig['disableTooltip'];
rowCount: number; rowCount: number;
} }

View File

@ -1,5 +1,5 @@
import type React from 'react'; import type React from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { import {
type CategoryAxisStyleConfig, type CategoryAxisStyleConfig,
type ChartEncodes, type ChartEncodes,
@ -17,11 +17,11 @@ import { StylingMetric } from './StylingMetric';
export const StylingAppVisualize: React.FC< export const StylingAppVisualize: React.FC<
{ {
barLayout: IBusterMetricChartConfig['barLayout']; barLayout: BusterMetricChartConfig['barLayout'];
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
className?: string; className?: string;
colors: string[]; colors: string[];
disableTooltip: IBusterMetricChartConfig['disableTooltip']; disableTooltip: BusterMetricChartConfig['disableTooltip'];
} & Required<YAxisConfig> & } & Required<YAxisConfig> &
Required<CategoryAxisStyleConfig> & Required<CategoryAxisStyleConfig> &
Required<Y2AxisConfig> & Required<Y2AxisConfig> &

View File

@ -1,16 +1,15 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Input } from '@/components/ui/inputs'; import { Input } from '@/components/ui/inputs';
import { LabelAndInput } from '../../Common'; import { LabelAndInput } from '../../Common';
export const EditHeaderTitle: React.FC<{ export const EditHeaderTitle: React.FC<{
value: string | undefined; value: string | undefined;
type: 'header' | 'subHeader'; type: 'header' | 'subHeader';
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ value, onUpdateChartConfig, type }) => { }> = React.memo(({ value, onUpdateChartConfig, type }) => {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const key: keyof IBusterMetricChartConfig = const key: keyof BusterMetricChartConfig = type === 'header' ? 'metricHeader' : 'metricSubHeader';
type === 'header' ? 'metricHeader' : 'metricSubHeader';
const title = type === 'header' ? 'Header' : 'Sub-header'; const title = type === 'header' ? 'Header' : 'Sub-header';
const placeholder = type === 'header' ? 'Enter header' : 'Enter sub-header'; const placeholder = type === 'header' ? 'Enter header' : 'Enter sub-header';

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { DEFAULT_COLUMN_SETTINGS } from '@/api/asset_interfaces'; import { DEFAULT_COLUMN_SETTINGS } from '@/api/asset_interfaces';
import { ChartType, type DerivedMetricTitle } from '@/api/asset_interfaces/metric/charts'; import { ChartType, type DerivedMetricTitle } from '@/api/asset_interfaces/metric/charts';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
@ -15,15 +15,15 @@ import type { createColumnFieldOptions } from './helpers';
export const EditMetricField: React.FC<{ export const EditMetricField: React.FC<{
label?: string; label?: string;
columnId: IBusterMetricChartConfig['metricColumnId']; columnId: BusterMetricChartConfig['metricColumnId'];
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
columnFieldOptions: ReturnType<typeof createColumnFieldOptions>; columnFieldOptions: ReturnType<typeof createColumnFieldOptions>;
rowCount: number; rowCount: number;
onUpdateMetricField: (config: { onUpdateMetricField: (config: {
metricColumnId: string; metricColumnId: string;
metricValueAggregate?: DerivedMetricTitle['aggregate']; metricValueAggregate?: DerivedMetricTitle['aggregate'];
}) => void; }) => void;
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = React.memo( }> = React.memo(
({ ({
columnId, columnId,
@ -82,9 +82,9 @@ export const EditMetricField: React.FC<{
EditMetricField.displayName = 'EditMetricField'; EditMetricField.displayName = 'EditMetricField';
const StylingPopover: React.FC<{ const StylingPopover: React.FC<{
metricColumnId: IBusterMetricChartConfig['metricColumnId']; metricColumnId: BusterMetricChartConfig['metricColumnId'];
columnLabelFormat: IBusterMetricChartConfig['columnLabelFormats'][string]; columnLabelFormat: BusterMetricChartConfig['columnLabelFormats'][string];
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
rowCount: number; rowCount: number;
}> = React.memo(({ metricColumnId, columnLabelFormat, rowCount }) => { }> = React.memo(({ metricColumnId, columnLabelFormat, rowCount }) => {
return ( return (

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { Select, type SelectItem } from '@/components/ui/select'; import { Select, type SelectItem } from '@/components/ui/select';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { LabelAndInput } from '../../Common'; import { LabelAndInput } from '../../Common';
@ -26,11 +26,11 @@ const allOptions: SelectItem<'custom' | 'columnTitle' | 'columnValue' | 'none'>[
const onlyCustomOptions = [allOptions[0], allOptions[1]]; const onlyCustomOptions = [allOptions[0], allOptions[1]];
export const EditMetricHeader: React.FC<{ export const EditMetricHeader: React.FC<{
header: IBusterMetricChartConfig['metricHeader'] | IBusterMetricChartConfig['metricSubHeader']; header: BusterMetricChartConfig['metricHeader'] | BusterMetricChartConfig['metricSubHeader'];
type: 'header' | 'subHeader'; type: 'header' | 'subHeader';
firstColumnId: string; firstColumnId: string;
hideDerivedMetricOption: boolean; hideDerivedMetricOption: boolean;
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = React.memo(({ header, type, firstColumnId, hideDerivedMetricOption, onUpdateChartConfig }) => { }> = React.memo(({ header, type, firstColumnId, hideDerivedMetricOption, onUpdateChartConfig }) => {
const selectedOption = useMemo(() => { const selectedOption = useMemo(() => {
if (header === null) return 'none'; if (header === null) return 'none';

View File

@ -1,6 +1,6 @@
import last from 'lodash/last'; import last from 'lodash/last';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { ColumnLabelFormat } from '@/api/asset_interfaces/metric/charts'; import type { ColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
import type { SelectItem } from '@/components/ui/select'; import type { SelectItem } from '@/components/ui/select';
import { Select } from '@/components/ui/select'; import { Select } from '@/components/ui/select';
@ -8,7 +8,7 @@ import { useMemoizedFn } from '@/hooks';
import { isNumericColumnStyle, isNumericColumnType } from '@/lib'; import { isNumericColumnStyle, isNumericColumnType } from '@/lib';
import { LabelAndInput } from '../../Common'; import { LabelAndInput } from '../../Common';
export const AGGREGATE_OPTIONS: SelectItem<IBusterMetricChartConfig['metricValueAggregate']>[] = [ export const AGGREGATE_OPTIONS: SelectItem<BusterMetricChartConfig['metricValueAggregate']>[] = [
{ label: 'Sum', value: 'sum' }, { label: 'Sum', value: 'sum' },
{ label: 'Average', value: 'average' }, { label: 'Average', value: 'average' },
{ label: 'Median', value: 'median' }, { label: 'Median', value: 'median' },
@ -19,9 +19,9 @@ export const AGGREGATE_OPTIONS: SelectItem<IBusterMetricChartConfig['metricValue
]; ];
export const EditMetricAggregate: React.FC<{ export const EditMetricAggregate: React.FC<{
aggregate: IBusterMetricChartConfig['metricValueAggregate']; aggregate: BusterMetricChartConfig['metricValueAggregate'];
columnId?: string; columnId?: string;
onUpdateAggregate: (aggregate: IBusterMetricChartConfig['metricValueAggregate']) => void; onUpdateAggregate: (aggregate: BusterMetricChartConfig['metricValueAggregate']) => void;
columnLabelFormat: ColumnLabelFormat | undefined; columnLabelFormat: ColumnLabelFormat | undefined;
}> = React.memo(({ aggregate, onUpdateAggregate, columnId, columnLabelFormat }) => { }> = React.memo(({ aggregate, onUpdateAggregate, columnId, columnLabelFormat }) => {
const isNumberColumn = columnLabelFormat?.columnType const isNumberColumn = columnLabelFormat?.columnType
@ -38,7 +38,7 @@ export const EditMetricAggregate: React.FC<{
}, [aggregate, disableOptions]); }, [aggregate, disableOptions]);
const onUpdateMetricValueAggregate = useMemoizedFn((value: string) => { const onUpdateMetricValueAggregate = useMemoizedFn((value: string) => {
onUpdateAggregate(value as IBusterMetricChartConfig['metricValueAggregate']); onUpdateAggregate(value as BusterMetricChartConfig['metricValueAggregate']);
}); });
return ( return (

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { ColumnMetaData, IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { ColumnMetaData, BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { DerivedMetricTitle } from '@/api/asset_interfaces/metric/charts'; import type { DerivedMetricTitle } from '@/api/asset_interfaces/metric/charts';
import { Separator } from '@/components/ui/seperator'; import { Separator } from '@/components/ui/seperator';
import { useUpdateMetricChart } from '@/context/Metrics'; import { useUpdateMetricChart } from '@/context/Metrics';
@ -12,12 +12,12 @@ import { createColumnFieldOptions } from './helpers';
export const StylingMetric: React.FC<{ export const StylingMetric: React.FC<{
className?: string; className?: string;
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
metricHeader: IBusterMetricChartConfig['metricHeader']; metricHeader: BusterMetricChartConfig['metricHeader'];
metricSubHeader: IBusterMetricChartConfig['metricSubHeader']; metricSubHeader: BusterMetricChartConfig['metricSubHeader'];
rowCount: number; rowCount: number;
metricValueAggregate: IBusterMetricChartConfig['metricValueAggregate']; metricValueAggregate: BusterMetricChartConfig['metricValueAggregate'];
metricColumnId: IBusterMetricChartConfig['metricColumnId']; metricColumnId: BusterMetricChartConfig['metricColumnId'];
columnMetadata: ColumnMetaData[]; columnMetadata: ColumnMetaData[];
}> = ({ }> = ({
className, className,
@ -31,7 +31,7 @@ export const StylingMetric: React.FC<{
}) => { }) => {
const { onUpdateMetricChartConfig } = useUpdateMetricChart(); const { onUpdateMetricChartConfig } = useUpdateMetricChart();
const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<IBusterMetricChartConfig>) => { const onUpdateChartConfig = useMemoizedFn((chartConfig: Partial<BusterMetricChartConfig>) => {
onUpdateMetricChartConfig({ chartConfig }); onUpdateMetricChartConfig({ chartConfig });
}); });
@ -82,12 +82,12 @@ export const StylingMetric: React.FC<{
}; };
const PrimaryMetricStyling: React.FC<{ const PrimaryMetricStyling: React.FC<{
metricColumnId: IBusterMetricChartConfig['metricColumnId']; metricColumnId: BusterMetricChartConfig['metricColumnId'];
metricValueAggregate: IBusterMetricChartConfig['metricValueAggregate']; metricValueAggregate: BusterMetricChartConfig['metricValueAggregate'];
columnFieldOptions: ReturnType<typeof createColumnFieldOptions>; columnFieldOptions: ReturnType<typeof createColumnFieldOptions>;
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
rowCount: number; rowCount: number;
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = ({ }> = ({
metricColumnId, metricColumnId,
columnLabelFormats, columnLabelFormats,
@ -104,7 +104,7 @@ const PrimaryMetricStyling: React.FC<{
metricColumnId: string; metricColumnId: string;
metricValueAggregate?: DerivedMetricTitle['aggregate']; metricValueAggregate?: DerivedMetricTitle['aggregate'];
}) => { }) => {
const newConfig: Partial<IBusterMetricChartConfig> = { const newConfig: Partial<BusterMetricChartConfig> = {
metricColumnId metricColumnId
}; };
if (metricValueAggregate) { if (metricValueAggregate) {
@ -116,7 +116,7 @@ const PrimaryMetricStyling: React.FC<{
); );
const onUpdateAggregate = useMemoizedFn( const onUpdateAggregate = useMemoizedFn(
(aggregate: IBusterMetricChartConfig['metricValueAggregate']) => { (aggregate: BusterMetricChartConfig['metricValueAggregate']) => {
onUpdateChartConfig({ metricValueAggregate: aggregate }); onUpdateChartConfig({ metricValueAggregate: aggregate });
} }
); );
@ -142,12 +142,12 @@ const PrimaryMetricStyling: React.FC<{
}; };
const HeaderMetricStyling: React.FC<{ const HeaderMetricStyling: React.FC<{
header: IBusterMetricChartConfig['metricHeader'] | IBusterMetricChartConfig['metricSubHeader']; header: BusterMetricChartConfig['metricHeader'] | BusterMetricChartConfig['metricSubHeader'];
columnFieldOptions: ReturnType<typeof createColumnFieldOptions>; columnFieldOptions: ReturnType<typeof createColumnFieldOptions>;
rowCount: number; rowCount: number;
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'];
type: 'header' | 'subHeader'; type: 'header' | 'subHeader';
onUpdateChartConfig: (chartConfig: Partial<IBusterMetricChartConfig>) => void; onUpdateChartConfig: (chartConfig: Partial<BusterMetricChartConfig>) => void;
}> = ({ header, type, columnFieldOptions, rowCount, columnLabelFormats, onUpdateChartConfig }) => { }> = ({ header, type, columnFieldOptions, rowCount, columnLabelFormats, onUpdateChartConfig }) => {
const isStringHeader = typeof header === 'string'; const isStringHeader = typeof header === 'string';
const isObjectHeader = typeof header === 'object'; const isObjectHeader = typeof header === 'object';
@ -187,7 +187,7 @@ const HeaderMetricStyling: React.FC<{
); );
const onUpdateAggregate = useMemoizedFn( const onUpdateAggregate = useMemoizedFn(
(aggregate: IBusterMetricChartConfig['metricValueAggregate']) => { (aggregate: BusterMetricChartConfig['metricValueAggregate']) => {
const key = type === 'header' ? 'metricHeader' : 'metricSubHeader'; const key = type === 'header' ? 'metricHeader' : 'metricSubHeader';
const newConfig: DerivedMetricTitle = { const newConfig: DerivedMetricTitle = {
columnId: (header as DerivedMetricTitle)?.columnId, columnId: (header as DerivedMetricTitle)?.columnId,

View File

@ -1,11 +1,11 @@
import type { ColumnMetaData, IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { ColumnMetaData, BusterMetricChartConfig } from '@/api/asset_interfaces';
import type { SelectItem } from '@/components/ui/select'; import type { SelectItem } from '@/components/ui/select';
import { formatLabel } from '@/lib'; import { formatLabel } from '@/lib';
import { ColumnTypeIcon } from '../SelectAxis/config'; import { ColumnTypeIcon } from '../SelectAxis/config';
export const createColumnFieldOptions = ( export const createColumnFieldOptions = (
columnMetadata: ColumnMetaData[], columnMetadata: ColumnMetaData[],
columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats'], columnLabelFormats: BusterMetricChartConfig['columnLabelFormats'],
iconClass: string iconClass: string
): SelectItem<string>[] => { ): SelectItem<string>[] => {
return columnMetadata.map<SelectItem<string>>((column) => { return columnMetadata.map<SelectItem<string>>((column) => {

View File

@ -1,13 +1,13 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import type { BusterMetricData, DataMetadata, IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetricData, BusterMetric } from '@/api/asset_interfaces/metric';
import { ChartType } from '@/api/asset_interfaces/metric/charts'; import type { DataMetadata } from '@buster/server-shared/metrics';
import { BusterChart } from '@/components/ui/charts'; import { BusterChart } from '@/components/ui/charts';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
import { METRIC_CHART_CONTAINER_ID } from './config'; import { METRIC_CHART_CONTAINER_ID } from './config';
interface MetricViewChartContentProps { interface MetricViewChartContentProps {
className?: string; className?: string;
chartConfig: IBusterMetric['chart_config']; chartConfig: BusterMetric['chart_config'];
metricData: BusterMetricData['data']; metricData: BusterMetricData['data'];
dataMetadata: DataMetadata | undefined; dataMetadata: DataMetadata | undefined;
fetchedData: boolean; fetchedData: boolean;

View File

@ -1,7 +1,7 @@
import type { import type {
ColumnMetaData, ColumnMetaData,
IBusterMetric, BusterMetric,
IBusterMetricChartConfig BusterMetricChartConfig
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import type { import type {
BusterChartConfigProps, BusterChartConfigProps,
@ -57,9 +57,9 @@ export const didColumnDataChange = (
* @returns A new chart configuration suitable for the changed SQL data * @returns A new chart configuration suitable for the changed SQL data
*/ */
export const simplifyChatConfigForSQLChange = ( export const simplifyChatConfigForSQLChange = (
chartConfig: IBusterMetricChartConfig, chartConfig: BusterMetricChartConfig,
data_metadata: IBusterMetric['data_metadata'] data_metadata: BusterMetric['data_metadata']
): IBusterMetricChartConfig => { ): BusterMetricChartConfig => {
// Create a new mapping of column name to format settings // Create a new mapping of column name to format settings
// This preserves existing format settings only when the column type hasn't changed // This preserves existing format settings only when the column type hasn't changed
const columnLabelFormats = data_metadata?.column_metadata?.reduce< const columnLabelFormats = data_metadata?.column_metadata?.reduce<

View File

@ -1,6 +1,7 @@
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRef } from 'react'; import { useRef } from 'react';
import type { BusterMetricData, IBusterMetricChartConfig } from '@/api/asset_interfaces/metric'; import type { ChartConfigProps } from '@buster/server-shared/metrics';
import type { BusterMetricData } from '@/api/asset_interfaces/metric';
import type { RunSQLResponse } from '@/api/asset_interfaces/sql'; import type { RunSQLResponse } from '@/api/asset_interfaces/sql';
import { useRunSQL as useRunSQLQuery } from '@/api/buster_rest'; import { useRunSQL as useRunSQLQuery } from '@/api/buster_rest';
import { useGetLatestMetricVersionMemoized, useUpdateMetric } from '@/api/buster_rest/metrics'; import { useGetLatestMetricVersionMemoized, useUpdateMetric } from '@/api/buster_rest/metrics';
@ -38,7 +39,7 @@ export const useMetricRunSQL = () => {
const getLatestMetricVersion = useGetLatestMetricVersionMemoized(); const getLatestMetricVersion = useGetLatestMetricVersionMemoized();
const originalConfigs = useRef<{ const originalConfigs = useRef<{
chartConfig: IBusterMetricChartConfig; chartConfig: ChartConfigProps;
sql: string; sql: string;
data: BusterMetricData['data']; data: BusterMetricData['data'];
dataMetadata: BusterMetricData['data_metadata']; dataMetadata: BusterMetricData['data_metadata'];
@ -88,7 +89,7 @@ export const useMetricRunSQL = () => {
const newColumnData = data_metadata?.column_metadata; const newColumnData = data_metadata?.column_metadata;
const didDataMetadataChange = didColumnDataChange(oldColumnData, newColumnData); const didDataMetadataChange = didColumnDataChange(oldColumnData, newColumnData);
const totallyDefaultChartConfig: IBusterMetricChartConfig = didDataMetadataChange const totallyDefaultChartConfig: ChartConfigProps = didDataMetadataChange
? simplifyChatConfigForSQLChange(metricMessage.chart_config, data_metadata) ? simplifyChatConfigForSQLChange(metricMessage.chart_config, data_metadata)
: metricMessage.chart_config; : metricMessage.chart_config;

View File

@ -1,10 +1,10 @@
import type { ColumnLabelFormat } from '@buster/server-shared/metrics';
import { import {
type ColumnLabelFormat,
DEFAULT_COLUMN_LABEL_FORMAT, DEFAULT_COLUMN_LABEL_FORMAT,
DEFAULT_DATE_FORMAT_DAY_OF_WEEK, DEFAULT_DATE_FORMAT_DAY_OF_WEEK,
DEFAULT_DATE_FORMAT_MONTH_OF_YEAR, DEFAULT_DATE_FORMAT_MONTH_OF_YEAR,
DEFAULT_DATE_FORMAT_QUARTER DEFAULT_DATE_FORMAT_QUARTER
} from '@/api/asset_interfaces/metric'; } from '@buster/server-shared/metrics';
import { formatDate } from './date'; import { formatDate } from './date';
import { formatNumber, roundNumber } from './numbers'; import { formatNumber, roundNumber } from './numbers';
import { makeHumanReadble } from './text'; import { makeHumanReadble } from './text';

View File

@ -1,12 +1,12 @@
import type React from 'react'; import type React from 'react';
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import type { BusterMetricData, IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetricData, BusterMetric } from '@/api/asset_interfaces/metric';
import { downloadImageData, exportElementToImage } from './exportUtils'; import { downloadImageData, exportElementToImage } from './exportUtils';
import { timeout } from './timeout'; import { timeout } from './timeout';
export const generateChartDownloadImage = async ( export const generateChartDownloadImage = async (
message: IBusterMetric, message: BusterMetric,
messageData: NonNullable<BusterMetricData['data']>, messageData: NonNullable<BusterMetricData['data']>,
isDark = false isDark = false
) => { ) => {
@ -61,7 +61,7 @@ export const generateChartDownloadImage = async (
export const generateChartPreviewImage = async ( export const generateChartPreviewImage = async (
message: { message: {
chart_config: IBusterMetric['chart_config']; chart_config: BusterMetric['chart_config'];
} | null, } | null,
messageData: BusterMetricData, messageData: BusterMetricData,
isDark = true isDark = true
@ -77,7 +77,7 @@ export const generateChartPreviewImage = async (
const container = ( const container = (
<PreviewImageReactComponent <PreviewImageReactComponent
message={message as IBusterMetric} message={message as BusterMetric}
messageData={messageData} messageData={messageData}
isDark={isDark} isDark={isDark}
/> />
@ -149,7 +149,7 @@ const ChartPreviewImage = ({
message, message,
messageData messageData
}: { }: {
message: IBusterMetric; message: BusterMetric;
messageData: BusterMetricData; messageData: BusterMetricData;
}) => { }) => {
const data = messageData?.data || []; const data = messageData?.data || [];
@ -174,7 +174,7 @@ const ChartPreviewImage = ({
export const PreviewImageReactComponent: React.FC<{ export const PreviewImageReactComponent: React.FC<{
message: { message: {
chart_config: IBusterMetric['chart_config']; chart_config: BusterMetric['chart_config'];
} | null; } | null;
messageData: BusterMetricData; messageData: BusterMetricData;
isDark: boolean; isDark: boolean;
@ -210,7 +210,7 @@ export const PreviewImageReactComponent: React.FC<{
}`}> }`}>
{BusterLogo} {BusterLogo}
{hasData && message?.chart_config ? ( {hasData && message?.chart_config ? (
<ChartPreviewImage message={message as IBusterMetric} messageData={messageData} /> <ChartPreviewImage message={message as BusterMetric} messageData={messageData} />
) : ( ) : (
<div <div
className={`${isDark ? 'text-stone-400' : 'text-stone-700'}`} className={`${isDark ? 'text-stone-400' : 'text-stone-700'}`}

View File

@ -3,7 +3,7 @@ import {
type ColumnLabelFormat, type ColumnLabelFormat,
type ColumnMetaData, type ColumnMetaData,
DEFAULT_COLUMN_LABEL_FORMAT, DEFAULT_COLUMN_LABEL_FORMAT,
type IBusterMetricChartConfig, type BusterMetricChartConfig,
type IColumnLabelFormat, type IColumnLabelFormat,
type SimplifiedColumnType type SimplifiedColumnType
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
@ -12,7 +12,7 @@ import { isDateColumnType, isNumericColumnType, simplifyColumnType } from '@/lib
export const createDefaultColumnLabelFormats = ( export const createDefaultColumnLabelFormats = (
columnLabelFormats: Record<string, IColumnLabelFormat> | undefined, columnLabelFormats: Record<string, IColumnLabelFormat> | undefined,
columnsMetaData: ColumnMetaData[] | undefined columnsMetaData: ColumnMetaData[] | undefined
): IBusterMetricChartConfig['columnLabelFormats'] => { ): BusterMetricChartConfig['columnLabelFormats'] => {
if (!columnsMetaData) return {}; if (!columnsMetaData) return {};
return columnsMetaData.reduce( return columnsMetaData.reduce(
@ -25,7 +25,7 @@ export const createDefaultColumnLabelFormats = (
}); });
return acc; return acc;
}, },
{} as IBusterMetricChartConfig['columnLabelFormats'] {} as BusterMetricChartConfig['columnLabelFormats']
); );
}; };

View File

@ -2,17 +2,17 @@ import { create } from 'mutative';
import { import {
type ColumnMetaData, type ColumnMetaData,
DEFAULT_COLUMN_SETTINGS, DEFAULT_COLUMN_SETTINGS,
type IBusterMetricChartConfig type BusterMetricChartConfig
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import type { ColumnSettings } from '@/api/asset_interfaces/metric/charts'; import type { ColumnSettings } from '@/api/asset_interfaces/metric/charts';
export const createDefaultColumnSettings = ( export const createDefaultColumnSettings = (
existingColumnSettings: Record<string, ColumnSettings> | undefined, existingColumnSettings: Record<string, ColumnSettings> | undefined,
columnsMetaData: ColumnMetaData[] | undefined columnsMetaData: ColumnMetaData[] | undefined
): IBusterMetricChartConfig['columnSettings'] => { ): BusterMetricChartConfig['columnSettings'] => {
if (!columnsMetaData) return {}; if (!columnsMetaData) return {};
return create({} as IBusterMetricChartConfig['columnSettings'], (draft) => { return create({} as BusterMetricChartConfig['columnSettings'], (draft) => {
for (const column of columnsMetaData) { for (const column of columnsMetaData) {
draft[column.name] = create(DEFAULT_COLUMN_SETTINGS, (settingsDraft) => { draft[column.name] = create(DEFAULT_COLUMN_SETTINGS, (settingsDraft) => {
if (existingColumnSettings?.[column.name]) { if (existingColumnSettings?.[column.name]) {

View File

@ -1,13 +1,12 @@
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import { create } from 'mutative'; import { create } from 'mutative';
import { type BusterMetric, type BusterMetricChartConfig } from '@/api/asset_interfaces/metric';
import { import {
type BusterMetric,
type DataMetadata,
DEFAULT_CHART_CONFIG, DEFAULT_CHART_CONFIG,
DEFAULT_CHART_CONFIG_ENTRIES, DEFAULT_CHART_CONFIG_ENTRIES,
type IBusterMetricChartConfig type ChartConfigProps,
} from '@/api/asset_interfaces/metric'; type DataMetadata
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric/charts'; } from '@buster/server-shared/metrics';
import { import {
createDefaultBarAndLineAxis, createDefaultBarAndLineAxis,
createDefaultPieAxis, createDefaultPieAxis,
@ -18,27 +17,27 @@ import { createDefaultColumnSettings } from './createDefaultColumnSettings';
const keySpecificHandlers: Partial< const keySpecificHandlers: Partial<
Record< Record<
keyof IBusterMetricChartConfig, keyof BusterMetricChartConfig,
( (
value: unknown, value: unknown,
dataMetadata: DataMetadata | undefined, dataMetadata: DataMetadata | undefined,
pieChartAxis: IBusterMetricChartConfig['pieChartAxis'] | undefined pieChartAxis: BusterMetricChartConfig['pieChartAxis'] | undefined
) => unknown ) => unknown
> >
> = { > = {
colors: (value: unknown) => { colors: (value: unknown) => {
const colors = value as IBusterMetricChartConfig['colors']; const colors = value as BusterMetricChartConfig['colors'];
if (isEmpty(colors)) return DEFAULT_CHART_CONFIG.colors; if (isEmpty(colors)) return DEFAULT_CHART_CONFIG.colors;
if (colors.length >= 3) return colors; //we need at least 3 colors for the chart icons if (colors.length >= 3) return colors; //we need at least 3 colors for the chart icons
return Array.from({ length: 3 }, (_, index) => colors[index % colors.length]); return Array.from({ length: 3 }, (_, index) => colors[index % colors.length]);
}, },
scatterDotSize: (value: unknown) => { scatterDotSize: (value: unknown) => {
const scatterDotSize = value as IBusterMetricChartConfig['scatterDotSize']; const scatterDotSize = value as BusterMetricChartConfig['scatterDotSize'];
if (isEmpty(scatterDotSize)) return DEFAULT_CHART_CONFIG.scatterDotSize; if (isEmpty(scatterDotSize)) return DEFAULT_CHART_CONFIG.scatterDotSize;
return scatterDotSize; return scatterDotSize;
}, },
barAndLineAxis: (value: unknown, dataMetadata) => { barAndLineAxis: (value: unknown, dataMetadata) => {
const barAndLineAxis = value as IBusterMetricChartConfig['barAndLineAxis']; const barAndLineAxis = value as BusterMetricChartConfig['barAndLineAxis'];
if (isEmpty(barAndLineAxis)) { if (isEmpty(barAndLineAxis)) {
return createDefaultBarAndLineAxis(dataMetadata?.column_metadata); return createDefaultBarAndLineAxis(dataMetadata?.column_metadata);
} }
@ -50,7 +49,7 @@ const keySpecificHandlers: Partial<
}; };
}, },
pieChartAxis: (value: unknown, dataMetadata) => { pieChartAxis: (value: unknown, dataMetadata) => {
const pieChartAxis = value as IBusterMetricChartConfig['pieChartAxis']; const pieChartAxis = value as BusterMetricChartConfig['pieChartAxis'];
if (isEmpty(pieChartAxis)) return createDefaultPieAxis(dataMetadata?.column_metadata); if (isEmpty(pieChartAxis)) return createDefaultPieAxis(dataMetadata?.column_metadata);
return { return {
x: pieChartAxis.x || DEFAULT_CHART_CONFIG.pieChartAxis.x, x: pieChartAxis.x || DEFAULT_CHART_CONFIG.pieChartAxis.x,
@ -59,7 +58,7 @@ const keySpecificHandlers: Partial<
}; };
}, },
scatterAxis: (value: unknown, dataMetadata) => { scatterAxis: (value: unknown, dataMetadata) => {
const scatterAxis = value as IBusterMetricChartConfig['scatterAxis']; const scatterAxis = value as BusterMetricChartConfig['scatterAxis'];
if (isEmpty(scatterAxis)) return createDefaultScatterAxis(dataMetadata?.column_metadata); if (isEmpty(scatterAxis)) return createDefaultScatterAxis(dataMetadata?.column_metadata);
return { return {
x: scatterAxis.x || DEFAULT_CHART_CONFIG.scatterAxis.x, x: scatterAxis.x || DEFAULT_CHART_CONFIG.scatterAxis.x,
@ -70,7 +69,7 @@ const keySpecificHandlers: Partial<
}; };
}, },
comboChartAxis: (value: unknown, dataMetadata) => { comboChartAxis: (value: unknown, dataMetadata) => {
const comboChartAxis = value as IBusterMetricChartConfig['comboChartAxis']; const comboChartAxis = value as BusterMetricChartConfig['comboChartAxis'];
if (isEmpty(comboChartAxis)) return createDefaultBarAndLineAxis(dataMetadata?.column_metadata); if (isEmpty(comboChartAxis)) return createDefaultBarAndLineAxis(dataMetadata?.column_metadata);
return { return {
x: comboChartAxis.x || DEFAULT_CHART_CONFIG.comboChartAxis.x, x: comboChartAxis.x || DEFAULT_CHART_CONFIG.comboChartAxis.x,
@ -81,7 +80,7 @@ const keySpecificHandlers: Partial<
}; };
}, },
metricColumnId: (value: unknown, dataMetadata) => { metricColumnId: (value: unknown, dataMetadata) => {
const metricColumnId = value as IBusterMetricChartConfig['metricColumnId']; const metricColumnId = value as BusterMetricChartConfig['metricColumnId'];
if (isEmpty(metricColumnId)) { if (isEmpty(metricColumnId)) {
const firstNumberColumn = dataMetadata?.column_metadata?.find( const firstNumberColumn = dataMetadata?.column_metadata?.find(
(m) => m.simple_type === 'number' (m) => m.simple_type === 'number'
@ -91,25 +90,25 @@ const keySpecificHandlers: Partial<
return metricColumnId; return metricColumnId;
}, },
metricHeader: (value: unknown) => { metricHeader: (value: unknown) => {
const metricHeader = value as IBusterMetricChartConfig['metricHeader']; const metricHeader = value as BusterMetricChartConfig['metricHeader'];
if (isEmpty(metricHeader)) return DEFAULT_CHART_CONFIG.metricHeader; if (isEmpty(metricHeader)) return DEFAULT_CHART_CONFIG.metricHeader;
return metricHeader; return metricHeader;
}, },
metricSubHeader: (value: unknown) => { metricSubHeader: (value: unknown) => {
const metricSubHeader = value as IBusterMetricChartConfig['metricSubHeader']; const metricSubHeader = value as BusterMetricChartConfig['metricSubHeader'];
if (isEmpty(metricSubHeader)) return DEFAULT_CHART_CONFIG.metricSubHeader; if (isEmpty(metricSubHeader)) return DEFAULT_CHART_CONFIG.metricSubHeader;
return metricSubHeader; return metricSubHeader;
}, },
columnLabelFormats: (value: unknown, dataMetadata) => { columnLabelFormats: (value: unknown, dataMetadata) => {
const columnLabelFormats = value as IBusterMetricChartConfig['columnLabelFormats']; const columnLabelFormats = value as BusterMetricChartConfig['columnLabelFormats'];
return createDefaultColumnLabelFormats(columnLabelFormats, dataMetadata?.column_metadata); return createDefaultColumnLabelFormats(columnLabelFormats, dataMetadata?.column_metadata);
}, },
columnSettings: (value: unknown, dataMetadata) => { columnSettings: (value: unknown, dataMetadata) => {
const columnSettings = value as IBusterMetricChartConfig['columnSettings']; const columnSettings = value as BusterMetricChartConfig['columnSettings'];
return createDefaultColumnSettings(columnSettings, dataMetadata?.column_metadata); return createDefaultColumnSettings(columnSettings, dataMetadata?.column_metadata);
}, },
pieLabelPosition: (value: unknown, dataMetadata, pieChartAxis) => { pieLabelPosition: (value: unknown, dataMetadata, pieChartAxis) => {
const pieLabelPosition = value as IBusterMetricChartConfig['pieLabelPosition']; const pieLabelPosition = value as BusterMetricChartConfig['pieLabelPosition'];
// if (isEmpty(pieLabelPosition)) { // if (isEmpty(pieLabelPosition)) {
// const firstPieColumn = pieChartAxis?.x?.[0]; // const firstPieColumn = pieChartAxis?.x?.[0];
// const firstPieColumnMetaData = dataMetadata?.column_metadata?.find( // const firstPieColumnMetaData = dataMetadata?.column_metadata?.find(
@ -124,14 +123,14 @@ const keySpecificHandlers: Partial<
export const createDefaultChartConfig = ( export const createDefaultChartConfig = (
message: Pick<BusterMetric, 'chart_config' | 'data_metadata'> message: Pick<BusterMetric, 'chart_config' | 'data_metadata'>
): IBusterMetricChartConfig => { ): BusterMetricChartConfig => {
const chartConfig: BusterChartConfigProps | undefined = message.chart_config; const chartConfig: ChartConfigProps | undefined = message.chart_config;
const dataMetadata = message.data_metadata; const dataMetadata = message.data_metadata;
const pieChartAxis = chartConfig?.pieChartAxis; const pieChartAxis = chartConfig?.pieChartAxis;
const newChartConfig = create(DEFAULT_CHART_CONFIG, (draft) => { const newChartConfig = create(DEFAULT_CHART_CONFIG, (draft) => {
for (const [_key, defaultValue] of DEFAULT_CHART_CONFIG_ENTRIES) { for (const [_key, defaultValue] of DEFAULT_CHART_CONFIG_ENTRIES) {
const key = _key as keyof IBusterMetricChartConfig; const key = _key as keyof BusterMetricChartConfig;
const chartConfigValue = chartConfig?.[key]; const chartConfigValue = chartConfig?.[key];
const handler = keySpecificHandlers[key]; const handler = keySpecificHandlers[key];

View File

@ -1,9 +1,9 @@
import { DEFAULT_IBUSTER_METRIC, type IBusterMetric } from '@/api/asset_interfaces/metric'; import { DEFAULT_IBUSTER_METRIC, type BusterMetric } from '@/api/asset_interfaces/metric';
export const resolveEmptyMetric = ( export const resolveEmptyMetric = (
metric: IBusterMetric | undefined, metric: BusterMetric | undefined,
metricId: string metricId: string
): IBusterMetric => { ): BusterMetric => {
if (!metric || !metric?.id) { if (!metric || !metric?.id) {
return { ...DEFAULT_IBUSTER_METRIC, ...metric, id: metricId }; return { ...DEFAULT_IBUSTER_METRIC, ...metric, id: metricId };
} }

View File

@ -1,10 +1,10 @@
import isEqual from 'lodash/isEqual'; import isEqual from 'lodash/isEqual';
import type { DataMetadata, IBusterMetric } from '@/api/asset_interfaces/metric'; import type { DataMetadata, BusterMetric } from '@/api/asset_interfaces/metric';
import { import {
DEFAULT_CHART_CONFIG_ENTRIES, DEFAULT_CHART_CONFIG_ENTRIES,
DEFAULT_COLUMN_LABEL_FORMAT, DEFAULT_COLUMN_LABEL_FORMAT,
DEFAULT_COLUMN_SETTINGS, DEFAULT_COLUMN_SETTINGS,
type IBusterMetricChartConfig type BusterMetricChartConfig
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import type { import type {
BarAndLineAxis, BarAndLineAxis,
@ -23,15 +23,15 @@ const DEFAULT_COLUMN_SETTINGS_ENTRIES = Object.entries(DEFAULT_COLUMN_SETTINGS);
const DEFAULT_COLUMN_LABEL_FORMATS_ENTRIES = Object.entries(DEFAULT_COLUMN_LABEL_FORMAT); const DEFAULT_COLUMN_LABEL_FORMATS_ENTRIES = Object.entries(DEFAULT_COLUMN_LABEL_FORMAT);
export const getChangedTopLevelMessageValues = ( export const getChangedTopLevelMessageValues = (
newMetric: IBusterMetric, newMetric: BusterMetric,
oldMetric: IBusterMetric oldMetric: BusterMetric
) => { ) => {
const changes = getChangedValues(oldMetric, newMetric, ['name', 'status', 'sql', 'file']); const changes = getChangedValues(oldMetric, newMetric, ['name', 'status', 'sql', 'file']);
return changes; return changes;
}; };
const keySpecificHandlers: Partial< const keySpecificHandlers: Partial<
Record<keyof IBusterMetricChartConfig, (value: unknown) => unknown> Record<keyof BusterMetricChartConfig, (value: unknown) => unknown>
> = { > = {
barAndLineAxis: (value: unknown) => value as BarAndLineAxis, barAndLineAxis: (value: unknown) => value as BarAndLineAxis,
scatterAxis: (value: unknown) => value as ScatterAxis, scatterAxis: (value: unknown) => value as ScatterAxis,
@ -97,14 +97,14 @@ const keySpecificHandlers: Partial<
} }
}; };
export const getChangesFromDefaultChartConfig = (newMetric: IBusterMetric) => { export const getChangesFromDefaultChartConfig = (newMetric: BusterMetric) => {
const chartConfig = newMetric.chart_config; const chartConfig = newMetric.chart_config;
if (!chartConfig) return {} as BusterChartConfigProps; if (!chartConfig) return {} as BusterChartConfigProps;
const diff: Partial<IBusterMetricChartConfig> = {}; const diff: Partial<BusterMetricChartConfig> = {};
for (const [_key, defaultValue] of DEFAULT_CHART_CONFIG_ENTRIES) { for (const [_key, defaultValue] of DEFAULT_CHART_CONFIG_ENTRIES) {
const key = _key as keyof IBusterMetricChartConfig; const key = _key as keyof BusterMetricChartConfig;
const chartConfigValue = chartConfig[key]; const chartConfigValue = chartConfig[key];
const handler = keySpecificHandlers[key]; const handler = keySpecificHandlers[key];
@ -127,7 +127,7 @@ export const getChangesFromDefaultChartConfig = (newMetric: IBusterMetric) => {
}; };
export const combineChangeFromDefaultChartConfig = ( export const combineChangeFromDefaultChartConfig = (
newMetric: IBusterMetric, newMetric: BusterMetric,
dataMetadata: DataMetadata dataMetadata: DataMetadata
) => { ) => {
const chartConfig = createDefaultChartConfig({ const chartConfig = createDefaultChartConfig({
@ -138,8 +138,8 @@ export const combineChangeFromDefaultChartConfig = (
}; };
export const prepareMetricUpdateMetric = ( export const prepareMetricUpdateMetric = (
newMetric: IBusterMetric, newMetric: BusterMetric,
prevMetric: IBusterMetric prevMetric: BusterMetric
): Parameters<typeof updateMetric>[0] | null => { ): Parameters<typeof updateMetric>[0] | null => {
const changedTopLevelValues = getChangedTopLevelMessageValues( const changedTopLevelValues = getChangedTopLevelMessageValues(
newMetric, newMetric,

View File

@ -2,16 +2,16 @@ import {
ChartEncodes, ChartEncodes,
ChartType, ChartType,
ColumnMetaData, ColumnMetaData,
IBusterMetricChartConfig BusterMetricChartConfig
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
export interface SelectChartTypeProps { export interface SelectChartTypeProps {
selectedChartType: ChartType; selectedChartType: ChartType;
lineGroupType: IBusterMetricChartConfig['lineGroupType']; lineGroupType: BusterMetricChartConfig['lineGroupType'];
barGroupType: IBusterMetricChartConfig['barGroupType']; barGroupType: BusterMetricChartConfig['barGroupType'];
barLayout: IBusterMetricChartConfig['barLayout']; barLayout: BusterMetricChartConfig['barLayout'];
colors: string[]; colors: string[];
columnMetadata: ColumnMetaData[]; columnMetadata: ColumnMetaData[];
columnSettings: IBusterMetricChartConfig['columnSettings']; columnSettings: BusterMetricChartConfig['columnSettings'];
selectedAxis: ChartEncodes; selectedAxis: ChartEncodes;
} }

View File

@ -1,5 +1,5 @@
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import type { IBusterMetricChartConfig } from '@/api/asset_interfaces'; import type { BusterMetricChartConfig } from '@/api/asset_interfaces';
import { ChartType } from '@/api/asset_interfaces/metric/charts'; import { ChartType } from '@/api/asset_interfaces/metric/charts';
import { CHART_ICON_LIST, ChartIconType, DETERMINE_SELECTED_CHART_TYPE_ORDER } from './config'; import { CHART_ICON_LIST, ChartIconType, DETERMINE_SELECTED_CHART_TYPE_ORDER } from './config';
import type { SelectChartTypeProps } from './chartIcon.types'; import type { SelectChartTypeProps } from './chartIcon.types';
@ -37,7 +37,7 @@ export const getSelectedChartTypeConfig = (
const chartTypeMethod: Record< const chartTypeMethod: Record<
ChartIconType, ChartIconType,
() => Partial<IBusterMetricChartConfig> & { () => Partial<BusterMetricChartConfig> & {
hasAreaStyle?: boolean; hasAreaStyle?: boolean;
} }
> = { > = {
@ -130,14 +130,14 @@ export const disableTypeMethod: Record<
export const selectedChartTypeMethod = ( export const selectedChartTypeMethod = (
chartIconType: ChartIconType, chartIconType: ChartIconType,
columnSettings: IBusterMetricChartConfig['columnSettings'] columnSettings: BusterMetricChartConfig['columnSettings']
): Partial<IBusterMetricChartConfig> => { ): Partial<BusterMetricChartConfig> => {
const fullRes = chartTypeMethod[chartIconType](); const fullRes = chartTypeMethod[chartIconType]();
const hasAreaStyle = !!fullRes.hasAreaStyle; const hasAreaStyle = !!fullRes.hasAreaStyle;
const resOmitted = omit(fullRes, 'hasAreaStyle'); const resOmitted = omit(fullRes, 'hasAreaStyle');
if (resOmitted.selectedChartType === 'line') { if (resOmitted.selectedChartType === 'line') {
const newColumnSettings: IBusterMetricChartConfig['columnSettings'] = Object.fromEntries( const newColumnSettings: BusterMetricChartConfig['columnSettings'] = Object.fromEntries(
Object.entries(columnSettings).map(([key, value]) => [ Object.entries(columnSettings).map(([key, value]) => [
key, key,
{ {

View File

@ -1,10 +1,10 @@
import type { BusterMetric, IBusterMetric } from '@/api/asset_interfaces/metric'; import type { BusterMetric, BusterMetric } from '@/api/asset_interfaces/metric';
import { createDefaultChartConfig } from './messageAutoChartHandler'; import { createDefaultChartConfig } from './messageAutoChartHandler';
export const upgradeMetricToIMetric = ( export const upgradeMetricToIMetric = (
metric: BusterMetric, metric: BusterMetric,
oldMetric: IBusterMetric | null | undefined oldMetric: BusterMetric | null | undefined
): IBusterMetric => { ): BusterMetric => {
const chart_config = createDefaultChartConfig(metric); const chart_config = createDefaultChartConfig(metric);
return { return {
...oldMetric, ...oldMetric,

View File

@ -1,12 +1,12 @@
import { import {
type BusterMetricListItem, type BusterMetricListItem,
ChartType, ChartType,
type DataMetadata,
DEFAULT_CHART_CONFIG, DEFAULT_CHART_CONFIG,
type IBusterMetric, type BusterMetric,
type IBusterMetricChartConfig type BusterMetricChartConfig
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import { ShareRole, VerificationStatus } from '@/api/asset_interfaces/share'; import { ShareRole, VerificationStatus } from '@/api/asset_interfaces/share';
import type { DataMetadata } from '@buster/server-shared/metrics';
// Utility functions for predictable mock data generation // Utility functions for predictable mock data generation
const CHART_TYPES: ChartType[] = ['bar', 'table', 'line', 'pie', 'scatter', 'metric']; const CHART_TYPES: ChartType[] = ['bar', 'table', 'line', 'pie', 'scatter', 'metric'];
@ -62,7 +62,7 @@ const generatePredictableEmail = (id: string): string => {
return `${name}.${hash % 100}@${domain}`; return `${name}.${hash % 100}@${domain}`;
}; };
const createMockChartConfig = (id: string): IBusterMetricChartConfig => { const createMockChartConfig = (id: string): BusterMetricChartConfig => {
const hash = Array.from(id).reduce((acc, char) => acc + char.charCodeAt(0), 0); const hash = Array.from(id).reduce((acc, char) => acc + char.charCodeAt(0), 0);
const chartType: ChartType = CHART_TYPES[hash % CHART_TYPES.length]; const chartType: ChartType = CHART_TYPES[hash % CHART_TYPES.length];
@ -126,7 +126,7 @@ const dataMetadata: DataMetadata = {
row_count: 10 row_count: 10
}; };
export const createMockMetric = (id: string): IBusterMetric => { export const createMockMetric = (id: string): BusterMetric => {
const chart_config = createMockChartConfig(id); const chart_config = createMockChartConfig(id);
return { return {

View File

@ -1,4 +1,5 @@
import type { BusterMetricData, DataMetadata } from '@/api/asset_interfaces/metric'; import type { BusterMetricData } from '@/api/asset_interfaces/metric';
import type { DataMetadata } from '@buster/server-shared/metrics';
const PRODUCTS = [ const PRODUCTS = [
'Laptop', 'Laptop',

Some files were not shown because too many files have changed in this diff Show More