Remove report components from boards and sanitize saved layouts

This commit is contained in:
Mike Cao 2026-02-12 21:32:14 -08:00
parent 57c4a6ed51
commit b09694ddb6
2 changed files with 31 additions and 69 deletions

View file

@ -5,6 +5,7 @@ import { v4 as uuid } from 'uuid';
import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks';
import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery';
import type { Board, BoardParameters } from '@/lib/types';
import { getComponentDefinition } from './boardComponentRegistry';
export type LayoutGetter = () => Partial<BoardParameters> | null;
@ -27,6 +28,29 @@ const createDefaultBoard = (): Partial<Board> => ({
},
});
function sanitizeBoardParameters(parameters?: BoardParameters): BoardParameters | undefined {
if (!parameters?.rows) {
return parameters;
}
return {
...parameters,
rows: parameters.rows.map(row => ({
...row,
columns: row.columns.map(column => {
if (column.component && !getComponentDefinition(column.component.type)) {
return {
...column,
component: null,
};
}
return column;
}),
})),
};
}
export function BoardProvider({
boardId,
editing = false,
@ -52,7 +76,10 @@ export function BoardProvider({
useEffect(() => {
if (data) {
setBoard(data);
setBoard({
...data,
parameters: sanitizeBoardParameters(data.parameters),
});
}
}, [data]);
@ -74,7 +101,9 @@ export function BoardProvider({
// Get current layout sizes from BoardBody if registered
const layoutData = layoutGetterRef.current?.();
const parameters = layoutData ? { ...board.parameters, ...layoutData } : board.parameters;
const parameters = sanitizeBoardParameters(
layoutData ? { ...board.parameters, ...layoutData } : board.parameters,
);
const result = await mutateAsync({
...board,

View file

@ -1,12 +1,4 @@
import type { ComponentType } from 'react';
import { Attribution } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution';
import { Breakdown } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/Breakdown';
import { Funnel } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel';
import { Goal } from '@/app/(main)/websites/[websiteId]/(reports)/goals/Goal';
import { Journey } from '@/app/(main)/websites/[websiteId]/(reports)/journeys/Journey';
import { Retention } from '@/app/(main)/websites/[websiteId]/(reports)/retention/Retention';
import { Revenue } from '@/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue';
import { UTM } from '@/app/(main)/websites/[websiteId]/(reports)/utm/UTM';
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { WebsiteMetricsBar } from '@/app/(main)/websites/[websiteId]/WebsiteMetricsBar';
import { EventsChart } from '@/components/metrics/EventsChart';
@ -36,7 +28,6 @@ export const CATEGORIES = [
{ key: 'overview', name: 'Overview' },
{ key: 'tables', name: 'Tables' },
{ key: 'visualization', name: 'Visualization' },
{ key: 'reports', name: 'Reports' },
] as const;
const METRIC_TYPES = [
@ -130,64 +121,6 @@ const componentDefinitions: ComponentDefinition[] = [
category: 'visualization',
component: EventsChart,
},
// Reports
{
type: 'Retention',
name: 'Retention',
description: 'User retention cohort analysis',
category: 'reports',
component: Retention,
},
{
type: 'Funnel',
name: 'Funnel',
description: 'Conversion funnel visualization',
category: 'reports',
component: Funnel,
},
{
type: 'Goal',
name: 'Goal',
description: 'Goal tracking and progress',
category: 'reports',
component: Goal,
},
{
type: 'Journey',
name: 'Journey',
description: 'User navigation flow',
category: 'reports',
component: Journey,
},
{
type: 'UTM',
name: 'UTM',
description: 'UTM campaign performance',
category: 'reports',
component: UTM,
},
{
type: 'Revenue',
name: 'Revenue',
description: 'Revenue analytics and trends',
category: 'reports',
component: Revenue,
},
{
type: 'Attribution',
name: 'Attribution',
description: 'Traffic source attribution',
category: 'reports',
component: Attribution,
},
{
type: 'Breakdown',
name: 'Breakdown',
description: 'Multi-dimensional data breakdown',
category: 'reports',
component: Breakdown,
},
];
const definitionMap = new Map(componentDefinitions.map(def => [def.type, def]));