mirror of https://github.com/buster-so/buster.git
update server shared to include new types
This commit is contained in:
parent
7364f328d4
commit
4cdde9203f
|
@ -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>;
|
|
|
@ -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: {}
|
|
||||||
// };
|
|
|
@ -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>;
|
|
|
@ -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';
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>;
|
|
|
@ -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>;
|
|
|
@ -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
|
|
||||||
};
|
|
|
@ -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';
|
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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'];
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
|
@ -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}</>;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
|
@ -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;
|
},
|
||||||
}, {})
|
{}
|
||||||
|
)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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'}>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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 }) => {
|
||||||
|
|
|
@ -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']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
},
|
||||||
}, {})
|
{}
|
||||||
|
)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
({
|
({
|
||||||
|
|
|
@ -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[];
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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' }) => {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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> &
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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<
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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'}`}
|
||||||
|
|
|
@ -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']
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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]) {
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue