mirror of
https://github.com/umami-software/umami.git
synced 2026-02-16 02:25:35 +01:00
Remove report components from boards and sanitize saved layouts
This commit is contained in:
parent
57c4a6ed51
commit
b09694ddb6
2 changed files with 31 additions and 69 deletions
|
|
@ -5,6 +5,7 @@ import { v4 as uuid } from 'uuid';
|
||||||
import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks';
|
import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks';
|
||||||
import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery';
|
import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery';
|
||||||
import type { Board, BoardParameters } from '@/lib/types';
|
import type { Board, BoardParameters } from '@/lib/types';
|
||||||
|
import { getComponentDefinition } from './boardComponentRegistry';
|
||||||
|
|
||||||
export type LayoutGetter = () => Partial<BoardParameters> | null;
|
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({
|
export function BoardProvider({
|
||||||
boardId,
|
boardId,
|
||||||
editing = false,
|
editing = false,
|
||||||
|
|
@ -52,7 +76,10 @@ export function BoardProvider({
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
setBoard(data);
|
setBoard({
|
||||||
|
...data,
|
||||||
|
parameters: sanitizeBoardParameters(data.parameters),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
|
|
@ -74,7 +101,9 @@ export function BoardProvider({
|
||||||
|
|
||||||
// Get current layout sizes from BoardBody if registered
|
// Get current layout sizes from BoardBody if registered
|
||||||
const layoutData = layoutGetterRef.current?.();
|
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({
|
const result = await mutateAsync({
|
||||||
...board,
|
...board,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,4 @@
|
||||||
import type { ComponentType } from 'react';
|
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 { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
|
||||||
import { WebsiteMetricsBar } from '@/app/(main)/websites/[websiteId]/WebsiteMetricsBar';
|
import { WebsiteMetricsBar } from '@/app/(main)/websites/[websiteId]/WebsiteMetricsBar';
|
||||||
import { EventsChart } from '@/components/metrics/EventsChart';
|
import { EventsChart } from '@/components/metrics/EventsChart';
|
||||||
|
|
@ -36,7 +28,6 @@ export const CATEGORIES = [
|
||||||
{ key: 'overview', name: 'Overview' },
|
{ key: 'overview', name: 'Overview' },
|
||||||
{ key: 'tables', name: 'Tables' },
|
{ key: 'tables', name: 'Tables' },
|
||||||
{ key: 'visualization', name: 'Visualization' },
|
{ key: 'visualization', name: 'Visualization' },
|
||||||
{ key: 'reports', name: 'Reports' },
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const METRIC_TYPES = [
|
const METRIC_TYPES = [
|
||||||
|
|
@ -130,64 +121,6 @@ const componentDefinitions: ComponentDefinition[] = [
|
||||||
category: 'visualization',
|
category: 'visualization',
|
||||||
component: EventsChart,
|
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]));
|
const definitionMap = new Map(componentDefinitions.map(def => [def.type, def]));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue